[英]What are the difference using app.Run and app.UseEndpoints in ASP.NET Core?
[英]How to add custom routed action as a delegate instance to ASP.NET Core 3.1 app in app.UseEndPoints?
我在將路由映射到其處理程序時嘗試使用本地委托實例,即返回IActionResult
的 function ,就像在Controller
中定義的常規Action
一樣。
這是我嘗試過的方法:
using System.Globalization;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddLocalization(options => options.ResourcesPath = "Resources");
services.AddMvcCore();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
var supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("zh-CN"),
new CultureInfo("ja-JP"),
};
app.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("en-US"),
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures
});
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
RouteHandler actionA = () => new ContentResult {Content = "Hello A!"};
ContentRouteHandler actionB = () => new ContentResult {Content = "Hello B!"};
app.UseEndpoints(endpoints =>
{
endpoints.Map("HelloA", context => WriteActionResult(context, actionA()));
endpoints.Map("HelloB", context => WriteActionResult(context, actionB()));
});
}
public static Task WriteActionResult<TResult>(HttpContext context, TResult result) where TResult : IActionResult
{
var executor = context.RequestServices.GetRequiredService<IActionResultExecutor<TResult>>();
var routeData = context.GetRouteData() ?? new RouteData();
var actionContext = new ActionContext(context, routeData, new ActionDescriptor());
return executor.ExecuteAsync(actionContext, result);
}
public delegate IActionResult RouteHandler();
public delegate ContentResult ContentRouteHandler();
}
核心部分是
RouteHandler actionA = () => new ContentResult {Content = "Hello A!"};
ContentRouteHandler actionB = () => new ContentResult {Content = "Hello B!"};
app.UseEndpoints(endpoints =>
{
endpoints.Map("HelloA", context => WriteActionResult(context, actionA()));
endpoints.Map("HelloB", context => WriteActionResult(context, actionB()));
});
然后在瀏覽器中,響應請求http://localhost:59716/HelloA
:
執行context.RequestServices.GetRequiredService<IActionResultExecutor<TResult>>();
在WriteActionResult<TResult>()
:
InvalidOperationException:沒有為“Microsoft.AspNetCore.Mvc.Infrastructure.IActionResultExecutor`1[Microsoft.AspNetCore.Mvc.IActionResult]”類型注冊的服務。
但是請求http://localhost:59716/HelloB
的響應是正常的:
我已經閱讀了IActionResultExecutor
如何在services.AddMvcCore()
中注冊的來源。
但是我不明白為什么它無法處理delegate IActionResult RouteHandler()
類型的委托實例,而delegate ContentResult ContentRouteHandler()
卻成功了。
我的問題是如何解決這個問題?
使用反射
public static Task WriteActionResult<TResult>(HttpContext context, TResult result)
where TResult : class, IActionResult
{
var resultType = result.GetType();
var executorType = typeof(IActionResultExecutor<>).MakeGenericType(resultType);
var executor = context.RequestServices.GetRequiredService(executorType);
var routeData = context.GetRouteData() ?? new RouteData();
var actionContext = new ActionContext(context, routeData, new ActionDescriptor());
var method = executorType.GetMethod(nameof(IActionResultExecutor<IActionResult>.ExecuteAsync)) ?? throw new MissingMethodException($"Missing 'ExecuteAsync' method");
return (Task)method.Invoke(executor, new[] {actionContext, Convert.ChangeType(result, resultType)});
}
對於第一條路線:
endpoints.Map("HelloA", context => WriteActionResult(context, actionA()));
您正在調用WriteActionResult<IActionResult>(context, actionA())
,這會導致IActionResultExecutor<IActionResult>
得到解決。
默認情況下沒有注冊IActionResultExecutor<IActionResult>
。 所以拋出異常。
但是,默認注冊了IActionResultExecutor<ContentResult>
。 因此,當您調用第二條路線時:
endpoints.Map("HelloB", context => WriteActionResult<ContentResult>(context, actionB()));
它只是工作。
要修復第一條路線,請嘗試以下操作:
endpoints.MapGet(
"HelloA",
context => WriteActionResult(context, (ContentResult)actionA())
);
或者您可以像這樣修復RouteHandler
:
public delegate T RouteHandler<out T>() where T : IActionResult;
解決方案是使用dynamic
:
前:
RouteHandler actionA =
() => new ContentResult {Content = "Hello A!"};
后:
Func<dynamic> actionA =
() => new ContentResult {Content = "Hello A!"};
結果:
在運行時, Func<dynamic>
將被解析為實際類型Func<ContentResult>
,因此actionA()
的返回類型將為ContentResult
,稍后可以由IActionResultExecutor<ContentResult>
使用,該類型已經注冊。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.