GendoIkari
GendoIkari

Reputation: 11914

Null reference exception in WriteAttributeTo method

The following code gives a NULL reference error when str is NULL, but only on our production server, not on our development or testing servers.

<div>
<input value="@Html.Raw(str)" />
</div>

This works just fine:

<div>
<input value="@str" />
</div>

As does this:

<div>
Values is: @Html.Raw(str)
</div>

So it's not an issue of @Html.Raw not being able to accept a NULL parameter. I'm not sure what exactly it returns in that case though; but it's somehow different on one server than on another.

Both are running the same version of System.Web.Mvc, though I don't know know what other DLLs to check. System.Web.WebPages, which is the assembly that should contain the MVC method that's crashing, is the same version on both servers. This is MVC version 4; .Net 4.5.

How is such a thing possible? The error occurs in the WriteAttributeTo method, though I don't even know why that would be called here, since it's using standard HTML input tags, not the @Html.TextBoxFor helper.

Edit One thing that might be helpful is if others try putting that code in a View of their own to see if it works or breaks. At least then I would know if it's my production environment or the testing environment that's behaving unexpectedly.

Here is the full stack trace:

at System.Web.WebPages.WebPageExecutingBase.WriteAttributeTo(String pageVirtualPath, TextWriter writer, String name, PositionTagged1 prefix, PositionTagged1 suffix, AttributeValue[] values) at System.Web.WebPages.WebPageExecutingBase.WriteAttributeTo(TextWriter writer, String name, PositionTagged1 prefix, PositionTagged1 suffix, AttributeValue[] values) at System.Web.WebPages.WebPageExecutingBase.WriteAttribute(String name, PositionTagged1 prefix, PositionTagged1 suffix, AttributeValue[] values) at ASP._Page_Views_AdminSurvey_TopDown_cshtml.Execute() in c:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\fdd62ffd\90d151d1\App_Web_xsolwitr.2.cs:line 0 at System.Web.WebPages.WebPageBase.ExecutePageHierarchy() at System.Web.Mvc.WebViewPage.ExecutePageHierarchy() at System.Web.WebPages.StartPage.ExecutePageHierarchy() at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage) at System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context) at System.Web.Mvc.ControllerActionInvoker.<>c_DisplayClass1a.b_17() at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func1 continuation) at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func1 continuation) at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters, ActionResult actionResult) at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c_DisplayClass25.b_22(IAsyncResult asyncResult) at System.Web.Mvc.Controller.<>c_DisplayClass1d.b_18(IAsyncResult asyncResult) at System.Web.Mvc.Async.AsyncResultWrapper.<>c_DisplayClass4.b_3(IAsyncResult ar) at System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) at System.Web.Mvc.Async.AsyncResultWrapper.<>c_DisplayClass4.b_3(IAsyncResult ar) at System.Web.Mvc.MvcHandler.<>c_DisplayClass6.<>c_DisplayClassb.b_4(IAsyncResult asyncResult) at System.Web.Mvc.Async.AsyncResultWrapper.<>c_DisplayClass4.b__3(IAsyncResult ar) at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

Upvotes: 7

Views: 1328

Answers (4)

dav_i
dav_i

Reputation: 28137

Very interesting problem and I'm glad you found your answer!

Just a quick fix if for some reason you are stuck with the old version of the DLL - use the null coalescing operator ?? to make sure the contents are never null

<div>
    <input value="@Html.Raw(str ?? "")" />
</div>

Upvotes: 0

Dave Alperovich
Dave Alperovich

Reputation: 32500

Let's dig into the Razor View Engine:

When your Action Method calls

return View()

The View() method returns a ViewResult Object. The ViewResult Object has an ExecuteResult() Method -- which is responsible for creating the HTML Document.

When ExecuteResult() method encounters a Helper like @Html.Raw, it checks context. In the case of populating attributes, the Razor View Engine tries to be intelligent (or not dumb) by following rules and avoiding pit falls. The method used for attribute value rendering is WebPageExecutingBase.WriteAttributeTo().

If you look up the signature for WriteAttributeTo(), you see that it takes a ParamArray last. Again, we're looking into abstract methods (not published), but I suspect the implentation for WriteAttributeTo() method has not accounted for a null array and raises an exception.

Upvotes: 1

GendoIkari
GendoIkari

Reputation: 11914

Thanks to help from nemesv and Dave A, I have been able to track down the issue. It's a 2-part answer.

1) The reason for the exception appeared to be that there was a bug in the Razor implementation of combining Html.Raw inside an HTML attribute. When the Razor View Engine comes across text inside an HTML attribute, it uses the WebPageExecutingBase.WriteAttributeTo() method, even if it's just inside plain HTML. Previously I was under the impression that the Razor View Engine only processed the server-side commands (code that comes after the @ symbol). Although both Html.Raw and WriteAttibuteTo() allowed null values, special processing is needed to handle combining the 2, and that code was crashing if there was a null value.

2) This has since been updated/fixed in the most recent release of System.Web.WebPages.dll, which leads to the second part of the answer. The project referenced Ver 2.0.20505.0 of that dll, and it was deployed in the bin folder of the project. This version contains the bug.

But even though it was referenced by the project, and in the bin folder, the testing server didn't use that version of the DLL for assembly binding. fuslog.exe revealed that it was binding an assembly that was registered in the GAC instead, which was Ver 2.0.20710.0. The QA server had this in the GAC while the production server did not. I didn't know that the GAC would override a dll that's in the bin folder.

I have updated my project to reference the latest ASPNetMVC package, which includes Ver 2.0.30506.0 of the WebPages dll.

Upvotes: 5

James
James

Reputation: 82136

Could this minor build number difference actually make a difference?

Of course it can, a minor build generally consists of non-breaking changes but that doesn't mean that they can't contain bugs. It looks like the issue is occurring in System.Web.WebPages.WebPageExecutingBase therefore it's probably safe to assume that the System.Web.dll version mismatch is probably the source of the problem.

You could run both DLLs through a disassembler and see if there are any obvious changes in and around that area, however, if you know the issue is fixed in the later build then just use that on your deployment machine.


There was an issue relating to Html.Raw not decoding text correctly when being used in an attribute that was fixed in August, not sure that was the change between the 2 versions which fixed the problem.

Upvotes: 2

Related Questions