2

MVC4 と Unity 2.1 を使用しています。サービスには、セッション状態から取得した資格情報に基づくサービス キーが必要です。

次のようにサービスを登録します。

container.RegisterType<IInventoryService, InventoryService>();

InventoryService のコンストラクターも同様に単純です。

public InventoryService(ServiceKey serviceKey) {  ...  }

私の Web サイトでサービスが必要になったとき、セッションからの資格情報を使用してサービス キーを自動的に作成するサービス ロケーターを使用します。

public static T Resolve<T>(ServiceKey serviceKey = null)
    {
        if (serviceKey == null)
        {
            serviceKey = SessionManager.ServiceKey;
        }

        var parameterOverride = new ParameterOverride(SERVICEKEY_PARAMETERNAME, serviceKey);

        return Resolve<T>(null, parameterOverride);
    }

これはうまくいきました。問題は、サイトを MVC に変換し、既存のサービス ロケーター (依存関係ファクトリ) を使用する単純な依存関係リゾルバーを使用して、サービスをコントローラーに挿入しようとしていることです。

public class CustomDependencyResolver : IDependencyResolver
{
    public object GetService(Type serviceType)
    {
        return MvcDependencyFactory.Resolve(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return MvcDependencyFactory.ResolveAll(serviceType);
    }
}

私のコントローラーは次のようになります。

public InventoryController(IInventoryService inventoryService) { ... }

問題は、MVC が、インベントリ コントローラーをインスタンス化しようとしたときに、パラメーターのないコンストラクターが見つからないというエラーを表示することです。Unityにサービスキーを登録していないことが原因だと思います。しかし、そうしようとすると、セッションが構築される前に、MVC がコントローラーを解決しようとし、続いてサービスを解決しようとしていることがわかります。

私はこれについて正しく考えていませんか?サービスでセッション資格情報を使用する、コントローラーでサービスを使用する、コントローラーを構築するためにリゾルバーを使用するなど、各ステップはかなり合理的だと感じていますが、これを機能させるために頭を悩ませてきました。

4

3 に答える 3

1

Unity の InjectionFactory (Microsoft.Practices.Unity.InjectionFactory) を使用して、依存関係の解決を処理する関数を指定できます。この関数は、依存関係が解決されたときにのみ実行されます。以下の例では、「c」は引数として渡された Unity コンテナーであり、関数内で追加の解決を行うことができます。

交換:

container.RegisterType<IInventoryService, InventoryService>();

と:

container.RegisterType<IInventoryService>(new InjectionFactory(c =>
    new InventoryService(SessionManager.ServiceKey)));
于 2013-08-16T14:48:28.810 に答える
-1

以下はカスタムの IDependencyResolver です。これがどのように機能し、IoC コンテナーの解決とは異なるかを掘り下げてみると、かなり単純明快でした。MVC が試みた IControllerActivator の解決をキャプチャするには、try/catches が必要です (ソース: http://www.devtrends.co.uk/blog/do-not-implement-icontrolleractivator-in-asp.net-mvc-3 )。IControllerActivator を解決できない場合は、代わりにカスタム IDependencyResolver がコントローラーに対してクエリされます (選択した IoC コンテナーを使用します)。

以下のクラスを基本的な MVC4 の App_Start フォルダーに追加しました。

using System;
using System.Collections.Generic;
using System.Web.Mvc;
using Microsoft.Practices.Unity;
using Sample.Web.Controllers;

namespace Sample.Web.App_Start
{
    public static class UnityConfig
    {
        public static void ConfigureContainer()
        {
            IUnityContainer container = BuildUnityContainer();
            DependencyResolver.SetResolver(new UnityDependencyResolver(container));
        }

        private static IUnityContainer BuildUnityContainer()
        {
            var container = new UnityContainer();

            container.RegisterType<IHomeService>(new InjectionFactory( c =>
                new HomeService("this string is a dependency.")));
            container.RegisterType<IController, HomeController>("Home");

            return container;
        }
    }

    public class UnityDependencyResolver : IDependencyResolver
    {
        private readonly IUnityContainer _container;

        public UnityDependencyResolver(IUnityContainer container)
        {
            _container = container;
        }

        public object GetService(Type serviceType)
        {
            try
            {
                return _container.Resolve(serviceType);
            }
            catch (ResolutionFailedException)
            {
                return null;
            }
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            try
            {
                return _container.ResolveAll(serviceType);
            }
            catch (ResolutionFailedException)
            {
                return new List<object>();
            }
        }
    }
}

これが私の単純なコントローラーです:

using System.Web.Mvc;

namespace Sample.Web.Controllers
{
    public class HomeController : Controller
    {
        private readonly IHomeService _service;

        public HomeController(IHomeService service)
        {
            _service = service;
        }

        public ActionResult Index()
        {
            ViewBag.SomeData = _service.GetSomeData();
            return View();
        }
    }

    public interface IHomeService
    {
        string GetSomeData();
    }

    public class HomeService : IHomeService
    {
        private readonly string _data;

        public HomeService(string data)
        {
            _data = data;
        }

        public string GetSomeData()
        {
            return _data;
        }
    }
}

これが私の壮大な見解です:

@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>
<p>@ViewBag.SomeData</p>
于 2013-08-17T00:30:49.437 に答える