web-dev-qa-db-ja.com

ASP.Net MVCでグローバルフィルターを選択的に無効にする方法

NHibernateセッションを開いたり閉じたりするすべてのコントローラーアクションに対してグローバルフィルターを設定しました。これらのアクションの95%はデータベースアクセスが必要ですが、5%は必要ありません。 5%でこのグローバルフィルターを無効にする簡単な方法はありますか。他の方法でデータベースを必要とするアクションのみを装飾することもできますが、それははるかに手間がかかります。

70
zszep

マーカー属性を書くことができます:

public class SkipMyGlobalActionFilterAttribute : Attribute
{
}

次に、アクション上のこのマーカーの存在について、グローバルアクションフィルターテストで:

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
    }
}

グローバルフィルターから一部のアクションを除外する場合は、マーカー属性でアクションを装飾します。

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

この素晴らしい投稿で説明されていることもできます:

フィルターの除外

カスタムExcludeFilterAttributeを実装してから、カスタムExcludeFilterProviderを実装するだけです。

きれいな解決策と私のために素晴らしかった!

18

とはいえ、ダリン・ディミトロフが受け入れた答えは問題なく、うまく機能していますが、私にとっては、最も簡単で効率的な答えが here でした。

ロジックを開始する直前に、ブールプロパティを属性に追加してチェックするだけです。

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.
    }
}

次に、5%のアクションで次のように使用します。

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

カスタムフィルタープロバイダーを作成します。 IFilterProviderを実装するクラスを作成します。このIFilterProviderインターフェイスには、実行する必要のあるFiltersを返すGetFiltersメソッドがあります。

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);
        }
}

================================================== ===========================
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
Swapnil

AspNetCoreでは、@ darin-dimitrovが受け入れた回答を次のように機能させることができます。

まず、マーカー属性にIFilterMetadataを実装します。

public class SkipMyGlobalActionFilterAttribute : Attribute, IFilterMetadata
{
}

次に、Filtersでこの属性のActionExecutingContextプロパティを検索します。

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

        // etc
    }
}
1
g t

少なくとも最近では、これは非常に簡単です。アクションからすべてのアクションフィルターを除外するには、OverrideActionFiltersAttributeを追加するだけです。

他のフィルターにも同様の属性があります:OverrideAuthenticationAttributeOverrideAuthorizationAttributeおよびOverrideExceptionAttribute

参照してください https://www.strathweb.com/2013/06/overriding-filters-in-asp-net-web-api-vnext/

1
Markus Wagner

次のようにフィルターコードを変更できます。

 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
        }
    }

そしてそれを使用します:

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

まあ、ASP.NET Coreで動作するようになったと思います。
コードは次のとおりです。

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);
    }

関連するコードは「IsExcluded」メソッドにあります。

0
ashilon