2011-06-14 13 views
9

Quiero ser capaz de reorganizar mi estructura de sitio ASP.NET MVC para que coincida más con la forma en que Rails lo hace (Hacemos ambos raíles y ASP.net en mi empresa).Cómo modificar el archivo estático ASP.NET MVC raíz

En Rails, hay una carpeta "pública" que se comporta como la raíz del sitio. Por ejemplo, podría colocar un "test.html" y acceder al archivo con la url http://domain.com/test.html que serviría el archivo estático html.

En asp.net MVC hay una carpeta de "Contenido" que quiero comportarme como la raíz. Entonces, en lugar de acceder a http://domain.com/content/myfile.html, quiero poder hacer http://domain.com/myfile.html.

sé que sólo puede soltar el archivo en la raíz del proyecto, pero tengo que hacer esto con muchos archivos, incluyendo CSS, JS, HTML, imágenes, etc y quiero compartir algunos activos estandarizados a través de los carriles y aspnetmvc.

¿Hay alguna manera de hacerlo?

Respuesta

8

Hay otra posible solución. En lugar de usar código, puede usar una regla de reescritura para manejar esto por usted. Si está utilizando IIS 7 o superior, puede usar el Módulo de reescritura de URL de Microsoft.

Una regla como la siguiente, probablemente lo haría:

<rule name="Rewrite static files to content" stopProcessing="true"> 
    <match url="^([^/]+(?:\.css|\.js))$" /> 
    <conditions> 
     <add input="{APPL_PHYSICAL_PATH}content{SCRIPT_NAME}" matchType="IsFile" /> 
    </conditions> 
    <action type="Rewrite" url="/content/{R:1}" /> 
</rule> 

Las verificaciones de la regla para una petición a un css o js limar la raíz del sitio. Luego verifica si el archivo existe en la carpeta de contenido. Si existe, entonces la reescritura devolverá el archivo en la carpeta de contenido. Solo he probado esto un poco, pero parece funcionar. Ciertamente necesita más pruebas y posible refinamiento.

+0

Esa es una buena idea. Pensamiento muy inteligente. – NerdFury

+0

Esta parece ser la forma más eficiente de hacerlo tanto en esfuerzo como en rendimiento. Voy a intentar esto. ¡Gracias! – AlbertVo

2

La única solución que se me ocurre es utilizar un controlador personalizado y una ruta para hacer esto por usted. Pero no es una solución limpia.

Primero necesita una clase PublicController con un método de acción GetFile. Esto supone que todos los archivos están en la carpeta pública/de contenido directamente. Manejar carpetas hace las cosas más complicadas.

public class PublicController : Controller 
{ 
    private IDictionary<String, String> mimeTypes = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) 
                 {{"css", "text/css"}, {"jpg", "image/jpg"}}; 

    public ActionResult GetFile(string file) 
    { 
     var path = Path.Combine(Server.MapPath("~/Content"), file); 

     if (!System.IO.File.Exists(path)) throw new HttpException(404, "File Not Found"); 
     var extension = GetExtension(file); // psuedocode 
     var mimetype = mimeTypes.ContainsKey(extension) ? mimeTypes[extension] : "text/plain"; 
     return File(path, mimetype); 
    } 
} 

Ahora, sólo tendrá una ruta cerca de la parte inferior de la lista de rutas que tiene este aspecto:

routes.MapRoute("PublicContent", "{file}", new {controller = "Public", action = "GetFile"}); 

El problema es, ahora, cuando usted acaba de poner en un nombre de controlador como 'Home 'en lugar de utilizar el método de acción Índice en el HomeController, supone que desea descargar un archivo llamado "Inicio" desde el directorio de contenido. Por lo tanto, por encima de la ruta del archivo, deberá agregar una ruta para cada controlador, de modo que sepa para obtener la acción Índice.

routes.MapRoute("HomeIndex", "Home", new { controller = "Home", action = "Index" }); 

lo tanto, una forma de evitar eso es cambiar la ruta a:

routes.MapRoute("PublicContent", "{file}.{extension}", new {controller = "Public", action = "GetFile"}); 

Y el método de acción a esto:

public ActionResult GetFile(string file, string extension) 
    { 
     var path = Path.Combine(Server.MapPath("~/Content"), file + "." + extension); 

     if (!System.IO.File.Exists(path)) throw new HttpException(404, "File Not Found"); 

     var mimetype = mimeTypes.ContainsKey(extension) ? mimeTypes[extension] : "text/plain"; 
     return File(path, mimetype); 
    } 

Como dije, esto supone que todos los archivos están en el directorio de contenido y no en subcarpetas. Pero si lo que quería hacer subcarpetas como contenido/css/site.css se podría añadir sus rutas como esta:

 routes.MapRoute("PublicContent_sub", "{subfolder}/{file}.{extension}", new { controller = "Public", action = "GetFileInFolder" }); 
     routes.MapRoute("PublicContent", "{file}.{extension}", new { controller = "Public", action = "GetFile"}); 

Ahora el método de acción tiene que cambiar también.

public ActionResult GetFile(string file, string extension) 
    { 
     return GetFileInFolder("", file, extension); 
    } 

    public ActionResult GetFileInFolder(string subfolder, string file, string extension) 
    { 
     var path = Path.Combine(Server.MapPath("~/Content"), subfolder, file + "." + extension); 

     if (!System.IO.File.Exists(path)) throw new HttpException(404, "File Not Found"); 

     var mimetype = mimeTypes.ContainsKey(extension) ? mimeTypes[extension] : "text/plain"; 
     return File(path, mimetype); 
    } 

Si comienza a obtener varios niveles de profundidad en la estructura de carpetas, esto se vuelve más feo y feo. Pero tal vez esto funcione para ti. Estoy seguro de que estabas esperando una casilla de verificación en las propiedades del proyecto, pero si hay una, no lo sé.

+0

Gracias por tomarse el tiempo para explicar todo eso. Sí, eso es un poco más complicado de lo que esperaba. Esperaba que hubiera una manera de anular el comportamiento similar a la forma en que puedes crear tu propio viewEngine para anular ViewPathLocations. – AlbertVo

+0

@AlbertVo - Sí, nada de eso, por lo que sé. La convención sobre la configuración algunas veces significa que las cosas no funcionan de la manera que usted desea. Pero ciertamente es posible que yo tampoco sepa algo. – NerdFury

+0

Esto definitivamente funcionará, pero no me gusta esa idea porque obliga a que cada solicitud de archivos estáticos pase por toda la canalización del framework. IIS7 servirá los archivos estáticos ** mucho ** más rápido directamente. Una regla de reescritura de URL debería ofrecer un mejor rendimiento. –

Cuestiones relacionadas