Как передать значения конструктору в моей службе wcf?
Я хотел бы передать значения в конструкторе класса, который реализует службу.
однако ServiceHost позволяет мне только передать имя типа для создания, а не какие аргументы передать его контрструктору.
Я хотел бы иметь возможность пройти на заводе, который создает мой объект обслуживания.
то, что я нашел до сих пор:
поведение инъекции зависимостей WCF что больше, чем то, что я ищу ибо и, кажется, слишком сложен для моих нужд.
8 ответов:
вам нужно будет реализовать комбинацию пользовательских
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 }Регистрация MyServiceHostFactory в вашем MyService.svc-файл или используйте MyServiceHost непосредственно в коде для сценариев самостоятельного размещения.
вы можете легко обобщить этот подход, и на самом деле некоторые контейнеры DI уже сделали это для вы (реплика: Виндзорский центр WCF).
вы можете просто создать и экземпляр
Serviceи передать этот экземплярServiceHost"объект". Единственное, что вам нужно сделать, это добавить[ServiceBehaviour]атрибут для вашего сервиса и отметьте все возвращаемые объекты с
ответ Марка с
IInstanceProviderявляется правильным.вместо использования пользовательского ServiceHostFactory вы также можете использовать пользовательский атрибут (скажем
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третий вариант: вы также можете применить поведение службы с помощью файла конфигурации.
Я работал с ответом Марка, но (для моего сценария, по крайней мере), это было бесполезно сложно. Один из
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) { } }
винт это... я смешал инъекцию зависимостей и шаблоны локатора служб (но в основном это все еще инъекция зависимостей, и это даже происходит в конструкторе, что означает, что вы можете иметь состояние только для чтения).
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-это большая, толстая, статическая коллекция делегатов, которая создает для вас материал. Что добавляет еще один?
Это было очень полезное решение, особенно для тех, кто новичок в WCF верстальщик. Я хочу опубликовать небольшой совет для всех пользователей, которые могут использовать это для IIS службы. MyServiceHost должен наследовать WebServiceHost, не только ServiceHost.
public class MyServiceHost : WebServiceHost { public MyServiceHost(MyService instance, Type serviceType, params Uri[] baseAddresses) : base(instance, baseAddresses) { } }Это создаст все необходимые привязки и т. д. Для ваших конечных точек в IIS.
Я использую статические переменные своего типа. Не уверен, что это лучший способ, но он работает для меня:
public class MyServer { public static string CustomerDisplayName; ... }когда я создаю экземпляр узла службы, я делаю следующее:
protected override void OnStart(string[] args) { MyServer.CustomerDisplayName = "Test customer"; ... selfHost = new ServiceHost(typeof(MyServer), baseAddress); .... }
мы столкнулись с этой же проблемой и решил ее следующим образом. Это простое решение.
в Visual Studio просто создайте обычное приложение службы WCF и удалите его интерфейс. Оставь это .cs-файл на месте (просто переименуйте его) и откройте этот cs-файл и замените имя интерфейса вашим исходным именем класса, который реализует логику службы (таким образом, класс службы использует наследование и заменяет вашу фактическую реализацию). Добавить значение по умолчанию конструктор, который вызывает конструкторы базового класса, например:
public class Service1 : MyLogicNamespace.MyService { public Service1() : base(new MyDependency1(), new MyDependency2()) {} }базовый класс MyService является фактической реализацией сервиса. Этот базовый класс не должен иметь конструктор без параметров, а только конструкторы с параметрами, принимающими зависимости.
служба должна использовать этот класс вместо исходного MyService.
Это простое решение и работает как шарм : - D
Comments