2012-03-08 71 views
0

因此,這將是一個有趣的帖子,因爲我必須包括我所有的代碼並試圖解釋清楚,我怎麼也設置我的架構。通用服務工廠<T>爲WCF通道工廠和StructureMap與MVC 3

我已將所有服務和DataContracts放置在中央程序集(DMT.WCF.Contracts)中。這樣做是爲了讓我的應用程序的分佈式部分都可以引用相同類型的服務接口和合同,這非常好。

我已經建立了StructureMap容器​​注入以下列方式我的依賴,通過指定ServiceContext,將家中所有的服務接口的屬性,使他們能夠詮釋他的申請後引用。

public interface IServiceContext 
{ 

} 

public class ServiceContext: IServiceContext 
{ 
    public IAuthenticationService AuthenticationService { get; set; } 
    public ServiceContext(IAuthenticationService authenticationService) 
    { 
     AuthenticationService = authenticationService; 
    } 
} 

然後,我有我的StructureMapControllerFactory看起來像下面這樣:

public class StructureMapControllerFactory:DefaultControllerFactory 
{ 
    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) 
    { 
     if (controllerType == null) return null; 
     return ObjectFactory.GetInstance(controllerType) as IController; 
    } 
} 

,這在我的Global.asax配置如下所示:

protected void Application_Start() 
    { 
     ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory()); 
     AreaRegistration.RegisterAllAreas(); 
     RegisterGlobalFilters(GlobalFilters.Filters); 
     RegisterRoutes(RouteTable.Routes); 

     Configure(); 

    } 

我想脫鉤我的服務從我的應用程序儘可能多,所以我已經實現了以下ServiceFactory類,用於在配置IoC容器時處理向StructureMap提供代理服務:

public static class ServiceFactory 
{ 
    private static readonly ClientSection _clientSection = ConfigurationManager.GetSection("system.serviceModel/client") as ClientSection; 

    public static T Create<T>() 
    { 
     T context = default(T); 
     foreach(ChannelEndpointElement endpoint in _clientSection.Endpoints) 
     { 
      if(endpoint.Contract == typeof(T).FullName) 
      { 
       IEnumerable<Type> assignables = typeof (Binding).Assembly.GetTypes().Where(p => typeof(Binding).IsAssignableFrom(p)); 
       Type bindingType = assignables.Single(p => p.Name.ToLower().Equals(endpoint.Binding.ToLower())); 
       context = ChannelFactory<T>.CreateChannel((Binding)Activator.CreateInstance(bindingType, false), new EndpointAddress(endpoint.Address)); 
      } 
     } 
     return context; 
    } 

} 

這讓我創建代理時,從配置文件直接拉,所以我並不需要選擇「添加服務引用」(因爲這在技術上是添加依賴)。

在我的Global.asax,我現在可以配置我的StructureMap集裝箱這樣的:

protected void Configure() 
    { 
     ObjectFactory.Configure(x => 
     { 
      x.Scan(scanner => scanner.AddAllTypesOf<IController>()); 
      x.For<IAuthenticationService>().Use(ServiceFactory.Create<IAuthenticationService>()); 
      x.For<IServiceContext>().Use<ServiceContext>(); 

     }); 
    } 

雖然我最初能夠通過以下方式來使用:

IAuthenticationService service = ServiceContext.AuthenticationService.Authenticat(...); 

我現在無法啓動我的應用程序沒有例外拋出如下:

StructureMap configuration failures: 
Error: 104 
Source: Registry: StructureMap.Configuration.DSL.Registry, StructureMap, Version=2.6.1.0, Culture=neutral, PublicKeyToken=e60ad81abae3c223 
Type Instance '685e2e2a-f271-4163-a6fa-ba074e4082d1' (Object: DMT.WCF.Contracts.Authentication.IAuthenticationService) cannot be plugged into type DMT.WCF.Contracts.Authentication.IAuthenticationService, DMT.WCF.Contracts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null 

我不知道這是爲什麼發生。就像我說的那樣,我最初能夠把它啓動並運行,但我不確定發生了什麼變化。

我已經看過數以百計關於此錯誤消息引用的,但他們都是特定於不似乎符合我的,除非我可以俯瞰我的問題的問題。

幫助!!!

+0

無法幫助您使用StructureMap配置,但您在實例化WCF服務代理時遇到了一些迫在眉睫的問題。您正在爲服務代理創建單例。如果從代理到服務的呼叫失敗,則代理狀態將變爲Faulted,並且隨後的呼叫將始終引發異常。您必須實例化一個新的代理並在進一步的調用中處理出錯的代理。另外,如果使用像netTcpBinding這樣的會話綁定,您可能會遇到多線程場景(如Web站點)中的資源問題。 (續) – 2012-03-08 19:46:24

+0

(續)更好的方法是實例化和處理每個Web請求。它可以創建ChannelFactory的單例,這將節省一些開銷。然後在每個請求中,使用ChannelFactory創建一個新的Channel(服務代理)。在服務調用發生故障時,您仍然需要處理並在請求結束時處理代理實例。 – 2012-03-08 19:46:37

回答

0

此操作不使用ChannelFactory來創建一個通道安全客戶端嗎?

context = ChannelFactory<T>.CreateChannel(
    (Binding)Activator.CreateInstance(bindingType, false), 
    new EndpointAddress(endpoint.Address)); 
0

好吧,這裏有兩個問題。正如Sixto Saez提到的那樣,WCF需要考慮的問題。在StructureMap前面,我的猜測是你的工廠方法可能會返回一個接口的默認實例。

兩個建議...

  1. 您的容器配置後立刻加入到ObjectFactory.AssertConfigurationIsValid()的調用...確保你弄清楚後有什麼不對:-)它應該拋出一個非常類似的錯誤再次刪除它,但它實際上會嘗試解決每個配置類型的每個實例。通常情況下,你會得到一個錯誤的錯誤。然後您可以開始查找配置錯誤的位置。

  2. 它可能與您的可插拔類型的工廠方法有關。您可以嘗試讓這些實例即時創建。使用IContext語法來做到這一點 - context => // Make Foo Here。

protected void Configure() 
{ 
    ObjectFactory.Configure(x => 
    { 
     x.Scan(scanner => scanner.AddAllTypesOf<IController>()); 

     // Skip using this 
     // x.For<IAuthenticationService>() 
     // .Use(ServiceFactory.Create<IAuthenticationService>()); 

     // Use the IContext syntax instead. Normally you'd grab the instance out of the 
     // container, but you can use this to resolve an instance "live" from 
     // somewhere other than the container 
     x.For<IAuthenticationService>() 
      .Use(context => ServiceFactory.Create<IAuthenticationService>()); 

     x.For<IServiceContext>().Use<ServiceContext>(); 
    }); 

    // Remove this from production code because it resolves the entire container... 
    ObjectFactory.AssertConfigurationIsValid(); 
} 

我猜,使用IContext語法可能有助於修復配置錯誤。如果沒有,你可以使用Assert去。我認爲其他評論涵蓋了WCF的問題,但在StructureMap配置錯誤的時候評估這些問題是很難的。