代码改变世界

【原创】Asp.net MVC 学习笔记之-为什么使用Html.TextBox方法会出现异常?

2011-01-12 21:18  刺客之家  阅读(939)  评论(0编辑  收藏  举报

在上篇文章:【原创】Asp.net MVC学习笔记之-基于类型来绑定Model的属性 中,例举了如何使用基于类型和基于用途2种方式结合来限制Model的绑定,由此引发了一个意想不到的问题。

先看一下前台页面的代码:

 

代码
<p>
<label for="Test1">Test1:</label>
<%= Html.TextBox("Test1") %>
<%= Html.ValidationMessage("Test1", "*") %>
</p>
<p>
<label for="Test2">Test2:</label>
<%= Html.TextBox("Test2") %>
<%= Html.ValidationMessage("Test2", "*") %>
</p>
<p>
<label for="Test3">Test3:</label>
<%= Html.TextBox("Test3") %>
<%= Html.ValidationMessage("Test3", "*") %>
</p>
<p>
<label for="Test4">Test4:</label>
<%= Html.TextBox("Test4") %>
<%= Html.ValidationMessage("Test4", "*") %>
</p>
<p>
<label for="Test5">Test5:</label>
<%= Html.TextBox("Test5") %>
<%= Html.ValidationMessage("Test5", "*") %>
</p>

 

 

 当页面输入的数据在Controller里经过数据绑定之后,只剩下了Test3一项有值,其他几个都是null,然后当程序走到

Html.TextBox的时候就出错了,报错如下:

 

代码
堆栈跟踪:


[NullReferenceException: 未将对象引用设置到对象的实例。]
System.Web.Mvc.HtmlHelper.GetModelStateValue(String key, Type destinationType) +63
System.Web.Mvc.Html.InputExtensions.InputHelper(HtmlHelper htmlHelper, InputType inputType, String name, Object value, Boolean useViewData, Boolean isChecked, Boolean setId, Boolean isExplicitValue, IDictionary`2 htmlAttributes) +519
System.Web.Mvc.Html.InputExtensions.TextBox(HtmlHelper htmlHelper, String name, Object value, IDictionary`2 htmlAttributes) +34
System.Web.Mvc.Html.InputExtensions.TextBox(HtmlHelper htmlHelper, String name) +60
ASP.views_dinners_create_aspx.__RenderContent2(HtmlTextWriter __w, Control parameterContainer) in e:\学习资料\我的学习文件\工作学习\【12】-网页方向\MVC\一步一步学asp.net_mvc\Projects\NerdDinner\NerdDinner\Views\Dinners\Create.aspx:30
System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +256
System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +19
System.Web.UI.Control.Render(HtmlTextWriter writer) +10
System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27
System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +99
System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25
ASP.views_shared_site_master.__Render__control1(HtmlTextWriter __w, Control parameterContainer) in e:\学习资料\我的学习文件\工作学习\【12】-网页方向\MVC\一步一步学asp.net_mvc\Projects\NerdDinner\NerdDinner\Views\Shared\Site.Master:26
System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +256
System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +19
System.Web.UI.Control.Render(HtmlTextWriter writer) +10
System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27
System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +99
System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25
System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +134
System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +19
System.Web.UI.Page.Render(HtmlTextWriter writer) +29
System.Web.Mvc.ViewPage.Render(HtmlTextWriter writer) +59
System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27
System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +99
System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1266


 

找了半天也没找到原因,于是我把数据绑定的限制去掉试了一下,就没问题了,于是我想问题可能出在这个方法上面,祭出

Reflector,直接打开C盘下的System.Web.MVC.Dll,看个究竟:

通过HtmlHelper.TextBox方法,很容易跟到这个函数:

 

代码
private static string InputHelper(this HtmlHelper htmlHelper, InputType inputType, string name, object value, bool useViewData, bool isChecked, bool setId, bool isExplicitValue, IDictionary<string, object> htmlAttributes)
{
ModelState state;
if (string.IsNullOrEmpty(name))
{
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "name");
}
TagBuilder builder
= new TagBuilder("input");
builder.MergeAttributes
<string, object>(htmlAttributes);
builder.MergeAttribute(
"type", HtmlHelper.GetInputTypeString(inputType));
builder.MergeAttribute(
"name", name, true);
string str = Convert.ToString(value, CultureInfo.CurrentCulture);
bool flag = false;
switch (inputType)
{
case InputType.CheckBox:
{
bool? modelStateValue = htmlHelper.GetModelStateValue(name, typeof(bool)) as bool?;
if (modelStateValue.HasValue)
{
isChecked
= modelStateValue.Value;
flag
= true;
}
break;
}
case InputType.Password:
if (value != null)
{
builder.MergeAttribute(
"value", str, isExplicitValue);
}
goto Label_0152;

case InputType.Radio:
break;

default:
{
string str3 = (string) htmlHelper.GetModelStateValue(name, typeof(string));
builder.MergeAttribute(
"value", str3 ?? (useViewData ? htmlHelper.EvalString(name) : str), isExplicitValue);
goto Label_0152;
}
}
if (!flag)
{
string a = htmlHelper.GetModelStateValue(name, typeof(string)) as string;
if (a != null)
{
isChecked
= string.Equals(a, str, StringComparison.Ordinal);
flag
= true;
}
}
if (!flag && useViewData)
{
isChecked
= htmlHelper.EvalBoolean(name);
}
if (isChecked)
{
builder.MergeAttribute(
"checked", "checked");
}
builder.MergeAttribute(
"value", str, isExplicitValue);
Label_0152:
if (setId)
{
builder.GenerateId(name);
}
if (htmlHelper.ViewData.ModelState.TryGetValue(name, out state) && (state.Errors.Count > 0))
{
builder.AddCssClass(HtmlHelper.ValidationInputCssClassName);
}
if (inputType == InputType.CheckBox)
{
StringBuilder builder2
= new StringBuilder();
builder2.Append(builder.ToString(TagRenderMode.SelfClosing));
TagBuilder builder3
= new TagBuilder("input");
builder3.MergeAttribute(
"type", HtmlHelper.GetInputTypeString(InputType.Hidden));
builder3.MergeAttribute(
"name", name);
builder3.MergeAttribute(
"value", "false");
builder2.Append(builder3.ToString(TagRenderMode.SelfClosing));
return builder2.ToString();
}
return builder.ToString(TagRenderMode.SelfClosing);
}




这里注意Switch应该是走到default里,继续跟,发现这个函数有问题:

 

代码
internal object GetModelStateValue(string key, Type destinationType)
{
ModelState state;
if (this.ViewData.ModelState.TryGetValue(key, out state))
{
return state.Value.ConvertTo(destinationType, null);
}
return null;
}


其中这句话怎么看怎么不爽:return state.Value.ConvertTo(destinationType, null);

于是我在Controller里自己试了一把:

 

代码
System.Web.Mvc.ModelState state;
if (this.ViewData.ModelState.TryGetValue("Test1", out state))
{
var result
= state.Value.ConvertTo(typeof(string), null);

}

监视器打开,问题找到了

 

至于这后面隐藏了MVC的什么内部实现,等我搞清楚了再回头看看。今天的问题算是告一段落了。

 

 

 

 

 

本博客文章若非标记转载,均为原创,转载请注明出处~