Copied to clipboard

Flag this post as spam?

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


  • nickornotto 317 posts 679 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.

  • This forum is in read-only mode while we transition to the new forum.

    You can continue this topic on the new forum by tapping the "Continue discussion" link below.

Please Sign in or register to post replies