5

I am writing an HtmlHelper extension and I need to search for the existence of a template by name. The template in question may be a display or editor template depending on the context. My initial thought was to use ViewEngines.Engines.FindPartialView method. However, it appears that this method is not searching the ~/Views/Shared/DisplayTemplates and ~/Views/Shared/EditorTemplates directories.
I suppose this is for good reason. After all, how would the ViewEngine know whether to return the display or editor template without some additional information of context?

So, that leads to the question: how can I search for a specific EditorTemplate/DisplayTemplate I've considered adding a custom view engine to the ViewEngines collection to include these locations. I'm concerned, however, that this might be problematic.

My main concern is that the DisplayTemplate/EditorTemplate view might be served up for something unintended. Does anyone else see this as a problem?
Is it a better idea just to new up a specific DisplayTemplateViewEngine/EditorTemplateViewEngine instance when necessary and keep the ViewEngines collection clear of this specific functionality?
Is there something else I'm missing?

0

3 Answers 3

4

I absolutely love that the MVC framework is open source! I was able to determine, from the TemplateHelpers class (internal to the MVC Runtime) that the DataBoundControlMode is considered when rendering a template. The answer was simple! All I have to do is prefix the template name with the appropriate template director. So, to find a display template:

var metadata = ModelMetadata.FromLambdaExpression(expression, HtmlHelper.ViewData);
ViewEngines.Engines.FindPartialView(
    _controllerContext, 
    string.Format("DisplayTemplates/{0}", metadata.TemplateHint))

No additional view engines or routing required! In case you're interested in the application, my helper is auto-generating UI components for a given model. I wanted to enable the existence of a custom template to bypass the automated rendering.

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

3 Comments

This is the answer. However I can't mark it as such for a couple of day. Sorry if you were attracted to this post because of it's apparent 'unanswered' status.
What is metadata.TemplateHint or where does it come from?
@xr280xr: Updated to include metadata definition. Hope that serve you!
0

A WebFormViewEngine has a few properties that define (patterns for) locations to search for views.

You either follow the convention of the view engine you use, or create a custom view engine (that for examlpe extends Razor) with custom view paths.

The latter is explained here:

public class CustomViewEngine : RazorViewEngine
{
    public CustomViewEngine()
    {
        var viewLocations =  new[] {  
            "~/Views/{1}/{0}.cshtml",  
            "~/Views/Shared/{0}.cshtml",  
            "~/Views/Shared/DisplayTemplates/{0}.cshtml",  
            "~/Views/Shared/DisplayTemplates/{1}/{0}.cshtml",
            // etc
        };

        this.PartialViewLocationFormats = viewLocations;
        this.ViewLocationFormats = viewLocations;
    }
}

So I guess in your helper you should look up the current view engine and look up its view location paths and search them in order. Doesn't an Html helper have a method or property for getting the view you're currently running in?

5 Comments

Thanks for the reply. I'm not actually breaking convention; my structure is withing the expected MVC architecture definitions. The issue is that the FindPartialView method of the ViewEnginesCollection doesn't search for those locations because it wouldn't know if you wanted to the display or editor version. I did find a solution, however. See my answer for reference. Thanks again.
1) Is the code in your example the default Razor behavior? 2) What do {0} and {1} refer to?
@Shimmy this is the default. The replacement values are {0} = view name, {1} = controller name and {2} = area name (see ViewLocation and AreaAwareViewLocation at the bottom of this file).
So how do I use a view that's under another controller's view's EditorTemplates folder?
@Shimmy ask a new question.
0

Why you just map the relative path

string path = Server.MapPath("~/View/");

And then check if the file exits base on the .cshtml exit's in that specific directory

string fileName = "MyView.cshtml";
if (File.Exists(path + fileName))
    //do somethings
else
    //do another things

1 Comment

One benefit of using the ViewEngine is that it can be mocked making it testable. This solution be really difficult to unit test. Glad for your input, though!

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.