2
votes

Update

Thinking that the culprit was some conflict between MvcContrib dependencies and a .NET 4.5 web app, I tried to avoid using MvcContrib PA's, so I completely rebuilt a new solution without using them (I'm experimenting with Autofac + MEF). Yet, even in this solution I got exactly the same error. By commenting out a line at a time of my view, it turns out that the offending method is @Html.EditorFor for the model's Title property. If I replace it with @Html.TextBoxFor, everything seems to work. So this seems to rule out any issue with PA and MvcContrib. Any idea?

Original post

I'm experiencing a strange issue with an MVC4 Razor app with some portable areas (http://lostechies.com/erichexter/2009/11/01/asp-net-mvc-portable-areas-via-mvccontrib/), which has suddenly starting throwing exceptions when using an HTML helper in my area view. The exception is like:

System.NullReferenceException was unhandled by user code
  HResult=-2147467261
  Message=Object reference not set to an instance of an object.
  Source=App_Web_field.master.5f132152.8jdnc_7s
  StackTrace:
       at ASP.views_inputbuilders_editortemplates_field_master.__Render__control1(HtmlTextWriter __w, Control parameterContainer) in http://server/Views/InputBuilders/EditorTemplates/Field.Master:line 5
       at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
       at System.Web.UI.Control.RenderChildren(HtmlTextWriter writer)
       at System.Web.UI.Control.Render(HtmlTextWriter writer)
       at System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter)
       at System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter)
       at System.Web.UI.Control.RenderControl(HtmlTextWriter writer)
       at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
       at System.Web.UI.Control.RenderChildren(HtmlTextWriter writer)
       at System.Web.UI.Page.Render(HtmlTextWriter writer)
       at System.Web.Mvc.ViewPage.Render(HtmlTextWriter writer)
       at System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter)
       at System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter)
       at System.Web.UI.Control.RenderControl(HtmlTextWriter writer)
       at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
  InnerException: 

My view relevant code is:


@using Cad.Web.Areas.Assets
@model Cad.Web.Areas.Editing.Models.ItemEditModel

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>@StringResources.NewItem</legend>
        @Html.HiddenFor(model => model.Id)
        @Html.HiddenFor(model => model.AuthorId)

        <ol>
            <li>
                @Html.LabelFor(model => model.Title)    
                @Html.EditorFor(model => model.Title)
                @Html.ValidationMessageFor(model => model.Title)
            </li>
            <li>
                @Html.LabelFor(model => model.Description)
                @Html.TextAreaFor(model => model.Description, 4, 60, null)
                @Html.ValidationMessageFor(model => model.Description)
            </li>
        </ol>

        @Html.AntiForgeryToken()
        <input type="submit" value="@StringResources.Create" />
    </fieldset>
}

If I comment out the content of the two li everything works. If I uncomment them, I get the exception as soon as the action method returns its result. I can confirm the model being passed to the view is not null, and I can even access its fields without errors e.g. by adding a paragraph with @Model.Title. I tried setting a breakpoint in any of the @Html... lines, but it is not hit and the same exception is thrown.

Looks like there is something wrong with my portable areas including views, but I'm getting no clue from this exception. Here is my procedure for building the whole architecture with PA, at least this could be useful to newbies like me (VS2012, C#, MVC4):

a) create a new blank solution. In it, create a new class library project which holds the PA. Add to this project MvcContrib.Mvc3-ci using NuGet, and the references to MVC assemblies (System.Web.Mvc, System.Web.Routing, System.Web.Razor, etc: I just copied all the MVC related references from my host web project -see below, under (b)-). Create your PA folder, with subfolders for controllers, models and views. Set the views to embedded resources, and add an area registration class derived from PortableAreaRegistration (in the same namespace of the PA folder), like this:

public class EditingAreaRegistration : PortableAreaRegistration
{
    public override string AreaName { get { return "Editing"; } }

    public override void RegisterArea(AreaRegistrationContext context, IApplicationBus bus)
    {
        base.RegisterArea(context, bus);
        context.MapRoute(
            "Editing_default",
            "Editing/{controller}/{action}/{id}",
            new { action = "Index", id = UrlParameter.Optional }
        );
    }
}

Also, in the Areas folder add a minimal web.config:

<?xml version="1.0"?>
<configuration>
    <system.web>
      <compilation debug="true" targetFramework="4.5" />
      <httpRuntime targetFramework="4.5" />
    </system.web>
</configuration>

And in the Views folder I place a _ViewStart.cshtml (I take mine from the host web app).

b) create a host web application, referencing the PA project and the same MvcContrib. In global.asax add a call to PortableAreaRegistration.RegisterEmbeddedViewEngine(), so that it looks like this:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    PortableAreaRegistration.RegisterEmbeddedViewEngine();

    WebApiConfig.Register(GlobalConfiguration.Configuration);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
    AuthConfig.RegisterAuth();
}

I also added a (non-portable) area in this web application (for admin purposes); there, in the Areas folder I ensure that the pages element in web.config has validateRequest="false" (http://www.myclojureadventure.com/2010/06/mvccontrib-portable-areas-part-1.html). I can then specify the area name in my routes (of course, tools like Resharper will signal an error in the view, but I can safely ignore it) and I am taken to the PA as if it were physically located in the host web app.

1

1 Answers

0
votes

Could you show your model?

Is any of your model fields a foreign object?

Without knowing what your model look like you could try this:

    <ol>
        <li>
            @if(Model.Title!=null) {
               @Html.LabelFor(model => model.Title)    
               @Html.EditorFor(model => model.Title)
               @Html.ValidationMessageFor(model => model.Title)
            }
        </li>
        <li>
            @if(Model.Description!=null) {
               @Html.LabelFor(model => model.Description)
               @Html.TextAreaFor(model => model.Description, 4, 60, null)
               @Html.ValidationMessageFor(model => model.Description)
            }
        </li>
    </ol>

Even though -you- know your object is not null, your view does not know. If your model does have a foreign object reference, for example

public Description Description { get; set; }

You could try changing that into

public virtual Description Description { get; set; }

and see what happens.