2008-10-17 14 views
6

En una aplicación que aloja varios servicios WCF, ¿cuál sería la mejor manera de agregar información de configuración personalizada para cada servicio? Por ejemplo, es posible que desee pasar o establecer un nombre de empresa o especificar ConnectionString un servicio o algún otro parámetro.Configuración personalizada del servicio WCF

Supongo que esto podría ser posible mediante la implementación de IServiceBehavior.

es decir algo así como ....

<behaviors> 
    <serviceBehaviors> 
    <behavior name="MyBehavior"> 
     <serviceMetadata httpGetEnabled="true" /> 
     <serviceDebug /> 
     <customBehavior myCompany="ABC" /> 
    </behavior> 
    <behavior name="MyOtherBehavior"> 
     <serviceMetadata httpGetEnabled="true" /> 
     <serviceDebug /> 
     <customBehavior myCompany="DEF" /> 
    </behavior> 
    </serviceBehaviors> 
</behaviors> 

<services> 
    <service behaviorConfiguration="MyBehavior" name="MyNameSpace.MyService"> 
    <endpoint address="" behaviorConfiguration="" binding="netTcpBinding" 
     name="TcpEndpoint" contract="MyNameSpace.IMyService" /> 
    <endpoint address="mex" binding="mexTcpBinding" bindingConfiguration="" 
     name="TcpMexEndpoint" contract="IMetadataExchange" /> 
    <host> 
     <baseAddresses> 
     <add baseAddress="net.tcp://localhost:4000/MyService" /> 
     </baseAddresses> 
    </host> 
    </service> 
    <service behaviorConfiguration="MyOtherBehavior" name="MyNameSpace.MyOtherService"> 
    <endpoint address="" behaviorConfiguration="" binding="netTcpBinding" 
     name="TcpEndpoint" contract="MyNameSpace.IMyOtherService" /> 
    <endpoint address="mex" binding="mexTcpBinding" bindingConfiguration="" 
     name="TcpMexEndpoint" contract="IMetadataExchange" /> 
    <host> 
     <baseAddresses> 
     <add baseAddress="net.tcp://localhost:4000/MyOtherService" /> 
     </baseAddresses> 
    </host> 
    </service> 
</services> 

fijaría en ABC y DEF MyService en MyOtherService (suponiendo que tengan alguna de las interfaces común con un nombre de la empresa).

¿Alguien puede explicar cómo implementar esto?

TIA

Michael

Respuesta

0

Depende mucho de dónde y cómo se vaya a utilizar dicha información. Si no es algo que va a hacer mucho con la infraestructura (es decir, hacer que los servicios se ejecuten y procesar las solicitudes), me sentiría tentado a decir que tratar de incluir eso en los comportamientos de WCF podría agregar más complejidad de la que vale. Probablemente sea más simple usar una sección de configuración personalizada propia.

¿Podría aclarar cómo espera utilizar esta información en tiempo de ejecución? Tal vez de esa manera podamos brindar consejos más explícitos ...

0

Bueno, creo que el ejemplo que he dado es bastante elaborado. Trataré de seguir elaborando ...

Básicamente, quiero poder pasar datos de configuración personalizados a un servicio WCF en una aplicación en la que se pueden ejecutar varios servicios WCF.

Entonces, eso significa que en la instancia de un servicio que se ejecuta en la aplicación quiero acceder a datos que se han configurado específicamente para ese servicio (y no otro servicio). Creo que podría hacer esto simplemente usando la configuración de la aplicación y usando el tipo del servicio como la clave. Esperaba que WCF tuviera algunos constructos mejores para esto.

8

Sé que esto es viejo, pero nunca fue marcado respondió, así que pensé que podría tomar una foto. Si entiendo lo que está buscando, puede hacerlo con un ServiceHostFactory personalizado.
Buena publicación en este here.

te prepara yuour ServiceHostFactory encargo de este modo:

<%@ ServiceHost 
Language="C#" 
Debug="true" 
Service="Ionic.Samples.Webservices.Sep20.CustomConfigService" 
Factory="Ionic.ServiceModel.ServiceHostFactory"%> 

Luego, en su ServiceHostFactory, puede anular un método llamado ApplyConfiguration. Normalmente, para las aplicaciones WCF alojadas en IIS, WCF busca automáticamente config en web.config. En este ejemplo, anulamos ese comportamiento para buscar primero un archivo de configuración con el nombre de la Descripción del servicio WCF.

protected override void ApplyConfiguration() 
{ 
    // generate the name of the custom configFile, from the service name: 
    string configFilename = System.IO.Path.Combine (physicalPath, 
     String.Format("{0}.config", this.Description.Name)); 

    if (string.IsNullOrEmpty(configFilename) || !System.IO.File.Exists(configFilename)) 
     base.ApplyConfiguration(); 
    else 
     LoadConfigFromCustomLocation(configFilename); 
} 

Se podría reemplazar esto con "nada" - por ejemplo, en busca de configuración en una tabla de base de datos.

Unos pocos métodos más completan el rompecabezas.

private string _physicalPath = null; 
private string physicalPath 
{ 
    get 
    { 
     if (_physicalPath == null) 
     { 
      // if hosted in IIS 
      _physicalPath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath; 

      if (String.IsNullOrEmpty(_physicalPath)) 
      { 
       // for hosting outside of IIS 
       _physicalPath= System.IO.Directory.GetCurrentDirectory(); 
      } 
     } 
     return _physicalPath; 
    } 
} 


private void LoadConfigFromCustomLocation(string configFilename) 
{ 
    var filemap = new System.Configuration.ExeConfigurationFileMap(); 
    filemap.ExeConfigFilename = configFilename; 
    System.Configuration.Configuration config = 
     System.Configuration.ConfigurationManager.OpenMappedExeConfiguration 
     (filemap, 
     System.Configuration.ConfigurationUserLevel.None); 
    var serviceModel = System.ServiceModel.Configuration.ServiceModelSectionGroup.GetSectionGroup(config); 
    bool loaded= false; 
    foreach (System.ServiceModel.Configuration.ServiceElement se in serviceModel.Services.Services) 
    { 
     if(!loaded) 
      if (se.Name == this.Description.ConfigurationName) 
      { 
       base.LoadConfigurationSection(se); 
       loaded= true; 
      } 
    } 

    if (!loaded) 
     throw new ArgumentException("ServiceElement doesn't exist"); 
} 
3

Estaba teniendo un problema similar, pero estaba usando DuplexChannel. Basado en un post que encontré me encontré He resuelto de esta manera:

public class CustomDuplexChannelFactory<TChannel> : DuplexChannelFactory<TChannel> 
{ 
    public static string ConfigurationPath { get; set; } 

    public CustomDuplexChannelFactory(InstanceContext callbackInstance) 
     : base(callbackInstance) 
    { 
    } 

    protected override ServiceEndpoint CreateDescription() 
    { 
     ServiceEndpoint serviceEndpoint = base.CreateDescription(); 

     if(ConfigurationPath == null || !File.Exists(ConfigurationPath)) 
      return base.CreateDescription(); 

     ExeConfigurationFileMap executionFileMap = new ExeConfigurationFileMap(); 
     executionFileMap.ExeConfigFilename = ConfigurationPath; 
     System.Configuration.Configuration config = ConfigurationManager.OpenMappedExeConfiguration(executionFileMap, ConfigurationUserLevel.None); 
     ServiceModelSectionGroup serviceModeGroup = ServiceModelSectionGroup.GetSectionGroup(config); 
     ChannelEndpointElement selectedEndpoint = null; 
     foreach(ChannelEndpointElement endpoint in serviceModeGroup.Client.Endpoints) 
     { 
      if(endpoint.Contract == serviceEndpoint.Contract.ConfigurationName) 
      { 
       selectedEndpoint = endpoint; break; 
      } 
     } 
     if(selectedEndpoint != null) 
     { 
      if(serviceEndpoint.Binding == null) 
      { 
       serviceEndpoint.Binding = CreateBinding(selectedEndpoint.Binding, serviceModeGroup); 
      } if(serviceEndpoint.Address == null) 
      { 
       serviceEndpoint.Address = new EndpointAddress(selectedEndpoint.Address, 
       GetIdentity(selectedEndpoint.Identity), selectedEndpoint.Headers.Headers); 
      } if(serviceEndpoint.Behaviors.Count == 0 && !String.IsNullOrEmpty(selectedEndpoint.BehaviorConfiguration)) 
      { 
       AddBehaviors(selectedEndpoint.BehaviorConfiguration, 
        serviceEndpoint, serviceModeGroup); 
      } 
      serviceEndpoint.Name = selectedEndpoint.Contract; 
     } 
     return serviceEndpoint; 
    } 

    private Binding CreateBinding(string bindingName, ServiceModelSectionGroup group) 
    { 
     BindingCollectionElement bindingElementCollection = group.Bindings[bindingName]; 
     if(bindingElementCollection.ConfiguredBindings.Count > 0) 
     { 
      IBindingConfigurationElement be = bindingElementCollection.ConfiguredBindings[0]; 
      Binding binding = GetBinding(be); if(be != null) 
      { 
       be.ApplyConfiguration(binding); 
      } 
      return binding; 
     } 
     return null; 
    } 

    private void AddBehaviors(string behaviorConfiguration, ServiceEndpoint serviceEndpoint, ServiceModelSectionGroup group) 
    { 
     EndpointBehaviorElement behaviorElement = group.Behaviors.EndpointBehaviors[behaviorConfiguration]; 
     for(int i = 0; i < behaviorElement.Count; i++) 
     { 
      BehaviorExtensionElement behaviorExtension = behaviorElement[i]; 
      object extension = behaviorExtension.GetType().InvokeMember("CreateBehavior", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, behaviorExtension, null); 
      if(extension != null) 
      { 
       serviceEndpoint.Behaviors.Add((IEndpointBehavior)extension); 
      } 
     } 
    } 

    private EndpointIdentity GetIdentity(IdentityElement element) 
    { 
     EndpointIdentity identity = null; 
     PropertyInformationCollection properties = element.ElementInformation.Properties; 
     if(properties["userPrincipalName"].ValueOrigin != PropertyValueOrigin.Default) 
     { 
      return EndpointIdentity.CreateUpnIdentity(element.UserPrincipalName.Value); 
     } 
     if(properties["servicePrincipalName"].ValueOrigin != PropertyValueOrigin.Default) 
     { 
      return EndpointIdentity.CreateSpnIdentity(element.ServicePrincipalName.Value); 
     } 
     if(properties["dns"].ValueOrigin != PropertyValueOrigin.Default) 
     { 
      return EndpointIdentity.CreateDnsIdentity(element.Dns.Value); 
     } 
     if(properties["rsa"].ValueOrigin != PropertyValueOrigin.Default) 
     { 
      return EndpointIdentity.CreateRsaIdentity(element.Rsa.Value); 
     } 
     if(properties["certificate"].ValueOrigin != PropertyValueOrigin.Default) 
     { 
      X509Certificate2Collection supportingCertificates = new X509Certificate2Collection(); 
      supportingCertificates.Import(Convert.FromBase64String(element.Certificate.EncodedValue)); 

      if(supportingCertificates.Count == 0) 
      { 
       throw new InvalidOperationException("UnableToLoadCertificateIdentity"); 
      } 

      X509Certificate2 primaryCertificate = supportingCertificates[0]; supportingCertificates.RemoveAt(0); 
      return EndpointIdentity.CreateX509CertificateIdentity(primaryCertificate, supportingCertificates); 
     } 
     return identity; 
    } 

    private Binding GetBinding(IBindingConfigurationElement configurationElement) 
    { 
     if(configurationElement is CustomBindingElement) 
      return new CustomBinding(); 
     else if(configurationElement is BasicHttpBindingElement) 
      return new BasicHttpBinding(); 
     else if(configurationElement is NetMsmqBindingElement) 
      return new NetMsmqBinding(); 
     else if(configurationElement is NetNamedPipeBindingElement) 
      return new NetNamedPipeBinding(); 
     else if(configurationElement is NetPeerTcpBindingElement) 
      return new NetPeerTcpBinding(); 
     else if(configurationElement is NetTcpBindingElement) 
      return new NetTcpBinding(); 
     else if(configurationElement is WSDualHttpBindingElement) 
      return new WSDualHttpBinding(); 
     else if(configurationElement is WSHttpBindingElement) 
      return new WSHttpBinding(); 
     else if(configurationElement is WSFederationHttpBindingElement) 
      return new WSFederationHttpBinding(); 
     return null; 
    } 
} 

hice un resumen de esto en mi blog

Cuestiones relacionadas