2015-12-16 6 views
10

Ich versuche, die Controller meiner ASP.NET Core-Routen auf einen bestimmten Namespace zu beschränken.Route zu Controller-Namespace in ASP.NET Core beschränken

In früheren Versionen von ASP.NET MVC gab es eine Überladung, die beim Hinzufügen von Routen einen string[] namespaces Parameter zur Verfügung stellte. Dies ist in ASP.NET MVC fehlt 6. Nach einiger googeln habe ich versucht, das Spiel mit so etwas wie

app.UseMvc(routes => { 
    var dataTokens = new RouteValueDictionary { 
     { 
      "Namespaces", new[] {"ProjectA.SomeNamespace.Controllers"} 
     } 
    }; 

    routes.MapRoute(
     name: "default", 
     template: "{controller=Home}/{action=Index}/{id?}", 
     defaults: null, 
     constraints: null, 
     dataTokens: dataTokens 
    ); 
}); 

aber es scheint nicht zu tun, was ich will. Gibt es eine Möglichkeit, die Routing-Engine auf einen bestimmten Namespace zu beschränken?

aktualisiert

ich es einfach realisiert werden kann, etwas mit der Tatsache zu tun hat, dass ich Attribut bin mit auf jedem einzelnen Controller-Routing? Führt das Attribut-Routing die von app.UseMvc() definierten Routen durch?

Update 2

Weitere Details:

Ich habe zwei völlig unabhängige Web-API-Projekte. Übrigens sind einige der Routen in beiden identisch (dh ~/api/ping). Diese Projekte sind in der Produktion unabhängig, einer ist ein Endpunkt für Benutzer, einer ist ein Endpunkt für Administratoren.

Ich habe auch Unit-Tests, mit Microsoft.AspNet.TestHost. Einige dieser Komponententests erfordern die Funktionalität beider Web-API-Projekte (z. B. "admin" -Endpunkt zum vollständigen Einrichten eines Testfalls für "Benutzer"). Aber wenn ich beide API-Projekte verweisen, wird die testhost verwirrt wegen der identischen Routen und es beschwert sich über „mehrere passende Routen“:

Microsoft.AspNet.Diagnostics.DeveloperExceptionPageMiddleware: Error: An unhandled exception has occurred while executing the request 
Microsoft.AspNet.Mvc.Infrastructure.AmbiguousActionException: Multiple actions matched. The following actions matched route data and had all constraints satisfied: 
    ProjectA.SomeNamespace.Controllers.PingController.Ping 
    ProjectB.SomeNamespace.Controllers.PingController.Ping 
at Microsoft.AspNet.Mvc.Infrastructure.DefaultActionSelector.SelectAsync(RouteContext context) 
at Microsoft.AspNet.Mvc.Infrastructure.MvcRouteHandler.<RouteAsync>d__6.MoveNext() 
+0

"mehrere übereinstimmende Routen" - können Sie hier einen vollständigen Fehler mit Stack-Trace setzen? –

+0

Sicher, bitte sehen Sie meine aktualisierte Frage. –

Antwort

13

Update:

Ich habe Lösung gefunden durch ActionConstraint mit . Sie müssen ein benutzerdefiniertes Aktionsbeschränkungsattribut für doppelte Aktionen hinzufügen.

Beispiel mit doppelten Indexmethoden.

Erste Homecontroller

namespace WebApplication.Controllers 
{ 
    public class HomeController : Controller 
    { 
     [NamespaceConstraint] 
     public IActionResult Index() 
     { 
      return View(); 
     } 
    } 
} 

Second Homecontroller

namespace WebApplication 
{ 
    public class HomeController : Controller 
    { 
     [NamespaceConstraint] 
     public IActionResult Index() 
     { 
      return View(); 
     } 
    } 
} 

Configure Routing

app.UseMvc(cR => 
    cR.MapRoute("default", "{controller}/{action}", null, null, 
    new { Namespace = "WebApplication.Controllers.HomeController" })); 

Aktion Einschränkung

namespace WebApplication 
{ 
    public class NamespaceConstraint : ActionMethodSelectorAttribute 
    { 
     public override bool IsValidForRequest(RouteContext routeContext, ActionDescriptor action) 
     { 
      var dataTokenNamespace = (string)routeContext.RouteData.DataTokens.FirstOrDefault(dt => dt.Key == "Namespace").Value; 
      var actionNamespace = ((ControllerActionDescriptor)action).MethodInfo.DeclaringType.FullName; 

      return dataTokenNamespace == actionNamespace; 
     } 
    } 
} 

Erste Antwort:

-Attribut Funk-Routing auf den Strecken von app.UseMvc() definiert?

Attribut Routing und Convention-based Routing (routes.MapRoute(...) arbeiten unabhängig voneinander.Und Attribut-Routen haben Vorteile gegenüber herkömmlichen Routen.

aber es scheint nicht zu tun, was ich will. Gibt es eine Möglichkeit, die Routing-Engine auf einen bestimmten Namespace zu beschränken?

Answer from developers:

Anstatt eine Liste von Namensräumen zu gruppieren Ihre Controllern empfehlen wir Bereiche verwenden. Sie können Ihren Controllern (unabhängig davon, in welcher Assembly sie sich befinden) einen bestimmten Bereich zuweisen und dann eine Route für diesen Bereich erstellen.

Sie können eine Testwebsite anzeigen, auf der ein Beispiel für die Verwendung von Bereichen in MVC 6 angezeigt wird: https://github.com/aspnet/Mvc/tree/dev/test/WebSites/RoutingWebSite.

Beispiel für die Verwendung Bereich mit Konvention basierten Routing

Controller:

//Reached through /admin/users 
//have to be located into: project_root/Areas/Admin/ 
[Area("Admin")] 
public class UsersController : Controller 
{ 

} 

konfigurieren Konvention basiertes Routing:

app.UseMvc(routes => 
{ 
     routes.MapRoute(
     "areaRoute", 
     "{area:exists}/{controller}/{action}", 
     new { controller = "Home", action = "Index" }); 
} 

Beispiel für die Verwendung Bereich mit attributbasierten Routing

+0

Vielen Dank für Ihre ausgezeichnete Antwort. Dies funktioniert in den meisten Fällen sicher, aber ich denke, es ist in meinem speziellen Fall suboptimal (ich hätte mehr Details zur Verfügung stellen sollen, ich werde das sofort beheben): Ich habe zwei völlig unabhängige Web-API-Projekte. Übrigens sind einige der Routen identisch (dh "~/api/ping"). Ich habe Komponententests mit 'Microsoft.AspNet.TestHost'. Einige dieser Komponententests erfordern die Funktionalität beider Web-API-Projekte (z. B. um einen Testfall vollständig einzurichten). Aber wenn ich auf beide API-Projekte referenziere, wird der 'TestHost' wegen der identischen Routen verwirrt. –

+0

@saxx Ich habe die Antwort aktualisiert. –

+0

Vielen Dank für Ihre Zeit, Routing-Einschränkungen hier zu verwenden ist eine brilliante Idee :) Ich werde Ihre Antwort als Lösung markieren, Sie haben es definitiv verdient, werden aber auch eine andere Antwort schreiben, weil ich Ihren Ansatz etwas ändern musste, weil Das 'dataTokens' funktioniert nicht mit Attribut-Routing. –