[Fixes #4223] Added a facade for ViewComponentResult

This commit is contained in:
jacalvar 2016-05-25 17:12:46 -07:00
parent 8493064fe5
commit 5f4ca4fa66
4 changed files with 152 additions and 84 deletions

View File

@ -139,6 +139,7 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAddSingleton<
IViewComponentDescriptorCollectionProvider,
DefaultViewComponentDescriptorCollectionProvider>();
services.TryAddSingleton<ViewComponentResultExecutor>();
services.TryAddSingleton<ViewComponentInvokerCache>();
services.TryAddTransient<IViewComponentDescriptorProvider, DefaultViewComponentDescriptorProvider>();

View File

@ -0,0 +1,142 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
{
public class ViewComponentResultExecutor
{
private readonly HtmlEncoder _htmlEncoder;
private readonly HtmlHelperOptions _htmlHelperOptions;
private readonly ILogger<ViewComponentResult> _logger;
private readonly IModelMetadataProvider _modelMetadataProvider;
private readonly ITempDataDictionaryFactory _tempDataDictionaryFactory;
private readonly IViewComponentHelper _viewComponentHelper;
public ViewComponentResultExecutor(
IOptions<MvcViewOptions> mvcHelperOptions,
IViewComponentHelper viewComponentHelper,
ILoggerFactory loggerFactory,
HtmlEncoder htmlEncoder,
IModelMetadataProvider modelMetadataProvider,
ITempDataDictionaryFactory tempDataDictionaryFactory)
{
if (mvcHelperOptions == null)
{
throw new ArgumentNullException(nameof(mvcHelperOptions));
}
if (viewComponentHelper == null)
{
throw new ArgumentNullException(nameof(viewComponentHelper));
}
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
if (htmlEncoder == null)
{
throw new ArgumentNullException(nameof(htmlEncoder));
}
if (modelMetadataProvider == null)
{
throw new ArgumentNullException(nameof(modelMetadataProvider));
}
if (tempDataDictionaryFactory == null)
{
throw new ArgumentNullException(nameof(tempDataDictionaryFactory));
}
_htmlHelperOptions = mvcHelperOptions.Value.HtmlHelperOptions;
_viewComponentHelper = viewComponentHelper;
_logger = loggerFactory.CreateLogger<ViewComponentResult>();
_htmlEncoder = htmlEncoder;
_modelMetadataProvider = modelMetadataProvider;
_tempDataDictionaryFactory = tempDataDictionaryFactory;
}
public async Task ExecuteAsync(ActionContext context, ViewComponentResult viewComponentResult)
{
var response = context.HttpContext.Response;
var viewData = viewComponentResult.ViewData;
if (viewData == null)
{
viewData = new ViewDataDictionary(_modelMetadataProvider, context.ModelState);
}
var tempData = viewComponentResult.TempData;
if (tempData == null)
{
tempData = _tempDataDictionaryFactory.GetTempData(context.HttpContext);
}
string resolvedContentType;
Encoding resolvedContentTypeEncoding;
ResponseContentTypeHelper.ResolveContentTypeAndEncoding(
viewComponentResult.ContentType,
response.ContentType,
ViewExecutor.DefaultContentType,
out resolvedContentType,
out resolvedContentTypeEncoding);
response.ContentType = resolvedContentType;
if (viewComponentResult.StatusCode != null)
{
response.StatusCode = viewComponentResult.StatusCode.Value;
}
using (var writer = new HttpResponseStreamWriter(response.Body, resolvedContentTypeEncoding))
{
var viewContext = new ViewContext(
context,
NullView.Instance,
viewData,
tempData,
writer,
_htmlHelperOptions);
(_viewComponentHelper as IViewContextAware)?.Contextualize(viewContext);
var result = await GetViewComponentResult(_viewComponentHelper, _logger, viewComponentResult);
result.WriteTo(writer, _htmlEncoder);
}
}
private Task<IHtmlContent> GetViewComponentResult(IViewComponentHelper viewComponentHelper, ILogger logger, ViewComponentResult result)
{
if (result.ViewComponentType == null && result.ViewComponentName == null)
{
throw new InvalidOperationException(Resources.FormatViewComponentResult_NameOrTypeMustBeSet(
nameof(ViewComponentResult.ViewComponentName),
nameof(ViewComponentResult.ViewComponentType)));
}
else if (result.ViewComponentType == null)
{
logger.ViewComponentResultExecuting(result.ViewComponentName);
return viewComponentHelper.InvokeAsync(result.ViewComponentName, result.Arguments);
}
else
{
logger.ViewComponentResultExecuting(result.ViewComponentType);
return viewComponentHelper.InvokeAsync(result.ViewComponentType, result.Arguments);
}
}
}
}

View File

@ -2,20 +2,11 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Mvc
{
@ -68,83 +59,16 @@ namespace Microsoft.AspNetCore.Mvc
public IViewEngine ViewEngine { get; set; }
/// <inheritdoc />
public override async Task ExecuteResultAsync(ActionContext context)
public override Task ExecuteResultAsync(ActionContext context)
{
var response = context.HttpContext.Response;
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var services = context.HttpContext.RequestServices;
var htmlHelperOptions = services.GetRequiredService<IOptions<MvcViewOptions>>().Value.HtmlHelperOptions;
var viewComponentHelper = services.GetRequiredService<IViewComponentHelper>();
var loggerFactory = services.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger<ViewComponentResult>();
var htmlEncoder = services.GetRequiredService<HtmlEncoder>();
var viewData = ViewData;
if (viewData == null)
{
var modelMetadataProvider = services.GetRequiredService<IModelMetadataProvider>();
viewData = new ViewDataDictionary(modelMetadataProvider, context.ModelState);
}
var tempData = TempData;
if (tempData == null)
{
var factory = services.GetRequiredService<ITempDataDictionaryFactory>();
tempData = factory.GetTempData(context.HttpContext);
}
string resolvedContentType = null;
Encoding resolvedContentTypeEncoding = null;
ResponseContentTypeHelper.ResolveContentTypeAndEncoding(
ContentType,
response.ContentType,
ViewExecutor.DefaultContentType,
out resolvedContentType,
out resolvedContentTypeEncoding);
response.ContentType = resolvedContentType;
if (StatusCode != null)
{
response.StatusCode = StatusCode.Value;
}
using (var writer = new HttpResponseStreamWriter(response.Body, resolvedContentTypeEncoding))
{
var viewContext = new ViewContext(
context,
NullView.Instance,
viewData,
tempData,
writer,
htmlHelperOptions);
(viewComponentHelper as IViewContextAware)?.Contextualize(viewContext);
var result = await GetViewComponentResult(viewComponentHelper, logger);
result.WriteTo(writer, htmlEncoder);
}
}
private Task<IHtmlContent> GetViewComponentResult(IViewComponentHelper viewComponentHelper, ILogger logger)
{
if (ViewComponentType == null && ViewComponentName == null)
{
throw new InvalidOperationException(Resources.FormatViewComponentResult_NameOrTypeMustBeSet(
nameof(ViewComponentName),
nameof(ViewComponentType)));
}
else if (ViewComponentType == null)
{
logger.ViewComponentResultExecuting(ViewComponentName);
return viewComponentHelper.InvokeAsync(ViewComponentName, Arguments);
}
else
{
logger.ViewComponentResultExecuting(ViewComponentType);
return viewComponentHelper.InvokeAsync(ViewComponentType, Arguments);
}
var executor = services.GetRequiredService<ViewComponentResultExecutor>();
return executor.ExecuteAsync(context, this);
}
}
}

View File

@ -532,6 +532,7 @@ namespace Microsoft.AspNetCore.Mvc
services.AddSingleton<ITempDataProvider, SessionStateTempDataProvider>();
services.AddSingleton<HtmlEncoder, HtmlTestEncoder>();
services.AddSingleton<IViewBufferScope, TestViewBufferScope>();
services.AddSingleton<ViewComponentResultExecutor>();
return services;
}