1

Mvc3 とUnity.Mvc3を使用して、テスト可能で分離されたサイトを構築していますが、明らかに何か間違っています。

私のApplication_Start()私は依存関係を登録します:

// container is a property of the MvcApplication
// and the HierarchicalLifetimeManager should make sure that the registrations
// only last for this request (or should it?)
_container.Register<Interface, Class>(new HierarchicalLifetimeManager())   

次にSession_Start()、依存関係を解決して、いくつかのデータをセッションに保存しようとします。

var obj = _container.Resolve<Interface>();

この時点で、Unity がインターフェイスを解決できないという例外が発生しましたが、そのインターフェイスのクラスを登録したと思っていましたか???

私は途方に暮れており、解決策を見つけるのがますます難しくなっています。

編集:

これが私のコード全体で、不要な部分がいくつか省略されています。

public class MvcApplication : System.Web.HttpApplication  
{   
    // as EDIT 2 says, this is wrong...
    //private IUnityContainer _container = new UnityContainer();
   
    protected void Application_Start()
    {
        // mvc stuff, routes, areas and whatnot

        // create container here and it works, almost
        var container = new UnityContainer();

        // register dependencies            
        string connectionString = "String from config";
        container.RegisterInstance<DbContext>(new CustomContext(connectionString), new HierarchicalLifetimeManager())
                 .RegisterType<IUnitOfWork, UnitOfWork>(new HierarchicalLifetimeManager())
                 .RegisterType(typeof(IRepository<>), typeof(Repository<>), new HierarchicalLifetimeManager());

        // register controller resolver
        DependencyResolver.SetResolver(new UnityDependencyResolver(container));

        // if i try to resolve repos here, it works and they all have the same context
        // just like the unit of work
    }

    protected void Session_Start()
    {
        // here the container complains that it can't resolve the interface
         
        // wrong
        //var userRepo = _container.Resolve<IRepository<User>>();

        // right, but still failes, because it is resolving DbContext
        // instead of using the CustomContext instance
        var userRepo = DependencyResolver.Current.GetService<IRepository<User>>();

        // save some user data to session           
    }
}


public class SampleController : Controller {

    // here the container tries to resolve the System.Data.Entity.DbContext
    // instead of just giving the repo that instance that I registered
    public SampleController(IRepository<Entity> repo) {
    }

}

私は明らかに、この Unit-of-work や依存関係の注入などで惨めな失敗をしています。最悪の部分は、理由がわからないことです...ですから、歯を抜く前に助けてください。

編集2:

部分的にあります。上記のようにコンテナを作成すると、Session_Start(). Application_Start()ローカル変数として作成し、を使用するDependencyResolverと、機能します。どのように、そしてなぜ、私を打ちますか?

ただし、インスタンスではDbContextなく、まだ解決しようとしています。CustomContext

解決:

では、取引は次のとおりです。

問題 1) のコンテナへのアクセスSession_Start():

DependencyResolverEDIT 2 で説明したように、ローカル コンテナー変数を使用することで解決し、 worksを介してコンテナーにアクセスします。

問題 2) 登録された db コンテキスト インスタンスの解決:

インスタンスの登録が機能しないことがわかりました。ただし、これは次のことを行います。

container.RegisterType<DbContext, CustomContext>(null, new HierarchicalLifetimeManager(), new InjectionConstructor(connectionString))

しかし、なぜこれがこのように機能するのかまだ理解できていないので、私は本当に満足していません. 久しぶりに本か何かを読まなければならないようだ。

よろしくお願いします。

4

2 に答える 2

1

問題は、で使用RegisterInstanceしていることですHierarchecalLifetimeManager。Unity.Mvc3プロジェクトはそのLifetimeManagerを使用してその魔法を実行しているため(およびHttpModulesを使用して子コンテナーの作成と破棄を管理しているため)、リクエストごとに新しいインスタンスを取得しようとしていると思います。

問題は、新しいリクエストが届くと、新しいオブジェクトを作成したいのですが、その方法がわからないことです。アプリの起動時にインスタンスを一度登録しただけで、オブジェクトを作成する方法ではありません。したがって、それを機能させるには、RegisterType()を使用する必要があります。

2つの選択肢があります。

  1. InjectionConstructorを使用して、注入された値を指定します。RegisterType<DbContext, CustomContext>(new HierarchecalLifetimeManager(), new InjectionConstructor(connectionString))

  2. 工場を使用する:(Container.RegisterType<DbContext>(new InjectionFactory(c => new CustomContext(connectionString)), new HierarcicalLifetimeManager())これに触発されて

*注:パラメーターの順序が間違っている可能性があります。

アプリケーション全体に真のシングルトンインスタンスが必要な場合は、ContainerControlledLifetimeManager()(これは実際にはRegisterInstanceのデフォルトであるため、指定する必要はありません)を使用します。しかし、サイトが使用されるにつれて、DbContextはかなり巨大になります。

さらに、Session_Start()にアイテムが登録されていないという最初の問題について:

ASP.NETは、HttpApplicationクラスのプールを維持します。つまり、Unityコンテナをメンバー変数にすると、すべて独自の登録を持つ複数のインスタンスが作成されます。Application_Start()は1回だけ呼び出され、Session_Start()は、登録なしで別のインスタンスを使用して呼び出すことができます。これを解決するには、静的変数を使用する必要があります(これは、最終的にDependencyResolverで実行したことです)。

于 2013-02-14T05:42:11.457 に答える
1

コンテナーに直接アクセスする代わりに(Qからコンテナーへの参照を取得した場所が明確ではありませんか?)、MVC依存関係リゾルバーにそれを解決させてみませんか?

依存関係リゾルバーを設定します(Application_Start()):

DependencyResolver.SetResolver(new UnityDependencyResolver(container));

インターフェイスを解決します(Session_Start()):

var obj = DependencyResolver.Current.GetService<IMyInterface>();
于 2013-02-13T20:07:16.783 に答える