如何实现自定义C#特性禁用ASP.NET Core WebAPI控制器方法?
批量禁用ASP.NET Core WebAPI基础控制器CRUD方法的解决方案
问题背景
我有一个ASP.NET Core WebAPI应用,已实现通用基础控制器ProcessMiningControllerBase<T>,为所有继承它的控制器提供CRUD操作(GetAll、GetById、Insert、Update、Delete)。部分控制器需要禁用某些CRUD方法,虽然可以用[NonAction]特性逐个标记,但希望实现一个可应用于控制器的特性,批量指定要禁用的方法。
相关代码
基础服务接口
public interface IBaseService<T> where T : DomainObject { Task<PagedResultViewModel<T>> GetAllAsync(BaseRequestViewModel request); Task<SingleResultViewModel<T>> GetByIdAsync(int id); Task<SingleResultViewModel<T>> InsertAsync(T entity); Task<SingleResultViewModel<T>> UpdateAsync(T entity); Task<SingleResultViewModel<T>> DeleteAsync(int id); }
自定义基础控制器
public class ProcessMiningControllerBase<T> : ControllerBase where T : DomainObject { private readonly IBaseService<T> _baseService; public ProcessMiningControllerBase(IBaseService<T> baseService) { _baseService = baseService; } [HttpPost] public virtual async Task<PagedResultViewModel<T>> GetAllAsync(BaseRequestViewModel request) { return await _baseService.GetAllAsync(request); } [HttpGet("{id}")] public virtual async Task<SingleResultViewModel<T>> GetByIdAsync(int id) { return await _baseService.GetByIdAsync(id); } [HttpPost] public virtual async Task<SingleResultViewModel<T>> InsertAsync(T entity) { return await _baseService.InsertAsync(entity); } [HttpPut] public virtual async Task<SingleResultViewModel<T>> UpdateAsync(T entity) { return await _baseService.UpdateAsync(entity); } [HttpDelete("{id}")] public virtual async Task<SingleResultViewModel<T>> DeleteAsync(int id) { return await _baseService.DeleteAsync(id); } }
实现步骤
1. 定义CRUD操作枚举
创建带[Flags]特性的枚举,用于标识要禁用的CRUD方法:
[Flags] public enum CrudActions { None = 0, GetAll = 1 << 0, GetById = 1 << 1, Insert = 1 << 2, Update = 1 << 3, Delete = 1 << 4, All = GetAll | GetById | Insert | Update | Delete }
2. 创建控制器级禁用特性
实现可应用于控制器的自定义特性,接收要禁用的CRUD操作枚举:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] public class DisableCrudActionsAttribute : Attribute { public CrudActions DisabledActions { get; } public DisableCrudActionsAttribute(CrudActions disabledActions) { DisabledActions = disabledActions; } }
3. 实现约定处理逻辑
通过IActionModelConvention在API模型构建阶段,自动为指定方法添加[NonAction]特性:
public class DisableCrudActionsConvention : IActionModelConvention { public void Apply(ActionModel action) { var disableAttribute = action.Controller.ControllerType.GetCustomAttribute<DisableCrudActionsAttribute>(); if (disableAttribute == null) return; var disabledActions = disableAttribute.DisabledActions; // 匹配基础控制器中的方法名,添加NonAction特性 if ((disabledActions & CrudActions.GetAll) != 0 && action.ActionName == nameof(ProcessMiningControllerBase<DomainObject>.GetAllAsync)) { action.Filters.Add(new NonActionAttribute()); } if ((disabledActions & CrudActions.GetById) != 0 && action.ActionName == nameof(ProcessMiningControllerBase<DomainObject>.GetByIdAsync)) { action.Filters.Add(new NonActionAttribute()); } if ((disabledActions & CrudActions.Insert) != 0 && action.ActionName == nameof(ProcessMiningControllerBase<DomainObject>.InsertAsync)) { action.Filters.Add(new NonActionAttribute()); } if ((disabledActions & CrudActions.Update) != 0 && action.ActionName == nameof(ProcessMiningControllerBase<DomainObject>.UpdateAsync)) { action.Filters.Add(new NonActionAttribute()); } if ((disabledActions & CrudActions.Delete) != 0 && action.ActionName == nameof(ProcessMiningControllerBase<DomainObject>.DeleteAsync)) { action.Filters.Add(new NonActionAttribute()); } } }
4. 注册约定到服务
在Program.cs中添加该约定到控制器配置:
builder.Services.AddControllers(options => { options.Conventions.Add(new DisableCrudActionsConvention()); });
5. 使用示例
在需要禁用特定CRUD方法的控制器上应用特性即可,比如禁用Insert和Delete:
[DisableCrudActions(CrudActions.Insert | CrudActions.Delete)] public class SampleController : ProcessMiningControllerBase<SampleDomainObject> { public SampleController(IBaseService<SampleDomainObject> baseService) : base(baseService) { } }
说明
- 该方案通过约定机制批量处理,避免了在每个方法上重复标记
[NonAction] - 方法匹配基于方法名,确保和基础控制器中的方法名称一致即可
- 枚举使用
[Flags]支持同时禁用多个操作
内容的提问来源于stack exchange,提问作者Amir Monfared
相关产品推荐
相关产品推荐

