2

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.

lucuma
  • 18,247
  • 4
  • 66
  • 91

1 Answers1

3

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!"
mythz
  • 141,670
  • 29
  • 246
  • 390
  • After adding the page (first example) how do I retrieve it again? GetViewPage returns null still? – lucuma Apr 20 '17 at 14:28
  • @lucuma Adding the page should return the page? – mythz Apr 20 '17 at 14:29
  • That is correct, it does, but if I need to send an email to 1000 employees I wanted to add it one time and just retrieve it on the next 999. What is the point of `AddPage` ? – lucuma Apr 20 '17 at 14:30
  • It adds the compiled page, you can reuse the razorView instance returned with different models to generate html for each model. Don't use add `~/` when adding the page. – mythz Apr 20 '17 at 14:33
  • I understand I can cache the `razorView` that is returned from AddPage myself which is what I think you are saying I need to do. The GetViewPage never returns it after adding it. – lucuma Apr 20 '17 at 14:35
  • @lucuma I've added a [working test example](https://github.com/ServiceStack/ServiceStack/commit/e751df1ed401d55710ca7229965a2474f489c216) – mythz Apr 20 '17 at 14:52
  • @lucuma `AddPage` is on `RazorFormat` and there are [WriteFile extension methods on IVirtualPathProvider](https://github.com/ServiceStack/ServiceStack/blob/master/src/ServiceStack/VirtualPath/VirtualPathProviderExtensions.cs) – mythz Apr 20 '17 at 14:58
  • I removed my last comment (tired). I removed the /views from the path and I think that caused it to not find it on the getviewpage. Your example works in my project. Very much appreciate your help and answers. – lucuma Apr 20 '17 at 15:05