キャッスルウィンザーのWebAPIにおける依存性注入

Castle Windsorを使用してWebApiアプリケーションにDependency Injectionを実装したいと思います。私は次のサンプルコードを持っています -

インターフェース -

public interface IWatch
{
    {
        DateTime GetTime();
    }
}

ウォッチクラスに続いて IWatch インターフェースを実装しています -

public class Watch:IWatch
{
        public DateTime GetTime()
        {
            return DateTime.Now;
        }
}

WebApiコントローラ - 下記のような WatchController -

public class WatchController : ApiController
{
        private readonly IWatch _watch;

        public WatchController()
        {
            _watch = new Watch();
        }

        //http://localhost:48036/api/Watch
        public string Get()
        {
            var message = string.Format("The current time on the server is: {0}", _watch.GetTime());
            return message;
        }
}

現在、WatchControllerコンストラクタでWatchでIWatchオブジェクトを開始しています。私はウィンザーキャッスル依存性注入の原理を使用してコンストラクタ内部のIWatchを初期化する依存関係を取り除きたい

誰でもWebApiのこのケースで依存性注入を実装する手順を教えてくれますか?前もって感謝します!

20
はい、私はすでにこのリンクを試していますが、関連する解決策は見つかりませんでした。
追加された 著者 Sumit Deshpande,
次に、あなたが問題を抱えている具体的な部分について説明してください。
追加された 著者 CodeCaster,

3 答え

CodeCaster、Noctis、Cristianoはあなたのすべての助けと指導に感謝します.. 私はちょうど私の上記の質問の解決策を得ました -

最初のステップは、 WebApiで Windsor.Castle パッケージをインストールするためにnugetを使用することですソリューション。

enter image description here

次のコードスニペットを考えてみましょう。

Interface IWatch.cs

public interface IWatch
{
     DateTime GetTime();
}

Class Watch.cs

public class Watch:IWatch
{
    public DateTime GetTime()
    {
        return DateTime.Now;
    }
}

ApiController WatchController.cs は次のように定義されています:

public class WatchController : ApiController
{
     private readonly IWatch _watch;

     public WatchController(IWatch watch)
     {
         _watch = watch;
     }

     public string Get()
     {
         var message = string.Format("The current time on the server is: {0}", _watch.GetTime());
         return message;
     }
}

コントローラでは、IWatchオブジェクトを介して依存関係をWatchControllerコンストラクタに挿入しました。私は、 IDependencyResolver IDependencyScope を使用して、Web APIの依存関係注入を実現します。 IDependencyResolverインターフェイスは、要求スコープ外のすべてを解決するために使用されます。

WindsorDependencyResolver.cs

internal sealed class WindsorDependencyResolver : IDependencyResolver
{
    private readonly IWindsorContainer _container;

    public WindsorDependencyResolver(IWindsorContainer container)
    {
        if (container == null)
        {
            throw new ArgumentNullException("container");
        }

        _container = container;
    }
    public object GetService(Type t)
    {
        return _container.Kernel.HasComponent(t) ? _container.Resolve(t) : null;
    }

    public IEnumerable GetServices(Type t)
    {
        return _container.ResolveAll(t).Cast().ToArray();
    }

    public IDependencyScope BeginScope()
    {
        return new WindsorDependencyScope(_container);
    }

    public void Dispose()
    {

    }
}

WindsorDependencyScope.cs

internal sealed class WindsorDependencyScope : IDependencyScope
{
    private readonly IWindsorContainer _container;
    private readonly IDisposable _scope;

    public WindsorDependencyScope(IWindsorContainer container)
    {
        if (container == null)
        {
            throw new ArgumentNullException("container");
        }
        _container = container;
        _scope = container.BeginScope();
    }

    public object GetService(Type t)
    {
        return _container.Kernel.HasComponent(t) ? _container.Resolve(t) : null;
    }

    public IEnumerable GetServices(Type t)
    {
        return _container.ResolveAll(t).Cast().ToArray();
    }

    public void Dispose()
    {
        _scope.Dispose();
    }
}

WatchInstaller.cs

インストーラーは IWindsorInstaller インターフェースを実装するタイプです。インタフェースにはInstallという単一のメソッドがあります。メソッドはコンテナのインスタンスを取得し、次にFluent Registration APIを使用してコンポーネントを登録できます。

public class WatchInstaller : IWindsorInstaller
{
      public void Install(IWindsorContainer container, IConfigurationStore store)
      {
      //Need to Register controllers explicitly in your container
      //Failing to do so Will receive Exception:

      //> An error occurred when trying to create //a controller of type
      //> 'xxxxController'. Make sure that the controller has a parameterless
      //> public constructor.

      //Reason::Basically, what happened is that you didn't register your controllers explicitly in your container. 
      //Windsor tries to resolve unregistered concrete types for you, but because it can't resolve it (caused by an error in your configuration), it return null.
      //It is forced to return null, because Web API forces it to do so due to the IDependencyResolver contract. 
      //Since Windsor returns null, Web API will try to create the controller itself, but since it doesn't have a default constructor it will throw the "Make sure that the controller has a parameterless public constructor" exception.
      //This exception message is misleading and doesn't explain the real cause.

      container.Register(Classes.FromThisAssembly()
                            .BasedOn()
                            .LifestylePerWebRequest());***
          container.Register(
              Component.For().ImplementedBy()
          );
      }
}

最後に、デフォルトの依存関係リゾルバをGlobal.asax.cs(Application_Startメソッド)のWindsor実装に置き換え、依存関係をインストールする必要があります。

    private static IWindsorContainer _container;
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);

        ConfigureWindsor(GlobalConfiguration.Configuration);
    }

    public static void ConfigureWindsor(HttpConfiguration configuration)
    {
        _container = new WindsorContainer();
        _container.Install(FromAssembly.This());
        _container.Kernel.Resolver.AddSubResolver(new CollectionResolver(_container.Kernel, true));
        var dependencyResolver = new WindsorDependencyResolver(_container);
        configuration.DependencyResolver = dependencyResolver;
    }    
64
追加された
私は、これには一握りのアップボックス以上のものがないことはかなり驚くべきことです。あなたが入れたすべての作品について、あなたは数十に値します!
追加された 著者 Tomas Lycken,
なぜこれはMVC5コントローラでは使えないのですか?
追加された 著者 KthProg,
シナリオを詳細に指定してください
追加された 著者 Sumit Deshpande,
IWatchの実装が異なる場合はどうなりますか?
追加された 著者 Chookoos,
なぜあなたはコンテナを静的にしたのですか?
追加された 著者 Mariusz Jamro,
これは何のためのものか: "container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel、true));"私の場合はこれがなくても動作しますが、これと同じ例はありません。
追加された 著者 Guillermo Ruffino,
@SumitDeshpande、私はあなたの答えに従っている。しかし、私は "オブジェクトのインスタンスに設定されていないオブジェクト参照"エラーメッセージが表示されます。もしあなたが望むなら、私が書いたコードを保存します。
追加された 著者 Balanjaneyulu K,

webapiのためのウィンザー配管に関するMark Seemannの記事を読んでください。

3
追加された

私はキャッスルウィンザーと直接仕事をしませんでしたが、ロジックは似ているはずです:

あなたの WatchController ctorは次のようになります:

public WatchController(IWatch watch) 
{
    _watch = watch;
}

これが依存関係を注入する場所です。

WatchController クラスを登録するロケータに相当するものを用意し、必要なものに応じてどの時計を受け取るべきかを教えてください。デザイン/ランタイム、曜日、乱数...あなたが必要とするものは何でも...

次のコードはMVVM-Lightのものですが、上記の段落を明確にする必要があります:

static ViewModelLocator()
{
    ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

   //This will run in design mode, so all your VS design data will come from here
    if (ViewModelBase.IsInDesignModeStatic)
    {
        SimpleIoc.Default.Register();
    }
   //This will run REAL stuff, in runtime
    else
    {
        SimpleIoc.Default.Register();
    }

   //You register your classes, so the framework can do the injection for you
    SimpleIoc.Default.Register();
    ...
}
1
追加された
私はMVVMを初めて使用しているので、あなたの回答を詳しく説明できれば助かります。ありがとう!
追加された 著者 Sumit Deshpande,
CodeCasterと同様に、何を試しましたか?具体的に。誰もが他の人のコードを書くよりも良いことがあります。 DIに関する簡単な情報が必要な場合は、こちらをご覧ください: James Shoreのブログ< a>。重い銃(少し長いですが)が必要な場合は、この Martin Fowlerの記事をお試しください。より具体的にするには、質問を更新してください
追加された 著者 Noctis,