Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • nickornotto 397 posts 900 karma points
    Feb 26, 2020 @ 20:17
    nickornotto
    0

    How to supply ContentModel for a view as string in RenderMvcController from PublishedContentModel (ModelsBuilder auto-generated)

    I am trying to adopt SPA (react) + umbraco solution described here: https://github.com/systempioneer/React-Umbraco-Example/blob/master/UmbracoReactStarterKit/Controllers/ReactRoutesController.cs to Umbraco 8.

    The default controller is a controller of type RenderMvcController which expects a model of type ContentModel (former RenderModel in umbraco v7).

    The problem is that the supplied model when converting model to string is PublishedContentModel which is the auto-generated model by ModelsBuilder.

    I had to make a few changes to adopt the source code to Umbraco 8 but the resulting values are of the same type like in the base solution above.

    The ContentModel that needs to be returned to the view:

    public class MasterModel : ContentModel
    {
        public MasterModel(IPublishedContent content) : base(content)
        {
        }
    
        public InitialState InitialState { get; set; }
    }
    

    This is my controller:

    public class ReactRoutesController : ReactRenderMvcController
    {
        public override ActionResult Index(ContentModel model)
        {
            return View("Master", CreateMasterModel());
        }
    
        private MasterModel CreateMasterModel()
        {
            var home = Umbraco.ContentAtRoot().First();
            var viewResult = ViewFromContentId(CurrentPage.Id); // returns view with model of type PublishedContentModel
            var viewResultAsString = viewResult.RenderToString(); // this calls RenderToString() shown below
            var model = new MasterModel(CurrentPage)
            {
                InitialState = new InitialState
                {
                    content = GetContentPages(),
                    homeUrl = home.Url,
                    location = Request.Url.AbsolutePath,
                    currentContent = new InitialState.CurrentContent
                    {
                        Name = CurrentPage.Name,
                        Url = Request.Url.AbsolutePath,
                        Content = viewResultAsString
                    },
                    currentPageName = CurrentPage.Name
                }
            };
    
            return model;
        }
    }
    

    inheriting from:

    public class ReactRenderMvcController : RenderMvcController
    {
        public ViewResult ViewFromContentId(int id)
        {
            var result = Umbraco.ContentQuery.Content(id); // gets the current document type with doc type model
            var renderModel = ViewExtensions.CreateRenderModel(result, RouteData).Content;
    
            return View(renderModel.GetTemplateAlias(), renderModel);
        }
    
    }
    

    The extension which is supposed to render the string from the view:

    public static class ViewExtensions
    {
        // https://stackoverflow.com/a/19208941
        public static string RenderToString(this ViewResult partialView)
        {
            var httpContext = HttpContext.Current;
    
            if (httpContext == null)
            {
                throw new NotSupportedException("An HTTP context is required to render the partial view to a string");
            }
    
            var controllerName = httpContext.Request.RequestContext.RouteData.Values["controller"].ToString();
    
            var controller = (ControllerBase)ControllerBuilder.Current.GetControllerFactory().CreateController(httpContext.Request.RequestContext, controllerName);
    
            var controllerContext = new ControllerContext(httpContext.Request.RequestContext, controller);
    
            var view = ViewEngines.Engines.FindPartialView(controllerContext, partialView.ViewName).View;
    
            var sb = new StringBuilder();
    
            using (var sw = new StringWriter(sb))
            {
                using (var tw = new HtmlTextWriter(sw))
                {
                    var viewContext = new ViewContext(controllerContext, view, partialView.ViewData, partialView.TempData, tw);
                    view.Render(viewContext, tw); // <---- THIS IS WHERE THE ERROR OCCURS - I guess it's because the controller expects `ContentModel` while it is being supplied `PublishedContentModel` instead - partialView parameter has model of type `PublishedContentModel`
                }
            }
    
            return sb.ToString();
        }
    

    The actual error says:

    Cannot bind source type Umbraco.Web.PublishedModels.Home to model type MyDomain.Models.MasterModel. The source is a ModelsBuilder type, but the view model is not.
    

    To be honest I don't know how this could work on the original version the solution is made for ( v.7.6.2). I tried to install it but getting an error on db installation and not able to run it. umbraco's RenderMvcController always expected RenderModel, not a PublishedContentModel.

Please Sign in or register to post replies

Write your reply to:

Draft