7

How does MVC 6 renders a view. What's the actual method in Razor ViewEngine that generates the html output? Also if possible please explain the process of rendering a view.

May be you could point me to a file on mvc source on github. thanks!

eadam
  • 23,151
  • 18
  • 48
  • 71
  • I'm afraid this is a bit too broad to answer, but basically a ViewResult (`return View()`) compiles the appropriate view using the C# compiler on-the-fly. I don't think this is documented anywhere except in the source itself. What stops you from downloading the source tree and finding what you're looking for? What exactly are you trying to do, why do you want to know? – CodeCaster Jan 12 '15 at 13:08
  • I am trying to build my own htmlHelper on the fly through code and then Render view depending on the model supplied. I am looking into the source code as well but seems bit hard to find without documentation. – eadam Jan 12 '15 at 13:51
  • That aim sounds a little backwards. Surely the controller could/should make the decision. Do you actually mean partial views? – iCollect.it Ltd Jan 12 '15 at 14:08
  • @Eilon Check the answer below. – Helen Araya Jan 25 '16 at 17:52

2 Answers2

5

Here is a complete solution of what you are looking for. I used dependency injection to get the HtmlHelper in the controller. You can inject your own helper if you want too.

using Microsoft.AspNet.Html.Abstractions;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.ViewEngines;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Mvc.ViewFeatures.Internal;
using Microsoft.Extensions.WebEncoders;
using System.ComponentModel.DataAnnotations;
using System;

 public class MyController : Controller
 {
    private readonly IHtmlGenerator htmlGenerator;
    ICompositeViewEngine viewEngine;
    IModelMetadataProvider metadataProvider;
    private readonly IHtmlHelper helper;
    IHtmlEncoder htmlEncoder;
    IUrlEncoder urlEncoder;
    IJavaScriptStringEncoder javaScriptStringEncoder;

    public MyController(IHtmlHelper helper, IHtmlGenerator htmlGenerator, ICompositeViewEngine viewEngine, IModelMetadataProvider metadataProvider, IHtmlEncoder htmlEncoder, IUrlEncoder urlEncoder, IJavaScriptStringEncoder javaScriptStringEncoder)
    {

        this.htmlGenerator = htmlGenerator;
        this.viewEngine = viewEngine;
        this.metadataProvider = metadataProvider;
        this.htmlEncoder = htmlEncoder;
        this.urlEncoder = urlEncoder;
        this.javaScriptStringEncoder = javaScriptStringEncoder;
        this.helper = helper;
    }

    [HttpGet]
    public IActionResult MyHtmlGenerator()
    {
        MyViewModel temp = new MyViewModel();


        var options = new HtmlHelperOptions();
        options.ClientValidationEnabled = true;

        ViewDataDictionary<MyViewModel> dic = new ViewDataDictionary<MyViewModel>(this.metadataProvider, new ModelStateDictionary());

        ViewContext cc = new ViewContext(ActionContext, new FakeView(), dic, TempData, TextWriter.Null, options);

        var type = typeof(MyViewModel);
        var metadata = this.metadataProvider.GetMetadataForType(type);


        ModelExplorer modelEx = new ModelExplorer(this.metadataProvider, metadata, temp);
        ViewData["Description"] = "test desc";
        ViewData["Id"] = 1;

        this.ViewData = new ViewDataDictionary(this.metadataProvider, new ModelStateDictionary());

        IHtmlHelper<MyViewModel> dd = new HtmlHelper<MyViewModel>(this.htmlGenerator, this.viewEngine, this.metadataProvider, this.htmlEncoder, this.urlEncoder, this.javaScriptStringEncoder);
        ((ICanHasViewContext)dd).Contextualize(cc);
        dd.ViewContext.ViewData = this.ViewData;

        var desc = GetString(dd.TextBoxFor(m => m.ID));
        var ID = GetString(dd.TextBoxFor(m => m.Description));

        // Do whatever you want with the ID and desc

        return new ContentResult() { Content = ID + desc };

    }

    public static string GetString(IHtmlContent content)
    {
        var writer = new System.IO.StringWriter();
        content.WriteTo(writer, new HtmlEncoder());
        return writer.ToString();
    }
}


public class MyViewModel : BaseAssetViewModel
{
    //  [RegularExpression(@"^-?\d{1,13}(\.\d{0,5})?$|^-?\.\d{1,5}$")]
    [Required]
    public int ID { get; set; }

    [MinLength(2)]
    public string Description { get; set; }

    // Property with no validation
    public string Other { get; set; }
}


public class FakeView : IView
{
    string IView.Path
    {
        get
        {
            throw new NotImplementedException();
        }
    }

    public Task RenderAsync(ViewContext viewContext)
    {
        throw new InvalidOperationException();
    }

    Task IView.RenderAsync(ViewContext context)
    {
        throw new NotImplementedException();
    }
}
RonC
  • 31,330
  • 19
  • 94
  • 139
Helen Araya
  • 1,886
  • 3
  • 28
  • 54
  • Thanks, I was wondering how can I create a ModelExplorer to be able to use IHtmlGenerator to generate htm elements. Although isnt this too much since it gets executed every time? – Haytam Sep 08 '18 at 10:03
1

I don't know if this may be of help, may be you have to start to look at tag helpers:

https://github.com/DamianEdwards/TagHelperStarterWeb

they're working to a different way to create helpers that integrate in the page in a more natural way.

Luca Morelli
  • 2,530
  • 3
  • 28
  • 45