7

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)

GendoIkari
  • 11,734
  • 6
  • 62
  • 104
  • The string value is null? Or is something else? Maybe this string has some unicode that is messing up with the writer. – Fals Oct 25 '13 at 21:36
  • It's only happens when it's null. Tested it by just using null directly instead of the variable also; same result. – GendoIkari Oct 25 '13 at 21:39
  • Can you repro the issue in a newly created MVC4 app (only one controller one aciton one view) deployed on your production server? Or this problem only exists in your real app? If you can repro it can you upload your repro somewhere (github/skydrive/etc)? – nemesv Oct 30 '13 at 16:43
  • @nemesv, Both servers are set up with the application being its own website in IIS. Can't see a difference in the settings of each site. I'll try to create a new app for testing now. – GendoIkari Oct 30 '13 at 16:44
  • @nemesv, the new project worked fine on both servers at first. I checked and found that when I created a new MVC project, it referenced Microsoft.AspNet.WebPages v2.0.20710.0. But my other project was referencing v2.0.20505.0. I changed the reference and re-deployed, sure enough it broke on just the prod server. So it must be a difference between those 2 versions of WebPages.dll. But... if the project references the old version, then why would that server pick up the new version? The old version is sitting in the bin folder. Could it be finding the newer version elsewhere? – GendoIkari Oct 30 '13 at 17:48
  • From the GAC? You can try to setup fuslog on the server to see which dlls are loaded form where... – nemesv Oct 30 '13 at 18:28
  • I thought I'd checked the GAC, because I checked C:\Windows\assembly, but fuslog revealed that it was coming from C:\Windows\Microsoft.NET\assembly. The prod server didn't have it in GAC at all, so it loaded from bin. (I would have thought that bin took precedence, but I guess not). Thanks! Last thing I don't know... how could the new version have gotten registered on the one server (that server also has VS and the code itself), and how do I get the prod server up to date with the same version in the GAC? – GendoIkari Oct 30 '13 at 19:14
  • I don't know maybe a windows update contained the newer version. However according to this page [Repository Tags and Version Numbers](http://aspnetwebstack.codeplex.com/wikipage?title=Building%20from%20Source). The VS 2012 RC comes with the version x.0.20505.0 and the VS 2012 RTM with the version x.0.20710.0 – nemesv Oct 30 '13 at 20:00
  • I just did an install-package command, and it updated the reference to x.0.30506.0. I'll test this version out and plan to deploy it from now on. However, the GAC still contains x.0.20710.0, and that's what's loaded when I run this on the dev server. I'll probably just uninstall it from the GAC. – GendoIkari Oct 30 '13 at 20:07
  • problem here is your Html helper object is null , set breakpoint on html.raw line and see Html is null or not.. – Vishal Sharma Nov 02 '13 at 11:33
  • @DaveA, since multiple people helped me find the solution, there was no obvious way to award the bounty. However, since you were the most helpful of the people who have an actual answer below, I've awarded it to your answer. – GendoIkari Nov 04 '13 at 18:16

4 Answers4

5

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.

Dave Alperovich
  • 32,320
  • 8
  • 79
  • 101
GendoIkari
  • 11,734
  • 6
  • 62
  • 104
2

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.

James
  • 80,725
  • 18
  • 167
  • 237
  • That does look like the sort of thing that would explain this, but that code should be in System.Web.WebPages.dll, not System.Web.dll. System.Web.WebPages.dll is deployed in the bin folder of my project, thus identical on both servers. Also, our prod server had a pending restart and after restarting System.Web.dll was updated; the problem still exists. – GendoIkari Oct 30 '13 at 15:16
  • I just confirmed that both servers are running the updated version of that particular code. Test")" /> properly leaves the HTML unencoded, which is what the issue fixed. – GendoIkari Oct 30 '13 at 15:30
1

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.

Dave Alperovich
  • 32,320
  • 8
  • 79
  • 101
  • Isn't the code actually open source? http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.WebPages/WebPageExecutingBase.cs. I can see there that if ParamArray is NULL, it would seem to crash it. But shouldn't that be in the system.web.webpages assembly? In which case both servers have the same code there. – GendoIkari Oct 30 '13 at 01:06
  • But your response is definitely helpful. I never understood before now that the Razor Engine worked that way. I figured that only the server-side code (@) was looked at by the server; and the rest was left as-is. I see now that the engine actually parses the entire View, and reads in (then writes out) the regular HTML tags too. This explains why WriteAttributeTo() would be called, at least. Before I thought it would only get called for HTML helpers. – GendoIkari Oct 30 '13 at 01:09
  • One other thing that's not clear... works fine. That should be calling WriteAttributeValues with the same NULL parameter, shouldn't it? It appears that Html.Raw(null) just returns null... – GendoIkari Oct 30 '13 at 01:15
  • @GendoIkari, 1) Yes, all code is in codeplex, but that's an awfull trace job if you're curious. MSDN doesn't publish any info, so we're left to do it our selves. That could be painfull. – Dave Alperovich Oct 30 '13 at 01:17
  • @GendoIkari, 2) There is a difference between using a Helper like `Raw` and just a `@var`. The simpler way does NOT tend to be intelligent. It's a simple parse-replace. Helpers try to be (too) intelligent. – Dave Alperovich Oct 30 '13 at 01:19
  • @GendoIkari, I see that my answer was sloppily written. I will update later and clarify better the difference between inline vars and Helpers. – Dave Alperovich Oct 30 '13 at 01:23
  • Thanks, you've already been helpful. I guess my main concern is that something can work perfectly in development and QA, then suddenly be broken in production. If system.web.webpages is identical on both servers, what else could make that difference here? – GendoIkari Oct 30 '13 at 01:25
  • @GendoIkari, That's a great question. Sorry, but I'm lost. Nothing about the Razor Engine should vary between the QA and Production. These Helpers **DO NOT** just change without good reason or code everywhere would suffer. Sorry! – Dave Alperovich Oct 30 '13 at 01:28
0

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>
dav_i
  • 27,509
  • 17
  • 104
  • 136