Question

I have a helper method in a file under the App_Code directory. The method works perfectly fine in MVC 3, but after upgrading to MVC 4 it doesn't. It's failing at the first @if() block...

[Edit] This looks like a parsing error in the Razor engine. I'm getting the 'Object reference not set to an instance of an object' error when all my objects and their properties are NOT null. I guess I'll have to go to Microsoft directly.

[Edit] The error message is the old 'Object reference not set to an instance of an object.' This is weird because each object AND property in the condition are valid and not null.

@helper RenderConnectButton(System.Web.Mvc.HtmlHelper helper, ContactTwitterHandleDto contactTwitterHandle, ContactFacebookAccountDto contactFacebookAccount) {
    <ul class="socialMedia inlineList">           
        @if (contactTwitterHandle != null && contactTwitterHandle.IsValid.HasValue && contactTwitterHandle.IsValid.Value)
        {
            var tHandle = "@" + contactTwitterHandle.Handle;
            <li class="twitter">
                <a class="btn" href="http://www.twitter.com/@contactTwitterHandle.Handle" target="_blank">
                    <i></i>
                    <span class="label">@tHandle</span> 
                </a>
                @if(contactTwitterHandle.FollowerCount.HasValue)
                {
                    <div class="count" id="c">
                        <i></i>
                        <u></u>
                        <span class="followers" title="@contactTwitterHandle.FollowerCount.Value followers">@FollowerCount(contactTwitterHandle.FollowerCount.Value)</span>
                    </div>
                }                    
            </li>
            <script type="text/javascript">
                $("#twitter").click(function () {
                    window.location.href = '@(helper.BuildUrlFromExpression<TenantController>(t => t.LinkTwitterAccount()))';
                })
            </script>
        }

        @if (contactFacebookAccount != null && contactFacebookAccount.IsValid.HasValue && contactFacebookAccount.IsValid.Value)
        {
            <li class="facebook">
                <a class="btn" href="@contactFacebookAccount.Url" target="_blank">
                    <i></i>
                    <span class="label">@contactFacebookAccount.Name</span> 
                </a>
                @if(contactFacebookAccount.FriendCount.HasValue)
                {
                    <div class="count" id="c">
                        <i></i>
                        <u></u>
                        <span class="followers" title="@contactFacebookAccount.FriendCount.Value friends">@FriendCount(contactFacebookAccount.FriendCount.Value)</span>
                    </div>
                }
            </li>                
        }
    </ul> }

[UPDATE] I changed the code a bit and now it's even stranger. I'm getting the same error as above at the line:

var tLink = "http://www.twitter.com/" + contactTwitterHandle.Handle; 

contactTwitterHandle and contactTwitterHandle.Handle are both NOT null.

@helper RenderConnectButton(System.Web.Mvc.HtmlHelper helper, ContactTwitterHandleDto contactTwitterHandle, ContactFacebookAccountDto contactFacebookAccount) {
    <ul class="socialMedia inlineList">           
        @if (contactTwitterHandle != null && contactTwitterHandle.IsValid.HasValue && contactTwitterHandle.IsValid.Value)
        {
            var tHandle = "@" + contactTwitterHandle.Handle;
            var tLink = "http://www.twitter.com/" + contactTwitterHandle.Handle;
            <li class="twitter">
                <a class="btn" href="@tLink" target="_blank">
                    <i></i>
                    <span class="label">@tHandle</span> 
                </a>
                @if(contactTwitterHandle.FollowerCount.HasValue)
                {
                    <div class="count" id="c">
                        <i></i>
                        <u></u>
                        <span class="followers" title="@contactTwitterHandle.FollowerCount.Value followers">@FollowerCount(contactTwitterHandle.FollowerCount.Value)</span>
                    </div>
                }                    
            </li>
            <script type="text/javascript">
                $("#twitter").click(function () {
                    window.location.href = '@(helper.BuildUrlFromExpression<TenantController>(t => t.LinkTwitterAccount()))';
                })
            </script>
        }

        @if (contactFacebookAccount != null && contactFacebookAccount.IsValid.HasValue && contactFacebookAccount.IsValid.Value)
        {
            <li class="facebook">
                <a class="btn" href="@contactFacebookAccount.Url" target="_blank">
                    <i></i>
                    <span class="label">@contactFacebookAccount.Name</span> 
                </a>
                @if(contactFacebookAccount.FriendCount.HasValue)
                {
                    <div class="count" id="c">
                        <i></i>
                        <u></u>
                        <span class="followers" title="@contactFacebookAccount.FriendCount.Value friends">@FriendCount(contactFacebookAccount.FriendCount.Value)</span>
                    </div>
                }
            </li>                
        }
    </ul>
}
Was it helpful?

Solution

I found the work-around for this problem, but first a little history. For this particular MVC project, we decided to start implementing Razor gradually. The app has a lot of "modal" areas which are filled by making an AJAX call to get a partial view. These partial views were the first to get implemented as Razor views. Later, we wanted to implement a new feature in a standard ASPX view page using a Razor partial view, but the ASPX view engine cannot render a partial Razor view so instead of using a Razor view I added a MVC helper file in the App_Code folder with a method that renders the feature. This method is what is causing the error after upgrading to MVC4. The page with the feature rendered by this method is what I'm converting to a Razor view page so I realized today that all I need to do is move the code from that method into a Razor partial view. This fixed the problem, however, I still maintain that this is a bug in the Razor engine for rendering with helper methods.

OTHER TIPS

I dummied down the method to this:

@helper RenderConnectButton(System.Web.Mvc.HtmlHelper helper, ContactTwitterHandleDto contactTwitterHandle, ContactFacebookAccountDto contactFacebookAccount) {

    <ul class="socialMedia inlineList">
        @if (contactTwitterHandle != null && contactTwitterHandle.IsValid.HasValue && contactTwitterHandle.IsValid.Value)
        {
            var tHandle = contactTwitterHandle.Handle;

            <li class="twitter">
                <a class="btn" href="http://twitter.com/@tHandle" target="_blank">
                    <i></i>
                    <span class="label">@tHandle</span> 
                </a>
            </li>
        }

    </ul>
}

If I remove @tHandle from the line:

            <a class="btn" href="http://twitter.com/@tHandle" target="_blank">

It will parse fine. If I put the Url above in a variable, then I get the error.

It's failing when trying to parse a string that is a Url.

Stack trace:

   at System.Web.WebPages.HelperPage.WriteAttributeTo(TextWriter writer, String name, PositionTagged`1 prefix, PositionTagged`1 suffix, AttributeValue[] values)
   at ASP.MvcSocialMediaHelpers.<>c__DisplayClass1.<RenderConnectButton>b__0(TextWriter __razor_helper_writer) in c:\OberonScrum\Branches\RazorUpgrade\Source\Web\App_Code\MvcSocialMediaHelpers.cshtml:line 83
   at System.Web.WebPages.HelperResult.ToString()
   at System.String.Concat(Object arg0, Object arg1)
   at ASP.views_contact_detail_aspx.__RenderMainContent(HtmlTextWriter __w, Control parameterContainer) in c:\OberonScrum\Branches\RazorUpgrade\Source\Web\Views\Contact\Detail.aspx:line 13
   at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
   at ASP.views_shared_twocolumnleftmain_master.__Render__control1(HtmlTextWriter __w, Control parameterContainer) in c:\OberonScrum\Branches\RazorUpgrade\Source\Web\Views\Shared\TwoColumnLeftMain.Master:line 109
   at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
   at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
   at System.Web.Mvc.ViewPage.Render(HtmlTextWriter writer)
   at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

[UPDATE] Tried working around the issue using TagBuilder and rendering with Html.Raw(); got the same result.

@helper RenderConnectButton(System.Web.Mvc.HtmlHelper helper, ContactTwitterHandleDto contactTwitterHandle, ContactFacebookAccountDto contactFacebookAccount) {
    <ul class="socialMedia inlineList">
        @if (contactTwitterHandle != null && contactTwitterHandle.IsValid.HasValue && contactTwitterHandle.IsValid.Value)
        {
            var tHandle = contactTwitterHandle.Handle;
            var a = new TagBuilder("a");
            a.Attributes.Add("href", "http://twitter.com/" + @tHandle);
            a.Attributes.Add("target", "_blank");
            a.Attributes.Add("class", "btn");
            a.InnerHtml = string.Format("<i></i><span class=\"label\">{0}</span>", @tHandle);

            <li class="twitter">
                @Html.Raw(a.ToString())
            </li>
        }
    </ul>
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top