Los puntos en la URL causan 404 con ASP.NET mvc e IIS

303

Tengo un proyecto que requiere que mis URL tengan puntos en la ruta. Por ejemplo, puedo tener una URL como www.example.com/people/michael.phelps

Las URL con el punto generan un 404. Mi enrutamiento está bien. Si paso michaelphelps, sin el punto, entonces todo funciona. Si agrego el punto, obtengo un error 404. El sitio de muestra se ejecuta en Windows 7 con IIS8 Express. URLScan no se está ejecutando.

Intenté agregar lo siguiente a mi web.config:

<security>
  <requestFiltering allowDoubleEscaping="true"/>
</security>

Desafortunadamente eso no hizo la diferencia. Acabo de recibir un error 404.0 No encontrado.

Este es un proyecto MVC4 pero no creo que sea relevante. Mi enrutamiento funciona bien y los parámetros que espero están allí, hasta que incluyan un punto.

¿Qué necesito configurar para poder tener puntos en mi URL?

marca
fuente
93
No puedo creer que haya pasado tanto tiempo en este. La URL funciona bien si agrego una barra inclinada final. Por ejemplo, www.example.com/people/michael.phelps/ sin embargo, sin la barra inclinada final, IIS arroja un error 404.
Mark
15
Mark: eso se debe a que sin la barra inclinada final, IIS cree que es un archivo que debe buscar. Agregar la barra tiene el efecto de ... este no es un archivo real. Además, la siguiente opción de configuración le dice a IIS que si no es un archivo, intente enrutarlo.
Tommy
Tengo el mismo problema después de actualizar mi proyecto a mvc 4 + asp.net 4.5.
Tadeu Maia
Como solución, estoy usando IIS Rewrite para agregar la barra diagonal final a mis URL.
Mark
44
Esto no funciona para mi. La URL funciona bien con "." dentro de la URL, pero cuando está al final da un error
Arcadian

Respuestas:

379

Obtuve esto trabajando editando los controladores HTTP de mi sitio. Para mis necesidades, esto funciona bien y resuelve mi problema.

Simplemente agregué un nuevo controlador HTTP que busca criterios de ruta específicos. Si la solicitud coincide, se envía correctamente a .NET para su procesamiento. Estoy mucho más feliz con esta solución que URLRewrite hackear o habilitar RAMMFAR.

Por ejemplo, para que .NET procese la URL www.example.com/people/michael.phelps agregue la siguiente línea al web.config de su sitio dentro del system.webServer / handlerselemento:

<add name="ApiURIs-ISAPI-Integrated-4.0"
     path="/people/*"
     verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
     type="System.Web.Handlers.TransferRequestHandler"
     preCondition="integratedMode,runtimeVersionv4.0" />

Editar

Hay otras publicaciones que sugieren que la solución a este problema es RAMMFARo RunAllManagedModulesForAllRequests. Habilitar esta opción habilitará todos los módulos administrados para todas las solicitudes. Eso significa que los archivos estáticos como imágenes, PDF y todo lo demás serán procesados ​​por .NET cuando no sea necesario. Es mejor dejar esta opción a menos que tenga un caso específico.

marca
fuente
3
Aquí hay un ejemplo completo stackoverflow.com/a/16607685/801189 basado en esta respuesta
VB
10
después de agregar esto con [ruta = "*"], todas las solicitudes a cualquier archivo estático como .css, .js fallan. Tengo una ruta personalizada que maneja las URL que se parecen a este " dominio / ABCDE.FGHIJ ". Todos mis archivos estáticos están en mi directorio / Content. ¿Hay alguna manera de excluir todo ese directorio de esto? establecer RAMMFAR en trabajos verdaderos pero me gustaría evitar esa sobrecarga.
lamarant
2
IIS local funciona con una barra diagonal inicial, pero IIS8 entiende la ruta solo sin la primera barra diagonal.
Pavel Voronin
2
Tengo el mismo problema que @lamarant ... Bloquea los archivos estáticos. ¿Sabes por qué? Usando MVC4 aquí.
eestein
3
Funciona en MVC5, pero si coloca una barra diagonal al comienzo de la ruta, solo funciona cuando la ruta está inmediatamente después del nombre de host (no es relativo a la carpeta de la aplicación). Por ejemplo, path / people / * funcionaría para www.example.com/people/michael.phelps, pero no para www.example.com/app/people/michael.phelps. AFAIK no hay forma de hacer el camino relativo a la aplicación.
Hogan
46

Después de hurgar un poco, descubrí que relajadoUrlToFileSystemMapping no funcionó en absoluto para mí, lo que funcionó en mi caso fue configurar RAMMFAR en verdadero, lo mismo es válido para (.net 4.0 + mvc3) y (.net 4.5 + mvc4).

<system.webserver>
    <modules runAllManagedModulesForAllRequests="true">

Tenga en cuenta al configurar RAMMFAR la verdadera publicación de Hanselman sobre RAMMFAR y el rendimiento

Tadeu Maia
fuente
55
Tenga en cuenta al configurar RAMMFAR ... ¿Hay alguna pérdida de rendimiento si uso este <modules runAllManagedModulesForAllRequests = "true">
Shanker Paudel
1
En el caso del póster original, no debería ser necesario, ya que está usando IIS7 y superior. Ahí está el valor predeterminado y configurar RAMMFAR le está costando mucho. Ver msdn.microsoft.com/en-us/library/…
Richard
Aunque esto es útil, no fue suficiente para obtener períodos para dejar de devolver 404s en MVC5 / IIS7 para mí.
Chris Moschini
Solo para reiterar: desea evitar que esta opción
esté
Sin embargo, no haga esto en un sitio en vivo, si es posible.
NickG
27

Creo que debe establecer la propiedad RelaxUrlToFileSystemMapping en su web.config. Haack escribió un artículo sobre esto hace un tiempo (y hay otras publicaciones SO que hacen los mismos tipos de preguntas)

<system.web>
<httpRuntime relaxedUrlToFileSystemMapping="true" />

Editar De los comentarios a continuación, las versiones posteriores de .NET / IIS pueden requerir que esté en el system.WebServerelemento.

<system.webServer>
<httpRuntime relaxedUrlToFileSystemMapping="true" />
Tommy
fuente
2
Esto es lo que tenía con mvc3 + .net4.0 y funcionó maravillosamente, pero ya no funciona con mvc4 + .net4.5.
Tadeu Maia
44
Probé el relajadoUrlToFileSystemMapping sin éxito. No creo que funcione con las versiones más recientes de MVC.
Mark
Esto me permitió capturar la url /WEB-INF./web.xml y redirigirla a una página de error personalizada cuando muchas otras formas que intenté no funcionaron.
quentin-starin
3
Interesante. Dado que no funcionó para usted, estaba a punto de asumir que esto no funcionaría para mí ... dado que estoy en MVC4 con .NET4.5. Pero bingo, funcionó de todos modos. En mi caso, simplemente tenía una URL con un punto "." como el último personaje Estaba obteniendo 404 pero esto lo solucionó.
PandaWood
¿El suyo tiene repercusiones de seguridad?
Paesano2000
23

Me quedé atrapado en este problema durante mucho tiempo siguiendo todos los remedios diferentes sin resultado.

Noté que al agregar una barra diagonal [/] al final de la URL que contiene los puntos [.], No arrojó un error 404 y realmente funcionó.

Finalmente resolví el problema usando una regrabadora de URL como IIS URL Rewrite para observar un patrón particular y agregar la barra diagonal de entrenamiento.

Mi URL se ve así: /Contact/~firstname.lastname, por lo que mi patrón es simplemente: /Contact/~(.*[^/font>)$

Tengo esta idea de Scott Forsyth, vea el enlace a continuación: http://weblogs.asp.net/owscott/handing-mvc-paths-with-dots-in-the-path

Leon van Wyk
fuente
Esto funcionó para mí (MVC5). Otras sugerencias anteriores no funcionaron, y no fueron necesarias, solo una barra diagonal final. Cambiaré mis rutas como lo sugiere @ jonduncan05 aquí .
markau
Gracias Leon. Me salvó el día. No estoy seguro de todas las cosas de web.config de las que la gente habla aquí, pero agregar el final / fue la respuesta que necesitaba. En mi caso, tengo control sobre el controlador del lado del servidor y el javascript que lo estaba llamando, así que ¡acabo de actualizar el JavaScript y listo!
Frog Pr1nce
21

Simplemente agregue esta sección a Web.config, y todas las solicitudes a la ruta / {* pathInfo} serán manejadas por el controlador especificado, incluso cuando haya puntos en pathInfo. (tomado del ejemplo de ServiceStack MVC Host Web.config y esta respuesta https://stackoverflow.com/a/12151501/801189 )

Esto debería funcionar tanto para IIS 6 como para 7. Puede asignar controladores específicos a diferentes rutas después de la 'ruta' modificando path = "*" en los elementos 'agregar'

  <location path="route">
    <system.web>
      <httpHandlers>
        <add path="*" type="System.Web.Handlers.TransferRequestHandler" verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" />
      </httpHandlers>
    </system.web>
    <!-- Required for IIS 7.0 -->
    <system.webServer>
      <modules runAllManagedModulesForAllRequests="true" />
      <validation validateIntegratedModeConfiguration="false" />
      <handlers>
        <add name="ApiURIs-ISAPI-Integrated-4.0" path="*" type="System.Web.Handlers.TransferRequestHandler" verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" preCondition="integratedMode,runtimeVersionv4.0" />
      </handlers>
    </system.webServer>
  </location>
VB
fuente
2
Tenga cuidado con las consecuencias de rendimiento que tiene runAllManagedModulesForAllRequests (RAMMFAR). Esto habilitará todos los módulos administrados para cada solicitud. Los archivos estáticos, como las imágenes, pueden ser procesados ​​por IIS directamente, pero esto los procesa a través de cada módulo y agrega una sobrecarga a cada solicitud.
Mark
@Marcas. sí, pero creo que esto afectará solo la solicitud de ruta / ... si usamos la sección <location> y no establecemos runAllManagedModulesForAllRequests en la sección principal <system.webServer>.
VB
@VB Creo que solo el controlador es suficiente, a menos que tenga archivos en el sistema que coincidan con una URL que .NET debe procesar. Y por alguna razón, RAMMFAR no funcionó en el nivel de <ubicación>, pero la solución del controlador sí.
webXL
@webXL <ubicación> necesaria cuando no desea que MVC procese solicitudes a una ruta específica y agregue rutas. IgnoreRoute ("route / {* pathInfo}"); Luego, IIS buscará en la sección de ubicación <location path = "route"> y utilizará los controladores especificados en la sección de ubicación, pero omitirá completamente el enrutamiento de MVC y otros pasos de la tubería de MVC. En mi proyecto, la API de ServiceStack simplemente no funciona sin esa configuración.
VB
¿Por qué no se agrega simplemente el trabajo del controlador? En mi caso, tengo que agregar RAMMFAR junto con el controlador. Buscando alguna buena explicación aquí. :)
Aditya Patil
6

MVC 5.0 Solución alternativa.

Muchas de las respuestas sugeridas no parecen funcionar en MVC 5.0.

Como el problema de 404 puntos en la última sección se puede resolver cerrando esa sección con una barra diagonal, aquí está el pequeño truco que uso, limpio y simple.

Mientras mantiene un marcador de posición conveniente en su vista:

@Html.ActionLink("Change your Town", "Manage", "GeoData", new { id = User.Identity.Name }, null)

agregue un poco de jquery / javascript para hacer el trabajo:

<script>
    $('a:contains("Change your Town")').on("click", function (event) {
        event.preventDefault();
        window.location.href = '@Url.Action("Manage", "GeoData", new { id = User.Identity.Name })' + "/";
    });</script>

tenga en cuenta la barra inclinada final, que es responsable de cambiar

http://localhost:51003/GeoData/Manage/[email protected]

dentro

http://localhost:51003/GeoData/Manage/[email protected]/
Luke
fuente
5

Respuesta súper fácil para aquellos que solo tienen esto en una página web. Edite su actionlink y un + "/" al final del mismo.

  @Html.ActionLink("Edit", "Edit", new { id = item.name + "/" }) |
Jeremy Hobbs
fuente
¡Lo resolvió por mí! Simple y elegante! Lo más irritante es que funciona sin la '/' en Windows 10 durante el desarrollo, pero para Windows 2012 parece ser necesario.
Wim ten Brink
2

Es posible que desee pensar en usar guiones en lugar de puntos.

En Pro ASP MVC 3 Framework sugieren esto sobre hacer URL amigables:

Evite símbolos, códigos y secuencias de caracteres. Si desea un separador de palabras, use un guión (/ my-great-article). Los guiones bajos no son amigables, y los espacios codificados en URL son extraños (/ my + great + article) o repugnantes (/ my% 20great% 20article).

También menciona que las URL deberían ser fáciles de leer y cambiar para los humanos. Quizás una razón para pensar en usar un guión en lugar de un punto también proviene del mismo libro:

No use extensiones de nombre de archivo para páginas HTML (.aspx o .mvc), pero sí las use para tipos de archivos especializados (.jpg, .pdf, .zip, etc.). Los navegadores web no se preocupan por las extensiones de nombre de archivo si configura el tipo MIME adecuadamente, pero los humanos aún esperan que los archivos PDF terminen con .pdf

Entonces, aunque un período aún es legible para los humanos (aunque menos legible que los guiones, en mi opinión), aún puede ser un poco confuso / engañoso dependiendo de lo que viene después del período. ¿Qué pasa si alguien tiene un apellido de zip? Entonces la URL será /John.zip en lugar de / John-zip, algo que puede ser engañoso incluso para el desarrollador que escribió la aplicación.

sdm350
fuente
Es probable que sea un nombre de usuario u otro campo que contenga puntos inherentemente. Dicho esto, StackOverflow reemplaza todos los signos de puntuación (incluidos .) con guiones en sus URL de usuario: P
jli
Encontré esto porque tengo un servicio seguro de recuperación de archivos que obviamente contiene nombres de archivos en el parámetro de ruta ...
FlavorScape
Votado por la razón obvia: no responde la pregunta. Si pudiera, no permitiría que aparezcan puntos en mi URL. Aparecen, porque la URL se genera y tiene que ser legible por humanos.
mg30rg
2

Dependiendo de lo importante que sea para usted mantener su URI sin cadenas de consulta, también puede pasar el valor con puntos como parte de la cadena de consulta, no el URI.

Por ejemplo, www.example.com/people?name=michael.phelps funcionará, sin tener que cambiar ninguna configuración ni nada.

Pierde la elegancia de tener un URI limpio, pero esta solución no requiere cambiar o agregar configuraciones o controladores.

GR7
fuente
1

¿Sería posible cambiar su estructura de URL?
Para lo que estaba trabajando probé una ruta para

url: "Download/{fileName}"

pero falló con cualquier cosa que tuviera un. en eso.

Cambié la ruta a

    routes.MapRoute(
        name: "Download",
        url:  "{fileName}/Download",
        defaults: new { controller = "Home", action = "Download", }
    );

Ahora puedo poner localhost:xxxxx/File1.doc/Download y funciona bien.

Mis ayudantes en la vista también lo captaron

     @Html.ActionLink("click here", "Download", new { fileName = "File1.doc"})

eso hace un enlace a la localhost:xxxxx/File1.doc/Download formato.

Tal vez podría poner una palabra innecesaria como "/ view" o acción al final de su ruta para que su propiedad pueda terminar con un final /como/mike.smith/view

jonduncan05
fuente
1

Es tan simple como cambiar path = " ." a la ruta = " ". Simplemente elimine el punto en la ruta de ExensionlessUrlHandler-Integrated-4.0 en web.config.

Aquí hay un buen artículo https://weblog.west-wind.com/posts/2015/Nov/13/Serving-URLs-with-File-Extensions-in-an-ASPNET-MVC-Application

Jonny
fuente
Este enlace me llevó a la mejor solución para mi problema (el segmento contiene un carácter "." Pero los clientes no seguirán con un "/"). Solucionado al tener esta línea en <system.webServer> de web.config - <modules runAllManagedModulesForAllRequests = "true" />
NickBeaugié
1

Intenté todas las soluciones anteriores, pero ninguna funcionó para mí. Lo que funcionó fue desinstalar versiones .NET> 4.5, incluidas todas sus versiones multilingües; Eventualmente agregué versiones más nuevas (solo en inglés) pieza por pieza. En este momento las versiones instaladas en mi sistema son las siguientes:

  • 2,0
  • 3.0
  • 3.5 4
  • 4.5 4.5
  • 4.5.1
  • 4.5.2
  • 4.6
  • 4.6.1

Y todavía funciona en este punto. Tengo miedo de instalar 4.6.2 porque podría estropear todo.

Así que solo pude especular que 4.6.2 o todas esas versiones que no están en inglés estaban arruinando mi configuración.

jokab
fuente
0

Pude resolver mi versión particular de este problema (tuve que hacer /customer.html ruta a / customer, no se permiten barras diagonales finales) usando la solución en https://stackoverflow.com/a/13082446/1454265 , y sustituyendo la ruta = "*. html".

usuario1454265
fuente
0

Como solución también podría estar considerando codificar a un formato que no contenga símbolo. , como base64.

En js se debe agregar

btoa(parameter); 

En el controlador

byte[] bytes = Convert.FromBase64String(parameter);
string parameter= Encoding.UTF8.GetString(bytes);
Max Booreviy
fuente
0

Agregue la regla de reescritura de URL al archivo Web.config. Debe tener el módulo URL Rewrite ya instalado en IIS. Use la siguiente regla de reescritura como inspiración para la suya.

<?xml version="1.0" encoding="utf-8"?>
<configuration>

<system.webServer>
  <rewrite>
    <rules>
      <rule name="Add trailing slash for some URLs" stopProcessing="true">
        <match url="^(.*(\.).+[^\/])$" />
          <conditions>
              <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
              <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
          </conditions>
          <action type="Redirect" url="{R:1}/" />
      </rule>
    </rules>
    </rewrite>
</system.webServer>

</configuration> 
Amadeus Sánchez
fuente
0

Además, (relacionado) verifique el orden de sus asignaciones de controladores. Teníamos un .ashx con un .svc (por ejemplo, /foo.asmx/bar.svc/path) en la ruta de acceso. La asignación .svc fue primero 404 para la ruta .svc que coincidía antes que .asmx. No había pensado demasiado, pero tal vez la url que codifica el camino se encargaría de esto.

stuartm9999
fuente
-3
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace WebApplication1.Controllers
{
    [RoutePrefix("File")]
    [Route("{action=index}")]
    public class FileController : Controller
    {
        // GET: File
        public ActionResult Index()
        {
            return View();
        }

        [AllowAnonymous]
        [Route("Image/{extension?}/{filename}")]
        public ActionResult Image(string extension, string filename)
        {
            var dir = Server.MapPath("/app_data/images");

            var path = Path.Combine(dir, filename+"."+ (extension!=null?    extension:"jpg"));
           // var extension = filename.Substring(0,filename.LastIndexOf("."));

            return base.File(path, "image/jpeg");
        }
    }
}
hamyari afarinesh
fuente
1
¿Cómo responde esto a la pregunta de OP? ¿Te importaría describirlo por favor?
kayess
no es una solución, es un truco que requiere que la extensión del archivo se coloque en la ruta uri (sin punto), por ejemplo, "~ / Image / jpg / cow" para recuperar el archivo "/ app_data / images / cow / jpg" - - No es la solución que este tipo y todos los demás encuentran que necesita.
Shaun Wilson