![](/img/trans.png)
[英]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.