[英]WPF application with multiple WCF clients
我有一个使用Prism的WPF应用程序。
该应用程序加载几个模块。
每个模块都连接到一个或多个WCF服务。
连接详细信息位于模块库的“ app.config”文件中。
我的问题是-如何使'Shell'项目了解分散在不同程序集中不同'app.config'文件中的端点配置。
尝试连接的不同“模块”中的每个客户端都会抛出一个异常,即找不到“端点”信息...
更新:
另一种可能的解决方案是在自己的AppDomain中创建WCF客户端。
请参阅此处了解一些想法:
我想问题是如何与Prism一起使用...窍门可能是拥有自定义的IModuleManager(Prism V4),IModuleLoader(V1)或Catalog来处理加载WCF客户端模块,或者可能具有包装器模块依次加载您的WCF客户端。
https://prism.svn.codeplex.com/svn/V1/spikes/AGCompositeApplicationLibrary/AGComposite/Modularity/ModuleLoader.cs (来自Prism V1,仅供参考)。
我做与您正在做的事情类似的第一次尝试是通过在我的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配置(否则在尝试替换它时会有冲突)...可能是错误的。 .might相反,或者可能根本没有任何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);
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.