6


0

複数のWCFサービスをホストしているアプリケーションで、各サービスにカスタム構成情報を追加するための最善の方法は何ですか? たとえば、会社名を渡したり設定したり、connectionStringにサービスやその他のパラメータを指定したりできます。

私はこれがIServiceBehaviorを実装することによって可能かもしれないと思います。

すなわち……のようなもの


MyServiceにABCを設定し、MyOtherServiceにDEFを設定します(会社名と共通のインターフェースがあると仮定します)。

誰があなたがこれをどう実装するかについて詳しく述べることができますか?

TIA

マイケル

4 Answer


8


私はこれが古いことを知っています、しかしそれが答えられたとマークされることは決してありませんでした、それで私は私が写真を撮ると思いました。 私があなたが何をしているのか理解しているならば、あなたはカスタムServiceHostFactoryを使ってそれをすることができます。 この hereへの良い投稿。

あなたはあなたのカスタムServiceHostFactoryを次のように設定します。

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

その後、ServiceHostFactoryで、ApplyConfigurationというメソッドをオーバーライドできます。 通常、IISでホストされているWCFアプリケーションの場合、WCFは自動的にweb.config内の設定を探します。 この例では、その動作をオーバーライドして、最初にWCFサービス記述にちなんで名付けられた設定ファイルを探します。

protected override void ApplyConfiguration(){//サービス名からカスタムconfigFileの名前を生成します。string configFilename = System.IO.Path.Combine(physicalPath、String.Format( "{0} .config"、this.Description) 。名));

if(string.IsNullOrEmpty(configFilename)||!System.IO.File.Exists(configFilename))base.ApplyConfiguration();それ以外の場合はLoadConfigFromCustomLocation(configFilename); }

これを「何か」に置き換えることができます。たとえば、データベーステーブルで設定を探します。

さらにいくつかの方法でパズルが完成します。

プライベート文字列_physicalPath = null。プライベート文字列physicalPath {get {if(_physicalPath == null){// IISでホストされている場合_physicalPath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath;

if(String.IsNullOrEmpty(_physicalPath)){// IISの外部でホスティングする場合は_physicalPath = System.IO.Directory.GetCurrentDirectory(); _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 in serviceModel.Services.Services){if(!loaded)if(se.Name == this.Description.ConfigurationName){base.LoadConfigurationSection(se); loaded = true; }}

if(!loaded)は新しいArgumentException( "ServiceElementが存在しません")をスローします。 }


3


私は同様の問題を抱えていましたが、私はDuplexChannelを使用していました。 postに基づいて、私は私がこのように解決したのを見つけました:

パブリッククラスCustomDuplexChannelFactory:DuplexChannelFactory {パブリック静的文字列ConfigurationPath {get;}セット; }

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

保護されたオーバーライドServiceEndpoint CreateDescription(){ServiceEndpoint serviceEndpoint = base.CreateDescription();

if(ConfigurationPath == null ||!File.Exists(ConfigurationPath))は、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(serviceModeGroup.Client.Endpoints内のChannelEndpointElementエンドポイント){if(endpoint.Contract == serviceEndpoint.Contract.ConfigurationName){selectedEndpoint = endpoint;ブレーク; 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

プライベートバインディングCreateBinding(文字列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);バインディングを返します。 nullを返します。 }

private void AddBehaviors(string behaviorConfiguration、ServiceEndpoint serviceEndpoint、ServiceModelSectionGroupグループ){EndpointBehaviorElement behaviorElement = group.Behaviors.EndpointBehaviors [behaviorConfiguration]; for(int i = 0; i <behaviorElement.Count; i){BehaviorExtensionElement behaviorExtension = behaviorElement [i];オブジェクトの拡張子= 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 supportCertificates = new X509Certificate2Collection();} supportCertificates.Import(Convert.FromBase64String(element.Certificate.EncodedValue));

if(supportsCertificates.Count == 0){新しいInvalidOperationException( "UnableToLoadCertificateIdentity")をスローします。 }

X509Certificate2 primaryCertificate = supportsCertificates [0]; supportCertificates.RemoveAt(0); EndpointIdentity.CreateX509CertificateIdentity(primaryCertificate、supportCertificates)を返します。 IDを返す。 }

プライベートバインディングGetBinding(IBindingConfigurationElement configurationElement){if(configurationElementがCustomBindingElement)の場合はnew CustomBinding();そうでなければ(configurationElementがBasicHttpBindingElementである場合)new BasicHttpBinding()を返す。そうでなければ(configurationElementがNetMsmqBindingElementである場合)、新しいNetMsmqBinding()を返す。そうでなければ(configurationElementがNetNamedPipeBindingElementである場合)、新しいNetNamedPipeBinding()を返す。そうでなければ(configurationElementがNetPeerTcpBindingElementである場合)新しいNetPeerTcpBinding()を返す。そうでなければ(configurationElementがNetTcpBindingElementである場合)、新しいNetTcpBinding()を返す。そうでなければ(configurationElementがWSDualHttpBindingElementである場合)新しいWSDualHttpBinding()を返す。そうでなければ(configurationElementがWSHttpBindingElementである場合)新しいWSHttpBinding()を返す。そうでなければ(configurationElementがWSFederationHttpBindingElementである場合)新しいWSFederationHttpBinding()を返す。 nullを返します。 }}

私はこれを私の blogにまとめました。


0


それは、どこでどのようにあなたがその情報を使用することを期待しているかに依存します。 それが何かではない場合は、インフラストラクチャーで多くのことをすることになります(例: サービスを実行してリクエストを処理するようにしたので、それをWCFの振る舞いに組み込もうとすると、それ以上に複雑さが増す可能性があります。 おそらくあなた独自のカスタム設定セクションを使うほうが簡単でしょう。

実行時にこの情報をどのように使用すると予想しているのでしょうか。 たぶんそのように我々はより明白なアドバイスを提供することができます…​


0


まあ、私は私が与えた例はかなり手の込んだものだと思いました。 さらに詳しく説明します。

基本的に、実行中のWCFサービスがいくつかある可能性があるアプリケーションで、カスタム構成データをWCFサービスに渡すことができるようにしたいです。

それが意味することは私がそのサービスのために特別に構成されたデータにアクセスしたいと思うアプリケーションの中で走っているサービスのインスタンスにあるということです(そして他のサービスではない)。 私は、単にアプリケーション設定を使用し、サービスの種類をキーとして使用することでこれを実行できると思います。 私はWCFがこれのためにいくつかのより良い構成を持っているかもしれないことを望んでいました。