尝试向我的WCF服务添加IoC支持

Pet*_*ter 5 c# wcf ioc-container

我正在尝试向我的REST WCF服务(Windows Server 2008)添加IoC支持.我是新手,并且遵循以下视频中提供的说明:

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

该视频介绍了许多类,这些类可以帮助我在暴露WCF端点的同时启动和运行StructureMap的IoC.我在本文末尾发布了所有代码.

当我运行我的代码时,自定义类StructureMapServiceHost会抛出一个错误@ StructureMapServiceHost(类型serviceType,params Uri [] 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

我被告知:

提供的服务类型无法作为服务加载,因为它没有默认(无参数)构造函数.要解决此问题,请为该类型添加默认构造函数,或将该类型的实例传递给主机.

这是事实,但事实并非如此.但视频示例也没有.以下是我的服务:

[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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?谢谢.

编辑********************************

从StructureMapServiceHost我删除:

public StructureMapServiceHost(Type serviceType, params Uri[] baseAddress)
            : base(serviceType, baseAddress) { }
Run Code Online (Sandbox Code Playgroud)

并补充说:

public StructureMapServiceHost(Object singletonInstance, params Uri[] baseAddress)
            : base( singletonInstance, baseAddress) { }
Run Code Online (Sandbox Code Playgroud)

然后从我的UserService构造函数中删除参数.我没有收到错误:

HTML文档不包含Web服务发现信息.

Nea*_*eal 17

您的服务使用InstanceContextMode.SingleCall,WCF团队以其无限的智慧决定,当InstanceContextMode为SingleCall时,不会调用IInstanceProvider来创建实例(请参阅http://blogs.msdn.com/b/carlosfigueira/archive /2011/05/31/wcf-extensibility-iinstanceprovider.aspx - 接口declration标题下面的第二个参数).

当然,我有一种不太理想的方式在服务主机工厂中解决这个问题:

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是一项正在进行的工作,可能有更好的方法,但目前我找不到一个.


Fyo*_*kin 0

我现在无法观看视频(互联网限制),但我很确定他们示例中的类根本没有任何构造函数。在这种情况下,编译器会代表您生成一个空的无参数构造函数。因此,他们的类毕竟有一个默认的构造函数

就例外而言,这似乎非常简单:您的无参数构造函数不会初始化该Specification属性,因此它总是如此-一旦您尝试在方法中访问它null,这自然会导致 a 。NullReferenceException

看来您在这里的目的是UserService自己创建对象并将 a 传递IUserRepository给它,不是吗?(或者,也许,使用你的 IoC 框架?)

在这种情况下,您最好使用 的ServiceHost构造函数的重载,该构造函数采用 anobject而不是Type。这样,您将完全控制您的UserService对象,并且根本不需要默认构造函数。