Make ASP.NET MVC 3 Razor View Engine ignore .vbhtm

2019-02-01 02:33发布

问题:

How can I remove the VB Razor Engine or configure the RazorViewEngine to not use and look for .vbhtml files on disk? For new ASP.NET MVC 3 Razor projects, I always remove the WebFormViewEngine in Application_Start because I won't ever be using it and so I don't need it to search for .aspx, .ascx or .master files on disk. For this same reason I would like to avoid .vbhtml file searching.

回答1:

This is the code for your custom view engine:

public class CSRazorViewEngine : RazorViewEngine {

    public CSRazorViewEngine() {

        base.AreaViewLocationFormats = new string[] { 
            "~/Areas/{2}/Views/{1}/{0}.cshtml",
            "~/Areas/{2}/Views/Shared/{0}.cshtml"
        };

        base.AreaMasterLocationFormats = new string[] { 
            "~/Areas/{2}/Views/{1}/{0}.cshtml",
            "~/Areas/{2}/Views/Shared/{0}.cshtml"
        };

        base.AreaPartialViewLocationFormats = new string[] { 
            "~/Areas/{2}/Views/{1}/{0}.cshtml",
            "~/Areas/{2}/Views/Shared/{0}.cshtml"
        };

        base.ViewLocationFormats = new string[] {
            "~/Views/{1}/{0}.cshtml",
            "~/Views/Shared/{0}.cshtml"
        };

        base.PartialViewLocationFormats = new string[] {
            "~/Views/{1}/{0}.cshtml",
            "~/Views/Shared/{0}.cshtml"
        };

        base.MasterLocationFormats = new string[] {
            "~/Views/{1}/{0}.cshtml",
            "~/Views/Shared/{0}.cshtml"
        };

        base.FileExtensions = new string[] { "cshtml" };
    }
}

Register this on Application_Start method like this:

ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new CSRazorViewEngine());


回答2:

Why is there no point in removing search in .vbhtml if I'm never going to use it?

Here is how I do it (but I still don't know is it a good thing to remove vbhtml):

protected void Application_Start()
{
    ViewEngines.Engines.Clear();
    ViewEngines.Engines.Add(new RazorViewEngine().DisableVbhtml());

    ...
}

Extension method code:

public static RazorViewEngine DisableVbhtml(this RazorViewEngine engine)
{
    engine.AreaViewLocationFormats = FilterOutVbhtml(engine.AreaViewLocationFormats);
    engine.AreaMasterLocationFormats = FilterOutVbhtml(engine.AreaMasterLocationFormats);
    engine.AreaPartialViewLocationFormats = FilterOutVbhtml(engine.AreaPartialViewLocationFormats);
    engine.ViewLocationFormats = FilterOutVbhtml(engine.ViewLocationFormats);
    engine.MasterLocationFormats = FilterOutVbhtml(engine.MasterLocationFormats);
    engine.PartialViewLocationFormats = FilterOutVbhtml(engine.PartialViewLocationFormats);
    engine.FileExtensions = FilterOutVbhtml(engine.FileExtensions);

    return engine;
}

private static string[] FilterOutVbhtml(string[] source)
{
    return source.Where(s => !s.Contains("vbhtml")).ToArray();
}


回答3:

There is no point in doing this.

However, if you really want to, you can clear ViewEngines, then register your own RazorViewEngine with FileExtensions set to ".cshtml".



回答4:

I figured I'd merge the examples from @tugberk and @Dimps:

public class CSHtmlRazorViewEngine : RazorViewEngine {
    public CSHtmlRazorViewEngine()
        : base() {
        this.AreaMasterLocationFormats = Filter(base.AreaMasterLocationFormats);
        this.AreaPartialViewLocationFormats = Filter(base.AreaPartialViewLocationFormats);
        this.AreaViewLocationFormats = Filter(base.AreaViewLocationFormats);
        this.FileExtensions = Filter(base.FileExtensions);
        this.MasterLocationFormats = Filter(base.MasterLocationFormats);
        this.PartialViewLocationFormats = Filter(base.PartialViewLocationFormats);
        this.ViewLocationFormats = Filter(base.ViewLocationFormats);
    }

    private static string[] Filter(
        string[] source) {
        return source.Where(
            s =>
                s.Contains("cshtml")).ToArray();
    }
}


回答5:

A summary from above with a single class.

Use it like this:

ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new FilteredRazorViewEngine("cshtml"));

Class:

public class FilteredRazorViewEngine : RazorViewEngine
{
    private string _extension;

    public FilteredRazorViewEngine(string viewTypeExtension)
        : base()
    {
        _extension = viewTypeExtension;

        AreaMasterLocationFormats = Filter(base.AreaMasterLocationFormats);
        AreaPartialViewLocationFormats = Filter(base.AreaPartialViewLocationFormats);
        AreaViewLocationFormats = Filter(base.AreaViewLocationFormats);
        FileExtensions = Filter(base.FileExtensions);
        MasterLocationFormats = Filter(base.MasterLocationFormats);
        PartialViewLocationFormats = Filter(base.PartialViewLocationFormats);
        ViewLocationFormats = Filter(base.ViewLocationFormats);
    }

    private string[] Filter(string[] source)
    {
        return source.Where(
            s =>
                s.Contains(_extension)).ToArray();
    }
}


回答6:

Like @Alex, combining and extending previous solutions.

Just in case you want to specify extensions for other ViewEngines, inherit from the 'original' and either build or filter (your preference, I just thought filtering seemed more work than starting a fresh list).

Usage:

// custom extension(s)
ViewEngines.Engines.UseOnly(new ExtensionSpecificRazorViewEngine("cshtml"));
ViewEngines.Engines.UseOnly(new ExtensionSpecificRazorViewEngine("myhtml", "xhtml"));

// filtered from original extensions
ViewEngines.Engines.UseOnly(new ExtensionSpecificRazorViewEngine(false, "cshtml", "vbhtml"));

Engine-specific:

/// <summary>
/// Razor View Engine only expecting the specified extensions
/// </summary>
public class ExtensionSpecificRazorViewEngine : RazorViewEngine
{
    public ExtensionSpecificRazorViewEngine(params string[] extensions) : this(true, extensions) { }

    public ExtensionSpecificRazorViewEngine(bool isBuildOrFilter, params string[] extensions) : this(null, isBuildOrFilter, extensions) {}

    /// <summary>
    /// Create a new ViewEngine only expecting the provided extension
    /// </summary>
    /// <param name="viewPageActivator"></param>
    /// <param name="isBuildOrFilter"></param>
    /// <param name="extensions"></param>
    public ExtensionSpecificRazorViewEngine(IViewPageActivator viewPageActivator, bool isBuildOrFilter, params string[] extensions)
        : base(viewPageActivator)
    {
        if (isBuildOrFilter) this.BuildSpecifically(extensions);
        else this.FilterSpecifically(extensions);

        this.FileExtensions = extensions;
    }
}//---  class   ExtensionSpecificRazorViewEngine

Which uses:

/// <summary>
/// Because classes can't inherit from multiple classes, we put the build/filter logic in a helper
/// that's used by the ViewEngine implementation which inherits from RazorViewEngine or WebFormViewEngine, etc
/// </summary>
public static class ExtensionSpecificViewEngineExtensions
{
    /// <summary>
    /// <para>Given a collection of ViewEngines, clear them and add the indicated engine</para>
    /// <example>ex) <code>ViewEngines.Engines.UseOnly(new RazorViewEngine());</code></example>
    /// </summary>
    /// <param name="engines">list of available engines</param>
    /// <param name="engine">the only engine to use</param>
    public static void UseOnly(this ViewEngineCollection engines, IViewEngine engine)
    {
        engines.Clear();
        engines.Add(engine);
    }

    /// <summary>
    /// Build the lookup paths specifically for the indicated extension(s)
    /// </summary>
    /// <param name="engine"></param>
    /// <param name="extensions"></param>
    public static void BuildSpecifically(this BuildManagerViewEngine engine, string[] extensions)
    {
        engine.AreaMasterLocationFormats =      Build(extensions, "~/Areas/{2}");
        engine.AreaPartialViewLocationFormats = Build(extensions, "~/Areas/{2}");
        engine.AreaViewLocationFormats =        Build(extensions, "~/Areas/{2}");
        engine.FileExtensions =                 Build(extensions);
        engine.MasterLocationFormats =          Build(extensions);
        engine.PartialViewLocationFormats =     Build(extensions);
        engine.ViewLocationFormats =            Build(extensions);
    }
    /// <summary>
    /// Filter the existing, default extensions from the view engine's lookup paths for the indicated extensions
    /// </summary>
    /// <param name="engine"></param>
    /// <param name="extensions"></param>
    public static void FilterSpecifically(this BuildManagerViewEngine engine, string[] extensions)
    {
        engine.AreaMasterLocationFormats =      Filter(extensions, engine/*base*/.AreaMasterLocationFormats);
        engine.AreaPartialViewLocationFormats = Filter(extensions, engine/*base*/.AreaPartialViewLocationFormats);
        engine.AreaViewLocationFormats =        Filter(extensions, engine/*base*/.AreaViewLocationFormats);
        engine.FileExtensions =                 Filter(extensions, engine/*base*/.FileExtensions);
        engine.MasterLocationFormats =          Filter(extensions, engine/*base*/.MasterLocationFormats);
        engine.PartialViewLocationFormats =     Filter(extensions, engine/*base*/.PartialViewLocationFormats);
        engine.ViewLocationFormats =            Filter(extensions, engine/*base*/.ViewLocationFormats);
    }

    private static string[] Build(string[] extensions, string prefix = "~")
    {
        return extensions.SelectMany(x => new[] {
                prefix + "/Views/{1}/{0}." + x,
                prefix + "/Views/Shared/{0}." + x
            }).ToArray();
    }

    private static string[] Filter(string[] extensions, params string[] source)
    {
        return source.Where(s => extensions.Any(s.EndsWith)).ToArray();
    }
}//---  class   ExtensionSpecificViewEngineExtensions


回答7:

This one keeps the original RazorViewEngine and cleans away the VB extensions.

//Remove the legacy ASPX view engine
ViewEngines.Engines.Remove(ViewEngines.Engines.OfType<WebFormViewEngine>().Single());

//Remove VB from the remaining view engine
var target = ViewEngines.Engines.OfType<RazorViewEngine>().Single();
(new Expression<Func<RazorViewEngine,string[]>>[] {
    y => y.FileExtensions,
    y => y.ViewLocationFormats,
    y => y.PartialViewLocationFormats,
    y => y.MasterLocationFormats,
    y => y.AreaMasterLocationFormats,
    y => y.AreaPartialViewLocationFormats,
    y => y.AreaViewLocationFormats
}
).Select(y => (PropertyInfo)((MemberExpression)y.Body).Member).ToList()
    .ForEach(y => y.SetValue(target,((string[])y.GetValue(target))
    .Where(x => x.EndsWith("cshtml")).ToArray(),null));