0

My textbook shows an example of how to write custom view engine(implements IViewEngine, and the view it uses is a class that implements IView

public interface IViewEngine{
   ViewEngineResult FindView(ActionContext context, string viewName, bool isMainPage);
   ViewEngineResult GetView(string executingFilePath, string viewPath, bool isMainPage);
}

and

public interface IView {
   string Path { get; }
   Task RenderAsync(ViewContext context);
}

and below is a custom view that implements IView

public class DebugDataView : IView
{
    public string Path => String.Empty;

    public async Task RenderAsync(ViewContext context)
    {
        context.HttpContext.Response.ContentType = "text/plain";
        StringBuilder sb = new StringBuilder();
        sb.AppendLine("---Routing Data---");
        foreach (var kvp in context.RouteData.Values)
        {
            sb.AppendLine($"Key: {kvp.Key}, Value: {kvp.Value}");
        }
        sb.AppendLine("---View Data---");
        foreach (var kvp in context.ViewData)
        {
            sb.AppendLine($"Key: {kvp.Key}, Value: {kvp.Value}");
        }
        sb.AppendLine(context.ViewData.Model.ToString());
        await context.Writer.WriteAsync(sb.ToString());
    }
}

I have some questions

Q1-does mean that after the content in .cshtml view files is parsed by razor, then razor will create a View Object that implements IView behind the scene so that real content is implemented in RenderAsync?

Q2-the FindView or GetView method returns a ViewEngineResult object, then who will be turning ViewEngineResult object into response(html for clients), MVC or Razor Engine?

1 Answers1

0

Not in the way that you'd think. There's technically an underlying View<TModel> (which implements IView), but this is actually what's coming from the action. When you return something like View(model), it's returning a ViewResult and inside, it's building this backing class.

The actual cshtml file is just a text file for all intents an purposes. There's a filesystem reference to it (i.e. Path from the IView interface), but that's it. It's not "compiled" per se. The view engine gets fed the View<TModel> instance, with its path to the cshtml file, and then it loads the contents of that file and begins parsing it (Razor), the View<TModel> provides the data backing for that parsing process, i.e. when it comes across Razor code, the information is pull from the View<TModel> instance.

Once the view has been "rendered". The result is basically just a string, which is then dumped into the response. (Technically, there's some async to this, so the response can be and often is progressively built, not just created at the end. However, that's not really germane to the discussion.)

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • Thanks for your answer. So does it mean that after Razor has done the parsing, it(Razor) will create an object that implements `IView `, and encapsulates it into the `ViewEngineResult`? –  Aug 06 '19 at 13:50
  • No. The object is *already* there. That was created by returning from the action, before the actual cshtml view is even loaded. That's what I'm saying: cshtml is just text. It's not compiled and it doesn't get compiled. – Chris Pratt Aug 06 '19 at 13:54
  • I'm not talking about ViewResult object, the object I mean is `IView` object, I think it is created by Razor after Razor load .cshtml and have finished the parsing, am I correct? –  Aug 06 '19 at 13:57
  • No. Not at all. It's created by returning a view from the action. It's already instantiated before the cshtml is even read from the file system. – Chris Pratt Aug 06 '19 at 13:59
  • if it is created by returning a view from the action, so razor hasn't started the parsing, then how can `RenderAsync` method to be implemented? –  Aug 06 '19 at 14:03
  • That's what starts the Razor parsing. Not sure I understand the question. What do you think rendering is here? – Chris Pratt Aug 06 '19 at 14:08
  • My question is, since `RenderAsync` method is called by MVC to generate the response to the client , so `RenderAsync` method has all the essential C# code that can generate the response, those C# code comes from the parsing of .cshtml, so how come this `IView` object already exists before razor starts parsing? –  Aug 06 '19 at 14:19
  • See, that's the part I don't think you're getting. There is no C# code here. It's Razor syntax, which what looks like C# code. It's technically, ran dynamically as C#, similar to how you might do an exec in JS, but it's not code that's part of a class or something. It's just text. Razor is what makes it magic. – Chris Pratt Aug 06 '19 at 14:22
  • I think you refer to the .cshtml file? I'm actually referring to the C# class, I have added a custome view in my post, you will see what I mean. So my questions is, how `RenderAsync ` get implemented? –  Aug 06 '19 at 14:32