2011-01-19 28 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