1

asp.net mvc と Structuremap ioc/di を使用して小さな Web ショップを構築しています。Basket クラスは永続化のためにセッション オブジェクトを使用し、SM を使用して IBasket インターフェイスを介して Basket オブジェクトを作成したいと考えています。私のバスケットの実装では、コントローラー/アクション内で利用できるコンストラクターに HttpSessionStateBase (mvc のセッション状態ラッパー) が必要です。SM の IBasket 実装を登録するにはどうすればよいですか?
これは私のバスケットインターフェースです:

public interface IBasketService    {
    BasketContent GetBasket();
    void AddItem(Product productItem);
    void RemoveItem(Guid guid);
}

そしてSM登録:

ForRequestedType(typeof (IBasketService)).TheDefaultIsConcreteType(typeof (StoreBasketService));

しかし、私の StoreBasketService 実装にはコンストラクターがあります。

public StoreBasketService(HttpSessionStateBase sessionState)

コントローラーでのみ使用可能な HttpSessionStateBase オブジェクトを SM に提供するにはどうすればよいですか?
これが SM IOC/DI の初めての使用であり、公式ドキュメントや Web サイトで解決策や例を見つけることができません ;)

4

5 に答える 5

4

StoreBasketService でセッションを使用する必要がある場合は、HttpSessionStateBase を使用する代わりに、HttpSessionState のインターフェイスとラッパーを定義して、StructureMap にも登録できるようにします。ラッパーは、現在のセッション状態を取得します。環境。ラッパーを StructureMap に登録してから、StoreBasketService にインターフェイスをコンストラクターへの引数として取得させます。次に、構造マップは、インターフェイス ラッパーのインスタンスを作成し、それを StoreBasketService クラスに挿入する方法を認識している必要があります。

インターフェイスとラッパーを使用すると、単体テストでラッパーをモックできます。これは、HttpSessionStateBase で実際のセッションをモックできるのと同じ方法です。

public interface IHttpSessionStateWrapper
{
    HttpSessionState GetSessionState();
}

public class HttpSessionStateWrapper : IHttpSessionStateWrapper
{
    public virtual HttpSessionState GetSessionState()
    {
       return HttpContext.Current.Session;
    }
}

ForRquestedType(typeof(IHttpSessionStateWrapper))
   .TheDefaultIsConcreteType(typeof(IHttpSessionStateWrapper));

public class StoreBasketService
{
   HttpSessionState session;
   public StoreBasketService( IHttpSessionstateWrapper wrapper )
   {
      session = wrapper.GetSessionState();
   }

   // basket implementation ...
}

.CacheBy(InstanceScope.HttpContext)ただし、登録時に使用して、StructureMap に実際にバスケットをセッションに保存させることができます。実際には、セッションに物を保存するのではなく、StoreBasketService に内部ストレージを実装させる方が良い場合があります。そうすれば、(クラスの観点から) セッション状態への依存が完全に失われ、ソリューションがよりシンプルになる可能性があります。Dictionary<Guid,Product>これは、インターフェイスを介してアクセスする方法であるため、内部ストレージである可能性があります。

以下も参照してください。

http://www.lostechies.com/blogs/chad_myers/archive/2008/07/15/structuremap-basic-scenario-usage.aspx

http://www.lostechies.com/blogs/chad_myers/archive/2008/07/17/structuremap-medium-level-usage-scenarios.aspx

于 2008-11-02T22:31:24.583 に答える
1
ForRequestedType<IBasketService>()
    .TheDefault.Is.OfConcreteType<StoreBasketService>()
    .WithCtorArg("sessionState").EqualTo(HttpContext.Current.Session);

?? それは動作しますか?

于 2008-12-16T04:40:02.743 に答える
0

StructureMap を使い始めたばかりで、説明している結果が得られません。シンプルなクラスを使用して簡単なテストを実行し、Structuremap を cacheby HttpContext に構成しました。私が見ることができることから、CacheBy.HttpContext は、同じリクエスト内で同じインスタンスを取得することを意味します...同じセッション内ではありません

私のクラスのコンストラクターは、プライベート フィールドに日付/時刻を設定します。1 秒間隔で MyClass の 2 つのインスタンスを取得するボタンがあります。次に、両方のインスタンスの時刻をラベルに表示します。

このボタンを初めて押すと、オブジェクト A と B は同じインスタンスであり、予想どおり、作成時間がまったく同じです。

ボタンをもう一度クリックすると、インスタンスがセッションでキャッシュされる場合、作成時間が変更されていないと予想されます...ただし、私のテストでは、新しい作成時間が得られます...

構造マップ構成:

         ObjectFactory.Initialize(x=>x.ForRequestedType<MyClass>(). CacheBy(InstanceScope.HttpContext));

テストページのボタンクリックイベント

     protected void btnTest_Click(object sender, EventArgs e)
    {
        MyClass c = ObjectFactory.GetInstance<MyClass>();
        System.Threading.Thread.Sleep(1000);
        MyClass b = ObjectFactory.GetInstance<MyClass>();



        lblResult.Text = String.Format("cache by httpcontext First:{0}  Second:{1}  session id {2} ", c.GetTimeCreated(), b.GetTimeCreated(),Session.SessionID);
    }

私のクラス

public class MyClass
{
    private DateTime _timeCreated;
    public MyClass()
    {
        _timeCreated = DateTime.Now;
    }

    public string GetTimeCreated()
    {
        return _timeCreated.ToString("dd/MM/yyyy hh:mm:ss");
    }
}
于 2008-12-08T10:33:10.970 に答える
0

ObjectFactory.Inject メソッドの 1 つを使用して、HttpSessionStateBase を StructureMap に挿入することもできます。次に、注入された HttpSessionStateBase を使用してコンストラクターを呼び出します。

于 2008-12-08T10:38:06.267 に答える
0

カスタムスコープの作成を初めて試みました...それを使用して小さなWebアプリケーションを構築しましたが、私が見る限り、うまくいくようです。これにより、現在のユーザー セッション内のオブジェクトがキャッシュされ、同じセッション内にいる限り同じオブジェクトが返されます。

public class HttpSessionBuilder : CacheInterceptor
{
    private readonly string _prefix = Guid.NewGuid().ToString();

    protected override CacheInterceptor clone()
    {
        return this;
    }

    private string getKey(string instanceKey, Type pluginType)
    {
        return string.Format("{0}:{1}:{2}", pluginType.AssemblyQualifiedName, instanceKey, this._prefix);
    }

    public static bool HasContext()
    {
        return (HttpContext.Current.Session != null);
    }

    protected override bool isCached(string instanceKey, Type pluginType)
    {
        return HttpContext.Current.Session[this.getKey(instanceKey, pluginType)] != null;
    }

    protected override object retrieveFromCache(string instanceKey, Type pluginType)
    {
        return HttpContext.Current.Session[this.getKey(instanceKey, pluginType)];
    }

    protected override void storeInCache(string instanceKey, Type pluginType, object instance)
    {
        HttpContext.Current.Session.Add(this.getKey(instanceKey, pluginType), instance);
    }

}

global.asax Application_start で次のように ObjectFactory を構成する必要があります。

        ObjectFactory.Initialize(x=>
            x.ForRequestedType<MyClass>().InterceptConstructionWith(new HttpSessionBuilder()));
于 2008-12-08T18:49:22.233 に答える