2011-01-30 5 views
6

Sé que si crees que has encontrado un error en el framework .NET es muy probable que estés equivocado, pero es por eso que estoy escribiendo esta pregunta, así que por favor escúchame.¿Alguien puede recrear el siguiente error que estoy experimentando en rutas con 2 o más parámetros opcionales, en .NET 4.0/MVC3?

Estoy bastante seguro de que existe una diferencia entre las rutas en .NET 3.5 y .NET 4.0 cuando se trata de parámetros opcionales. Específicamente si tiene más de un parámetro opcional en su ruta. No he podido encontrar este cambio radical en notas de la versión de .NET 4.0 o MVC 3, por eso lo llamo un error.

EDIT: Este error solo se manifiesta cuando intentas construir una url de ruta usando un código como url o html helpers en mvc. Si realmente solicita la URL en un navegador, en una aplicación de mvc real, funciona bien. Entonces, si mi aplicación de prueba a continuación fuera una aplicación de mvc real, no habría ningún problema si intentara solicitar '/ root/test1'.

Lo que necesito hacer es ejecutar el siguiente programa de prueba, debe ser bastante fácil de entender, pero básicamente solo establece una ruta con algunos parámetros opcionales.

  1. Crear una nueva aplicación de consola .NET 4

  2. cambiar el marco de destino para '.NET Framework 4' en lugar de' .NET Framework 4 Client Profile'

  3. agregar referencias a:
    System.Web 4.0
    System.Web.Routing 4.0
    System.Web.Mvc 3,0

  4. Pega siguiente código al archivo Program.cs, sobrescribir el contenido anterior:

    using System; 
    using System.IO; 
    using System.Web; 
    using System.Web.Mvc; 
    using System.Web.Routing; 
    
    public class Program 
    { 
        static void Main() 
        { 
         var httpCtx = new HttpContextWrapper(new HttpContext(new HttpRequest(null, "http://localhost/", null), new HttpResponse(new StringWriter()))); 
    
         var routes = RouteTable.Routes; 
         routes.MapRoute("Test", "root/{test1}/{test2}/{test3}", new { test2 = UrlParameter.Optional, test3 = UrlParameter.Optional }); 
    
         var context = new RequestContext(httpCtx , new RouteData()); 
    
         var url = new UrlHelper(context); 
    
         var expected1 = "/root/test1"; 
         var expected2 = "/root/test1/test2"; 
         var expected3 = "/root/test1/test2/test3"; 
    
         var actual1 = url.RouteUrl("Test", new { test1 = "test1" }); 
         var actual2 = url.RouteUrl("Test", new { test1 = "test1", test2 = "test2" }); 
         var actual3 = url.RouteUrl("Test", new { test1 = "test1", test2 = "test2", test3 = "test3" }); 
    
         var result1 = actual1 == expected1; 
         var result2 = actual2 == expected2; 
         var result3 = actual3 == expected3; 
    
         Console.WriteLine("Test 1: {0} ({1})", result1 ? "Success" : "Fail", result1 ? string.Format("'{0}'", actual1) : string.Format("Expected '{0}' but was '{1}'", expected1, actual1 ?? "<null>")); 
         Console.WriteLine("Test 2: {0} ({1})", result2 ? "Success" : "Fail", result2 ? string.Format("'{0}'", actual2) : string.Format("Expected '{0}' but was '{1}'", expected2, actual2 ?? "<null>")); 
         Console.WriteLine("Test 3: {0} ({1})", result3 ? "Success" : "Fail", result3 ? string.Format("'{0}'", actual3) : string.Format("Expected '{0}' but was '{1}'", expected3, actual3 ?? "<null>")); 
         Console.ReadLine(); 
        } 
    } 
    
  5. Ejecutar el programa y tenga en cuenta las direcciones URL resultantes.
    En mi máquina el resultado es:

    Test 1: Fail (expected '/root/test1' but was '<null>') 
    Test 2: Success ('/root/test1/test2') 
    Test 3: Success ('/root/test1/test2/test3') 
    
  6. Ahora cambiar el marco de destino para .NET 3.5 agregar referencias a:
    System.Web.Mvc 2.0
    System.Web.Routing 3,5
    sistema. Web.Abstrations 3.5

  7. Ejecute el programa de nuevo y vea que los 3 casos de prueba tuvieron éxito.
    Esta vez, el resultado es:

    Test 1: Success ('/root/test1') 
    Test 2: Success ('/root/test1/test2') 
    Test 3: Success ('/root/test1/test2/test3') 
    

Así que me parece que hay un error en el .NET MVC 4 o 3. Si encuentra el mismo problema por favor vote sobre el problema siguiente en la conexión : https://connect.microsoft.com/VisualStudio/feedback/details/630568/url-routing-with-two-optional-parameters-unspecified-fails-on-asp-net-mvc3-rc2#details

Siéntase libre de probar esto en una aplicación MVC normal si cree que hay algo mal en el programa de prueba.

Respuesta

4

Por lo tanto, Phil Haack acaba de publicar un blog post que detalla que este es un problema conocido y se solucionará en la próxima versión del .NET framework, o tal vez si tenemos suerte como una corrección de errores para el dll particular. Aunque no estoy exactamente seguro de cómo lo arreglarán. Si proscribirán más de 1 parámetro opcional, o si lo resolverán de la manera que he esbozado en los comentarios a la respuesta de Darin. Al menos lo saben y pueden tomar medidas para especificar el comportamiento esperado con más de un parámetro opcional más en el futuro.

2

Solo el último parámetro de una definición de ruta puede ser opcional y esta regla se ha aplicado en ASP.NET MVC 3. En su ejemplo, tiene ambos test2 y test3 opcionales que no es posible.Considere la siguiente URL:

root/test1/test2 

Dada esta URL del motor de enrutamiento no puede decir si test2="test2" and test3="" o test2="" and test3="test2". Entonces, ¿por qué generar una URL que nunca se puede analizar de nuevo a sus tokens constituyentes?

Ahora tal vez sea un error o una característica o lo llames lo que sea, pero en todos los casos debes evitar tener tales rutas. En mi humilde opinión, el error aquí es que el marco no arroja una excepción diciéndole que solo el último parámetro en una definición de ruta puede ser opcional, pero por supuesto esa es solo mi opinión.

+1

Hola Darin, gracias por la respuesta. En su ejemplo, MVC2 establecería test2 = "test2", que es la forma intuitiva de resolver el problema y que permite varios parámetros opcionales. No veo por qué sería un problema especificar esto como la resolución aceptada, siempre que esté claramente documentada. Como dices es difícil saber si es un error o no. Lo único que puedo decir con certeza es que hay una diferencia no documentada (ruptura) entre MVC2 y MVC3. – JohannesH

+0

Además, el motor de enrutamiento en MVC3 no tiene problemas para enrutar una URL específica correctamente ... Es la generación de URL que no funciona. – JohannesH

+0

@JohannesH, lo que estoy de acuerdo contigo es que hay un cambio no documentado. Pero dejando eso de lado cuando hablas de una forma intuitiva de resolver el problema, no estoy de acuerdo contigo: para mí ambos son igualmente posibles. ¿Por qué esa sería la forma intuitiva si 'test2' puede estar vacío y queremos dar un valor a' test3'? ¿Cómo lo harías tú? Es solo un caso que no puede tener si ambos fueran opcionales: 'test2' empty y' test3' tiene un valor asumiendo que se solicita esta url: 'root/test1/test2'. –

Cuestiones relacionadas