Cách tắt chọn lọc bộ lọc chung trong ASP.Net MVC


77

Tôi đã thiết lập bộ lọc chung cho tất cả các hành động của bộ điều khiển mà tôi mở và đóng các phiên NHibernate. 95% hành động này cần một số quyền truy cập cơ sở dữ liệu, nhưng 5% thì không. Có cách nào dễ dàng để tắt bộ lọc chung này cho 5% đó không. Tôi có thể đi theo hướng khác và chỉ trang trí các hành động cần cơ sở dữ liệu, nhưng điều đó sẽ mất nhiều công sức hơn.


1
Còn về việc tạo một hành động khác và trang trí 5% với điều này. Một cái gì đó giống như NHibernateNotRequiredAttribute ()?
dreza,

Câu trả lời:


151

Bạn có thể viết một thuộc tính điểm đánh dấu:

public class SkipMyGlobalActionFilterAttribute : Attribute
{
}

và sau đó trong kiểm tra bộ lọc hành động toàn cầu của bạn để tìm sự hiện diện của điểm đánh dấu này trên hành động:

public class MyGlobalActionFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext.ActionDescriptor.GetCustomAttributes(typeof(SkipMyGlobalActionFilterAttribute), false).Any())
        {
            return;
        }

        // here do whatever you were intending to do
    }
}

và sau đó, nếu bạn muốn loại trừ một số hành động khỏi bộ lọc chung, chỉ cần trang trí nó bằng thuộc tính marker:

[SkipMyGlobalActionFilter]
public ActionResult Index()
{
    return View();
}

Giải pháp thực sự tuyệt vời. Tôi tự hỏi làm thế nào mà tôi không nghĩ đến điều này một mình. Cảm ơn.
zszep

5
Điều này là hữu ích, cảm ơn. Chỉ để giúp những người trong tương lai, bạn cũng có thể đặt điều tương tự trên Bộ điều khiển và sử dụng filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes để áp dụng cho tất cả các hành động.
Daryl Teo

4
bất cứ ai sau khi giải pháp api cú pháp là hơi khác nhau: actionContext.ActionDescriptor.GetCustomAttributes <SkipMyGlobalActionFilter> () Bất kỳ ().
AKD

Và nếu bạn cũng muốn bỏ qua thuộc tính bộ điều khiển cụ thể thì bạn nên thêm || trong bộ lọc điều kiệnContext.ControllerContext.ControllerDescriptor.GetCustomAttributes <SkipMyGlobalActionFilter> () .Any ()
akd

3
như Leniel đã viết, trong ASP.NET Core, filterContext.ActionDescriptor không có phương thức GetCustomAttributes. Làm thế nào để làm điều đó trong ASP.NET core?
ashilon

19

Bạn cũng có thể làm những gì được mô tả trong bài đăng tuyệt vời này:

Loại trừ một bộ lọc

Chỉ cần thực hiện một tùy chỉnh ExcludeFilterAttributevà sau đó là một tùy chỉnh ExcludeFilterProvider.

Giải pháp sạch sẽ và làm việc tuyệt vời cho tôi!


1
Bất kỳ giải pháp tương tự cho lõi aspnet?
smg

1
@smg vui lòng xem câu trả lời của @ gt bên dưới
Ali Hasan

11

Mặc dù, câu trả lời được chấp nhận bởi Darin Dimitrov là ổn và hoạt động tốt, nhưng đối với tôi, câu trả lời đơn giản và hiệu quả nhất được đặt ở đây .

Bạn chỉ cần thêm một thuộc tính boolean vào thuộc tính của mình và kiểm tra lại nó, ngay trước khi logic của bạn bắt đầu:

public class DataAccessAttribute: ActionFilterAttribute
{
    public bool Disable { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (Disable) return;

        // Your original logic for your 95% actions goes here.
    }
}

Sau đó, ở 5% hành động của bạn, chỉ cần sử dụng nó như thế này:

[DataAccessAttribute(Disable=true)]
public ActionResult Index()
{            
    return View();
}

Một chút "gotcha" mà tôi đã nhận thấy ở đây - nếu bạn chỉ định một Thứ tự trong khai báo chung của bộ lọc, bạn cũng phải chỉ định cùng một thứ tự trên thuộc tính. Ví dụ: [DataAccessAttribute(Disable=true,Order=2)]filters.Add(new DataAccessAttribute(), 2);
Jon Story

8

Trong AspNetCore, câu trả lời được chấp nhận bởi @ darin-dimitrov có thể được điều chỉnh để hoạt động như sau:

Đầu tiên, triển khai IFilterMetadatatrên thuộc tính marker:

public class SkipMyGlobalActionFilterAttribute : Attribute, IFilterMetadata
{
}

Sau đó, tìm kiếm Filtersthuộc tính cho thuộc tính này trên ActionExecutingContext:

public class MyGlobalActionFilter : IActionFilter
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (context.Filters.OfType<SkipMyGlobalActionFilterAttribute>().Any())
        {
            return;
        }

        // etc
    }
}

3

Ít nhất hiện nay, điều này khá dễ dàng: để loại trừ tất cả các bộ lọc hành động khỏi một hành động, chỉ cần thêm OverrideActionFiltersAttribute .

Có các thuộc tính tương tự cho các bộ lọc khác: OverrideAuthenticationAttribute , OverrideAuthorizationAttributeOverrideExceptionAttribute .

Xem thêm https://www.strathweb.com/2013/06/overriding-filters-in-asp-net-web-api-vnext/


Ngày nay là 2013+? Không chắc tại sao đây không phải là câu trả lời được chấp nhận vì nó có vẻ chuẩn.
Martin Capodici

2

Tạo Nhà cung cấp Bộ lọc tùy chỉnh. Viết một lớp sẽ triển khai IFilterProvider. Giao diện IFilterProvider này có phương thức GetFilters trả về Bộ lọc cần được thực thi.

public class MyFilterProvider : IFilterProvider
{
        private readonly List<Func<ControllerContext, object>> filterconditions = new List<Func<ControllerContext, object>>();
        public void Add(Func<ControllerContext, object> mycondition)
        {
            filterconditions.Add(mycondition);
        }

        public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
        {
            return from filtercondition in filterconditions
                   select filtercondition(controllerContext) into ctrlContext
                   where ctrlContext!= null
                   select new Filter(ctrlContext, FilterScope.Global);
        }
}

================================================== ===========================
Trong Global.asax.cs

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            MyFilterProvider provider = new MyFilterProvider();
            provider.Add(d => d.RouteData.Values["action"].ToString() != "SkipFilterAction1 " ? new NHibernateActionFilter() : null);
            FilterProviders.Providers.Add(provider);
        }


protected void Application_Start()
{
    RegisterGlobalFilters(GlobalFilters.Filters);
}

2

Tôi nghĩ rằng tôi đã làm cho nó hoạt động cho ASP.NET Core.
Đây là mã:

public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        // Prepare the audit
        _parameters = context.ActionArguments;

        await next();

        if (IsExcluded(context))
        {
            return;
        }

        var routeData = context.RouteData;

        var controllerName = (string)routeData.Values["controller"];
        var actionName = (string)routeData.Values["action"];

        // Log action data
        var auditEntry = new AuditEntry
        {
            ActionName = actionName,
            EntityType = controllerName,
            EntityID = GetEntityId(),
            PerformedAt = DateTime.Now,
            PersonID = context.HttpContext.Session.GetCurrentUser()?.PersonId.ToString()
        };

        _auditHandler.DbContext.Audits.Add(auditEntry);
        await _auditHandler.DbContext.SaveChangesAsync();
    }

    private bool IsExcluded(ActionContext context)
    {
        var controllerActionDescriptor = (Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor)context.ActionDescriptor;

        return controllerActionDescriptor.ControllerTypeInfo.IsDefined(typeof(ExcludeFromAuditing), false) ||
               controllerActionDescriptor.MethodInfo.IsDefined(typeof(ExcludeFromAuditing), false);
    }

Mã có liên quan nằm trong phương thức 'IsExcluded'.


1

Bạn có thể thay đổi mã bộ lọc của mình như sau:

 public class NHibernateActionFilter : ActionFilterAttribute
    {
        public IEnumerable<string> ActionsToSkip { get; set; }

        public NHibernateActionFilter(params string[] actionsToSkip)
        {
            ActionsToSkip = actionsToSkip;
        }

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (null != ActionsToSkip && ActionsToSkip.Any(a => 
String.Compare(a,  filterContext.ActionDescriptor.ActionName, true) == 0))
                {
                    return;
                }
           //here you code
        }
    }

Và sử dụng nó:

[NHibernateActionFilter(new[] { "SkipFilterAction1 ", "Action2"})]

2
Đó là một cách để làm điều đó, nhưng hơi khó để duy trì theo thời gian.
zszep

1
Nếu bạn thay đổi tên hành động của mình và quên thay đổi nó trong cách sử dụng thuộc tính, trình biên dịch sẽ không cảnh báo bạn. Điều này rất có thể gây ra đau đớn khi bảo dưỡng. Tôi thích câu trả lời của Darin hơn vì bạn không phải chỉ định các hành động theo cách thủ công.
Nashenas
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.