![](/img/trans.png)
[英]How to change the default controller and action in ASP.NET Core API?
[英]Use default interface method as controller action ASP.NET Core
如何使用默认接口方法作为 MVC controller 动作? 由于接口方法存在于接口类型上,默认情况下它们不会被 ASP 作为操作发现。 例子:
public interface IGetEntityControllerMixin<TEntity> : IControllerBase
where TEntity : class, IEntity, new()
{
IRepository<TEntity> Repository { get; }
[HttpGet("{id:int}")]
public async Task<ActionResult<TEntity>> Get(int id)
{
var entity = await Repository.GetByIdAsync(id);
return entity == null ? NotFound() : Ok(entity);
}
}
public interface IPagingEntityControllerMixin<TEntity> : IControllerBase
where TEntity : class, IEntity, new()
{ ... }
[ApiController]
[Route("[controller]")]
public class MyEntityController : ControllerBase,
IGetEntityControllerMixin<MyEntity>,
IPagingEntityControllerMixin<MyEntity>
{
public IRepository<MyEntity> Repository { get; }
public MyEntityController(IRepository<MyEntity> repository)
=> Repository = repository;
}
您可以注册IApplicationModelProvider
以通知 MVC 这些操作。
internal sealed class ControllerDefaultInterfaceMethodActionDescriptorProvider : IApplicationModelProvider
{
private readonly IServiceProvider _serviceProvider;
public ControllerDefaultInterfaceMethodActionDescriptorProvider(IServiceProvider serviceProvider) => _serviceProvider = serviceProvider;
public void OnProvidersExecuting(ApplicationModelProviderContext context) { }
// based on https://github.com/dotnet/aspnetcore/blob/d3b7623a90d79719c0efe5fa0098f698176efa16/src/Mvc/Mvc.Core/src/ApplicationModels/DefaultApplicationModelProvider.cs#L42
public void OnProvidersExecuted(ApplicationModelProviderContext context)
{
const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
var type = Type.GetType("Microsoft.AspNetCore.Mvc.ApplicationModels.DefaultApplicationModelProvider, Microsoft.AspNetCore.Mvc.Core");
Debug.Assert(type != null);
object defaultModelProvider = _serviceProvider.GetServices<IApplicationModelProvider>()
.First(x => x.GetType() == type);
// internal ActionModel? CreateActionModel(TypeInfo typeInfo, MethodInfo methodInfo)
Type createActionType = typeof(Func<,,,>).MakeGenericType(type, typeof(TypeInfo), typeof(MethodInfo), typeof(ActionModel));
var createActionModelDelegate = Delegate.CreateDelegate(createActionType, type.GetMethod("CreateActionModel", bindingFlags)!);
// internal ParameterModel CreateParameterModel(ParameterInfo parameterInfo)
Type createParameterModelType = typeof(Func<,,>).MakeGenericType(type, typeof(ParameterInfo), typeof(ParameterModel));
var createParameterModelDelegate = Delegate.CreateDelegate(createParameterModelType, type.GetMethod("CreateParameterModel", bindingFlags)!);
var createActionParams = new object [3];
createActionParams[0] = defaultModelProvider;
var createParameterParams = new object [2];
createParameterParams[0] = defaultModelProvider;
foreach (ControllerModel controllerModel in context.Result.Controllers)
{
var controllerType = controllerModel.ControllerType;
createActionParams[1] = controllerType;
foreach (Type @interface in controllerType.ImplementedInterfaces)
{
var mapping = controllerType.GetInterfaceMap(@interface);
for (var i = 0; i < mapping.InterfaceMethods.Length; ++i)
{
MethodInfo interfaceMethod = mapping.InterfaceMethods[i];
MethodInfo targetMethod = mapping.TargetMethods[i];
// check is method implemented by interface itself
if (targetMethod != interfaceMethod)
continue;
createActionParams[2] = interfaceMethod;
var actionModel = (ActionModel?)createActionModelDelegate.DynamicInvoke(createActionParams);
if (actionModel == null)
continue;
actionModel.Controller = controllerModel;
controllerModel.Actions.Add(actionModel);
foreach (var parameterInfo in actionModel.ActionMethod.GetParameters())
{
createParameterParams[1] = parameterInfo;
var parameterModel = (ParameterModel?)createParameterModelDelegate.DynamicInvoke(createParameterParams);
if (parameterModel != null)
{
parameterModel.Action = actionModel;
actionModel.Parameters.Add(parameterModel);
}
}
}
}
}
}
public int Order => 1;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.