2015-12-16 19 views
10

Sto provando a limitare i controller delle mie rotte ASP.NET Core a un determinato spazio dei nomi.Limita il percorso allo spazio dei nomi del controller in ASP.NET Core

Nelle versioni precedenti di ASP.NET MVC si verificava un sovraccarico che ha fornito un parametro string[] namespaces durante l'aggiunta di route. Questo non è presente in ASP.NET MVC 6. Così, dopo un po 'googling, ho provato a giocare con qualcosa di simile

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 
    ); 
}); 

ma non sembra fare quello che voglio. C'è un modo per limitare il motore di routing a un determinato spazio dei nomi?

Aggiornamento

Ho appena realizzato che può avere qualcosa a che fare con il fatto che sto usando l'attributo di routing su ogni singolo controllore? L'attributo routing funk su i percorsi definiti da app.UseMvc()?

Aggiornamento 2

Maggiori dettagli:

Ho due progetti Web API completamente indipendenti. Per inciso, alcuni dei percorsi sono identici in entrambi (ad esempio ~/api/ping). Questi progetti sono indipendenti nella produzione, uno è un endpoint per gli utenti, uno è un endpoint per gli amministratori.

Ho anche dei test unitari, utilizzando Microsoft.AspNet.TestHost. Alcuni di questi test di unità richiedono la funzionalità di entrambi questi progetti di API Web (ovvero richiedono l'endpoint "admin" per configurare completamente un caso di test per "utente"). Ma quando mi riferisco entrambi i progetti API, il testhost si confonde a causa dei percorsi identici e lamenta "molteplici percorsi corrispondenti":

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

"percorsi di corrispondenza multipli": puoi inserire l'errore completo con traccia dello stack qui? –

+0

Certo, per favore vedi la mia domanda aggiornata. –

risposta

13

Aggiornamento:

ho trovato la soluzione attraverso l'utilizzo ActionConstraint . Devi aggiungere l'attributo Vincolo di azione personalizzato per le azioni duplicate.

Esempio con metodi di indice duplicati.

Prima HomeController

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

Seconda HomeController

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

configurare il routing

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

vincolo azione

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; 
     } 
    } 
} 

Prima risposta:

Vuol attribuiscono instradamento funk i percorsi definiti da app.UseMvc()?

L'instradamento degli attributi e il routing basato su convenzione (routes.MapRoute(...) funzionano in modo indipendente.E le rotte attribuiscono un vantaggio rispetto alle rotte convenzionali.

ma non sembra fare quello che voglio. C'è un modo per limitare il motore di routing a un determinato spazio dei nomi?

Answer from developers:

Invece di utilizzare un elenco di spazi dei nomi di raggruppare i controllori si consiglia di utilizzare le aree. È possibile attribuire i controller (indipendentemente dal gruppo in cui si trovano) con un'area specifica e quindi creare una rotta per quell'area.

È possibile visualizzare un sito Web di test che mostra un esempio di utilizzo di Aree in MVC 6 qui: https://github.com/aspnet/Mvc/tree/dev/test/WebSites/RoutingWebSite.

Esempio usando Area con convenzione a base di routing

regolatore:

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

} 

Configurare convenzione Instradamento basato:

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

Esempio con Zona con attributo-based routing

//Reached through /admin/users 
//have to be located into: project_root/Areas/Admin/ 
[Area("Admin")] 
[Route("[area]/[controller]/[action]", Name = "[area]_[controller]_[action]")] 
public class UsersController : Controller 
{ 

} 
+0

Grazie per la tua eccellente risposta. Questo sicuramente funziona nella maggior parte dei casi, ma penso che sia non ottimale nel mio caso particolare (avrei dovuto fornire maggiori dettagli, lo aggiusterò immediatamente): Ho due progetti API Web completamente indipendenti. Tra l'altro alcuni percorsi sono identici (ad esempio '~/api/ping'). Ho dei test unitari, usando 'Microsoft.AspNet.TestHost'. Alcuni di questi test unitari richiedono la funzionalità di entrambi questi progetti API Web (ad esempio per impostare completamente un caso di test). Ma quando faccio riferimento a entrambi i progetti API, il 'TestHost' viene confuso a causa delle rotte identiche. –

+0

@saxx Ho aggiornato la risposta. –

+0

Grazie mille per il tuo tempo, usare i vincoli di routing qui è un'idea geniale :) Segnerò la tua risposta come la soluzione, te lo meriti sicuramente, ma posterò anche un'altra risposta, perché ho dovuto cambiare leggermente il tuo approccio perché il 'dataTokens' non funzionerà con il routing degli attributi. –

Problemi correlati