因此,這將是一個有趣的帖子,因爲我必須包括我所有的代碼並試圖解釋清楚,我怎麼也設置我的架構。通用服務工廠<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
我不知道這是爲什麼發生。就像我說的那樣,我最初能夠把它啓動並運行,但我不確定發生了什麼變化。
我已經看過數以百計關於此錯誤消息引用的,但他們都是特定於不似乎符合我的,除非我可以俯瞰我的問題的問題。
幫助!!!
無法幫助您使用StructureMap配置,但您在實例化WCF服務代理時遇到了一些迫在眉睫的問題。您正在爲服務代理創建單例。如果從代理到服務的呼叫失敗,則代理狀態將變爲Faulted,並且隨後的呼叫將始終引發異常。您必須實例化一個新的代理並在進一步的調用中處理出錯的代理。另外,如果使用像netTcpBinding這樣的會話綁定,您可能會遇到多線程場景(如Web站點)中的資源問題。 (續) – 2012-03-08 19:46:24
(續)更好的方法是實例化和處理每個Web請求。它可以創建ChannelFactory的單例,這將節省一些開銷。然後在每個請求中,使用ChannelFactory創建一個新的Channel(服務代理)。在服務調用發生故障時,您仍然需要處理並在請求結束時處理代理實例。 – 2012-03-08 19:46:37