usa servicio que pueden puede protocolo obtener ningun metadatos invocar extremo error enlace encuentra desconocido deberse componente wcf dependency-injection factory-pattern

wcf - servicio - no se pueden obtener metadatos de https



¿Cómo paso valores al constructor en mi servicio wcf? (8)

Me gustaría pasar valores al constructor en la clase que implementa mi servicio.

Sin embargo, ServiceHost solo me permite pasar el nombre del tipo para crear, no los argumentos para pasar a su contrstructor.

Me gustaría poder pasar en una fábrica que crea mi objeto de servicio.

Lo que he encontrado hasta ahora


Atorníllelo ... Combiné los patrones de inyección de dependencia y de localización de servicio (pero sobre todo sigue siendo una inyección de dependencia e incluso tiene lugar en el constructor, lo que significa que puede tener un estado de solo lectura).

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 } }

Las dependencias del servicio están claramente especificadas en el contrato de su clase Dependencies anidadas. Si está utilizando un contenedor IoC (uno que aún no soluciona el desastre de WCF), puede configurarlo para crear la instancia Dependencies lugar del servicio. De esta forma obtienes la cálida sensación difusa que te proporciona tu contenedor sin tener que saltar demasiados aros impuestos por WCF.

No voy a perder el sueño con este enfoque. Tampoco nadie más. Después de todo, tu contenedor de IoC es una gran colección de delegados estáticos que crean cosas para ti. ¿Qué está agregando uno más?


Estábamos enfrentando este mismo problema y lo hemos resuelto de la siguiente manera. Es una solución simple.

En Visual Studio simplemente cree una aplicación de servicio WCF normal y elimine su interfaz. Deje el archivo .cs en su lugar (simplemente renómbrelo) y abra ese archivo cs y reemplace el nombre de la interfaz con su nombre de clase original que implementa la lógica del servicio (de esta forma, la clase de servicio usa la herencia y reemplaza su implementación real). Agregue un constructor predeterminado que llame a los constructores de la clase base, así:

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

La clase base MyService es la implementación real del servicio. Esta clase base no debe tener un constructor sin parámetros, sino solo constructores con parámetros que acepten las dependencias.

El servicio debería usar esta clase en lugar del MyService original.

Es una solución simple y funciona como un encanto :-D


Esta fue una solución muy útil, especialmente para alguien que es un programador novato de WCF. Quise publicar un pequeño consejo para los usuarios que podrían estar usando esto para un servicio hospedado por IIS. MyServiceHost necesita heredar WebServiceHost , no solo ServiceHost.

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

Esto creará todos los enlaces necesarios, etc. para sus puntos finales en IIS.


La respuesta de Mark con IInstanceProvider es correcta.

En lugar de utilizar la función personalizada ServiceHostFactory, también podría usar un atributo personalizado (por ejemplo, MyInstanceProviderBehaviorAttribute ). Derivarlo de Attribute , hacer que implemente IServiceBehavior e implementar el método IServiceBehavior.ApplyDispatchBehavior como

// 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; } }

Luego, aplique el atributo a su clase de implementación del servicio

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

La tercera opción: también puede aplicar un comportamiento de servicio utilizando el archivo de configuración.


Simplemente puede crear una instancia de su Service y pasar esa instancia al objeto ServiceHost . Lo único que debe hacer es agregar un atributo [ServiceBehaviour] para su servicio y marcar todos los objetos devueltos con el atributo [DataContract] .

Aquí hay una maqueta:

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(); } }

y el uso:

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

Espero que esto haga la vida más fácil para alguien.


Trabajé con la respuesta de Mark, pero (al menos para mi caso), fue innecesariamente compleja. Uno de los constructores de ServiceHost acepta una instancia del servicio, que puede pasar directamente desde la implementación de ServiceHostFactory .

Para aprovechar el ejemplo de Mark, se vería así:

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


Yo uso variables estáticas de mi tipo. No estoy seguro si esta es la mejor manera, pero funciona para mí:

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

Cuando instalo el host del servicio, hago lo siguiente:

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


Deberá implementar una combinación de ServiceHostFactory , ServiceHost e IInstanceProvider .

Dado un servicio con esta firma de constructor:

public MyService(IDependency dep)

Aquí hay un ejemplo que puede activar 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 }

Registre MyServiceHostFactory en su archivo MyService.svc, o use MyServiceHost directamente en el código para escenarios de autohospedaje.

Puede generalizar fácilmente este enfoque, y de hecho algunos Contenedores DI ya lo han hecho por usted (cue: Facilidad WCF de Windsor).