简体   繁体   English

如何在 app.UseEndPoints 中将自定义路由操作作为委托实例添加到 ASP.NET Core 3.1 应用程序?

[英]How to add custom routed action as a delegate instance to ASP.NET Core 3.1 app in app.UseEndPoints?

I'm trying to use an local delegate instance when mapping route against its handler, namely a function that returns IActionResult , like a regular Action defined in a Controller .我在将路由映射到其处理程序时尝试使用本地委托实例,即返回IActionResult的 function ,就像在Controller中定义的常规Action一样。

Here is how I have tried:这是我尝试过的方法:

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();
}

The core part is核心部分是

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()));
});

Then in the browser, the response to request http://localhost:59716/HelloA :然后在浏览器中,响应请求http://localhost:59716/HelloA

An error occured when executing context.RequestServices.GetRequiredService<IActionResultExecutor<TResult>>();执行context.RequestServices.GetRequiredService<IActionResultExecutor<TResult>>(); in WriteActionResult<TResult>() :WriteActionResult<TResult>()

InvalidOperationException: No service for type 'Microsoft.AspNetCore.Mvc.Infrastructure.IActionResultExecutor`1[Microsoft.AspNetCore.Mvc.IActionResult]' has been registered. InvalidOperationException:没有为“Microsoft.AspNetCore.Mvc.Infrastructure.IActionResultExecutor`1[Microsoft.AspNetCore.Mvc.IActionResult]”类型注册的服务。

But the response to request http://localhost:59716/HelloB is normal:但是请求http://localhost:59716/HelloB的响应是正常的:

你好乙

I have read the source of how IActionResultExecutor is registered here in services.AddMvcCore() .我已经阅读了IActionResultExecutor如何在services.AddMvcCore()中注册来源。

But I failed to understand why it failed to handle a delegate instance of type delegate IActionResult RouteHandler() while it succeeded for delegate ContentResult ContentRouteHandler() .但是我不明白为什么它无法处理delegate IActionResult RouteHandler()类型的委托实例,而delegate ContentResult ContentRouteHandler()却成功了。

My question is how to solve this problem?我的问题是如何解决这个问题?

Use reflection使用反射

    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)});
}

For the first route:对于第一条路线:

endpoints.Map("HelloA", context => WriteActionResult(context, actionA()));

You are calling WriteActionResult<IActionResult>(context, actionA()) , in which causes IActionResultExecutor<IActionResult> to be resolved.您正在调用WriteActionResult<IActionResult>(context, actionA()) ,这会导致IActionResultExecutor<IActionResult>得到解决。

There is no IActionResultExecutor<IActionResult> by default registered.默认情况下没有注册IActionResultExecutor<IActionResult> So the exception is thrown.所以抛出异常。

However, there is IActionResultExecutor<ContentResult> by default registerd.但是,默认注册了IActionResultExecutor<ContentResult> So when you call the second route:因此,当您调用第二条路线时:

endpoints.Map("HelloB", context => WriteActionResult<ContentResult>(context, actionB()));

it just works.它只是工作。

To fix first route, try this:要修复第一条路线,请尝试以下操作:

endpoints.MapGet(
    "HelloA",
    context => WriteActionResult(context, (ContentResult)actionA())
);

Or you could fix RouteHandler like:或者您可以像这样修复RouteHandler

public delegate T RouteHandler<out T>() where T : IActionResult;

The solution is to use dynamic :解决方案是使用dynamic

Before:前:

RouteHandler actionA =
    () => new ContentResult {Content = "Hello A!"};

After:后:

Func<dynamic> actionA =
    () => new ContentResult {Content = "Hello A!"};

Result:结果:
/HellA 的结果

At runtime, Func<dynamic> will be resolved to the actual type Func<ContentResult> , so the return type of actionA() will be ContentResult and can be consumed later by IActionResultExecutor<ContentResult> , which has already been registered.在运行时, Func<dynamic>将被解析为实际类型Func<ContentResult> ,因此actionA()的返回类型将为ContentResult ,稍后可以由IActionResultExecutor<ContentResult>使用,该类型已经注册。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在 ASP.NET Core 中使用 app.Run 和 app.UseEndpoints 有什么区别? - What are the difference using app.Run and app.UseEndpoints in ASP.NET Core? ASP.NET CORE 没有 app.UseEndpoints() 方法 - ASP.NET CORE Don't have app.UseEndpoints() Method app.UseRouting() 和 app.UseEndPoints() 有什么区别? - What are the differences between app.UseRouting() and app.UseEndPoints()? 为什么在多次调用 app.UseEndpoints(..) 时不执行中间件? - Why is middleware not executed when there are multiple calls to app.UseEndpoints(..)? 将 ASP.NET CORE 3.1 MVC 应用程序部署到 azure 时出现问题 - Problem deploying ASP.NET CORE 3.1 MVC app to azure Asp.net 核心 3.1 保护 API 和 web 应用程序 - Asp.net core 3.1 securing API and web app ASP.NET Core 3.1 MVC 应用程序 - 在子目录中搜索视图 - ASP.NET Core 3.1 MVC app - search views in subdirectory 将客户端 Blazor 添加到现有的 Asp.Net Core 3.1 应用程序 - Add client-side Blazor to existing Asp.Net Core 3.1 App 如何在 ASP.NET Core 3.1 MVC 中进行自定义路由 - How to do custom routing in ASP.NET Core 3.1 MVC 具有 asp.net 核心 3 UseEndpoints 的多个 controller 路由模式 - Multiple controller route patterns with asp.net core 3 UseEndpoints
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM