Skip to main content

3 posts tagged with "partialview"

View All Tags

PartialView.ToString()

In the name of DRY I found myself puzzling how one could take a PartialViewResult and render it as a string. Simple, right?

In fact, in my head this was already a solved problem. I mean I've written about this before already! Except I haven't. Not really - what I did back then was link to what someone else had written and say "yay! well done chap - like he said!". It turns out that was a bad move. That blog appears to be gone and so I'm back to where I was. Ug. Lesson learned.

What are we trying to do?#

So, for the second time of asking, here is how to take a PartialViewResult and turn it into a string. It's an invaluable technique to deal with certain scenarios.

In my own case I have a toolbar in my application that is first pushed into the UI in my _Layout.cshtml by means of a trusty @Html.Action("Toolbar"). I wanted to be able to re-use the PartialViewResult returned by Toolbar on my controller inside a JSON payload. And despite the title of this post, PartialView.ToString()doesn't quite cut the mustard. Obvious really, if it did then why would I be writing this and you be reading this?

The solution is actually fairly simple. And, purely for swank, I'm going to offer it you 3 ways. Whatever's your poison.

Inheritance (it's so yesterday darling)#

Yes there was a time when everything was inheritance based. You were rewarded handsomely for making sure that was the case. However, times have changed and (with good reason) people tend to favour composition over inheritance. So, perhaps just for the memories, let first offer you the inheritance based approach:

protected string ConvertPartialViewToString(PartialViewResult partialView)
{
using (var sw = new StringWriter())
{
partialView.View = ViewEngines.Engines
.FindPartialView(ControllerContext, partialView.ViewName).View;
var vc = new ViewContext(
ControllerContext, partialView.View, partialView.ViewData, partialView.TempData, sw);
partialView.View.Render(vc, sw);
var partialViewString = sw.GetStringBuilder().ToString();
return partialViewString;
}
}

The idea being that the above method is placed onto a base controller which your controllers subclass. Thus using this method inside one of the controllers is as simple as:

var toolbarHtml = ConvertPartialViewToString(partialViewResult);

Extension method (sexier syntax)#

So the next choice is implementing this as an extension method. Here's my static class which adds ConvertToString onto PartialViewResult:

using System.IO;
using System.Web.Mvc;
namespace My.Utilities.Extensions
{
public static class PartialViewResultExtensions
{
public static string ConvertToString(this PartialViewResult partialView,
ControllerContext controllerContext)
{
using (var sw = new StringWriter())
{
partialView.View = ViewEngines.Engines
.FindPartialView(controllerContext, partialView.ViewName).View;
var vc = new ViewContext(
controllerContext, partialView.View, partialView.ViewData, partialView.TempData, sw);
partialView.View.Render(vc, sw);
var partialViewString = sw.GetStringBuilder().ToString();
return partialViewString;
}
}
}
}

I don't know about you but I do love an extension method - it often makes for much more readable code. In this case we can use:

var toolbarHtml = partialViewResult.ConvertToString(ControllerContext);

Which I think we can all agree is really rather lovely. Perhaps it would be more lovely if I didn't have to pass ControllerContext - but hey! Still quite nice.

Favouring Composition over Inheritance (testable)#

Although ASP.Net MVC was designed to be testable there are times when you think "really? Can it be that hard?". In fact for a well thought through discussion on the topic I advise you read this. (I'm aware of the irony implicit in linking to another blog post in a blog post that I only wrote because I first linked to another blog which vanished.... Infinite recursion anybody?)

The conclusion of the linked blog post is twofold

  1. Don't mock HTTPContext
  2. Use the facade pattern instead

Having testable code is not a optional bauble in my view - it's a necessity. So with my final approach that's exactly what I'll do.

using System.Web.Mvc;
namespace My.Interfaces
{
public interface IMvcInternals
{
string ConvertPartialViewToString(PartialViewResult partialView, ControllerContext controllerContext);
}
}
// ....
using System.IO;
using System.Web.Mvc;
using My.Interfaces;
namespace My.Utilities
{
public class MvcInternals : IMvcInternals
{
public string ConvertPartialViewToString(PartialViewResult partialView,
ControllerContext controllerContext)
{
using (var sw = new StringWriter())
{
partialView.View = ViewEngines.Engines
.FindPartialView(controllerContext, partialView.ViewName).View;
var vc = new ViewContext(
controllerContext, partialView.View, partialView.ViewData, partialView.TempData, sw);
partialView.View.Render(vc, sw);
var partialViewString = sw.GetStringBuilder().ToString();
return partialViewString;
}
}
}
}

So here I have a simple interface with a ConvertPartialViewToString method on it. This interface can be passed into a controller and then used like this:

var toolbarHtml = _mvcInternals.ConvertPartialViewToString(partialViewResult, ControllerContext);

Ah... that's the sweet mellifluous sound of easily testable code.

How to attribute encode a PartialView in MVC (Razor)

This post is plagiarism. But I'm plagiarising myself so I don't feel too bad.

I posted a question on StackOverflow recently asking if there was a simple way to attribute encode a PartialView in Razor / ASP.NET MVC. I ended up answering my own question and since I thought it was a useful solution it might be worth sharing.

The Question#

In the project I was working on I was using PartialViews to store the HTML that would be rendered in a tooltip in my ASP.NET MVC application. (In case you're curious I was using the jQuery Tools library for my tooltip effect.)

I had thought that Razor, clever beast that it is, would automatically attribute encode anything sat between quotes in my HTML. Unfortunately this doesn't appear to be the case. In the short term I was able to workaround this by using single quotation marks to encapsulate my PartialViews HTML. See below for an example:

<div class="tooltip"
title='@Html.Partial("_MyTooltipInAPartial")'>
Some content
</div>

Now this worked just fine but I was aware that if any PartialView needed to use single quotation marks I would have a problem. Let's say for a moment that _MyTooltipInAPartial.cshtml contained this:

<span style="color:green">fjkdsjf'lksdjdlks</span>

Well when I used my handy little single quote workaround, the following would result:

<div class="tooltip"
title='<span style="color:green">fjkdsjf'lksdjdlks</span>'>
Some content
</div>

Which although it doesn't show up so well in the code sample above is definite "does not compute, does not compute, does not compute *LOUD EXPLOSION*" territory.

The Answer#

This took me back to my original intent which was to encapsulate the HTML in double quotes like this:

<div class="tooltip"
title="@Html.Partial("_MyTooltipInAPartial")">
Some content
</div>

Though with the example discussed above we clearly had a problem whether we used single or double quotes. What to do?

Well the answer wasn't too complicated. After a little pondering I ended up scratching my own itch by writing an HTML helper method called PartialAttributeEncoded which made use of HttpUtility.HtmlAttributeEncode to HTML attribute encode a PartialView.

Here's the code:

Using the above helper is simplicity itself:

<div class="tooltip"
title="@Html.PartialAttributeEncoded("_MyTooltipInAPartial")">
Some content
</div>

And, given the example I've been going through, it would provide you with this output:

<div class="tooltip"
title="&lt;span style=&quot;color:green&quot;>fjkdsjf&#39;lksdjdlks</span>">
Some content
</div>

Now the HTML in the title attribute above might be an unreadable mess - but it's the unreadable mess you need. That's what the HTML we've been discussing looks like when it's been encoded.

Final thoughts#

I was surprised that Razor didn't handle this out of the box. I wonder if this is something that will come along with a later version? It's worth saying that I experienced this issue when working on an MVC 3 application. It's possible that this issue may actually have been solved with MVC 4 already; I haven't had chance to check yet though.

Rendering Partial View to a String

Well done that man!#

Every now and then I'm thinking to myself "wouldn't it be nice if you could do x..." And then I discover that someone else has thought the self same thoughts and better yet they have the answer! I had this situation recently and discovered the wonderful Kevin Craft had been there, done that and made the T-shirt. Here's his blog: http://craftycodeblog.com/2010/05/15/asp-net-mvc-render-partial-view-to-string/ I wanted to talk about how this simple post provided me with an elegant solution to something I've found niggling and unsatisfactory for a while now... ## How it helped

Just last week I was thinking about Partial Views. Some background. I'm working on an ASP.NET MVC 3 project which provides users with a nice web interface to manage the workflow surrounding certain types of financial asset. The user is presented with a web page which shows a kind of grid to the user. As the user hovers over a row they are presented with a context menu which allows them to perform certain workflow actions. If they perform an action then that row will need to be updated to reflect this. Back in the day this would have been achieved by doing a full postback to the server. At the server the action would be taken, the persistent storage updated and then the whole page would be served up to the user again with the relevant row of HTML updated but everything else staying as is. Now there's nothing wrong with this approach as such. I mean it works just fine. But in my case since I knew that it was only that single row of HTML that was going to be updated and so I was loath to re-render the whole page. It seemed a waste to get so much data back from the server when only a marginal amount was due to change. And also I didn't want the user to experience the screen refresh flash. Looks ugly. Now in the past when I've had a solution to this problem which from a UI perspective is good but from a development perspective slightly unsatisfactory. I would have my page call a controller method (via jQuery.ajax) to perform the action. This controller would return a JsonResult indicating success or failure and any data necessary to update the screen. Then in the success function I would manually update the HTML on the screen using the data provided. Now this solution works but there's a problem. Can you tell what it is yet? It's not very DRY. I'm repeating myself. When the page is initially rendered I have a View which renders (in this example) all the relevant HTML for the screen *including* the HTML for my rows of data. And likewise I have my JavaScript method for updating the screen too. So with this solution I have duplicated my GUI logic. If I update 1, I need to update the other. It's not a massive hardship but it is, as I say, unsatisfactory. I was recently thinking that it would be nice if I could refactor my row HTML into a Partial View which I could then use in 2 places: 1. In my standard View as I iterated through each element for display and 2. Nested inside a JsonResult...

The wonderful thing about approach 2 is that it allows me to massively simplify my success to this: ```js $("myRowSelector") .empty() .html(data.RowHTML); //Where RowHTML is the property that //contains my stringified PartialView

and if I later make changes to the `Partial View` these changes will not require me to make any changes to my JavaScript at all. Brilliant! And entirely satisfactory. On the grounds that someone else might have had the same idea I did a little googling around. Sure enough I discovered [Kevin Craft's post](<http://craftycodeblog.com/2010/05/15/asp-net-mvc-render-partial-view-to-string/>) which was just the ticket. It does exactly what I'd hoped. Besides being a nice and DRY solution this approach has a number of other advantages as well: - Given it's a `Partial View` the Visual Studio IDE provides a nice experience when coding it up with regards to intellisense / highlighting etc. Not something available when you're hand coding up a string which contains the HTML you'd like passed back...
- A wonderful debug experience. You can debug the rendering of a `Partial View` being rendered to a string in the same way as if the ASP.NET MVC framework was serving it up. I could have lived without this but it's fantastic to have it available.
- It's possible to nest \***multiple**\* `Partial Views` within your `JsonResult`. THIS IS WONDERFUL!!! This means that if several parts of your screen need to be updated (perhaps the row and a status panel as well) then as long as both are refactored into a `Partial View` you can generate them on the fly and pass them back.
<!-- -->
Excellent stuff!