MVC3 小写路由值的行为与大写不同?
对这里的大量代码表示歉意...我试图使其尽可能短:
我已经编写了(大部分是从这里窃取的)HtmlHelper 扩展来根据枚举写出RadioButton(分组)。我还设置了我的路线图,因此它使用枚举而不是“id”等。
我有两个枚举(对于本例)CurrencyType 和 StatusType
当我调用 URL /GBP/Open 时,我的 HtmlHelper 可以正常工作并设置选中 GBP 和 Open 的单选按钮。
当我调用 URL /gbp/open 时,帮助程序仍然检查值并且似乎可以工作...但是当调用 RadioButton().ToHtmlString() 时,“已检查”不存在??? 使用默认路由后,单选按钮仍然设置正确???
如果您在返回的 SelectList 上设置断点,那么您可以看到所选选项设置正确,所以我有点困惑问题出在哪里?
Empty MVC3 website called Area36...Area 51 was taken ;)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Linq.Expressions;
using System.Text;
namespace Area36.Models
{
public static class Extensions
{
public static SelectList ToSelectList<TEnum>(this TEnum enumObj)
{
var values = from TEnum e in Enum.GetValues(typeof(TEnum))
select new { ID = e, Name = e };
return new SelectList(values, "Id", "Name", enumObj);
}
public static void AppendFormatLine(this StringBuilder sb, string format, params object[] args)
{
sb.AppendFormat(format, args);
sb.AppendLine();
}
public static MvcHtmlString RadioButtonForEnum<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string fieldSet)
{
var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
var e = (TProperty)Enum.Parse(typeof(TProperty), metaData.Model.ToString());
var selectList = e.ToSelectList();
var sb = new StringBuilder();
if (selectList != null)
{
sb.AppendFormatLine("<fieldset><legend>{0}</legend>", fieldSet);
foreach (SelectListItem item in selectList)
{
var id = string.Format("{0}_{1}", metaData.PropertyName, item.Value);
if (htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix != string.Empty)
id.Insert(0, string.Format("{0}_", htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix));
var label = htmlHelper.Label(id, HttpUtility.HtmlEncode(item.Text));
var radio = htmlHelper.RadioButton(name: metaData.PropertyName, value: item.Value, isChecked: item.Selected, htmlAttributes: new { id = id }).ToHtmlString();
sb.AppendFormatLine("<div class=\"radio_{0}\">{1}{2}</div>", metaData.PropertyName, radio, label);
}
sb.AppendLine("</fieldset>");
}
return MvcHtmlString.Create(sb.ToString());
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Area36.Models;
namespace Area36.Controllers
{
public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult Index(CurrencyType currency, StatusType status)
{
return View(new ViewModel { Currency = currency, Status = status });
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Area36.Models
{
public class ViewModel
{
public CurrencyType Currency { get; set; }
public StatusType Status { get; set; }
}
}
@using Area36.Models
@model Area36.Models.ViewModel
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
@Html.RadioButtonForEnum(m => m.Currency, "Currency")
@Html.RadioButtonForEnum(m => m.Status, "Status")
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{currency}/{status}", // URL with parameters
new { controller = "Home", action = "Index", currency = CurrencyType.EUR, status = StatusType.Closed} // Parameter defaults
);
}
Apologies for lots of code in here...I've tried to keep it as short as possible:
I have written (stolen mostly from here) a HtmlHelper extension to write out a RadioButton (grouped) based upon an enum. I have also set my route map so it uses an enum instead of "id" etc.
I have two enum's (for this example) CurrencyType and StatusType
When I call the URL /GBP/Open, my HtmlHelper works correctly and sets the value of the radio buttons with GBP and Open checked.
When I call the URL /gbp/open - the Helper still checks the values and appears to work...but when RadioButton().ToHtmlString() is called the "checked" is not present????
With the default routing in place, the radio buttons are still set correctly too???
If you breakpoint the returned SelectList then you can see the option selected is set correctly, so I'm a little stumped as to where the problem is arising?
Empty MVC3 website called Area36...Area 51 was taken ;)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Linq.Expressions;
using System.Text;
namespace Area36.Models
{
public static class Extensions
{
public static SelectList ToSelectList<TEnum>(this TEnum enumObj)
{
var values = from TEnum e in Enum.GetValues(typeof(TEnum))
select new { ID = e, Name = e };
return new SelectList(values, "Id", "Name", enumObj);
}
public static void AppendFormatLine(this StringBuilder sb, string format, params object[] args)
{
sb.AppendFormat(format, args);
sb.AppendLine();
}
public static MvcHtmlString RadioButtonForEnum<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string fieldSet)
{
var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
var e = (TProperty)Enum.Parse(typeof(TProperty), metaData.Model.ToString());
var selectList = e.ToSelectList();
var sb = new StringBuilder();
if (selectList != null)
{
sb.AppendFormatLine("<fieldset><legend>{0}</legend>", fieldSet);
foreach (SelectListItem item in selectList)
{
var id = string.Format("{0}_{1}", metaData.PropertyName, item.Value);
if (htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix != string.Empty)
id.Insert(0, string.Format("{0}_", htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix));
var label = htmlHelper.Label(id, HttpUtility.HtmlEncode(item.Text));
var radio = htmlHelper.RadioButton(name: metaData.PropertyName, value: item.Value, isChecked: item.Selected, htmlAttributes: new { id = id }).ToHtmlString();
sb.AppendFormatLine("<div class=\"radio_{0}\">{1}{2}</div>", metaData.PropertyName, radio, label);
}
sb.AppendLine("</fieldset>");
}
return MvcHtmlString.Create(sb.ToString());
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Area36.Models;
namespace Area36.Controllers
{
public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult Index(CurrencyType currency, StatusType status)
{
return View(new ViewModel { Currency = currency, Status = status });
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Area36.Models
{
public class ViewModel
{
public CurrencyType Currency { get; set; }
public StatusType Status { get; set; }
}
}
@using Area36.Models
@model Area36.Models.ViewModel
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
@Html.RadioButtonForEnum(m => m.Currency, "Currency")
@Html.RadioButtonForEnum(m => m.Status, "Status")
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{currency}/{status}", // URL with parameters
new { controller = "Home", action = "Index", currency = CurrencyType.EUR, status = StatusType.Closed} // Parameter defaults
);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我尝试了各种选择来解决这个问题。强力传递了大写值。最令人惊讶的是,当我通过以下所有无线电按钮传递“ True”时,即使是输出相同,仅检查了大写URL按钮。
有了此代码和一些谷歌搜索,我找到了 this 。
如果您检查
以下是MVC3-RTM的代码。在这里,您可以根据ModelState进行修改的签名值,如果您检查ModelState.Values [index]的值。在调试模式下AntemptedValue,显然是在小写中(对于“ GBP/Open”)。这就是为什么小写URL不会渲染检查属性的原因。
I tried various options to solve this. Passed UpperCase values forcefully. Most surprisingly when I passed 'true' for all the radio buttons as follows, even then the output was same, buttons were checked only for uppercase url.
With some rnd with this code and some googling I found this.
If you check
Following is code from MVC3-rtm. Here you can see value of isChecked is modified depending on ModelState and if you check the value of modelState.Values[index].AttemptedValue in debug mode, it is obviously in lowercase (for "gbp/open"). That's why lowercase url doesn't render checked attribute.