Dis*_*nky 12 c# asp.net-mvc razor
对于有想法的人来说,这是一个奇怪的...我正在特定页面上渲染一个隐藏的布尔字段.但是,对于同一个字段,我会得到两个略有不同的标记,具体取决于特定事件是否在流程之前发生.生成的两个字段是;
<input id="HasPreviouslyIssuedCard" name="HasPreviouslyIssuedCard" type="hidden" value="false" />
Run Code Online (Sandbox Code Playgroud)
和
<input id="HasPreviouslyIssuedCard" name="HasPreviouslyIssuedCard" type="hidden" value="False" />
Run Code Online (Sandbox Code Playgroud)
问题是"值"属性中的文本的情况,您会注意到该文本是不同的,后来影响JS条件.生成这个的剃刀标记是;
@Html.Hidden("HasPreviouslyIssuedCard", Model.HasPreviouslyIssuedCard?.ToString(), new { id = nameof(Model.HasPreviouslyIssuedCard) })
Run Code Online (Sandbox Code Playgroud)
但是,我也尝试使用以下变体,在渲染隐藏字段时具有相同的差异;
@Html.HiddenFor(m => m.HasPreviouslyIssuedCard)
Run Code Online (Sandbox Code Playgroud)
我该怎么做才能获得这种差异?要获得大写变体,我在进入相关页面之前点击浏览器后退按钮.两种方法都以相同的方式加载数据,并以相同的方式将相同的值传递给渲染器.两种不同的输出.
请记住,这是一个要呈现的布尔值类型字段.应该没有太大的修补空间.有很多种方法可以解决这个问题,但由于我们在积压工作中有两个与布尔字段和后退按钮有关的项目,我想解释一下而不是解决它.
我最好的猜测是,按下后退按钮会以某种方式改变渲染器的状态,或者模型中的其他一些标志是不同的(有70多个字段,因为它是一个向导)正在改变渲染器如何解释如何设置布尔值值.值相同,页面相同,数据以相同的方式读取.
基于这个页面(为什么Boolean.ToString输出"True"而不是"true"),我们应该假设一直是获得大写变体,但这不是结果.
任何接受者/想法/想法?
编辑1
通过HiddenFor()方法挖掘MVC的渲染逻辑,最终Convert.ToString(value, CultureInfo.CurrentCulture)被称为.直接调用时,我不能让它产生一个小写的布尔值,但它显然是这样做的.我当前的文化代码设置为en-IE但我在直接调用时看到了大写的布尔值.
编辑2
我已经对我的应用程序进行了更多的修补和跟踪,并且可以提供更多有关正在发生的事情的详细信息,但我还没有能够在更简单的应用程序中重现这一点.
MVC 5应用:它有;
/通过HTTP检索根域的URL GET.布尔input标签呈现为True/False/Apply通过HTTP检索的URL向导中的第一页GET.布尔input标签呈现为True/FalsePOST.案例input标签现在呈现为true/ false.input标签现在以大写形式返回渲染(原始报告的问题).我一直在钻研MVC库,使用ILSpy来尝试扫描和MVC(如果我正确地读取代码)实际上使用了一个实现IConverter来编写布尔值,而Convert.ToString(value, CultureInfo.CurrentCulture)不像我原先想的那样.
从调用中追踪的代码堆栈HiddenFor()(我认为);
System.Web.Mvc.InputExtentions.HiddenFor() (公共职能)System.Web.Mvc.InputExtentions.HiddenHelper() (私有函数,这里有一些逻辑用于数组但不适用于我们的情况)System.Web.Mvc.InputExtentions.InputHelper() (私人功能,魔术发生在这里)反编译代码System.Web.Mvc.InputExtentions.InputHelper();
private static MvcHtmlString InputHelper(HtmlHelper htmlHelper, InputType inputType, ModelMetadata metadata, string name, object value, bool useViewData, bool isChecked, bool setId, bool isExplicitValue, string format, IDictionary<string, object> htmlAttributes)
{
string fullHtmlFieldName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
if (string.IsNullOrEmpty(fullHtmlFieldName))
{
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "name");
}
TagBuilder tagBuilder = new TagBuilder("input");
tagBuilder.MergeAttributes<string, object>(htmlAttributes);
tagBuilder.MergeAttribute("type", HtmlHelper.GetInputTypeString(inputType));
tagBuilder.MergeAttribute("name", fullHtmlFieldName, true);
string text = htmlHelper.FormatValue(value, format);
bool flag = false;
switch (inputType)
{
case InputType.CheckBox:
{
bool? flag2 = htmlHelper.GetModelStateValue(fullHtmlFieldName, typeof(bool)) as bool?;
if (flag2.HasValue)
{
isChecked = flag2.Value;
flag = true;
}
break;
}
case InputType.Hidden:
goto IL_131;
case InputType.Password:
if (value != null)
{
tagBuilder.MergeAttribute("value", text, isExplicitValue);
goto IL_16C;
}
goto IL_16C;
case InputType.Radio:
break;
default:
goto IL_131;
}
if (!flag)
{
string text2 = htmlHelper.GetModelStateValue(fullHtmlFieldName, typeof(string)) as string;
if (text2 != null)
{
isChecked = string.Equals(text2, text, StringComparison.Ordinal);
flag = true;
}
}
if (!flag && useViewData)
{
isChecked = htmlHelper.EvalBoolean(fullHtmlFieldName);
}
if (isChecked)
{
tagBuilder.MergeAttribute("checked", "checked");
}
tagBuilder.MergeAttribute("value", text, isExplicitValue);
goto IL_16C;
IL_131:
string text3 = (string)htmlHelper.GetModelStateValue(fullHtmlFieldName, typeof(string));
tagBuilder.MergeAttribute("value", text3 ?? (useViewData ? htmlHelper.EvalString(fullHtmlFieldName, format) : text), isExplicitValue);
IL_16C:
if (setId)
{
tagBuilder.GenerateId(fullHtmlFieldName);
}
ModelState modelState;
if (htmlHelper.ViewData.ModelState.TryGetValue(fullHtmlFieldName, out modelState) && modelState.Errors.Count > 0)
{
tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName);
}
tagBuilder.MergeAttributes<string, object>(htmlHelper.GetUnobtrusiveValidationAttributes(name, metadata));
if (inputType == InputType.CheckBox)
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(tagBuilder.ToString(TagRenderMode.SelfClosing));
TagBuilder tagBuilder2 = new TagBuilder("input");
tagBuilder2.MergeAttribute("type", HtmlHelper.GetInputTypeString(InputType.Hidden));
tagBuilder2.MergeAttribute("name", fullHtmlFieldName);
tagBuilder2.MergeAttribute("value", "false");
stringBuilder.Append(tagBuilder2.ToString(TagRenderMode.SelfClosing));
return MvcHtmlString.Create(stringBuilder.ToString());
}
return tagBuilder.ToMvcHtmlString(TagRenderMode.SelfClosing);
}
Run Code Online (Sandbox Code Playgroud)
编辑3
只是重述,因为有一些关于javascript方面的评论.我在尝试诊断问题时就考虑过这个问题.为了排除任何潜在的JS干扰/操纵,我使用Fiddler来捕获传输中的HTML.MVC正在生成的HTML正在改变案例 - 我可以在Fiddler中看到这一点,在JS甚至加载之前的某个时刻,从不介意运行.这不是JS问题.
看来我错了,毕竟是JS,尽管还没有到我试图排除它的地步。重现此事件的顺序;
form使用布尔隐藏字段+非提交按钮创建 HTMLonclick按钮的事件中,有一段 JS 将布尔字段设置为true(小写)POST 后,布尔字段将具有小写值而不是大写值。
这是怎么回事?好吧,如果集合中存在键HiddenFor(),(及其变体)将渲染布尔值ViewData.ModelState而不是模型属性的值。看起来很直观,但可以(并且对我来说)让您感到困惑的是,所有其他数据类型、模型绑定器都是非常具体的 - 值和模型的属性值将是相同的。除了布尔值的情况之外 - 模型绑定器足够智能,可以在转换 POST 时将和视为相同,但是如果通过 JS 布尔值设置,则这会使该值和字符串化属性值变得不正常。当模型属性的值显示为时,JS 将设置该值。而在 JS 中,.ToString()ModelStateModelStateTruetrueModelStateModelStatetrueToString()True"true" !== "True"
至于为什么在点击浏览器的“后退”按钮后会重置 - 我们的陷阱页面没有表单值,也没有通过 HTTP GET 链接回应用程序,这会导致HiddenFor调用模型属性.ToString()而不是从ModelStateas中提取它那时它还不在那儿。同样,在我的测试中,用户在通过 JS 设置很久之后就会处于向导中的某个点,因此当他们继续通过向导时,它将保持大写状态。
我的假设是 JS 在页面加载后启动。这实际上是由于 JS 在启动 POST 之前设置了一个值,并且该小写值通过ModelState. 去搞清楚。
编辑
复制代码;
模型;
public class Test
{
public bool Sample { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
剃刀标记;
@model TestModelValueCase.Models.Test
@{
ViewBag.Title = "Test Page";
}
@using (Html.BeginForm())
{
@Html.HiddenFor(m => m.Sample)
<div>
<label>Hidden Value:</label>
<span id="_uiValue"></span>
</div>
<button type="submit">Try Post</button>
}
@section scripts
{
<script type="text/javascript" language="javascript">
$(document).ready(function() {
var source = $('#@nameof(Model.Sample)');
$('#_uiValue').html(source.val());
source.val(true);
});
</script>
}
Run Code Online (Sandbox Code Playgroud)
控制器;
public ActionResult Index()
{
Test model = new Test();
return View(model);
}
[HttpPost]
public ActionResult Index(Test model)
{
return View(model);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
945 次 |
| 最近记录: |