2

suddenly my MVC application stopped using the custom EditorFor or DisplayFor templates I have. I'm not sure when exactly it failed since I've been changing the UI. I have the templates sitting in DisplayTemplates and EditorTemplates under the Shared folder. I do override the ViewEnginesCollection in Global.asax with this:

ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new CSHtmlRazorViewEngine {
    PartialViewLocationFormats = new string[] { 
        "~/Views/Shared/EditorTemplates/{0}.cshtml",
        "~/Views/Shared/Partials/{0}.cshtml"
    }
});

Where CSHtmlRazorViewEngine is:

public sealed class CSHtmlRazorViewEngine : RazorViewEngine {
    public CSHtmlRazorViewEngine()
        : base() {
        this.AreaViewLocationFormats = new string[2] {
            "~/Areas/{2}/Views/{1}/{0}.cshtml",
            "~/Areas/{2}/Views/Shared/{0}.cshtml"
        };
        this.AreaMasterLocationFormats = new string[2] {
            "~/Areas/{2}/Views/{1}/{0}.cshtml",
            "~/Areas/{2}/Views/Shared/{0}.cshtml"
        };
        this.AreaPartialViewLocationFormats = new string[2] {
            "~/Areas/{2}/Views/{1}/{0}.cshtml",
            "~/Areas/{2}/Views/Shared/{0}.cshtml"
        };
        this.ViewLocationFormats = new string[3] {
            "~/Views/{0}.cshtml",
            "~/Views/{1}/{0}.cshtml",
            "~/Views/Shared/{0}.cshtml"
        };
        this.MasterLocationFormats = new string[2] {
            "~/Views/{1}/{0}.cshtml",
            "~/Views/Shared/{0}.cshtml"
        };
        this.PartialViewLocationFormats = new string[2] {
            "~/Views/{1}/{0}.cshtml",
            "~/Views/Shared/{0}.cshtml"
        };
        this.FileExtensions = new string[1] {
            "cshtml"
        };
    }
}

I'm having a bit of a hard time understanding where I've gone wrong all of the sudden. Any recommendations on where to check for what?

UPDATE - Code Examples

Here's the Edit.cshtml page for an Office object:

<div class="Section">
    @using (Html.BeginForm("Edit", "Offices", new {
        id = Model.Office.Id
    }, FormMethod.Post)) {
        <div>
            <input type="submit" value="Save" />
        </div>
        @Html.EditorFor(m => m.Office, new {
            Regions = Model.Regions,
            States = Model.States
        })
    }
    @Html.Partial("Equipments", Model.Equipments)
</div>

And here's the EditorFor template for Office that's being requested:

@model Office
<p>
    @Html.Label("Name", "Name:")
    @Html.TextBox("Name", Model.Name, new {
        required = string.Empty
    })
</p>
<p>
    @Html.Label("RegionId", "Region:")
    @Html.DropDownList("RegionId", new SelectList((IEnumerable<Region>)ViewData["Regions"], "Id", "Name", Model.RegionId), string.Empty, new {
        required = string.Empty
    })
</p>
@Html.EditorFor(m => m.Address)

And here's the OfficesController.Edit() ActionResult:

[HttpGet]
public async Task<ActionResult> Edit(
    short id) {
    if (id > 0) {
        Office office = await base.Repository.FindSingleOrDefaultAsync<Office, short>(id);

        if (office != null) {
            Task<IQueryable<Equipment>> equipments = Task.Run(() => base.Repository.FindEquipment<Office>(id));
            Task<IQueryable<Region>> regions = Task.Run(() => base.Repository.Find<Region>());
            Task<IQueryable<State>> states = Task.Run(() => base.Repository.Find<State>());

            await Task.WhenAll(equipments, regions, states);

            return base.View(new OfficesView {
                Equipments = equipments.Result.ToList(),
                Office = office,
                Regions = regions.Result,
                States = states.Result,
                ViewData = new OfficeViewData {
                    Map = new Map {
                        Center = office.Address.Position.ToPoint(),
                        Polygons = (office.Boundaries != null) ? new Polygon[] {
                            office.Boundaries.ToPolygon()
                        } : null
                    }
                }
            });
        }
    }

    return base.RedirectToAction("List");
}

There are no compilation or run-time exceptions being generated. The EditorFor just silently fails to find the template and generates the default one instead. The code pattern pretty much repeats for every other object.

7
  • Are you getting any exceptions that it cannot find the view (i.e. the template)? Because if you are not getting any exceptions, the problem is not with your view locations, but elsewhere. Commented Feb 27, 2014 at 6:47
  • No, no exceptions, instead I just get the default generated editor for the object. Commented Feb 27, 2014 at 6:54
  • Can you maybe post a snippet of a form that uses one of your display and / or editor template, and the name of the display / editor template and possible if your data models / properties are decorated with [UIHint] a snippet of that. Commented Feb 27, 2014 at 7:04
  • @jacqijvv, I've updated my question with the code examples. Commented Feb 27, 2014 at 7:14
  • So just to make sure one more time, your editor template naming convention is Office.cshtml for the Office object, and Address.cshtml for the Address object etc? Commented Feb 27, 2014 at 7:19

1 Answer 1

4

MVC will add itself the EditorTemplates/ segment to the partial view name when looking for an editor template. You can check the source code here, ExecuteTemplate function.

You have set the partial view locations as:

"~/Views/Shared/EditorTemplates/{0}.cshtml"
"~/Views/Shared/Partials/{0}.cshtml"

When looking for the Address editor template, MVC will use EditorTemplates/Address as the partial view name. That means it will check the 2 following partial view locations:

~/Views/Shared/EditorTemplates/EditorTemplates/Address.cshtml
~/Views/Shared/Partials/EditorTemplates/Address.cshtml

If it cannot find them there, it will go back the default editor templates.

Probably your editor templates are sitting currently in the first EditorTemplates folder?

Sign up to request clarification or add additional context in comments.

1 Comment

Yup, that was it. What resolved the issue for me was when I moved the "~/Views/Shared/Partials/{0}.cshtml" format out of the init for the CSHtmlRazorViewEngine and directly into the class. Then in Global.asax, I just left it with an empty init and it all started working again.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.