4

I've been happily returning JsonResult objects or partial ASP.NET views from my controllers in ASP.NET.

I would like to return a rendered partial view as a property in a JSON object. e.g.

requesting

/post/detail/1

would return

{"PostId": 1, "Html": "<p>some markup rendered from a partial to inject</p>" }

This would allow me to know the PostId when I am handling the response in JavaScript. Any tips on the best way to do this?

Mohammad Sepahvand
  • 17,364
  • 22
  • 81
  • 122
Lance Fisher
  • 25,684
  • 22
  • 96
  • 122

3 Answers3

10

Here is some code that will work cause I needed to do this today. The original code is described here.

public static string RenderPartialToString(string controlName, object viewData)
{
    var viewContext = new ViewContext();
    var urlHelper = new UrlHelper(viewContext.RequestContext);
    var viewDataDictionary = new ViewDataDictionary(viewData);

    var viewPage = new ViewPage
    {
        ViewData = viewDataDictionary,
        ViewContext = viewContext,
        Url = urlHelper
    };

    var control = viewPage.LoadControl(controlName);
    viewPage.Controls.Add(control);

    var sb = new StringBuilder();
    using (var sw = new StringWriter(sb))
    using (var tw = new HtmlTextWriter(sw))
    {
            viewPage.RenderControl(tw);
    }

    return sb.ToString();
}

You can then use it to do RJS style json results

public virtual ActionResult Index()
{
    var jsonResult = new JsonResult
    {
        Data = new
        {
            main_content = RenderPartialToString("~/Views/contact/MyPartial.ascx", new SomeObject()),
            secondary_content = RenderPartialToString("~/Views/contact/MyPartial.ascx", new SomeObject()),
        }
    };

    return Json(jsonResult, JsonRequestBehavior.AllowGet);
}

And the partial has a strongly typed view model

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<SomeObject>" %>
<h1>My Partial</h1>
superlogical
  • 14,332
  • 9
  • 66
  • 76
  • +1 Nice solution Jake. Thanks for pointing out that my "answer" didn't work - like I said, at the time it was just an idea that I didn't have time to test. After you posted, I dug deeper & it was definitely a red herring (why the MVC team decided that `View.Render(context, writer)` should completely ignore the writer parameter & write straight to the Response stream is beyond me). I've removed it to cut down on the noise. My apologies if I wasted your time sending you down the wrong path. Next time I post code that logically looks like it should work, I'll actually test it first. :) – Alconja Feb 22 '10 at 22:25
  • No Worries @Alconja - These are the kind of features that we should open with the mvc team on codeplex, get cats to vote and these problems would go away :) – superlogical Feb 23 '10 at 01:22
2

Something like:

return new JsonResult { Data = new { PostId = 1; Html = "<p>some markup rendered from a partial to inject</p>" } };
rball
  • 6,925
  • 7
  • 49
  • 77
0

I was looking for a better way to do this myself because I assumed the way I was doing it was outdated. I forget where I got this and take no credit for it, but since I ended up here I figure I'll post what I use as well. Hope it helps anyone coming along looking for something newer than the answers above.

** NOTE This only addresses the rendering of the view to a string. The answers above address the question about putting the result into a property on a JSON object and the OP seemed pretty comfortable with that anyway.

public string RenderViewToString(string viewName, object model)
    {
        ViewData.Model = model;
        using (var sw = new StringWriter())
        {
            ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
            var viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
            viewResult.View.Render(viewContext, sw);
            viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View);
            return sw.GetStringBuilder().ToString();
        }
    }
Mike Devenney
  • 1,758
  • 1
  • 23
  • 42