Asp.net web api Asp.NETMVC核心中的ApiControllerActionSelector等效项

Asp.net web api Asp.NETMVC核心中的ApiControllerActionSelector等效项,asp.net-web-api,asp.net-core-mvc,Asp.net Web Api,Asp.net Core Mvc,我们正在从web api迁移到asp.net mvc core,我在web api中有一个操作选择器,如果url“$”符号中存在任何软件,我们用来调用控制器中的特定方法。 我们使用下面的ApiControllerActionSelector在web api中实现的这个功能就是在web api中实现同样功能的代码- public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext) {

我们正在从web api迁移到asp.net mvc core,我在web api中有一个操作选择器,如果url“$”符号中存在任何软件,我们用来调用控制器中的特定方法。 我们使用下面的ApiControllerActionSelector在web api中实现的这个功能就是在web api中实现同样功能的代码-

public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext) {
           string urlDecode = HttpUtility.UrlDecode(
               controllerContext.Request.RequestUri.ToString());
           if (urlDecode != null && urlDecode.Contains("$")) {
               if (controllerContext.Request.Method == HttpMethod.Post) {
                   MethodInfo method = controllerContext.ControllerDescriptor.ControllerType
                       .GetMethod(
                           "PostCustomOperation");
                   return
                       new ReflectedHttpActionDescriptor(
                           controllerContext.ControllerDescriptor, method);
               }
               if (controllerContext.Request.Method == HttpMethod.Get) {
                   MethodInfo method = controllerContext.ControllerDescriptor.ControllerType
                       .GetMethod(
                           "GetCustomOperation");
                   return
                       new ReflectedHttpActionDescriptor(
                           controllerContext.ControllerDescriptor, method);
               }
           }
           HttpActionDescriptor result = base.SelectAction(controllerContext);
           return result;
       }
在Asp.NETMVC核心中,我无法找到一种等效的方法来实现同样的功能,我尝试了实现IRouter,但我们也必须指定控制器,但我不知道这一点。
关于如何在Asp.net MVC core中实现相同或不可能实现的任何建议?

您需要的是
IActionSelector
。您可以在ConfigureServices中为其注册实现,
services.AddSingleton()
。默认实现是
ActionSelector
,您可以在自定义实现中委托给它。

我选择替换
iactionvokerfactory
。它比较短。下面是实现。然后我创建我自己的IActionInvoker包装

我的目标是在必要时再次调用控制器操作

public class PolicyActionInvokerFactory : IActionInvokerFactory
{
    private readonly IEFConcurrencyService efConcurrencyService;
    private readonly IActionInvokerProvider[] actionInvokerProviders;

    public PolicyActionInvokerFactory(
        IEFConcurrencyService efConcurrencyService,
        IEnumerable<IActionInvokerProvider> actionInvokerProviders
    )
    {
        this.efConcurrencyService = efConcurrencyService;
        this.actionInvokerProviders = actionInvokerProviders.OrderBy(item => item.Order).ToArray();
    }

    public IActionInvoker CreateInvoker(ActionContext actionContext)
    {
        var context = new ActionInvokerProviderContext(actionContext);

        foreach (var provider in actionInvokerProviders)
        {
            provider.OnProvidersExecuting(context);
        }

        for (var i = actionInvokerProviders.Length - 1; i >= 0; i--)
        {
            actionInvokerProviders[i].OnProvidersExecuted(context);
        }

        return new RetryActionInvoker(efConcurrencyService, context.Result, actionContext);
    }

    class RetryActionInvoker : IActionInvoker
    {
        private readonly IEFConcurrencyService efConcurrencyService;
        private readonly IActionInvoker inner;
        private readonly ActionContext actionContext;

        public RetryActionInvoker(
            IEFConcurrencyService efConcurrencyService,
            IActionInvoker inner,
            ActionContext actionContext
        )
        {
            this.efConcurrencyService = efConcurrencyService;
            this.inner = inner;
            this.actionContext = actionContext;
        }

        public Task InvokeAsync()
        {
            var methodInfo = actionContext.ActionDescriptor;
            var shouldUseRetryLogic = methodInfo.EndpointMetadata.Any(m => m is RetryOnDbExceptionAttribute);
            if (shouldUseRetryLogic)
            {
                return efConcurrencyService.RetryOnError(() => {
                    // You will need to rewind the body here if you are using [FromBody]
                    // This is a little out of scope, but you should EnableBuffering()
                    // Then rewind the body with something like this:
                    // actionContext.HttpContext.Request.Body.Seek(0, System.IO.SeekOrigin.Begin);
                    return inner.InvokeAsync();
                });
            }

            return inner.InvokeAsync();
        }
    }
}
公共类PolicyActionInvokerFactory:IActionInvokerFactory { 专用只读IEFConcurrencyService efConcurrencyService; 私有只读IActionInvokerProvider[]actionInvokerProviders; 公共政策行动调用工厂( IEFConcurrencyService efConcurrencyService, IEnumerable actionInvokerProviders ) { this.efConcurrencyService=efConcurrencyService; this.actionInvokerProviders=actionInvokerProviders.OrderBy(item=>item.Order.ToArray(); } 公共IActionVoker CreateInvoker(ActionContext ActionContext) { var context=新的ActionInvokerProviderContext(actionContext); foreach(actionInvokerProviders中的var提供程序) { provider.OnProvidersExecuting(上下文); } 对于(var i=actionInvokerProviders.Length-1;i>=0;i--) { actionInvokerProviders[i].OnProvidersExecuted(上下文); } 返回新的RetryActionInvoker(efConcurrencyService,context.Result,actionContext); } 类RetryActionInvoker:IActionInvoker { 专用只读IEFConcurrencyService efConcurrencyService; 私有只读IActionVoker内部; 私有只读ActionContext ActionContext; 公共RetryActionInvoker( IEFConcurrencyService efConcurrencyService, 艾克诺克内线, ActionContext ActionContext ) { this.efConcurrencyService=efConcurrencyService; this.inner=内部; this.actionContext=actionContext; } 公共任务InvokeAsync() { var methodInfo=actionContext.ActionDescriptor; var shouldUseRetryLogic=methodInfo.EndpointMetadata.Any(m=>m为RetryOnDbExceptionAttribute); if(shouldUseRetryLogic) { 返回efConcurrencyService.RetryOnError(()=>{ //如果使用[FromBody],则需要在此处倒带正文 //这有点超出范围,但您应该启用buffering() //然后用如下方法倒带身体: //actionContext.HttpContext.Request.Body.Seek(0,System.IO.SeekOrigin.Begin); 返回inner.InvokeAsync(); }); } 返回inner.InvokeAsync(); } } } 由于被标记为
内部
,您能建议一个如何授权给它的策略吗?如果是,我投你一票。:)不,不是:那我在网上链接了什么?我看到
Microsoft.AspNetCore.Mvc.Infrastructure.ActionSelector
是内部的,而您链接到的
Microsoft.AspNetCore.Mvc.internal.ActionSelector
是公共的。奇怪的是,
Internal
名称空间不在GitHub上。因此,就像Github将源代码移动到
基础设施中,并将其内部化一样。