Asp.net web api Asp.NETMVC核心中的ApiControllerActionSelector等效项
我们正在从web api迁移到asp.net mvc core,我在web api中有一个操作选择器,如果url“$”符号中存在任何软件,我们用来调用控制器中的特定方法。 我们使用下面的ApiControllerActionSelector在web api中实现的这个功能就是在web api中实现同样功能的代码-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) {
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将源代码移动到基础设施中,并将其内部化一样。