Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 7624295
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 31, 20262026-05-31T04:55:31+00:00 2026-05-31T04:55:31+00:00

I have a utility method that uses Display Templates to generate HTML: public static

  • 0

I have a utility method that uses Display Templates to generate HTML:

public static MvcHtmlString MyMethod(this HtmlHelper html)
{
    var model = new Model();

    var viewDataContainer = new ViewDataContainer<INode>(model);
    var modelHtmlHelper = new HtmlHelper<INode>(html.ViewContext, 
                                                        viewDataContainer);

    return modelHtmlHelper.DisplayFor(node => node, "TemplateName");
}

I am trying to write a test to verify its behaviour. So far I have come up with:

public class when_extension_method_is_used
{
    static MvcHtmlString output;

    Because of = () =>
    {
        var httpContext = new Mock<HttpContextBase>();
        httpContext.SetupGet(hc => hc.Items).Returns(new ListDictionary());

        var routeData = new RouteData();
        routeData.Values.Add("controller", "Test");

        var viewContext = new ViewContext
        {
            RouteData = routeData,
            HttpContext = httpContext.Object,
            ViewData = new ViewDataDictionary()
        };

        var viewDataContainer = new ViewPage();

        var htmlHelper = new HtmlHelper(viewContext, viewDataContainer);

        output = htmlHelper.MyMethod();
    };

    It should_just_work =
        () => output.ToString().ShouldEqual("<blink></blink>");
    }
}

This doesn’t work. I get a NullReferenceException at:

at System.Web.Compilation.BuildManager.GetVPathBuildResultFromCacheInternal(VirtualPath virtualPath, Boolean ensureIsUpToDate)
at System.Web.Compilation.BuildManager.GetVPathBuildResultInternal(VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate)
at System.Web.Compilation.BuildManager.GetVPathBuildResultWithNoAssert(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate)
at System.Web.Compilation.BuildManager.GetObjectFactory(String virtualPath, Boolean throwIfNotFound)
at System.Web.Mvc.BuildManagerWrapper.System.Web.Mvc.IBuildManager.FileExists(String virtualPath) in BuildManagerWrapper.cs: line 8
at System.Web.Mvc.BuildManagerViewEngine.FileExists(ControllerContext controllerContext, String virtualPath) in BuildManagerViewEngine.cs: line 42
at System.Web.Mvc.VirtualPathProviderViewEngine.GetPathFromGeneralName(ControllerContext controllerContext, List`1 locations, String name, String controllerName, String areaName, String cacheKey, String[]& searchedLocations) in VirtualPathProviderViewEngine.cs: line 180
at System.Web.Mvc.VirtualPathProviderViewEngine.GetPath(ControllerContext controllerContext, String[] locations, String[] areaLocations, String locationsPropertyName, String name, String controllerName, String cacheKeyPrefix, Boolean useCache, String[]& searchedLocations) in VirtualPathProviderViewEngine.cs: line 167
at System.Web.Mvc.VirtualPathProviderViewEngine.FindPartialView(ControllerContext controllerContext, String partialViewName, Boolean useCache) in VirtualPathProviderViewEngine.cs: line 113
at System.Web.Mvc.ViewEngineCollection.<>c__DisplayClass8.<FindPartialView>b__7(IViewEngine e) in ViewEngineCollection.cs: line 97
at System.Web.Mvc.ViewEngineCollection.Find(Func`2 lookup, Boolean trackSearchedPaths) in ViewEngineCollection.cs: line 66
at System.Web.Mvc.ViewEngineCollection.Find(Func`2 cacheLocator, Func`2 locator) in ViewEngineCollection.cs: line 48
at System.Web.Mvc.ViewEngineCollection.FindPartialView(ControllerContext controllerContext, String partialViewName) in ViewEngineCollection.cs: line 96
at System.Web.Mvc.Html.TemplateHelpers.ExecuteTemplate(HtmlHelper html, ViewDataDictionary viewData, String templateName, DataBoundControlMode mode, GetViewNamesDelegate getViewNames, GetDefaultActionsDelegate getDefaultActions) in TemplateHelpers.cs: line 66
at System.Web.Mvc.Html.TemplateHelpers.TemplateHelper(HtmlHelper html, ModelMetadata metadata, String htmlFieldName, String templateName, DataBoundControlMode mode, Object additionalViewData, ExecuteTemplateDelegate executeTemplate) in TemplateHelpers.cs: line 239
at System.Web.Mvc.Html.TemplateHelpers.TemplateHelper(HtmlHelper html, ModelMetadata metadata, String htmlFieldName, String templateName, DataBoundControlMode mode, Object additionalViewData) in TemplateHelpers.cs: line 192
at System.Web.Mvc.Html.TemplateHelpers.TemplateFor(HtmlHelper`1 html, Expression`1 expression, String templateName, String htmlFieldName, DataBoundControlMode mode, Object additionalViewData, TemplateHelperDelegate templateHelper) in TemplateHelpers.cs: line 181
at System.Web.Mvc.Html.TemplateHelpers.TemplateFor(HtmlHelper`1 html, Expression`1 expression, String templateName, String htmlFieldName, DataBoundControlMode mode, Object additionalViewData) in TemplateHelpers.cs: line 174
at System.Web.Mvc.Html.DisplayExtensions.DisplayFor(HtmlHelper`1 html, Expression`1 expression, String templateName) in DisplayExtensions.cs: line 43

The source of the exception is System.Web.VirtualPath.GetCacheKey():

public string GetCacheKey()
{
    // VirtualPathProvider property is null
    return HostingEnvironment.VirtualPathProvider.GetCacheKey(this);
}
  • Is there a way to initialise HostingEnvironment.VirtualPathProvider?
  • If not, is there a better way to test code that depends on Display Templates?
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-31T04:55:33+00:00Added an answer on May 31, 2026 at 4:55 am

    Created a workaround. It is ugly and violates best practices, but works.

    1) Add extensibility hook to extension method class:

    public static class MyExtensionMethods
    {
        static MyExtensionMethods()
        {
            Renderer = (html, model) =>
            {
                // this is the default implementation that will be used by MVC runtime
                var viewDataContainer = new ViewDataContainer<INode>(model);
                var modelHtmlHelper = new HtmlHelper<INode>(html.ViewContext, viewDataContainer);
    
                return modelHtmlHelper.DisplayFor(node => node, "TemplateName");
            };
        }
    
        public static Func<HtmlHelper, INode, MvcHtmlString> Renderer { get; set; }
    
        public static MvcHtmlString Menu(this HtmlHelper html)
        {
            var model = new Model();
            return Renderer(html, model);
        }
    }
    

    2) Use self-hosted Razor engine for template execution:

    using System;
    using System.CodeDom.Compiler;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using System.Web.Razor;
    using Microsoft.CSharp;
    
    namespace YourNamespace.Specifications.SpecUtils
    {
        public sealed class InMemoryRazorEngine
        {
            public static ExecutionResult Execute<TModel>(string razorTemplate, TModel model, params Assembly[] referenceAssemblies)
            {
                var razorEngineHost = new RazorEngineHost(new CSharpRazorCodeLanguage());
                razorEngineHost.DefaultNamespace = "RazorOutput";
                razorEngineHost.DefaultClassName = "Template";
                razorEngineHost.NamespaceImports.Add("System");
                razorEngineHost.DefaultBaseClass = typeof(RazorTemplateBase<TModel>).FullName;
    
                var razorTemplateEngine = new RazorTemplateEngine(razorEngineHost);
    
                using (var template = new StringReader(razorTemplate))
                {
                    var generatorResult = razorTemplateEngine.GenerateCode(template);
    
                    var compilerParameters = new CompilerParameters();
                    compilerParameters.GenerateInMemory = true;
                    compilerParameters.ReferencedAssemblies.Add(typeof(InMemoryRazorEngine).Assembly.Location);
                    if (referenceAssemblies != null)
                    {
                        foreach (var referenceAssembly in referenceAssemblies)
                        {
                            compilerParameters.ReferencedAssemblies.Add(referenceAssembly.Location);
                        }
                    }
    
                    var codeProvider = new CSharpCodeProvider();
                    var compilerResult = codeProvider.CompileAssemblyFromDom(compilerParameters, generatorResult.GeneratedCode);
    
                    var compiledTemplateType = compilerResult.CompiledAssembly.GetExportedTypes().Single();
                    var compiledTemplate = Activator.CreateInstance(compiledTemplateType);
    
                    var modelProperty = compiledTemplateType.GetProperty("Model");
                    modelProperty.SetValue(compiledTemplate, model, null);
    
                    var executeMethod = compiledTemplateType.GetMethod("Execute");
                    executeMethod.Invoke(compiledTemplate, null);
    
                    var builderProperty = compiledTemplateType.GetProperty("OutputBuilder");
                    var outputBuilder = (StringBuilder)builderProperty.GetValue(compiledTemplate, null);
                    var runtimeResult = outputBuilder.ToString();
    
                    return new ExecutionResult(generatorResult, compilerResult, runtimeResult);
                }
            }
    
            #region Nested type: ExecutionResult
    
            public sealed class ExecutionResult
            {
                public ExecutionResult(GeneratorResults generatorResult, CompilerResults compilerResult, string runtimeResult)
                {
                    GeneratorResult = generatorResult;
                    CompilerResult = compilerResult;
                    RuntimeResult = runtimeResult;
                }
    
                public GeneratorResults GeneratorResult { get; private set; }
                public CompilerResults CompilerResult { get; private set; }
                public string RuntimeResult { get; private set; }
            }
    
            #endregion
    
            #region Nested type: RazorTemplateBase
    
            public abstract class RazorTemplateBase<TModel>
            {
                protected RazorTemplateBase()
                {
                    OutputBuilder = new StringBuilder();
                }
    
                public TModel Model { get; set; }
                public StringBuilder OutputBuilder { get; private set; }
    
                public abstract void Execute();
    
                public virtual void Write(object value)
                {
                    OutputBuilder.Append(value);
                }
    
                public virtual void WriteLiteral(object value)
                {
                    OutputBuilder.Append(value);
                }
            }
    
            #endregion
        }
    }
    

    3) Override default extension method Renderer in your test

    public class when_extension_method_is_used
    {
        static MvcHtmlString output;
    
        Because of = () =>
        {    
            var htmlHelper = new HtmlHelper(new ViewContext(), new ViewPage());
    
            MyExtensionMethods.Renderer = (html, model) =>
            {
                const string template = "<blink>@Model</blink>";
    
                var executionResult = InMemoryRazorEngine.Execute(template, model);
                return new MvcHtmlString(executionResult.RuntimeResult);
            };
    
            output = htmlHelper.MyMethod();
        };
    
        It should_just_work =
            () => output.ToString().ShouldEqual("<blink>make UX experts cry!</blink>");
        }
    }
    

    Notes:

    • And in three easy steps you can now test the logic of your extension methods
    • I have implemented just enough code to get my tests working (namely @Model). If you need richer API support within the views – you will have to extend RazorTemplateBase
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

We have a static method in a utility class that will download a file
I have a utility method (= a static one) that I call a lot,
I have a utility that I put together that uses the .NET Framework to
I have a utility class that creates & returns a db connection: Public Shared
I have created a utility method that contains some try/catches in it. In those
I have a utility method that goes through various classes and recursively retrieves the
I have a small utility extension method that performs some null checks on some
I have a set of methods that do some utility work over SQL connection,
I have a utility (grep) that gives me a list of filenames and a
I have small utility that does some processing on a file and changes the

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.