2008-11-02 2 views
1

asp.net mvc 및 Structuremap ioc/di를 사용하여 작은 웹 쇼핑몰을 만들고 있습니다. My Basket 클래스는 지속성을 위해 세션 객체를 사용하며 SM을 사용하여 IBasket 인터페이스를 통해 내 바구니 객체를 생성합니다. 내 바구니 구현은 컨트롤러/액션 내부에서 사용할 수있는 생성자에서 HttpSessionStateBase (mvc의 세션 상태 래퍼)가 필요합니다. SM에 대한 IBasket 구현을 어떻게 등록합니까?StructureMap IOC/DI 및 객체 생성

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

그리고 SM 등록 :
이 내 바구니 인터페이스입니다

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

하지만 내 StoreBasketService 구현은 생성자가 : SM에

public StoreBasketService(HttpSessionStateBase sessionState) 

가 어떻게 제공 할 HttpSessionStateBase 객체를하는 컨트롤러에서만 사용할 수 있습니까?
이 SM IOC/DI의 첫 사용하고, 공식 문서 및 웹 사이트의 솔루션/예를 찾을 두지, 당신은 절대적 StoreBasketService 세션을 사용하게해야하는 경우)

답변

4

, 나는 유혹 할 것 HttpSessionStateBase를 사용하는 대신 HttpSessionState 주위에 인터페이스와 래퍼를 정의하여 StructureMap에도 등록 할 수 있도록합니다. 래퍼는 현재 컨텍스트에서 세션 상태를 가져옵니다. 래퍼를 StructureMap에 등록한 다음 StoreBasketService가 인터페이스를 생성자에 대한 인수로 사용하도록합니다. 구조체 맵은 인터페이스 래퍼의 인스턴스를 생성하여 StoreBasketService 클래스에 삽입하는 방법을 알아야합니다.

인터페이스와 래퍼를 사용하면 HttpSessionStateBase가 실제 세션을 조롱 할 수있는 것과 같은 방식으로 단위 테스트에서 mur를 조롱 할 수 있습니다.


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

    // basket implementation ... 
} 

public interface IHttpSessionStateWrapper 
{ 
    HttpSessionState GetSessionState(); 
} 

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

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

그러나, 당신은 StructureMap이 실제로 등록 할 때 .CacheBy(InstanceScope.HttpContext)를 사용하여 세션에 바구니를 저장할 수 있습니다. 실제로 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

+0

오늘은 고맙습니다. 그러나 SM과 함께 Basket 클래스를 캐싱하기 위해 IS.Httpcontext는 한 페이지 요청에서 사용할 수있는 httpcontext.items 사전에 객체를 저장하지만 전체 사용자 세션을 통해 필요합니다. –

0

난 그냥 StructureMap 시작, 그리고 당신이 묘사하는 결과를 얻을하지 않습니다

도 참조하십시오. 간단한 클래스를 사용하여 간단한 테스트를 수행했습니다. HttpContext를 cacheby로 구조 맵을 구성했습니다. CacheBy.HttpContext는 동일한 요청을 통해 동일한 인스턴스 내에서 동일한 인스턴스를 가져옵니다 ...

내 클래스의 생성자는 개인 필드에 날짜/시간을 설정합니다. 1 초 간격으로 MyClass의 인스턴스 2 개를 가져 오는 버튼이 있습니다 ... 그러면 두 인스턴스의 시간이 라벨에 표시됩니다.

처음으로이 버튼을 누르면 객체 A와 B는 생성 시간이 예상 한 것과 동일하므로 동일한 인스턴스입니다. 버튼을 한 번 클릭

, 당신은 ... 인스턴스가 세션에 캐시 될 경우 작성 시간 내 테스트에서 나는 새로운 창조의 시간을 얻을하지만 ... 변경되지 기대

Structuremap 구성 : 테스트 페이지

 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); 
    } 
을의

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

버튼을 클릭 이벤트

MyClass에

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

    public string GetTimeCreated() 
    { 
     return _timeCreated.ToString("dd/MM/yyyy hh:mm:ss"); 
    } 
} 
0

또한 StructureMap에 HttpSessionStateBase를 주입하기 위해 ObjectFactory.Inject 방법 중 하나를 사용할 수 있습니다. 그런 다음 삽입 된 HttpSessionStateBase를 사용하여 생성자를 호출합니다.

0

방금 ​​사용자 지정 범위를 만드는 데 첫 번째 시도를했습니다 ... 그걸로 작은 웹 응용 프로그램을 만들고, 볼 수있는 한 제대로 작동하는 것 같습니다. 이것은 현재 사용자 세션 내부의 객체를 캐시합니다하고 당신이 동일한 세션 내부에 남아있는 같은 객체를 반환합니다

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())); 
1
ForRequestedType<IBasketService>() 
    .TheDefault.Is.OfConcreteType<StoreBasketService>() 
    .WithCtorArg("sessionState").EqualTo(HttpContext.Current.Session); 

?? 그게 효과가 있니?