Search code examples
servicestackservicestack-razor

ServiceStack InMemoryVirtualPathProvider for Razor - GetViewPage null


I tested this with the default out of the box implementation and GetViewPage retrieves the view from the file system without a problem.

I swapped out the RazorFormat's VirtualFileSource for the inmemory one:

 Plugins.Add(new RazorFormat() {
            VirtualFileSources = new InMemoryVirtualPathProvider(this),
  });

In the service I'm writing a view if it doesn't exist:

 var helloView = razor.GetViewPage(email.BlastId.ToString());
 if (helloView==null)
 {
   ((InMemoryVirtualPathProvider)razor.VirtualFileSources)
   .WriteFile("~/views/"+email.BlastId + ".cshtml", email.Blast);
   // .WriteFile(email.BlastId + ".cshtml", email.Blast);  doesn't work
 }
 helloView = razor.GetViewPage(email.BlastId.ToString());
 //helloView is always null

I've confirmed that the RazorFormat's VirtualFileSource has the file, the GetViewPage just doesn't retrieve it.

Screenshot of the file located in the VirtualFileSource: https://db.tt/8oirKd9Msi

Furthermore this returns true: razor.VirtualFileSources.FileExists("~/views/"+email.BlastId + ".cshtml") I've tried it without the views folder/etc. It doesn't seem to make an impact.


Solution

  • The RazorFormat loads compiled views on Startup, so the view needs to exist in the VirtualFileSources before RazorFormat is registered in order for it to be available with GetViewPage().

    To add a file after RazorFormat has loaded, you need to call AddPage() after it's written to the Virtual File System, e.g:

    razorFormat.VirtualFileSources.WriteFile(filePath, contents);
    var razorView = razorFormat.AddPage(filePath);
    

    If you only wanted to create a temporary Razor View you can call CreatePage() to create the view:

    var razorView = razorFormat.CreatePage(razorHtml);
    

    And render it with:

    razorFormat.RenderToHtml(razorView, model);
    

    Or if both the Razor Page and model is temporary, it can be condensed in the 1-liner:

    var html = razorFormat.CreateAndRenderToHtml(razorHtml, model);
    

    Working Example

    const string template = "This is my sample view, Hello @Model.Name!";
    
    RazorFormat.VirtualFileSources.WriteFile("/Views/simple.cshtml", template);
    var addedView = RazorFormat.AddPage("/Views/simple.cshtml");
    var viewPage = RazorFormat.GetViewPage("simple"); //addedView == viewPage
    
    var html = RazorFormat.RenderToHtml(viewPage, new { Name = "World" });
    
    html.Print(); //= "This is my sample view, Hello World!"