• 轻松实现WCF服务的构造函数依赖注入


    今天在开发博客园博客程序的WCF服务时,想在“WCF服务实现”中通过构造函数进行依赖注入。代码如下:

        public class BlogService : IBlogService
    {
    private IBlogSiteService _blogSiteService;

    public BlogService(IBlogSiteService blogSiteService)
    {
    _blogSiteService = blogSiteService;
    }
    }

    依赖注入容器用的是Unity,IBlogSiteService的实现已经在WCF Host运行时通过Bootstrapper进行注入,参见寂寞如此美丽:脱离Application_Start,让初始化代码更优美

    可是在客户端调用这个WCF服务时,却出现异常:

    The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor.
    To fix the problem, add a default constructor to the type, or pass an instance of the type to the host.

    出现这个异常属正常现象,我没有告诉WCF Host,它怎么知道我要进行依赖注入,我们之间又没有心灵感应。WCF按常规办事,通过默认构造函数创建WCF服务的实例,所以引发异常。

    那如何解决这个问题呢?

    小软(微软)早就考虑到这一点了,提供了IInstanceProvider与IServiceBehavior接口。我们只需要实现这两个接口,并让实现IServiceBehavior的类成为一个Attribute(继承自Attribute),然后加在WCF服务实现类上,就可以实现WCF的构造函数依赖注入。

    具体实现步骤如下:

    一、实现IInstanceProvider接口 - IocInstanceProvider

    1. 新建一个类IocInstanceProvider,实现IInstanceProvider接口。

    2. 实现IInstanceProvider接口的三个方法,并引入你自己的IoC容器(比如我们用的是CNBlogs.Infrastructure.CrossCutting.IoC),也就是让WCF通过你的IoC容器获取WCF服务的实例。示例代码如下:

    public class IocInstanceProvider : IInstanceProvider
    {
    Type _serviceType;
    IContainer _container;

    public IocInstanceProvider(Type serviceType)
    {
    _serviceType = serviceType;
    _container = CNBlogs.Infrastructure.CrossCutting.IoC.
    IoCFactory.Instance.CurrentContainter;
    }

    #region IInstanceProvider Members

    public object GetInstance(InstanceContext instanceContext, Message message)
    {
    return _container.Resolve(_serviceType);
    }

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

    public void ReleaseInstance(InstanceContext instanceContext, object instance)
    {
    if (instance is IDisposable)
    ((IDisposable)instance).Dispose();
    }

    #endregion
    }

    注:你的IoC容器要事先注入了相应的WCF服务的实例。比如我们的注入:

    container.RegisterType<IBlogService, BlogService>();

    其中IBlogService是WCF服务接口,BlogService是WCF服务实现。

    二、实现IServiceBehavior接口 - IocServiceBehavior

    1. 新建一个类IocServiceBehavior,继承自Attribute,实现IServiceBehavior

    public class IocServiceBehavior : Attribute, IServiceBehavior

    2. 实现IServiceBehavior的AddBindingParameters()方法,并引入之前创建的IocInstanceProvider

    public class IocServiceBehavior : Attribute, IServiceBehavior
    {
    #region IServiceBehavior Members

    public void AddBindingParameters(ServiceDescription serviceDescription,
    ServiceHostBase serviceHostBase,
    Collection<ServiceEndpoint> endpoints,
    BindingParameterCollection bindingParameters)
    {
    foreach (var item in serviceHostBase.ChannelDispatchers)
    {
    var dispatcher = item as ChannelDispatcher;
    if (dispatcher != null)
    {
    dispatcher.Endpoints.ToList().ForEach(endpoint =>
    {
    endpoint.DispatchRuntime.InstanceProvider = new
    IocInstanceProvider(serviceDescription.ServiceType);
    });
    }
    }
    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription,
    ServiceHostBase serviceHostBase)
    {
    }

    public void Validate(ServiceDescription serviceDescription,
    ServiceHostBase serviceHostBase)
    {
    }

    #endregion
    }

    三、在WCF服务实现类上增加[IocServiceBehavior]属性

    代码如下:

    [IocServiceBehavior]
    public class BlogService : IBlogService
    {
    private IBlogSiteService _blogSiteService;

    public BlogService(IBlogSiteService blogSiteService)
    {
    _blogSiteService = blogSiteService;
    }

    #region IBlogService Members

    public BlogSiteDto GetBlogSiteWithPosts(int blogId,
    bool withPostBody, int itemcount)
    {
    return _blogSiteService.GetWithPosts(blogId,
    withPostBody, itemcount);
    }

    #endregion
    }

    搞定!是不是很轻松!

    上面的实现代码参考自Domain Oriented N-Layered .NET 4.0 Sample App(http://microsoftnlayerapp.codeplex.com/),如果你对DDD感兴趣,推荐阅读这个项目的代码。

    代码改进

    根据Artech的建议,并参考WCF Extensibility – IInstanceProvider,改进一下IocServiceBehavior的代码,实现ApplyDispatchBehavior接口,代码如下:

    public class IocServiceBehavior : Attribute, IServiceBehavior
    {
    #region IServiceBehavior Members

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

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription,
    ServiceHostBase serviceHostBase)
    {
    foreach (ChannelDispatcher cd in serviceHostBase.ChannelDispatchers)
    {
    foreach (EndpointDispatcher ed in cd.Endpoints)
    {
    if (!ed.IsSystemEndpoint)
    {
    ed.DispatchRuntime.InstanceProvider =
    new IocInstanceProvider(serviceDescription.ServiceType);
    }
    }
    }
    }

    public void Validate(ServiceDescription serviceDescription,
    ServiceHostBase serviceHostBase)
    {
    }

    #endregion
    }

    小结

    你IoC了吗?如果没有,你真的Out了。不仅ASP.NET可以轻松IoC(想爱容易,相处难:当ASP.NET MVC爱上IoC),而且单元测试也可以IoC(梦想成现实:用xUnit.net在单元测试中实现构造函数依赖注入)。

  • 相关阅读:
    数论知识点--以及模板
    【数学+思维】ZZULIOJ 1531: 小L的区间求和
    记忆化搜索模板题---leetcode 1155. 掷骰子的N种方法
    拓扑排序
    ZOJ
    multiset的应用
    HDU
    HDU
    D. Beautiful Array
    HDU
  • 原文地址:https://www.cnblogs.com/dudu/p/wcf_constructor_dependency_injection.html
Copyright © 2020-2023  润新知