gpt4 book ai didi

c# - ASP.NET Core Controller 返回的 ViewResult 消耗在哪里?

转载 作者:行者123 更新时间:2023-12-04 07:22:03 25 4
gpt4 key购买 nike

在 ASP.NET Core Controller class 的定义中,它定义了 View() method作为返回 ViewResult object .

namespace Microsoft.AspNetCore.Mvc
{
//...
public abstract class Controller : ControllerBase, IActionFilter, IFilterMetadata, IAsyncActionFilter, IDisposable
{
//...
public virtual ViewResult View();
//...
}
}
它在调用如下 Controller 方法并使用 ViewResult 的框架中的什么位置?调用 View() 返回方法?
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
}

最佳答案

整个过程相当复杂,由 ResourceInvoker class 内部管理。 ,但负责处理 ViewResult 的主要管道是 ViewExecutor class (source code)。ViewExecutor 的主要入口点是 ExecuteAsync() method ,它接受 ActionContext 和你的ViewResult .然后它使用已注册的 IViewEngine 定位适当的 View 。 (通常是 RazorViewEngine )来识别相应的 View 并返回 ViewEngineResult instance .那ViewEngineResult然后用于执行和渲染 View 。
扩展 ViewExecutor如果需要自定义逻辑,可以通过实现 IActionResultExecutor<> interface 来实现自己的 View 执行器类。然后使用 ASP.NET Core 的依赖注入(inject)容器将其注册为单例。这样做时,我建议引用 the out-of-the-box ViewResultExecutor 's source code .
如果您想实现自定义逻辑来定位 View ,这会很有用。例如,您可能想要考虑状态或上下文数据,例如路由数据、请求 header 、cookie、 session 等。定位 View 时。
因此,作为一个非常简单的示例,假设您希望允许使用查询字符串值(例如,?View=MyView)选择性地选择 View 。在这种情况下,您可以创建一个 QueryStringViewResultExecutor .这是一个基本的概念验证:

public class QueryStringViewResultExecutor : ViewExecutor, IActionResultExecutor<ViewResult> 
{
public QueryStringViewResultExecutor(
IOptions<MvcViewOptions> viewOptions,
IHttpResponseStreamWriterFactory writerFactory,
ICompositeViewEngine viewEngine,
ITempDataDictionaryFactory tempDataFactory,
DiagnosticListener diagnosticListener,
IModelMetadataProvider modelMetadataProvider
) : base(
viewOptions, writerFactory, viewEngine, tempDataFactory, diagnosticListener, modelMetadataProvider
)
{
}

public async Task ExecuteAsync(ActionContext context, ViewResult result)
{
var viewEngineResult = FindView(context, result); // See helper method below
viewEngineResult.EnsureSuccessful(originalLocations: null);
var view = viewEngineResult.View;

using (view as IDisposable)
{
await ExecuteAsync(
context,
view,
result.ViewData,
result.TempData,
result.ViewName,
result.StatusCode
).ConfigureAwait(false);
}
}

private ViewEngineResult FindView(ActionContext actionContext, ViewResult viewResult)
{

// Define variables
var view = (ViewEngineResult?)null;
var viewEngine = viewResult.ViewEngine?? ViewEngine;
var searchedPaths = new List<string>();
var requestContext = actionContext.HttpContext.Request;

// If defined, attempt to locate view based on query string variable
if (requestContext.Query.ContainsKey("View"))
{
var queryStringValue = requestContext.Query["View"].First<string>();
if (queryStringValue is not null)
{
view = viewEngine.FindView(actionContext, queryStringValue, isMainPage: true);
searchedPaths = searchedPaths.Union(view.SearchedLocations?? Array.Empty<string>()).ToList();
}
}

// If no view is found, fall back to the view defined on the viewResult
if (!view?.Success?? true)
{
view = viewEngine.FindView(actionContext, viewResult.ViewName, isMainPage: true);
searchedPaths = searchedPaths.Union(view.SearchedLocations ?? Array.Empty<string>()).ToList();
}

// Return view for processing by the razor engine
if (view is not null and { Success: true }) {
return view;
}
return ViewEngineResult.NotFound(viewResult.ViewName, searchedPaths);

}
}
然后,您将在您的 Startup.ConfigureServices() 中注册。方法为:
services.Services.TryAddSingleton<IActionResultExecutor<ViewResult>, QueryStringViewResultExecutor>();

Disclaimer: You may need to unregister the out-of-the-box ViewExecutor in order to avoid a conflict. Typically, however, you are registering an IActionResultExecutor<> with a custom ViewResult and, thus, that isn't necessary; see below.


扩展 ViewResult通常,您会希望将其与自定义 ViewResult 配对。 .为什么这很有用?通常是因为您需要向您的 ViewResultExecutor 传递额外的数据。来自您的 Controller .
因此,作为一个人为的示例,假设您有主题,并且可以选择基于该主题自定义 View 。然后您可以添加 Theme属性(property)到您的 ViewResult ,从而允许 ViewResultExecutor首先寻找基于主题的 View ,否则回退到非主题版本。
public class ThemedViewResult : ViewResult 
{

public string Theme { get; set; }

public override async Task ExecuteResultAsync(ActionContext context)
{
var executor = context.HttpContext.RequestServices.GetRequiredService<IActionResultExecutor<ThemedViewResult>>();
await executor.ExecuteAsync(context, this).ConfigureAwait(false);
}
}
即使您不需要自定义 ViewResult ,值得暂停一下来评估这段代码。标的 ViewResult类实现 IActionResult ,它公开了一个方法, ExecuteResultAsync() .这由 ResourceInvoker 调用顶部提到的类。这反过来又找到已注册的 IActionResultExecutor<> — 即我们在上一节中创建和注册的组件类型 — 并调用它的 ExecuteAsync()方法。

Note: This is a contrived example because often a theme would be accessible by other context data, such as the RouteData, a custom ClaimsPrincipal, or an ISession implementation. But you can imagine other times where this information would be request-specific, and best relayed from the Controller via the ViewResult. For instance, perhaps a CMS where the theme can be selected on a per page basis.


由于尚不清楚您是否真的需要扩展此功能,或者只是好奇一切如何组合在一起,因此上述示例仅作为概念验证;他们没有经过测试。不过,它们应该让您对 ViewResult 的位置和方式有一个基本的了解。处理,以及在您需要时扩展该行为的选项。

关于c# - ASP.NET Core Controller 返回的 ViewResult 消耗在哪里?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68431957/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com