2012-06-18 21 views
36

En la misma solución, hay una aplicación ASP.NET MVC4 Slick.App y una biblioteca de clases Awesome.Mvc.Lib. Awesome.Mvc.Lib contiene una clase de controlador.Controlador en ensamblaje y enrutamiento separados

public class ShinnyController : Controller 
{ 
    [HttpGet] 
    public string Index() 
    { 
     return "Hello, from Awesome.Mvc.Lib"; 
    } 
} 

Si tan sólo añadir la referencia de Slick.App a Awesome.Mvc.Lib, ejecutar la aplicación y el punto Brower a /shinny, voy a ver realmente la respuesta "Hola, desde Awesome.Mvc.Lib".

Esto es algo que no espero en absoluto. Todo el tiempo pensé que ASP.NET MVC respeta los espacios de nombres allí donde los controladores colocaron. Por lo tanto, los controladores de otros espacios de nombres no están expuestos, al menos antes de que yo no lo pidiera.

Traté de cambiar el registro de ruta predeterminado, para usar el parámetro de espacios de nombres.

routes.MapRoute(
     name: "Default", 
     url: "{controller}/{action}/{id}", 
     defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }, 
     namespaces: new [] { "Slick.App.Controllers" } 
    ); 

Aún así, la ruta ShinnyController todavía coincide con '/ shinny'.

Tengo una preocupación de que este es el comportamiento predeterminado. Mi pregunta es, ¿cómo decir explícitamente qué controladores están expuestos y evitar que la ruta predeterminada coincida con los controladores en una biblioteca de clases separada?

Respuesta

30

La lista de espacios de nombres de la ruta sólo se da prioridad a determinados espacios de nombres más de los otros, que no figuran:

new [] {"Namespace1", "Namespace2"} 

no da mayor prioridad a namespace1 como cabría esperar, sino simplemente da prioridad a ambos espacios de nombres sobre los demás.

Esto significa que los espacios de nombres en la lista se buscan primero para los controladores y luego, si no se encuentra coincidencia, se usan el resto de los controladores disponibles con ese nombre.

Puede suprimir el uso de controladores no priorizados por hacer esto:

var myRoute = routes.MapRoute(
     name: "Default", 
     url: "{controller}/{action}/{id}", 
     defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }, 
     namespaces: new [] { "Slick.App.Controllers" } 
    ); 

myRoute.DataTokens["UseNamespaceFallback"] = false; 
3

Puede heredar de DefaultControllerFactory así:

public class CustomControllerFactory : DefaultControllerFactory 
{ 
    protected override Type GetControllerType(System.Web.Routing.RequestContext requestContext, string controllerName) 
    { 
     var type = base.GetControllerType(requestContext, controllerName); 

     if (type != null && IsIngored(type)) 
     { 
      return null; 
     } 

     return type; 
    } 

    public static bool IsIngored(Type type) 
    { 
     return type.Assembly.GetCustomAttributes(typeof(IgnoreAssemblyAttribute), false).Any() 
      || type.GetCustomAttributes(typeof(IgnoreControllerAttribute), false).Any(); 
    } 
} 

Entonces algunos cambios a Global.asax

protected void Application_Start() 
    { 
     AreaRegistration.RegisterAllAreas(); 

     RegisterGlobalFilters(GlobalFilters.Filters); 
     RegisterRoutes(RouteTable.Routes); 

     ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory()); 
    } 

¡Y aquí está! Cualquier tipo marcado con IgnoreControllerAttribute no estará visible. Incluso puedes ocultar todo el conjunto.

Si necesita algún comportamiento basado configuración, no es una gran cosa para hacer todos los cambios necesarios;)

+1

Desafortunadamente, esto no es exactamente lo que es mi problema. Mi problema es que no tengo acceso a la aplicación de host, por lo que la creación de la fábrica de controlador personalizado no funcionaría para mí. –

+0

@alexanderb: No, puede hacer esto, usando esto: [assembly: System.Web.PreApplicationStartMethod (typeof (MvcTools.Hooks.PreApplicationStartCode), "Start")], consulte este enlace: http: //blog.davidebbo. com/2011/02/register-your-http-modules-at-runtime.html En el inicio, usted hace esto: System.Web.Mvc.ControllerBuilder.Current.SetControllerFactory (YOUR_ControllerFactory)); Todo lo que necesita hacer es conseguir que la aplicación host cargue su dll, lo que puede lograr mediante una entrada web.config;) –

Cuestiones relacionadas