我有一個使用Prism的WPF應用程序。有多個WCF客戶端的WPF應用程序
該應用程序加載了幾個模塊。
每個模塊都連接到一個或多個WCF服務。
連接詳細信息位於模塊庫的'app.config'文件中。
我的問題是:我如何讓'Shell'項目瞭解在不同程序集中的不同'app.config'文件中傳播的端點配置。
在不同的「模塊」,它試圖連接每個客戶端 - 拋出一個異常的「端點」信息無法找到...
我有一個使用Prism的WPF應用程序。有多個WCF客戶端的WPF應用程序
該應用程序加載了幾個模塊。
每個模塊都連接到一個或多個WCF服務。
連接詳細信息位於模塊庫的'app.config'文件中。
我的問題是:我如何讓'Shell'項目瞭解在不同程序集中的不同'app.config'文件中傳播的端點配置。
在不同的「模塊」,它試圖連接每個客戶端 - 拋出一個異常的「端點」信息無法找到...
UPDATE:
另一種可能的解決方案是創建WCF客戶端在他們自己的AppDomain中。
看到這裏的一些想法:
我想這個問題是如何得到這個與棱鏡工作,祕訣可能是有一個自定義IModuleManager(Prism V4),IModuleLoader(V1)或目錄來處理加載你的WCF客戶端模塊,或者可能有一個包裝模塊t帽子反過來加載你的WCF客戶端。
https://prism.svn.codeplex.com/svn/V1/spikes/AGCompositeApplicationLibrary/AGComposite/Modularity/ModuleLoader.cs(這是從棱鏡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");
}
我記不太清楚了,但我覺得我必須(在試圖取代它,否則會有衝突)沒有定義任何ServiceModel配置都在我的主要應用程序的app.config ...可能是錯誤的...可能是相反的,或者可能根本沒有任何app.config! :O /。由於某種原因,它很脆弱......我不記得我的頭頂。
我也嘗試在運行時從ConfigurationManager訪問ServiceModel配置,並試圖通過代碼修改它......但它沒有它。
無論如何,我不認爲上述將幫助你,因爲你將加載多個模塊,所以需要加載多個配置。從
和
ExceptionHandlingProxyBase<T>
:
所以嘗試上述後無論如何我切換到較不脆方法通過使用的組合
CustomClientChannelFactory<T>
從
我把一些必要的修正得到的ChannelFactory上班,我修改了它,所以我能選擇我是否想用自己的配置覆蓋離子文件,並支持覆蓋地址。
我用ExceptionHandlingProxyBase中此構造函數創建工廠:
public CustomClientChannel(Binding binding, string remoteAddress, string configurationPath)
可以忽略此解決方案的一部分ExceptionHandlingProxyBase ...這就是糖是重新建立通道每當通道故障,這樣您就不必擔心代理的狀態。
如果您仍然不想使用ChannelFactory,那麼您可以嘗試在您的AppDomain中黑客入侵ServiceModel配置。我試過了,但它似乎很難修改
以下是修復了(愚蠢地重命名爲CustomClientChannel)的ChannelFactory代碼。
/// <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-31 07:26:06
會很高興,如果您更新您的答案與您的解決方案,一旦你找到它...... :) – 2012-07-31 07:26:23
更好的解決方案在這裏:http://stackoverflow.com/questions/5045916/wcf-channelfactory-configuration-outside-of-app-config – 2012-08-01 21:16:10