具有多个WCF客户端的WPF应用程序

时间:2012-07-18 15:49:07

标签: .net wpf wcf prism wcf-client

我有一个使用Prism的WPF应用程序。

该应用程序加载了几个模块。

每个模块都连接到一个或多个WCF服务。

连接详细信息位于Module库的“app.config”文件中。

我的问题是 - 如何让“Shell”项目了解分布在不同程序集中不同“app.config”文件中的端点配置。

尝试连接的不同“模块”中的每个客户端 - 抛出了无法找到“端点”信息的异常...

1 个答案:

答案 0 :(得分:1)

更新:

另一种可能的解决方案是在自己的AppDomains中创建WCF客户端。

请参阅此处了解一些想法:

我想问题是如何使用Prism ...这个技巧可能是有一个自定义的IModuleManager(Prism V4),IModuleLoader(V1)或目录来处理加载你的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);
    }
    }
}