2011-01-19 30 views
5

我試圖將IoC支持添加到我的REST WCF服務(Windows Server 2008)。我是新來這和我跟隨在下面的視頻中提供的說明:試圖將IoC支持添加到我的WCF服務

http://www.dimecasts.net/Content/WatchEpisode/150

視頻走過了許多有助於我StructureMap的IoC起來,而露出WCF端點上運行的類。我在本帖末尾發佈了所有代碼。

當我運行我的代碼,自定義類StructureMapServiceHost拋出一個錯誤@的StructureMapServiceHost(類型的serviceType,則params烏里[] baseAddress)方法:

public class StructureMapServiceHost : ServiceHost 
{ 
    public StructureMapServiceHost() {} 

    public StructureMapServiceHost(Type serviceType, params Uri[] baseAddress) 
     : base(serviceType, baseAddress) 
    { 

    } 

    protected override void OnOpening() 
    { 
     Description.Behaviors.Add(new IoCServiceBehavior()); 
     base.OnOpening(); 
    } 
} 

我被告知:

提供的服務類型無法作爲服務加載,因爲它沒有缺省(無參數)構造函數。要解決該問題,請向該類型添加默認構造函數,或將該類型的實例傳遞給主機。

這是事實,它沒有。但是這個視頻的例子也沒有。以下是我的服務:

[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)] 
    public class UserService : IUserService 
    { 
     public UserService(IUserRepository specification) 
     { 
      Specification = specification; 
     } 

     public List<User> GetAllUsers() 
     { 
      return Specification.GetAllUsers(); 
     } 

     public User GetUser(string userId) 
     { 
      return Specification.GetUserById(new Guid(userId)); 
     } 

     private List<User> SearchForUsers(string searchString) 
     { 
      return Specification.SearchUsers(searchString); 
     } 

     public IUserRepository Specification { get; set; } 

    } 



public class IoCServiceBehavior : IServiceBehavior 
    { 
     public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) 
     { 
     } 

     public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, 
      Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) 
     { 
     } 

     public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) 
     { 
      foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers) 
      { 
       new StructureMapInstanceProvider(serviceDescription.ServiceType); 
      } 
     } 
    } 


public class StructureMapInstanceProvider : IInstanceProvider 
{ 
    private readonly Type _serviceType; 

    public StructureMapInstanceProvider(Type serviceType) 
    { 
     _serviceType = serviceType; 
    } 

    public object GetInstance(InstanceContext instanceContext) 
    { 
     return GetInstance(instanceContext, null); 
    } 

    public object GetInstance(InstanceContext instanceContext, Message message) 
    { 
     var instance = ObjectFactory.GetInstance(_serviceType); 

     return instance; 
    } 

    public void ReleaseInstance(InstanceContext instanceContext, object instance) 
    { 
     throw new NotImplementedException(); 
    } 
} 




public class StructureMapServiceHostFactory : ServiceHostFactory 
    { 
     public StructureMapServiceHostFactory() 
     { 
      IoCBootstrap.SetupIoc(); 
     } 

     protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses) 
     { 
      return new StructureMapServiceHost(serviceType, baseAddresses); 
     } 
    } 

任何想法?謝謝。

編輯* ** * ** * ** * ** * ** * ** * ** * ** * * * * ****

從StructureMapServiceHost我刪除了:

public StructureMapServiceHost(Type serviceType, params Uri[] baseAddress) 
      : base(serviceType, baseAddress) { } 

並補充說:

public StructureMapServiceHost(Object singletonInstance, params Uri[] baseAddress) 
      : base(singletonInstance, baseAddress) { } 

,然後取出從我UserService構造函數中的參數。我沒有得到錯誤:

The HTML document does not contain Web service discovery information.

回答

0

我不能看看視頻,現在(互聯網限制),但我敢肯定,在他們爲榜樣類沒有任何構造在全部爲。在這種情況下,編譯器將以您的名義生成一個空的無參數構造函數。因此,他們的類did畢竟有一個默認的構造函數。

至於例外,這似乎很簡單:你的參數的構造函數不初始化Specification屬性,所以它總是null - 這,自然導致NullReferenceException一旦你嘗試訪問它在你的方法。

看來你打算在這裏創建UserService對象,並將IUserRepository傳遞給它,不是嗎?(或者,也許,使用你的IoC框架?)

在這種情況下,你最好使用ServiceHost的構造函數,它接受一個object而不是Type過載。這樣,你將完全控制你的對象,你根本不需要默認的構造函數。

+0

由於陀。我嘗試了你的建議並得到一個新的錯誤。請參閱上面的我的編輯。你能告訴我我做錯了什麼嗎?代碼插圖可能有助於在這一點...非常感謝。 – 2011-01-19 18:45:47

+0

@Code Sherpa:嘗試使用瀏覽器訪問該服務,並查看它給您帶來的錯誤。 – 2011-01-19 19:56:59

17

您的服務使用InstanceContextMode.SingleCall,WCF團隊以其無限智慧決定,當InstanceContextMode爲SingleCall時,不會調用IInstanceProvider來創建實例(請參閱http://blogs.msdn.com/b/carlosfigueira/archive/2011/05/31/wcf-extensibility-iinstanceprovider.aspx - Interface declration標題下的第二段)。

Currrently我比在服務主機工廠得到周圍的理想方式少:

using System; 
using System.Collections.Generic; 
using System.ServiceModel; 
using System.ServiceModel.Activation; 
using StructureMap; 
using StructureMap.Pipeline; 
using System.Linq; 

using ServiceHostCreator = System.Func<System.Type, System.Uri[], System.ServiceModel.ServiceHost>; 

namespace x.ServiceExtensions 
{ 
    public class xWebServiceHostFactory : ServiceHostFactory 
    { 
     private readonly IDictionary<InstanceContextMode, ServiceHostCreator> _serviceHostCreators; 

     public xWebServiceHostFactory() 
     { 
      ObjectFactory.Initialize(init => 
             init.Scan(scan => 
                { 
                 scan.AssembliesFromApplicationBaseDirectory(); 
                 scan.IgnoreStructureMapAttributes(); 
                 scan.LookForRegistries(); 
                })); 
      _serviceHostCreators = new Dictionary<InstanceContextMode, ServiceHostCreator> 
             { 
              { InstanceContextMode.PerCall, (t, a) => PerCallServiceHostCreator(t, a) }, 
              { InstanceContextMode.PerSession, (t, a) => PerSessionServiceHostCreator(t, a) }, 
              { InstanceContextMode.Single, (t, a) => SingleInstanceServiceHostCreator(t, a) } 
             }; 
     } 

     protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses) 
     { 
      var serviceInstanceContextMode = GetServiceInstanceContextMode(serviceType); 
      var serviceHostCreator = _serviceHostCreators[ serviceInstanceContextMode ]; 
      return serviceHostCreator(serviceType, baseAddresses); 
     } 

     private static InstanceContextMode GetServiceInstanceContextMode(Type serviceType) 
     { 
      var serviceBehaviour = serviceType 
       .GetCustomAttributes(typeof (ServiceBehaviorAttribute), true) 
       .Cast<ServiceBehaviorAttribute>() 
       .SingleOrDefault(); 
      return serviceBehaviour.InstanceContextMode; 
     } 

     private static ServiceHost PerCallServiceHostCreator(Type serviceType, Uri[] baseAddresses) 
     { 
      var args = new ExplicitArguments(); 
      args.Set(serviceType); 
      args.Set(baseAddresses); 
      var serviceHost = ObjectFactory.GetInstance<TelaWebServiceHost>(args); 
      return serviceHost; 
     } 

     private static ServiceHost PerSessionServiceHostCreator(Type serviceType, Uri[] baseAddresses) 
     { 
      return PerCallServiceHostCreator(serviceType, baseAddresses); 
     } 

     private static ServiceHost SingleInstanceServiceHostCreator(Type serviceType, Uri[] baseAddresses) 
     { 
      var service = ObjectFactory.GetInstance(serviceType); 
      var args = new ExplicitArguments(); 
      args.Set(typeof(object), service); 
      args.Set(baseAddresses); 
      var serviceHost = ObjectFactory.GetInstance<TelaWebServiceHost>(args); 
      return serviceHost; 
     } 
    } 
} 

這是一項正在進行的工作,並有可能是一個更好的辦法,但在現階段,我可以」找到一個。

0

對於那些試圖做這樣的事情的人,我目前強烈建議使用Spring.NET作爲IoC容器。雖然它可能不像其他一些容器那麼容易(我不是特別喜歡它的XML配置),但它是迄今爲止最好的WCF集成。它還爲InstanceContextMode.SingleCall問題(使用其AOP /動態代理框架)提供了一個聰明而透明的解決方法。

http://www.springframework.net/docs/1.2.0-M1/reference/html/wcf.html

http://www.springframework.net/doc-latest/reference/html/wcf-quickstart.html