Copied to clipboard

Flag this post as spam?

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


  • Jesse Andrews 191 posts 716 karma points c-trib
    Aug 21, 2018 @ 21:26
    Jesse Andrews
    0

    Issue rendering grid partial as a string inside an api call when the grid data contains a leblender widget

    Umbraco: 7.11.1

    I'm trying to render the grid partial server side so that I can return the resulting html as a string in data returned by an api call. My current logic to get a stringified version of the grid partial can be seen below.

    public static string GetPartialAsString(Umbraco.Core.Models.IPublishedContent content, string viewName, object model, ViewDataDictionary data = null) {
        if (data == null) {
            data = new ViewDataDictionary();
        }
        data.Model = model;
        using (StringWriter sw = new StringWriter()) {
            var routeData = new RouteData();
            var doctype = content.DocumentTypeAlias;
            var controllerName = doctype.Substring(0, 1).ToUpper() + doctype.Substring(1) + "Controller";
            routeData.Values.Add("controller", controllerName);
            var controller = (BaseController)Activator.CreateInstance(Type.GetType(controllerName));
            var fakeControllerContext = new ControllerContext(new HttpContextWrapper(new HttpContext(new HttpRequest(null, content.UrlAbsolute(), $"id={content.Id}&doctype={content.DocumentTypeAlias}"), new HttpResponse(null))), routeData, controller);
            ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(fakeControllerContext, viewName + ".cshtml");
            ViewContext viewContext = new ViewContext(fakeControllerContext, viewResult.View, data, new TempDataDictionary(), sw);
            viewResult.View.Render(viewContext, sw);
            viewResult.ViewEngine.ReleaseView(fakeControllerContext, viewResult.View);
            return sw.GetStringBuilder().ToString();
        }
    }
    

    The controller it references is an empty class that extends the following class. The OutputCache attribute is from System.Web.Mvc and is used for page caching.

    public abstract class BaseController : RenderMvcController {
        [OutputCache(CacheProfile = "ControllerCache")]
        public override ActionResult Index(RenderModel model) {
            if (UmbracoContext.InPreviewMode) {
               HttpContext.Response.Cache.SetExpires
                       (DateTime.Now.AddDays(-1));
    
               HttpContext.Response.Cache.SetCacheability
                        (HttpCacheability.Public);
               HttpContext.Response.Cache.SetValidUntilExpires(true);
            }            
            return base.Index(model);
        }
    }
    

    It works correctly for the built grid controls, but falls over when trying to run a grid widget that uses LeBlender. The issue is that LeBlender makes a couple references to the current contexts when GetValue is called (see here for method that causes the error), which causes it to fail, as the context is pulling data from the context of the api instead of the page. The trace of the error can be seen below.

    at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
    at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
    at Lecoati.LeBlender.Extension.Helper.GetTargetContentType()
    at Lecoati.LeBlender.Extension.Models.LeBlenderPropertyModel.GetValue[T]()
    at Lecoati.LeBlender.Extension.Models.LeBlenderValue.GetValue[T](String propertyAlias)
    at ASP._Page_App_Plugins_Carousel_Views_carousel_cshtml.Execute() in c:\\Some_Directory\\App_Plugins\\Carousel\\Views\\Carousel.cshtml:line 13
    at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
    at System.Web.Mvc.WebViewPage.ExecutePageHierarchy()
    at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
    at System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance)
    at System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer)
    at Umbraco.Core.Profiling.ProfilingView.Render(ViewContext viewContext, TextWriter writer)
    at System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context)
    at System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
    at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult)
    at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult)
    

    According to this trace, the error occurs when the method calls int.TryParse against the id in the Request of the current HttpContext (see here). Since it can't find that id in the request, it throws an error. My issue is that I'm not sure how the fake context should be modified so that this id is correctly applied to the HttpContext in the partial view. I tried passing the data in as part of the HttpRequest in the fakeControllerContext, but that wasn't applied to the context inside the partial view.

    Any suggestions would be much appreciated.

Please Sign in or register to post replies

Write your reply to:

Draft