Add PartialAsync and RenderPartialAsync.

This enables Html.PartialAsync and Html.RenderPartialAsync.  It also includes a sample to showcase the features.  This is in reference to WEBFX-95.
This commit is contained in:
N. Taylor Mullen 2014-03-27 17:47:01 -07:00
parent a5ed1157d5
commit 2de5d57348
9 changed files with 176 additions and 20 deletions

View File

@ -0,0 +1,4 @@
@using MvcSample.Web.Models
@model User
<strong>Hello @Model.Name from Partial</strong>

View File

@ -11,6 +11,12 @@
{
return "Hello World";
}
public Task RenderHelloWorldPartial(User model)
{
// Imagine this method was a super complex method that was used as a helper method.
return Html.RenderPartialAsync("HelloWorldPartial", model);
}
}
<div class="jumbotron">
@ -21,6 +27,12 @@
<div class="row">
<h3 title="@Model.Name" class="@nullValue">Hello @Model.Name! Happy @Model.Age birthday.</h3>
<h3>This value was retrieved asynchronously: @(await AsyncValueRetrieval())</h3>
<h3>Partial Async: @await Html.PartialAsync("HelloWorldPartial", Model)</h3>
<h3>Render Partial Async (Custom model): @{ await RenderHelloWorldPartial(new User()
{
Name="Bob"
});
}</h3>
<div class="col-md-4">
<h2>Getting started</h2>

View File

@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Net;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNet.Abstractions;
namespace Microsoft.AspNet.Mvc.Rendering
@ -21,12 +23,15 @@ namespace Microsoft.AspNet.Mvc.Rendering
public static readonly string ValidationSummaryValidCssClassName = "validation-summary-valid";
private ViewContext _viewContext;
private IViewEngine _viewEngine;
/// <summary>
/// Initializes a new instance of the <see cref="HtmlHelper"/> class.
/// </summary>
public HtmlHelper()
public HtmlHelper(IViewEngine viewEngine)
{
_viewEngine = viewEngine;
// Underscores are fine characters in id's.
IdAttributeDotReplacement = "_";
}
@ -125,6 +130,42 @@ namespace Microsoft.AspNet.Mvc.Rendering
return TagBuilder.CreateSanitizedId(name, IdAttributeDotReplacement);
}
public async Task<HtmlString> PartialAsync([NotNull] string partialViewName, object model, ViewDataDictionary viewData)
{
using (var writer = new StringWriter(CultureInfo.CurrentCulture))
{
await RenderPartialCoreAsync(partialViewName, model, viewData, writer);
return new HtmlString(writer.ToString());
}
}
public Task RenderPartialAsync([NotNull] string partialViewName, object model, ViewDataDictionary viewData)
{
return RenderPartialCoreAsync(partialViewName, model, viewData, ViewContext.Writer);
}
protected virtual async Task RenderPartialCoreAsync([NotNull] string partialViewName,
object model,
ViewDataDictionary viewData,
TextWriter writer)
{
// Determine which ViewData we should use to construct a new ViewData
var baseViewData = viewData ?? ViewData;
var newViewData = new ViewDataDictionary(baseViewData, model);
var newViewContext = new ViewContext(ViewContext)
{
ViewData = newViewData,
Writer = writer
};
var viewEngineResult = await _viewEngine.FindPartialView(newViewContext.ViewEngineContext, partialViewName);
await viewEngineResult.View.RenderAsync(newViewContext);
}
/// <summary>
/// Returns the HTTP method that handles form input (GET or POST) as a string.
/// </summary>

View File

@ -8,8 +8,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// <summary>
/// Initializes a new instance of the <see cref="HtmlHelper{TModel}"/> class.
/// </summary>
public HtmlHelper()
: base()
public HtmlHelper(IViewEngine viewEngine)
: base(viewEngine)
{
}

View File

@ -0,0 +1,45 @@
using System.Threading.Tasks;
namespace Microsoft.AspNet.Mvc.Rendering
{
public static class PartialAsyncExtensions
{
/// <summary>
/// Renders the partial view with the parent's view data and model to a string.
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the model.</typeparam>
/// <param name="htmlHelper">The <see cref="HtmlHelper"/> instance that this method extends.</param>
/// <param name="partialViewName">The name of the partial view to render.</param>
/// <returns>A <see cref="Task{T}"/> that represents when rendering to the <see cref="HtmlString"/> has completed.</returns>
public static Task<HtmlString> PartialAsync<T>(this IHtmlHelper<T> htmlHelper, [NotNull] string partialViewName)
{
return htmlHelper.PartialAsync(partialViewName, htmlHelper.ViewData.Model, viewData: null);
}
/// <summary>
/// Renders the partial view with the given view data and, implicitly, the given view data's model to a string.
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the model.</typeparam>
/// <param name="htmlHelper">The <see cref="HtmlHelper"/> instance that this method extends.</param>
/// <param name="partialViewName">The name of the partial view to render.</param>
/// <param name="viewData">The <see cref="ViewDataDictionary"/> that is provided to the partial view that will be rendered.</param>
/// <returns>A <see cref="Task{T}"/> that represents when rendering to the <see cref="HtmlString"/> has completed.</returns>
public static Task<HtmlString> PartialAsync<T>(this IHtmlHelper<T> htmlHelper, [NotNull] string partialViewName, ViewDataDictionary viewData)
{
return htmlHelper.PartialAsync(partialViewName, htmlHelper.ViewData.Model, viewData: viewData);
}
/// <summary>
/// Renders the partial view with an empty view data and the given model to a string.
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the model.</typeparam>
/// <param name="htmlHelper">The <see cref="HtmlHelper"/> instance that this method extends.</param>
/// <param name="partialViewName">The name of the partial view to render.</param>
/// <param name="model">The model to provide to the partial view that will be rendered.</param>
/// <returns>A <see cref="Task{T}"/> that represents when rendering to the <see cref="HtmlString"/> has completed.</returns>
public static Task<HtmlString> PartialAsync<T>(this IHtmlHelper<T> htmlHelper, [NotNull] string partialViewName, object model)
{
return htmlHelper.PartialAsync(partialViewName, model, viewData: null);
}
}
}

View File

@ -0,0 +1,46 @@
using System.Threading.Tasks;
namespace Microsoft.AspNet.Mvc.Rendering
{
public static class RenderPartialAsyncExtensions
{
/// <summary>
/// Renders the partial view with the parent's view data and model.
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the model.</typeparam>
/// <param name="htmlHelper">The <see cref="HtmlHelper"/> instance that this method extends.</param>
/// <param name="partialViewName">The name of the partial view to render.</param>
/// <returns>A <see cref="Task"/> that represents when rendering has completed.</returns>
public static Task RenderPartialAsync<T>(this IHtmlHelper<T> htmlHelper, [NotNull] string partialViewName)
{
return htmlHelper.RenderPartialAsync(partialViewName, htmlHelper.ViewData.Model, viewData: htmlHelper.ViewData);
}
/// <summary>
/// Renders the partial view with the given view data and, implicitly, the given view data's model.
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the model.</typeparam>
/// <param name="htmlHelper">The <see cref="HtmlHelper"/> instance that this method extends.</param>
/// <param name="partialViewName">The name of the partial view to render.</param>
/// <param name="viewData">The <see cref="ViewDataDictionary"/> that is provided to the partial view that will be rendered.</param>
/// <returns>A <see cref="Task"/> that represents when rendering has completed.</returns>
public static Task RenderPartialAsync<T>(this IHtmlHelper<T> htmlHelper, [NotNull] string partialViewName, ViewDataDictionary viewData)
{
return htmlHelper.RenderPartialAsync(partialViewName, htmlHelper.ViewData.Model, viewData: viewData);
}
/// <summary>
/// Renders the partial view with an empty view data and the given model.
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the model.</typeparam>
/// <param name="htmlHelper">The <see cref="HtmlHelper"/> instance that this method extends.</param>
/// <param name="partialViewName">The name of the partial view to render.</param>
/// <param name="model">The model to provide to the partial view that will be rendered.</param>
/// <returns>A <see cref="Task"/> that represents when rendering has completed.</returns>
public static Task RenderPartialAsync<T>(this IHtmlHelper<T> htmlHelper, [NotNull] string partialViewName, object model)
{
return htmlHelper.RenderPartialAsync(partialViewName, model, htmlHelper.ViewData);
}
}
}

View File

@ -1,4 +1,5 @@
using System;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Mvc.Rendering
{
@ -64,5 +65,24 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// <param name="value">object with string representation as HTML markup.</param>
/// <returns>An <see cref="HtmlString"/> that represents HTML markup.</returns>
HtmlString Raw(object value);
/// <summary>
/// Returns a partial view in string format.
/// </summary>
/// <param name="partialViewName">The name of the partial view to render and return.</param>
/// <param name="model">A model to pass into the partial view.</param>
/// <param name="viewData">A <see cref="ViewDataDictionary"/> to pass into the partial view.</param>
/// <returns>A task that represents when rendering of the partial view into a string has completed.</returns>
Task<HtmlString> PartialAsync([NotNull] string partialViewName, object model, ViewDataDictionary viewData);
/// <summary>
/// Renders a partial view.
/// </summary>
/// <param name="partialViewName">The name of the partial view to render.</param>
/// <param name="model">A model to pass into the partial view.</param>
/// <param name="viewData">A <see cref="ViewDataDictionary"/> to pass into the partial view.</param>
/// <returns>A task that represents when rendering has completed.</returns>
Task RenderPartialAsync([NotNull] string partialViewName, object model, ViewDataDictionary viewData);
}
}

View File

@ -138,22 +138,6 @@ namespace Microsoft.AspNet.Mvc.Rendering
return string.Format(CultureInfo.CurrentCulture, GetString("ViewData_WrongTModelType"), p0, p1);
}
/// <summary>
/// The view '{0}' was not found. The following locations were searched:{1}.
/// </summary>
internal static string ViewEngine_ViewNotFound
{
get { return GetString("ViewEngine_ViewNotFound"); }
}
/// <summary>
/// The view '{0}' was not found. The following locations were searched:{1}.
/// </summary>
internal static string FormatViewEngine_ViewNotFound(object p0, object p1)
{
return string.Format(CultureInfo.CurrentCulture, GetString("ViewEngine_ViewNotFound"), p0, p1);
}
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);

View File

@ -13,6 +13,10 @@ namespace Microsoft.AspNet.Mvc.Rendering
private readonly FormContext _defaultFormContext = new FormContext();
private FormContext _formContext;
public ViewContext([NotNull] ViewContext viewContext)
: this(viewContext.ServiceProvider, viewContext.HttpContext, viewContext.ViewEngineContext)
{ }
public ViewContext(IServiceProvider serviceProvider, HttpContext httpContext,
IDictionary<string, object> viewEngineContext)