[Fixes #4223] Added a facade for ViewComponentResult
This commit is contained in:
parent
8493064fe5
commit
5f4ca4fa66
|
|
@ -139,6 +139,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
services.TryAddSingleton<
|
services.TryAddSingleton<
|
||||||
IViewComponentDescriptorCollectionProvider,
|
IViewComponentDescriptorCollectionProvider,
|
||||||
DefaultViewComponentDescriptorCollectionProvider>();
|
DefaultViewComponentDescriptorCollectionProvider>();
|
||||||
|
services.TryAddSingleton<ViewComponentResultExecutor>();
|
||||||
|
|
||||||
services.TryAddSingleton<ViewComponentInvokerCache>();
|
services.TryAddSingleton<ViewComponentInvokerCache>();
|
||||||
services.TryAddTransient<IViewComponentDescriptorProvider, DefaultViewComponentDescriptorProvider>();
|
services.TryAddTransient<IViewComponentDescriptorProvider, DefaultViewComponentDescriptorProvider>();
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,20 +2,11 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Text;
|
|
||||||
using System.Text.Encodings.Web;
|
|
||||||
using System.Threading.Tasks;
|
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.ViewEngines;
|
||||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||||
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
|
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
|
||||||
using Microsoft.AspNetCore.WebUtilities;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc
|
namespace Microsoft.AspNetCore.Mvc
|
||||||
{
|
{
|
||||||
|
|
@ -68,83 +59,16 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
public IViewEngine ViewEngine { get; set; }
|
public IViewEngine ViewEngine { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <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 services = context.HttpContext.RequestServices;
|
||||||
|
var executor = services.GetRequiredService<ViewComponentResultExecutor>();
|
||||||
var htmlHelperOptions = services.GetRequiredService<IOptions<MvcViewOptions>>().Value.HtmlHelperOptions;
|
return executor.ExecuteAsync(context, this);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -532,6 +532,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
services.AddSingleton<ITempDataProvider, SessionStateTempDataProvider>();
|
services.AddSingleton<ITempDataProvider, SessionStateTempDataProvider>();
|
||||||
services.AddSingleton<HtmlEncoder, HtmlTestEncoder>();
|
services.AddSingleton<HtmlEncoder, HtmlTestEncoder>();
|
||||||
services.AddSingleton<IViewBufferScope, TestViewBufferScope>();
|
services.AddSingleton<IViewBufferScope, TestViewBufferScope>();
|
||||||
|
services.AddSingleton<ViewComponentResultExecutor>();
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue