0

HTTP リクエストごとに登録されたアイテムにアクセスする必要があるグローバル フィルター属性があります。

// other ContainerBuilder stuff
builder.RegisterType<HttpDependency>().As<IHttpDependency>().InstancePerHttpRequest();

そして他の場所:

internal sealed class MyActionFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        // EVIL YUCKY SERVICE LOCATOR!
        var resolved = AutofacDependencyResolver.Current.RequestLifetimeScope.Resolve<IHttpDependency>();

        if (resolved.NeedsRedirect)
        {
            // does a redirect
        }

        base.OnActionExecuting(filterContext);
    }
}

そしてそれをグローバルフィルターとして登録します:

// in FilterConfig.cs
filters.Add(new MyActionFilter());

これはグローバル フィルターであるため、コンストラクター インジェクションを使用できません。つまり、アプリの起動時に HTTP コンテキストをすべての要求で再利用するべきではありません。サービスロケーターを介して手を差し伸べて取得することに頼らずに、これを適切に配線するにはどうすればよいですか?

4

2 に答える 2

1

1 つの方法は、Attribute からロジックを削除し、IActionFilter を実装するクラスに実装することです。次に、依存性注入が正しく機能するように、クラスがコンテナーに登録されます。このアプローチを使用するオーチャード CMS。

public class MyCustomActionFilterAttribute : Attribute
{
}

public class MyCustomActionFilter : FilterProvider, IActionFilter
{
    protected MyService Service { get; private set; }

    // MyService can be injected by the container...
    public MyCustomActionFilter(MyService service)
    {
        this.Service = service;
    }

    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
        // Check to see if the action has a matching attribute
        var attributes = filterContext.ActionDescriptor.GetCustomAttributes(typeof(MyCustomActionFilterAttribute), true);

        // Perform some logic here....
    }

    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
    }
}

フィルターをアクションに適用する IActionInvoker を作成することができます。このクラスは、DependencyResolver を使用して MVC を自動的にインスタンス化します。

public class FilterResolvingActionInvoker : ControllerActionInvoker
{
    protected IEnumerable<IFilterProvider> Providers { get; private set; }

    // Filters registered with the container are injected by the container
    public FilterResolvingActionInvoker(IEnumerable<IFilterProvider> providers)
    {
        this.Providers = providers;
    }

    // Add the filter to the current FilterInfo
    protected override FilterInfo GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
    {
        var filters = base.GetFilters(controllerContext, actionDescriptor);
        foreach (var provider in this.Providers)
        {
            provider.AddFilters(filters);
        }
        return filters;
    }
}

フィルターを登録できる共通インターフェースを定義します。

public interface IFilterProvider
{
    void AddFilters(FilterInfo filterInfo);
}

public abstract class FilterProvider : IFilterProvider
{
    public void AddFilters(FilterInfo filterInfo)
    {
        if (this is IActionFilter)
        {
            filterInfo.ActionFilters.Add(this as IActionFilter);
        }
    }
}

それらをコンテナビルダーに登録します。Autofac の拡張メソッドを作成して、アセンブリ内のすべての IFilterProvider を自動的に登録することもできます。

builder.RegisterType<FilterResolvingActionInvoker>().As<IActionInvoker>().InstancePerDependency();
builder.RegisterType<MyCustomActionFilter>().As<IFilterProvider>().InstancePerDependency();
于 2013-07-02T21:45:26.853 に答える
-1

いつものように、ロケーターを回避するオプションの 1 つは、Compositon Root にセットアップされたローカル ファクトリを持つことです。ファクトリは、ioc コンテナーを使用するようにセットアップされます。

http://netpl.blogspot.com/2012/12/di-factories-and-composition-root.html

このロケータは「技術的に」「似ている」(ファクトリ インスタンスを作成してサービスを要求する) と主張することもできますが、最終的に実装するために使用する実際の IoC コンテナーを含む他のインフラストラクチャへの依存関係は発生しません。 factory - 実際のファクトリの実装は、コンポジション ルート (グローバル アプリケーション クラスの近く) の一部です。

このようなアプローチは、インフラストラクチャの一部を担当する多くの分離された小さなファクトリにつながりますが、それでも各ファクトリには、コンポジション ルートの近くに実装できるプラグ可能なプロバイダーがあるため、外部依存を回避できます。

于 2013-07-02T21:11:58.910 に答える