首页 文章

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

提问于
浏览
100

我想将值传递给实现我的服务的类的构造函数 .

但是,ServiceHost只允许我传递要创建的类型的名称,而不是传递给其构造函数的参数 .

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

到目前为止我发现了什么:

8 回答

  • 3

    这是一个非常有用的解决方案 - 特别是对于新手WCF编码器的人 . 我确实想为任何可能将其用于IIS托管服务的用户发布一点提示 . MyServiceHost需要继承 WebServiceHost ,而不仅仅是ServiceHost .

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

    这将为IIS中的 endpoints 创建所有必需的绑定等 .

  • 5

    您需要实现自定义 ServiceHostFactoryServiceHostIInstanceProvider 的组合 .

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

    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工厂) .

  • 115

    您可以简单地创建 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();
    

    我希望这会让某人的生活更轻松 .

  • -1

    Mark对 IInstanceProvider 的回答是正确的 .

    您也可以使用自定义属性(例如 MyInstanceProviderBehaviorAttribute ),而不是使用自定义ServiceHostFactory . 从 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
    

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

  • -2

    我从马克的答案开始,但(至少在我的情景中),它是不必要的复杂 . 其中一个 ServiceHost 构造函数接受该服务的实例,您可以直接从 ServiceHostFactory 实现传入该实例 .

    为了搭载Mark的例子,它看起来像这样:

    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)
        {
        }
    }
    
  • 0

    拧紧它......我混合了依赖注入和服务定位器模式(但主要是依赖注入,它甚至发生在构造函数中,这意味着你可以拥有只读状态) .

    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混乱的容器),则可以将其配置为创建 Dependencies 实例而不是服务 . 通过这种方式,您可以获得容器给您的温暖模糊感,同时也不必跳过WCF强加的太多箍 .

    我不会因为这种方法而失眠 . 别人也不应该 . 毕竟,你是IoC容器是一个庞大,肥胖,静态的代表集合,为你创造东西 . 又增加了一个?

  • 12

    我们面临着同样的问题,并以下列方式解决了这个问题 . 这是一个简单的解决方案 .

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

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

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

    该服务应使用此类而不是原始MyService .

    这是一个简单的解决方案,就像一个魅力:-D

  • 10

    我使用我的类型的静态变量 . 不确定这是否是最佳方式,但它对我有用:

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

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

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

相关问题