代码之家  ›  专栏  ›  技术社区  ›  Ian Ringrose

如何将值传递给wcf服务上的构造函数?

  •  101
  • Ian Ringrose  · 技术社区  · 15 年前

    我想将值传递到实现我的服务的类的构造函数中。

    不过,servicehost只允许我传入要创建的类型的名称,而不允许传入要传递给其contstructor的参数。

    我希望能够传入创建我的服务对象的工厂。

    到目前为止我发现:

    8 回复  |  直到 8 年前
        1
  •  118
  •   piedar    9 年前

    您需要实现自定义 ServiceHostFactory , ServiceHost IInstanceProvider .

    给定具有此构造函数签名的服务:

    public MyService(IDependency dep)
    

    下面是一个可以启动myservice的示例:

    public class MyServiceHostFactory : ServiceHostFactory
    {
        private readonly IDependency dep;
    
        public MyServiceHostFactory()
        {
            this.dep = new MyClass();
        }
    
        protected override ServiceHost CreateServiceHost(Type serviceType,
            Uri[] baseAddresses)
        {
            return new MyServiceHost(this.dep, serviceType, baseAddresses);
        }
    }
    
    public class MyServiceHost : ServiceHost
    {
        public MyServiceHost(IDependency dep, Type serviceType, params Uri[] baseAddresses)
            : base(serviceType, baseAddresses)
        {
            if (dep == null)
            {
                throw new ArgumentNullException("dep");
            }
    
            foreach (var cd in this.ImplementedContracts.Values)
            {
                cd.Behaviors.Add(new MyInstanceProvider(dep));
            }
        }
    }
    
    public class MyInstanceProvider : IInstanceProvider, IContractBehavior
    {
        private readonly IDependency dep;
    
        public MyInstanceProvider(IDependency dep)
        {
            if (dep == null)
            {
                throw new ArgumentNullException("dep");
            }
    
            this.dep = dep;
        }
    
        #region IInstanceProvider Members
    
        public object GetInstance(InstanceContext instanceContext, Message message)
        {
            return this.GetInstance(instanceContext);
        }
    
        public object GetInstance(InstanceContext instanceContext)
        {
            return new MyService(this.dep);
        }
    
        public void ReleaseInstance(InstanceContext instanceContext, object instance)
        {
            var disposable = instance as IDisposable;
            if (disposable != null)
            {
                disposable.Dispose();
            }
        }
    
        #endregion
    
        #region IContractBehavior Members
    
        public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }
    
        public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
        }
    
        public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
        {
            dispatchRuntime.InstanceProvider = this;
        }
    
        public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
        {
        }
    
        #endregion
    }
    

    在myservice.svc文件中注册myservicehostfactory,或者在代码中直接使用myservicehost进行自托管。

    您可以很容易地推广这种方法,事实上一些di容器已经为您完成了这项工作(提示:windsor的wcf工具)。

        2
  •  12
  •   kerim    11 年前

    您可以简单地创建 Service 并将该实例传递给 ServiceHost 对象。你唯一要做的就是添加一个 [ServiceBehaviour] 属性,并用 [DataContract] 属性。

    这是一个模型:

    namespace Service
    {
        [ServiceContract]
        [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
        public class MyService
        {
            private readonly IDependency _dep;
    
            public MyService(IDependency dep)
            {
                _dep = dep;
            }
    
            public MyDataObject GetData()
            {
                return _dep.GetData();
            }
        }
    
        [DataContract]
        public class MyDataObject
        {
            public MyDataObject(string name)
            {
                Name = name;
            }
    
            public string Name { get; private set; }
        }
    
        public interface IDependency
        {
            MyDataObject GetData();
        }
    }
    

    以及用法:

    var dep = new Dependecy();
    var myService = new MyService(dep);
    var host = new ServiceHost(myService);
    
    host.Open();
    

    我希望这会让一个人的生活更轻松。

        3
  •  10
  •   Sam Holder Brian Adams    13 年前

    马克的回答是 IInstanceProvider 是正确的。

    您也可以使用自定义属性(例如 MyInstanceProviderBehaviorAttribute )从 Attribute ,使其实现 IServiceBehavior 并实施 IServiceBehavior.ApplyDispatchBehavior 类方法

    // YourInstanceProvider implements IInstanceProvider
    var instanceProvider = new YourInstanceProvider(<yourargs>);
    
    foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
    {
        foreach (var epDispatcher in dispatcher.Endpoints)
        {
            // this registers your custom IInstanceProvider
            epDispatcher.DispatchRuntime.InstanceProvider = instanceProvider;
        }
    }
    

    然后,将该属性应用于服务实现类

    [ServiceBehavior]
    [MyInstanceProviderBehavior(<params as you want>)]
    public class MyService : IMyContract
    

    第三个选项:您还可以使用配置文件应用服务行为。

        4
  •  5
  •   McGarnagle    12 年前

    我从马克的答案出发,但(至少就我的情况而言),这是不必要的复杂。其中之一 ServiceHost 构造函数接受服务的实例,您可以直接从 ServiceHostFactory 实施。

    以马克为例,应该是这样的:

    public class MyServiceHostFactory : ServiceHostFactory
    {
        private readonly IDependency _dep;
    
        public MyServiceHostFactory()
        {
            _dep = new MyClass();
        }
    
        protected override ServiceHost CreateServiceHost(Type serviceType,
            Uri[] baseAddresses)
        {
            var instance = new MyService(_dep);
            return new MyServiceHost(instance, serviceType, baseAddresses);
        }
    }
    
    public class MyServiceHost : ServiceHost
    {
        public MyServiceHost(MyService instance, Type serviceType, params Uri[] baseAddresses)
            : base(instance, baseAddresses)
        {
        }
    }
    
        5
  •  3
  •   Ronnie Overby    8 年前

    我把依赖注入和服务定位器模式混合在一起了(但大多数情况下它仍然是依赖注入,甚至发生在构造函数中,这意味着您可以拥有只读状态)。

    public class MyService : IMyService
    {
        private readonly Dependencies _dependencies;
    
        // set this before creating service host. this can use your IOC container or whatever.
        // if you don't like the mutability shown here (IoC containers are usually immutable after being configured)
        // you can use some sort of write-once object
        // or more advanced approach like authenticated access
        public static Func<Dependencies> GetDependencies { get; set; }     
        public class Dependencies
        {
            // whatever your service needs here.
            public Thing1 Thing1 {get;}
            public Thing2 Thing2 {get;}
    
            public Dependencies(Thing1 thing1, Thing2 thing2)
            {
                Thing1 = thing1;
                Thing2 = thing2;
            }
        }
    
        public MyService ()
        {
            _dependencies = GetDependencies(); // this will blow up at run time in the exact same way your IoC container will if it hasn't been properly configured up front. NO DIFFERENCE
        }
    }
    

    服务的依赖项在其嵌套的协定中明确指定 Dependencies 班级。如果您正在使用一个ioc容器(一个还没有为您修复wcf混乱的容器),您可以将其配置为创建 依赖关系 实例而不是服务。这样你就得到了温暖模糊的感觉,你的容器给你的同时,也不必跳过太多的箍施加wcf。

    我不会因为这种方法而失眠的。其他人也不应该。毕竟,您是ioc容器,它是一个大型的、胖的、静态的委托集合,可以为您创建一些东西。再加一个是什么?

        6
  •  0
  •   Eric Dieckman    11 年前

    这是一个非常有帮助的解决方案-特别是对谁是一个新手wcf编码。我确实想发布一些小提示给那些可能将其用于iis托管服务的用户。myServiceHost需要继承 Web服务主机 ,不仅仅是服务主机。

    public class MyServiceHost : WebServiceHost
    {
        public MyServiceHost(MyService instance, Type serviceType, params Uri[] baseAddresses)
            : base(instance, baseAddresses)
        {
        }
    }
    

    这将为IIS中的终结点创建所有必要的绑定等。

        7
  •  -1
  •   Ron Deijkers    11 年前

    我们面临着同样的问题,并以如下方式解决了它。这是一个简单的解决办法。

    在visual studio中,只需创建一个普通的wcf服务应用程序并删除它的接口。保留.cs文件(只需重命名它)并打开该cs文件,用实现服务逻辑的原始类名替换接口的名称(这样服务类使用继承并替换实际实现)。添加调用基类构造函数的默认构造函数,如下所示:

    public class Service1 : MyLogicNamespace.MyService
    {
        public Service1() : base(new MyDependency1(), new MyDependency2()) {}
    }
    

    myservice基类是服务的实际实现。此基类不应具有无参数构造函数,而应仅具有接受依赖项的参数的构造函数。

    服务应该使用这个类,而不是原始的myservice。

    这是一个简单的解决方案,工作起来很有魅力。

        8
  •  -2
  •   Boris    11 年前

    我使用我的类型的静态变量。不确定这是不是最好的方法,但对我来说很有效:

    public class MyServer
    {   
        public static string CustomerDisplayName;
        ...
    }
    

    当我实例化服务主机时,我会执行以下操作:

    protected override void OnStart(string[] args)
    {
        MyServer.CustomerDisplayName = "Test customer";
    
        ...
    
        selfHost = new ServiceHost(typeof(MyServer), baseAddress);
    
        ....
    }