2010-02-22 22 views
5

Tengo un sitio MVC 2 básico (RC2) con un controlador de nivel base ("Inicio") y un área ("Administrador") con un controlador ("Resumen"). Cuando llamo al http://website/Abstract, se llama al Controlador abstracto en el área de Administrador aunque no he especificado el Área en la URL. Para empeorar las cosas - no parece saber que está bajo administración porque no puede encontrar la vista asociada y sólo devuelve:ASP.NET MVC 2 RC 2 devuelve controlador específico de área cuando no hay área especificada

The view 'Index' or its master was not found. The following locations were searched: 
~/Views/Abstract/Index.aspx 
~/Views/Abstract/Index.ascx 
~/Views/Shared/Index.aspx 
~/Views/Shared/Index.ascx 

estoy haciendo algo mal? ¿Es esto un error? ¿Una característica?

+0

¿qué piensan todos de esto: http://stackoverflow.com/questions/2314524/asp-net-mvc-2-rc-2-returns-area-specific-controller-when-no-area-specified es básicamente decir que mi problema es por diseño y la única forma de evitarlo es codificar las rutas a cada controlador en el espacio de nombres predeterminado. – Bryan

+0

arriba el enlace al comentario de haack es incorrecto. una correcta: http://stackoverflow.com/questions/1639971/mvc-2-arearegistration-routes-order/1640825#1640825 – Bryan

+0

Sin ver las rutas que ha definido tanto en su área como en su sitio principal, es imposible contar. – Haacked

Respuesta

11

Mi amigo y yo estábamos experimentando el mismo problema con las zonas en ASP.NET MVC 2. Encontramos un "hack" que, hasta ahora, parece estar funcionando. Para la versión de tl; dr, vea la parte inferior de esta respuesta.

usted probablemente tiene algo similar a la siguiente en la clase "AdminAreaRegistration.cs" su zona "administrador" de:

// Web/Areas/Admin/AdminAreaRegistration.cs 

public override void RegisterArea(AreaRegistrationContext context) { 
    context.MapRoute(
     "Admin_default", 
     "Admin/{controller}/{action}/{id}", 
     new { action = "Index", id = UrlParameter.Optional } 
    ); 
} 

Por lo tanto, debe tener sentido de que cuando se hace una petición de "http://website/Abstract" , la ruta "Admin_default" no coincide con la solicitud. Entonces, por diseño, el marco MVC intenta hacer coincidir la solicitud con cualquier otra ruta definida. Si utilizó las herramientas de MVC en Visual Studio para crear su proyecto web, tendrá una ruta "Predeterminada" definida en su archivo "Global.asax" (en la raíz de su proyecto web). Debe tener un aspecto similar a este:

// Web/Global.asax.cs 

public static void RegisterRoutes(RouteCollection routes) { 
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 

    routes.MapRoute(
     "Default", 
     "{controller}/{action}/{id}", 
     new {controller = "Home", action = "Index", id = UrlParameter.Optional} 
    ); 
} 

La ruta "por defecto" tiene éxito en la adecuación de la solicitud de "http://website/Abstract", con "controlador" = "acción" "Resumen" = (valor por defecto) "Índice", e "id" = UrlParameter.Optional (valor predeterminado). Esta es la conducta correcta y prevista ... hasta ahora.

Ahora, la estructura MVC intentará cargar el Controlador "Abstracto". Por diseño, MVC buscará una clase llamada "AbstractController" que extienda "Controller" en cualquier lugar dentro de la jerarquía de archivos/espacios de nombres del proyecto web. Es importante tener en cuenta que la ubicación del archivo y el espacio de nombres de un Controlador no afectan la capacidad de MVC para encontrarlo; en otras palabras, solo porque ha colocado el "AbstractController" dentro de una carpeta llamada "Areas \ Admin \ Controllers" y ha cambiado el espacio de nombres para que sea "Web.Areas.Admin.Controllers" en lugar de, digamos, "Web.Controllers" , no significa que MVC no lo usará.

Cuando MVC ejecuta la acción "Index" en "AbstractController" que, muy probablemente, simplemente devuelva "View()", entonces MVC se confunde porque no sabe dónde encontrar la vista "Index". Como MVC ha coincidido con una ruta que no es de área (la ruta "Predeterminada" en Global.asax), cree que la vista coincidente debe ubicarse en carpetas que no sean de área. De este modo se obtiene el mensaje de error conocido:

The view 'Index' or its master was not found. The following locations were searched: 
~/Views/Abstract/Index.aspx 
~/Views/Abstract/Index.ascx 
~/Views/Shared/Index.aspx 
~/Views/Shared/Index.ascx 

Nosotros, al igual que usted, no quería que las solicitudes de "http://website/Abstract" para resolver a "AbstractController" zona "administrador" de; solo "http://website/Admin/Abstract" debería funcionar. No puedo pensar por qué alguien querría este comportamiento.

Una solución simple es eliminar la ruta "Predeterminada" en Global.asax, pero esto romperá cualquier Controlador/Vistas regular que no sea de área. Probablemente esta no sea una opción para la mayoría de las personas ...

Por lo tanto, pensamos que podría restringir el conjunto de controladores que MVC usaría para solicitudes coincidentes por la ruta "por defecto" en Global.asax:

// Web/Global.asax.cs 

public static void RegisterRoutes(RouteCollection routes) { 
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 

    routes.MapRoute(
     "Default", 
     "{controller}/{action}/{id}", 
     new {controller = "Home", action = "Index", id = UrlParameter.Optional}, 
     new[] {"Web.Controllers"} // Added this line 
    ); 
} 

Nop. Una solicitud para "http://website/Abstract" será todavía use "AbstractController" dentro del área "Administrador", aunque el espacio de nombres "AbstractController" sea "Web.Areas.Admin.Controllers" y (claramente) no "Web.Controllers" . Esto es completamente confuso; parece que esta lista blanca no tiene efecto diferible en la resolución del controlador MVC.

- tl; dr respuesta comienza aquí -

Después de algún piratería, nos dimos cuenta de cómo forzar MVC utilizar sólo los controladores dentro del espacio de nombres (s) de la lista blanca.

// Web/Global.asax.cs 

public static void RegisterRoutes(RouteCollection routes) { 
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 

    routes.MapRoute(
     "Default", 
     "{controller}/{action}/{id}", 
     new {controller = "Home", action = "Index", id = UrlParameter.Optional}, 
     new[] {"Web.Controllers"} 
    ).DataTokens["UseNamespaceFallback"] = false; // Added this line 
} 

establecer la clave "UseNamespaceFallback" del diccionario DataTokens en la ruta "por defecto" false. Ahora, cuando realizamos una solicitud de "http://website/Abstract", la ruta "Predeterminada" seguirá coincidiendo (¡esto es un comportamiento válido!) Pero MVC no utilizará ningún Controlador que no esté dentro del (los) espacio (s) de nombre definidos; en este caso, solo los Controladores dentro del espacio de nombres "Web.Controllers" son válidos. ¡Finalmente, esta es la funcionalidad que estábamos buscando! No podemos entender por qué este no es el comportamiento predeterminado. Extraño, ¿eh?

Espero que esto ayude.

+0

gracias por la respuesta detallada. la mejor respuesta que he visto hasta ahora. había recurrido a rutas de codificación estricta para todos mis controladores raíz. – Bryan

+0

esta es una gran respuesta. Acabo de conocer el mismo comportamiento y realmente sorprendido con él, en realidad. –

1

¿Ha configurado su enrutamiento correctamente? Cuando usa áreas, debe cambiar manualmente su código de enrutamiento para que MVC busque en los espacios de nombres correctos.

http://haacked.com/archive/2010/01/12/ambiguous-controller-names.aspx

+0

El artículo de Haack trata principalmente de aclarar los problemas relacionados con los nombres duplicados de los controladores. Intenté agregar el espacio de nombres del controlador predeterminado a mi ruta predeterminada, pero no ayuda. Parece que hay algo de confusión en cuanto a lo que realmente hace: http://stackoverflow.com/questions/721700/asp-net-mvc-controller-namespace-array Algunas personas piensan que solo da prioridad a cierto espacio de nombres, pero todas las otros aún son buscados. – Bryan

Cuestiones relacionadas