0

Prism を使用した WPF アプリケーションがあります。

アプリケーションはいくつかのモジュールをロードします。

各モジュールは、1 つ以上の WCF サービスに接続します。

接続の詳細は、モジュール ライブラリの「app.config」ファイルにあります。

私の質問は、さまざまなアセンブリのさまざまな 'app.config' ファイルにまたがるエンドポイント構成を 'Shell' プロジェクトに認識させるにはどうすればよいかということです。

接続を試みる異なる「モジュール」内の各クライアント - 「エンドポイント」情報が見つからないという例外をスローします...

4

1 に答える 1

1

アップデート:

別の潜在的な解決策は、独自の AppDomains に WCF クライアントを作成することです。

いくつかのアイデアについては、ここを参照してください。

問題は、これを Prism で動作させる方法だと思います...トリックは、カスタム IModuleManager (Prism V4)、IModuleLoader (V1)、または Catalog を使用して、WCF クライアント モジュールのロードを処理するか、ラッパー モジュールを用意することです。これにより、WCF クライアントが読み込まれます。


あなたがやっていることと同様のことをする最初の試みは、DLL モジュールでこれを行うことによって AppDomain 構成をハックすることでした。

    object o = AppDomain.CurrentDomain.GetData("APP_CONFIG_FILE");

    // See if there is a configuration defined by the Exe host, hosting this DLL.

    Configuration con = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

    // Do we need to override the configuration, to point to our "default" one?

    if (con.HasFile == false)
    {
        string sFullPathToConfig = Assembly.GetExecutingAssembly().Location + ".config";

        AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", sFullPathToConfig);

        ConfigurationManager.RefreshSection("system.serviceModel");
        ConfigurationManager.RefreshSection("system.diagnostics");
    }

正確には覚えていませんが、メインアプリケーション app.config で ServiceModel 構成をまったく定義する必要はなかったと思います (そうしないと、置き換えようとすると競合が発生します)...それは間違っている可能性があります.. . は逆の場合もあれば、app.config がまったくない場合もあります。:o/. なんらかの理由で脆かった....私は頭の上から覚えていない.

また、実行時に ConfigurationManager から ServiceModel 構成にアクセスし、それをコードで変更しようとしましたが、それはありませんでした。

とにかく、複数のモジュールをロードするので、上記は役に立たないと思うので、複数の構成をロードする必要があります。


とにかく、上記を試した後、次の組み合わせを使用して、より脆弱でない方法に切り替えました。

ExceptionHandlingProxyBase<T>

から

CustomClientChannelFactory<T>

から

ChannelFactory を機能させるために必要な修正をいくつか行い、独自の構成ファイルで上書きするかどうかを選択できるように変更し、アドレスの上書きもサポートするようにしました。

ExceptionHandlingProxyBase 内でこのコンストラクターを使用して、ファクトリを作成しました。

public CustomClientChannel(Binding binding, string remoteAddress, string configurationPath)

このソリューションの ExceptionHandlingProxyBase 部分は無視できます...これは、チャネルに障害が発生するたびにチャネルを再確立する単なる砂糖であるため、プロキシの状態を心配する必要はありません。

それでも ChannelFactory を使用したくない場合は、AppDomain の ServiceModel 構成をハッキングしてみてください。やってみたけど修正が難しそうだった

これが修正されたChannelFactoryコードです(ばかげてCustomClientChannelに名前が変更されました)。

/// <summary>
/// Custom client channel. Allows to specify a different configuration file
/// </summary>
/// <typeparam name="T"></typeparam>
public class CustomClientChannel<T> : ChannelFactory<T>
{
    string configurationPath;
    string endpointConfigurationName;
bool m_bOverrideConfiguration = false;
Uri m_OverrideAddress = null;

    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="configurationPath"></param>
    public CustomClientChannel(string configurationPath) : base(typeof(T))
    {
        this.configurationPath = configurationPath;
        base.InitializeEndpoint((string)null, null);
    }

    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="binding"></param>
    /// <param name="configurationPath"></param>
    public CustomClientChannel(Binding binding, string configurationPath)
        : this(binding, (EndpointAddress)null, configurationPath)

    {
    }

    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="serviceEndpoint"></param>
    /// <param name="configurationPath"></param>
    public CustomClientChannel(ServiceEndpoint serviceEndpoint, string configurationPath)
        : base(typeof(T))
    {
        this.configurationPath = configurationPath;
        base.InitializeEndpoint(serviceEndpoint);
    }

    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="endpointConfigurationName"></param>
    /// <param name="configurationPath"></param>
    public CustomClientChannel(string endpointConfigurationName, string configurationPath)
        : this(endpointConfigurationName, null, configurationPath)
    {
    }

    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="binding"></param>
    /// <param name="endpointAddress"></param>
    /// <param name="configurationPath"></param>
    public CustomClientChannel(Binding binding, EndpointAddress endpointAddress, string configurationPath)
        : base(typeof(T))
    {
        this.configurationPath = configurationPath;
        base.InitializeEndpoint(binding, endpointAddress);
    }

    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="binding"></param>
    /// <param name="remoteAddress"></param>
    /// <param name="configurationPath"></param>
    public CustomClientChannel(Binding binding, string remoteAddress, string configurationPath)
        : this(binding, new EndpointAddress(remoteAddress), configurationPath)
    {
    }

    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="endpointConfigurationName"></param>
    /// <param name="endpointAddress"></param>
    /// <param name="configurationPath"></param>
    public CustomClientChannel(string endpointConfigurationName, EndpointAddress endpointAddress, string configurationPath)
        : base(typeof(T))
    {
    m_OverrideAddress = (endpointAddress != null ? endpointAddress.Uri : null);

        this.configurationPath = configurationPath;
        this.endpointConfigurationName = endpointConfigurationName;
        base.InitializeEndpoint(endpointConfigurationName, endpointAddress);
    }

    /// <summary>
    /// Loads the serviceEndpoint description from the specified configuration file
    /// </summary>
    /// <returns></returns>
    protected override ServiceEndpoint CreateDescription()
    {
    if (string.IsNullOrEmpty(this.configurationPath))
    {
        System.Diagnostics.Debug.WriteLine("Not using overriding config file");

        return base.CreateDescription();
    }

    if (!System.IO.File.Exists(configurationPath))
    {
        System.Diagnostics.Debug.WriteLine("Overriding config file [" + configurationPath + "] doesn't exist");

        return base.CreateDescription();
    }

    m_bOverrideConfiguration = true;

        ServiceEndpoint serviceEndpoint = base.CreateDescription();

        if (endpointConfigurationName != null)
            serviceEndpoint.Name = endpointConfigurationName;

        ExeConfigurationFileMap map = new ExeConfigurationFileMap();
        map.ExeConfigFilename = this.configurationPath;

        Configuration config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
        ServiceModelSectionGroup group = ServiceModelSectionGroup.GetSectionGroup(config);

        ChannelEndpointElement selectedEndpoint = null;

        foreach (ChannelEndpointElement endpoint in group.Client.Endpoints)
        {
            if (endpoint.Contract == serviceEndpoint.Contract.ConfigurationName && 
                (this.endpointConfigurationName == null || this.endpointConfigurationName == endpoint.Name))
            {
                selectedEndpoint = endpoint;
                break;
            }
        }

        if (selectedEndpoint != null)
        {
            if (serviceEndpoint.Binding == null)
            {
                serviceEndpoint.Binding = CreateBinding(selectedEndpoint.Binding, selectedEndpoint.BindingConfiguration, group);
            }

        if (m_OverrideAddress != null)
        {
            serviceEndpoint.Address = new EndpointAddress(m_OverrideAddress, GetIdentity(selectedEndpoint.Identity), selectedEndpoint.Headers.Headers);
        }
        else
            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, group);
            }

            serviceEndpoint.Name = selectedEndpoint.Contract;
        }

        return serviceEndpoint;

    }

    /// <summary>
    /// Configures the binding for the selected endpoint
    /// </summary>
    /// <param name="bindingName"></param>
    /// <param name="group"></param>
    /// <returns></returns>
    private Binding CreateBinding(string bindingName, string bindingConfiguration, ServiceModelSectionGroup group)
    {
    IBindingConfigurationElement be = null;

        BindingCollectionElement bindingElementCollection = group.Bindings[bindingName];

    if (bindingElementCollection.ConfiguredBindings.Count > 0)
    {

        foreach (IBindingConfigurationElement bindingElem in bindingElementCollection.ConfiguredBindings)
        {

            if (string.Compare(bindingElem.Name, bindingConfiguration) == 0)
            {

                be = bindingElem;

                break;

            }

        }

        Binding binding = null;

        if (be != null)
        {

            binding = GetBinding(be);

            be.ApplyConfiguration(binding);

        }

        return binding;

    }

    return null;
    }

    /// <summary>
    /// Helper method to create the right binding depending on the configuration element
    /// </summary>
    /// <param name="configurationElement"></param>
    /// <returns></returns>
    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;
    }

    /// <summary>
    /// Adds the configured behavior to the selected endpoint
    /// </summary>
    /// <param name="behaviorConfiguration"></param>
    /// <param name="serviceEndpoint"></param>
    /// <param name="group"></param>
    private void AddBehaviors(string behaviorConfiguration, ServiceEndpoint serviceEndpoint, ServiceModelSectionGroup group)
    {
    if (group.Behaviors.EndpointBehaviors.Count == 0)
        return;

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

    /// <summary>
    /// Gets the endpoint identity from the configuration file
    /// </summary>
    /// <param name="element"></param>
    /// <returns></returns>
    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;
    }


    protected override void ApplyConfiguration(string configurationName)
    {
    if (!m_bOverrideConfiguration)
    {
        // This picks up the configuration from the inherited config settings defined
        // by the application i.e. the normal place.

        base.ApplyConfiguration(configurationName);
    }
    }
}
于 2012-07-30T20:26:05.023 に答える