代码改变世界

WCF 依赖注入-- Attribute

2013-06-27 17:39  yangtam  阅读(932)  评论(0)    收藏  举报

    最近,工作之余学习WCF(Windows Communication Fundation)时,感觉自己还有好多的东西需要学习呀⊙﹏⊙b汗,于是想记录下自己学习WCF的心得,以鼓励自己再接再厉,同时希望可以为其他想学习WCF的园友们抛砖引玉,虽然有很多大侠们已经写了很多类似的文章了。

   结合现实开发项目的情形,想在WCF服务中实现构造函数的依赖注入,就像在MVC中有一个名为DefaultControllerFactory的入口一样,那么在WCF中是否也有类似的类呢?下面是在MSDN中提到了三种方法:

  • 以编程方式,先将自定义服务行为添加到 Behaviors 属性,然后对 System.ServiceModel.ServiceHost 对象调用 ICommunicationObject.Open 方法。
  • 创建一个可实现 IServiceBehavior 的自定义属性,并利用它来标记要修改的服务类。 构造 ServiceHost 对象时, 会使用反射来发现服务类型的属性。 如果有属性实现 IServiceBehavior,则它们将会被添加到 ServiceDescription 上的行为集合中。
  • 扩展 System.ServiceModel.Configuration.BehaviorExtensionElement 类,以支持应用程序配置文件或计算机配置文件中的行为规范。 

    本文主要是使用第二种方法(Attribute)实现依赖注入。

    在上列子之前,需要我们了解两个接口:IInstanceProvider 和 IServiceBehavior。

  IInstanceProvider接口  声明一些方法,以便为服务提供服务对象,或回收该服务的服务对象。(MSDN)

    IServiceBehavior接口 提供一种在整个服务内修改或插入自定义扩展的机制,包括 ServiceHostBase。(MSDN)

    本例中使用的是NInject注入工具,需要了解NInject的园友可以登录官网:http://www.ninject.org/。闲话少说了,进入正题……

  • 新建一个类NInjectContainer, 主要是作为IoC容器,以便于后面依赖的注入。
    public class NInjectContainer : NinjectModule
        {
            public override void Load()
            {
                Bind<IUserRepository>().To<UserRepository>();
                Bind<UserService>().ToSelf().InSingletonScope();
            }
    
            private IKernel _kernel;
    
            public IKernel StandardKernel
            {
                get
                {
                    if(_kernel == null)
                    {
                        _kernel = new StandardKernel(this);
                    }
                    return _kernel;
                }
            }
        }
    

      NinjectModule是Ninject提供的,想了解的可以去官网看看。

  • 新建一个类NInjectInstanceProvider,该类继承 IInstanceProvider,该类主要是为服务提供服务对象,或回收该服务的服务对象
    public class NInjectInstanceProvider : IInstanceProvider
        {
            public NInjectContainer Container { get; private set; }
            public Type ServiceType { get; set; }
    
            public NInjectInstanceProvider(Type type)
            {
                ServiceType = type;
                Container = new NInjectContainer();
            }
    
            public object GetInstance(InstanceContext instanceContext)
            {
                return GetInstance(instanceContext, null);
            }
    
            public object GetInstance(InstanceContext instanceContext, Message message)
            {
                return Container.StandardKernel.Get(ServiceType);
            }
    
            public void ReleaseInstance(InstanceContext instanceContext, object instance)
            {
                Debug.WriteLine("ReleaseInstance");
            }
        }

     

  • 新建一个类NInjectServiceBehaviorAttribute,该类继承Attribute类,同时实现IServiceBehavior接口,该类主要提供一种在整个服务内修改或插入自定义扩展的机制
     public class NInjectServiceBehaviorAttribute : Attribute, 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 (var item in serviceHostBase.ChannelDispatchers)
                {
                    var dispatcher = item as ChannelDispatcher;
                    if (dispatcher != null)
                    {
                        dispatcher.Endpoints.ToList().ForEach(ep =>
                        {
                            ep.DispatchRuntime.InstanceProvider =
                                new NInjectInstanceProvider(
                                    serviceDescription.ServiceType);
                        });
                    }
                }
            }
        }
    
  • 新建一个服务IUserService及UserService,同时将NInjectServiceBehaviorAttribute应用在需要注入的服务上面
[ServiceContract(Namespace = "http://www.iyasoft.cn.Samples")]
    public interface IUserService
    {
        [OperationContract]
        string Add(User user);

        [OperationContract]
        string Update(User user);

        [OperationContract]
        string Delete(string name);

        [OperationContract]
        string GetUsers();

    }

    [NInjectServiceBehavior]
    public class UserService : IUserService
    {
        private readonly IUserRepository _repository;

        public UserService(IUserRepository repository)
        {
            _repository = repository;
        }

        public string Add(User user)
        {
            return _repository.Add(user);
        }

        public string Update(User user)
        {
            return _repository.Update(user);
        }

        public string Delete(string name)
        {
            return _repository.Delete(name);
        }

        public string GetUsers()
        {
            return _repository.GetUsers();
        }
    }

  主函数的调用如下:

class Program
    {
        static void Main(string[] args)
        {
            try
            {
                ServiceHostBase host = new ServiceHost(typeof(UserService));
                host.Opened += (sender, e) => Console.WriteLine("server is opened");
                host.Open();

                var channelFactory = new ChannelFactory<IUserService>("client");
                IUserService userService1 = channelFactory.CreateChannel();
                Console.WriteLine(userService1.Add(new User()));
                Console.WriteLine(userService1.Delete("user"));
                Console.WriteLine(userService1.Update(new User()));
                Console.WriteLine(userService1.GetUsers());
                channelFactory.Close();

                Console.WriteLine();
                Console.WriteLine("Press <ENTER> to terminate client.");
                Console.ReadLine();

                Console.WriteLine("\n+++ press any key to close a ServiceHost +++\n");
                Console.ReadLine();

                host.Close();


            }
            catch { }
        }

  

这样就完成了WCF中服务的依赖注入......,下面我们看看运行结果:

我也是新学习WCF的菜鸟,不对的地方请各位大侠指出,谢谢!

附上源码:WcfServiceDependencyInject.rar