Using the Razor templating engine outside of MVC (with full mvc razor support)
Asked Answered
W

1

9

I was searching for this "holy grail" for a long time. I went through massive amount of plugins, projects, solutions etc. Each solution missing something. But first thing first.

What we want to achieve is to have posibility to render views to string (taken from mvc application) Of course the whole proccess should be done as class library (not an MVC application)

What i would expect is three step procces like this:

  1. Instal "some plugin" from nuget and configured it
  2. Copy-Paste Model and Views from MVC application to class library project (Important!!! Views copied without any modification needed to "adjust" views to "some plugin")
  3. Write some lines of code saying : "hello my 'some plugin' - render me a view called : 'myExampleView.cshtml'"

One important condition : i'm expecting exactly the same support in views as i would get in views in MVC (@Html, @RenderBody @RenderSection etc.)

And as a result i would get this view redered as a string - simple as that. Is it possible or am i only "dreaming" ? Which plugin offers all of that (and maybe even more ?:) )

For now - closest to this description was RazorEngine but i don't see posibility to pass csthml view name (it would be enough to pass path to cshtml view) Of course i can write code to load file content to string and pass it to RunCompile method but if there would be any "RederSection" - it wouldn't be handled properly (at least i assume it wouldn't)

To summarize: I want razor MVC (usability the same as in MVC application.In fact, views from MVC application would be simply copied to this class library) In this class library i can reference everything (including mentioned System.Web) This is, what i would call my "ideal solution"

What i want is to call:

namespace Example
{
    class Program
    {
        static void Main(string[] args)
        {
            string renderedView = MyDreamRazoEngine.Render("MyView", new MyViewModel () { Prop1= "a", Prop2 = "b", Prop3= new List<string>() { "c", "d", "e"})
        }
    }
}

where model (located in /Model/MyViewModel.cs) definition is :

namespace Example.Models
{
    public class MyViewModel()
    {
        public string Prop1{get;set;}
        public string Prop2{get;set;}
        public List<string> Prop3{get;set;}
    }
}

and view MyView (located in /View/MyView.cshtml) definition is:

@model Example.Models.MyViewModel
This is my view with Prop1 : @Prop1 and Prop2 : @Prop2 and list :
@foreach (var p in @Model.Prop3)
{
    @{Html.RenderPartial("viewPartial", @p);}
}

and partial view viewPartial (located in /View/viewPartial.cshtml) definition is :

@model String

<span>I present this param3 value @Model</span>

From what i can tell, everything (excluding "automatic" files handling) is possible to achieve using RazorEngine project. But maybe even files handling (exactly the same as in MVC - searching for templates in Views and Subdirectories of Views) is available in this engine ? Or is it something i must write by myself ? Or maybe some other plugin gives me all this features ?

@@UPDATE

Anish direct me to this solution : razor media type formatter for webapi

It uses razorengine and support views, in exactly the same manner as MVC application (almost) But... it doesn't work (for sure i'm missing something) What i have right now is :

public class RazoEngineExample
    {
        private static HttpRequestMessage _request;
        static void Main(string[] args)
        {
            var viewParser = new RazorViewParser(baseTemplateType: typeof(WebApiContrib.Formatting.Razor.HtmlTemplateBase<>));
            var formatter = new RazorViewFormatter(viewParser: viewParser);
            var config = new HttpConfiguration();
            config.Formatters.Add(formatter);

            _request = new HttpRequestMessage();
            _request.SetConfiguration(config);
            _request.RegisterForDispose(config);

            var output = renderView();

            Console.WriteLine(output.Result);

            _request.Dispose();
            _request = null;
        }

        private static async Task<string> renderView()
        {
            var cts = new CancellationTokenSource();
            var view = new ViewResult(_request, "view", new SampleModel() { Prop1 = "p1", Prop2 = "p2", Prop3 = new List<string> { "pe1", "pe2", "pe3" } });

            var response = await view.ExecuteAsync(cts.Token);
            var output = await response.Content.ReadAsStringAsync();
            return output;
        }
    }

It is compiling allright and it even works (if i remove partial rendering from this view) If i use partial view i get such error:

[ArgumentNullException] value cannot be null. parameter name: view

Another thing (but definietly less important) is console message written by razorengine :

RazorEngine: We can't cleanup temp files if you use RazorEngine on the default A ppdomain. Create a new AppDomain and use RazorEngine from there. Read the quickstart or https://github.com/Antaris/RazorEngine/issues/244 for det ails! You can ignore this and all following 'Please clean ... manually' messages if yo u are using DisableTempFileLocking, which is not recommended. Please clean 'C:\Users[user_account]\AppData\Local\Temp\RazorEngine_qeouaznq. ett' manually!

I've checked - and there are read/write permissions (on this folder) set properly.

Please help!!! I'm so close :)

Wad answered 29/7, 2015 at 8:14 Comment(0)
S
5

Yes this is all possible. Similar questions have been been asked previously

Have a look at this answer.

This one points to the answer above.

This project also looks promising, it uses Razor with OWIN.

You may not be able use @Html, @RenderBody and @RenderSection from the Microsoft.AspNet.WebPages package without a dependency on System.Web.

From what i can tell, everything (excluding "automatic" files handling) is possible to achieve using RazorEngine project. But maybe even files handling (exactly the same as in MVC - searching for templates in Views and Subdirectories of Views) is available in this engine ? Or is it something i must write by myself ? Or maybe some other plugin gives me all this features ?

There is a razor media type formatter for webapi. It exposes an IViewLocator interface as part of its api and its default implementation appears to use the file location conventions you have mentioned. You may be able to expand on this project to achieve your goals.

Sundberg answered 29/7, 2015 at 9:5 Comment(6)
Anish - i've looked through all links attached in your response. There is nothing, that i can mark as "full solution" You wrote: "There are of course various methods of implementation depending on your needs" --> I've stated my needs very clearly. I want razor MVC (usability the same as in MVC application.In fact, views from MVC application would be simply copied to this class library) In this class library i can reference everything (including mentioned System.Web)Wad
@PiotrFilipowicz I've updated my answer and added a link that may help you.Sundberg
thanks for tip. Nevertheless it is still not complete and "one-click" solution. After copying part of the code from unit tests (available on github page), that renders string from view - i'm still getting : “The name 'HTML' does not exist in the current context” The generated source code for this view has only simple usings (system, collection generic etc) So, it quite obvious, that it wouldn't know what "html" is. Even if i add proper using (and proper reference) still it wouldn't know about html (as this is HtmlHelper) My need ("no changes in views required") is not fulfilledWad
Previous comment was about : razor media type formatter for webapi (WebApiContrib.Formatting.Razor)Wad
Ok. I See that there is proper template (with HTML support - called HtmlTemplateBase) After changing "initialisation" to : var viewParser = new RazorViewParser(baseTemplateType: typeof(HtmlTemplateBase<>)); var formatter = new RazorViewFormatter(viewParser: viewParser); I see, that generated source code contains changed template to HtmlTemplateBase but still.... the error message is : “The name 'Html' does not exist in the current context”Wad
I've updated my original question about "latest" progress. Now i'm dealing with error : "value cannot be null. parameter name: view"Wad

© 2022 - 2024 — McMap. All rights reserved.