ASP.NET MVC3: Incoherencias en el tratamiento de doubles

 ·  ☕ 4 min  ·  ✍️ eiximenis

    Nota: Este post ha sido importado de mi blog de geeks.ms. Es posible que algo no se vea del todo "correctamente". En cualquier caso puedes acceder a la versión original aquí

    Muy, muy, muy molesto… ASP.NET MVC3 corriendo sobre un servidor web configurado en español (cultura es-ES).

    Con la tabla de rutas estándar, cuatro acciones como las siguientes:

    1. [HttpPost]
    2. public ActionResult Index(DoubleModel model)
    3. {
    4.     ViewBag.Valor = model.Valor;
    5.  
    6.     return View("Resultado");
    7. }
    8.  
    9. [HttpPost]
    10. public ActionResult IndexSoloDouble(double? valor)
    11. {
    12.     ViewBag.Valor = valor;
    13.  
    14.     return View("Resultado");
    15. }
    16.  
    17.  
    18. public ActionResult IndexRuta(double? id)
    19. {
    20.     ViewBag.Valor = id;
    21.     return View("Resultado");
    22. }
    23.  
    24. public ActionResult IndexGet(double? valor)
    25. {
    26.     ViewBag.Valor = valor;
    27.     return View("Resultado");
    28.     
    29. }

    La clase DoubleMode simplemente tiene una propiedad double llamada Valor.

    1. La primera acción recibe un double via POST  dentro de un modelo
    2. La segunda recibe un double via POST sólo
    3. La tercera acción recibe un double como parámetro de ruta
    4. La cuarta acción recibe un double via querystring

    Pues bien:

    1. La primera acción acepta 12,10 pero no 12.10 (usa la cultura del servidor web)
    2. La segunda acción acepta 12,10 pero no 12.10 (usa la cultura del servidor web)
    3. La tercera acción acepta 12.10 pero no 12,10 (usa la cultura ¿invariante?)
    4. La cuarta acción acepta 12.10 pero no 12, 10 (como la tercera, parece usar la invariante).

    Aquí tenéis el código de la vista usada para enviar los datos:

    1. @using MvcApplication1.Models
    2. @model DoubleModel
    3.  
    4. @{
    5.     ViewBag.Title = "Index";
    6. }
    7.  
    8. <h2>Indexh2>
    9.  
    10. @{
    11.     Html.EnableClientValidation(false);
    12. }
    13.  
    14. @using (Html.BeginForm()) {
    15.     <div>
    16.     Introduce el valor:
    17.     <input type="hidden" name="Valor" value="12,10" />
    18.     div>
    19.     <input type="submit" value="enviar 12,10 via POST" />
    20. }
    21.  
    22. @using (Html.BeginForm()) {
    23.     <div>
    24.     <input type="hidden" name="Valor" value="12.10" />
    25.     div>
    26.     <input type="submit" value< /span>="enviar 12.10 via POST" />
    27.     <li>
            }
          </li>
          <li style="background: #f3f3f3">
            &#160;
          </li>
          <li>
            &#160;
          </li>
          <li style="background: #f3f3f3">
            <span style="background: #ffff00">@</span><span style="color: #0000ff">using</span> (Html.BeginForm(<span style="color: #a31515">"IndexSoloDouble"</span>,<span style="color: #a31515">"Home"</span>))
          </li>
          <li>
            {
          </li>
          <li style="background: #f3f3f3">
            &#160;&#160;&#160; <span style="color: #0000ff"><</span><span style="color: #800000">div</span><span style="color: #0000ff">></span>
          </li>
          <li>
            &#160;&#160;&#160; <span style="color: #0000ff"><</span><span style="color: #800000">input</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="hidden"</span> <span style="color: #ff0000">name</span><span style="color: #0000ff">="Valor"</span> <span style="color: #ff0000">value</span><span style="color: #0000ff">="12,10"</span> <span style="color: #0000ff">/></span>
          </li>
          <li style="background: #f3f3f3">
            &#160;&#160;&#160; <span style="color: #0000ff"></</span><span style="color: #800000">div</span><span style="color: #0000ff">></span>
          </li>
          <li>
            &#160;&#160;&#160; <span style="color: #0000ff"><</span><span style="color: #800000">input</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="submit"</span> <span style="color: #ff0000">value</span><span style="color: #0000ff">="enviar 12,10 via POST (solo double)"</span> <span style="color: #0000ff">/></span>
          </li>
          <li style="background: #f3f3f3">
            }
          </li>
          <li>
            &#160;
          </li>
          <li style="background: #f3f3f3">
            &#160;
          </li>
          <li>
            <span style="background: #ffff00">@</span><span style="color: #0000ff">using</span> (Html.BeginForm(<span style="color: #a31515">"IndexSoloDouble"</span>, <span style="color: #a31515">"Home"</span>))
          </li>
          <li style="background: #f3f3f3">
            {
          </li>
          <li>
            &#160;&#160;&#160; <span style="color: #0000ff"><</span><span style="color: #800000">div</span><span style="color: #0000ff">></span>
          </li>
          <li style="background: #f3f3f3">
            &#160;&#160;&#160; <span style="color: #0000ff"><</span><span style="color: #800000">input</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="hidden"</span> <span style="color: #ff0000">name</span><span style="color: #0000ff">="Valor"</span> <span style="color: #ff0000">value</span><span style="color: #0000ff">="12.10"</span> <span style="color: #0000ff">/></span>
          </li>
          <li>
            &#160;&#160;&#160; <span style="color: #0000ff"></</span><span style="color: #800000">div</span><span style="color: #0000ff">></span>
          </li>
          <li style="background: #f3f3f3">
            &#160;&#160;&#160; <span style="color: #0000ff"><</span><span style="color: #800000">input</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="submit"</span> <span style="color: #ff0000">value</span><span style="color: #0000ff">="enviar 12.10 via POST (solo double)"</span> <span style="color: #0000ff">/></span>
          </li>
          <li>
            }
          </li>
          <li style="background: #f3f3f3">
            &#160;
          </li>
          <li>
            &#160;
          </li>
          <li style="background: #f3f3f3">
            &#160;
          </li>
          <li>
            <span style="background: #ffff00">@</span>Html.ActionLink(<span style="color: #a31515">"Enviar 12,10 via GET"</span>, <span style="color: #a31515">"IndexGet"</span>, <span style="color: #0000ff">new</span> { valor = <span style="color: #a31515">"12,10"</span> }); | <span style="background: #ffff00">@</span>Html.ActionLink(<span style="color: #a31515">"Enviar 12.10 via GET"</span>, <span style="color: #a31515">"IndexGet"</span>, <span style="color: #0000ff">new</span> { valor = <span style="color: #a31515">"12.10"</span> });
          </li>
          <li style="background: #f3f3f3">
            <span style="color: #0000ff"><</span><span style="color: #800000">br</span><span style="color: #0000ff">/></span>
          </li>
          <li>
            <span style="background: #ffff00">@</span>Html.ActionLink(<span style="color: #a31515">"Enviar 12,10 en ruta"</span>, <span style="color: #a31515">"IndexRuta"</span>, <span style="color: #0000ff">new</span> { id = <span style="color: #a31515">"12,10"</span> }); | <span style="background: #ffff00">@</span>Html.ActionLink(<span style="color: #a31515">"Enviar 12.10 en ruta"</span>, <span style="color: #a31515">"IndexRuta"</span>, <span style="color: #0000ff">new</span> { id = <span style="color: #a31515">"12.10"</span> });
          </li></ol></div> </p></div> 
          
          <p>
            El problema parece estar en los ValueProviders de URL (RouteDataValueProvider y QueryStringVaueProvider), que parecen ignorar la cultura, mientras que el ValueProvider de POST (FormValueProvider) la respeta.
          </p>
          
          <p>
            Lo dicho… muy molesto 🙁
          </p>
          
          <p>
            Saludos!
          </p>
          
          <p>
            <em><strong>Editado 16:43.</strong></em> PD: <a href="http://www.iloire.com/">Iván Loire</a> (<a href="http://twitter.com/#!/ivanloire">@ivanloire</a>) me comenta que este comportamiento es por diseño: los locales NO se aplican en los parámetros de URL para mantener las URLs canónicas. Si usáramos los locales del usuario podríamos tener URLs distintas que sirviesen el mismo contenido, y URLs válidas para un usuario podrían no serlo para otro. Es por ello que en MVC han optado por usar la cultura invariante en los ValueProviders de la URL. Dejo dos enlaces que me ha pasado Iván a dos posts donde se explica esto: <a href="http://bit.ly/tIZX64">http://bit.ly/tIZX64</a> y <a title="http://bit.ly/vCgbmf" href="http://bit.ly/vCgbmf">http://bit.ly/vCgbmf</a>
          </p>
    Si quieres, puedes invitarme a un café xD

    eiximenis
    ESCRITO POR
    eiximenis
    Compulsive Developer