共用方式為


Loading WCF Client Configuration from Different Files with ConfigurationChannelFactory

One
pain point with configuration that WCF developers have run into in
previous versions of the framework is the limitation that WCF clients
can only use the hosting executable’s configuration file. This can be
problematic for clients that need to call multiple services because the
configuration for all of these services would have to be mashed together
in one big configuration file. This can also be a problem for client
libraries: since libraries don’t have configuration files, every
executable that uses the library needs to provide it with the right
configuration in its own configuration file.

Fortunately, this restriction has been lifted in WCF 4.0 with the introduction of ConfigurationChannelFactory. This new class allows you to create clients that can take in any Configuration object to configure your client. This means that you’re no longer limited to using the App.config for your executable. To demonstrate this new class, let’s say you have a client that needs to call out to a web service that returns stock information and another web service that returns weather information.

In WCF 4.0, you can do this:

Configuration stockConfiguration = ConfigurationManager.OpenMappedExeConfiguration(new ExeConfigurationFileMap { ExeConfigFilename = @"C:\Temp\StockClient.config"}, ConfigurationUserLevel.None);

ConfigurationChannelFactory<StockQuoteSoap> stockChannelFactory = new ConfigurationChannelFactory<StockQuoteSoap>("StockQuoteSoap", stockConfiguration, null);

StockQuoteSoap stockClient = stockChannelFactory.CreateChannel();

GetQuoteResponse stockResponse = stockClient.GetQuote(new GetQuoteRequest { Body = new GetQuoteRequestBody { symbol = "MSFT" } });

Console.WriteLine(stockResponse.Body.GetQuoteResult);

stockChannelFactory.Close();

Configuration weatherConfiguration = ConfigurationManager.OpenMappedExeConfiguration(new ExeConfigurationFileMap { ExeConfigFilename = @"C:\Temp\WeatherClient.config" }, ConfigurationUserLevel.None);

ConfigurationChannelFactory<GlobalWeatherSoap> weatherChannelFactory = new ConfigurationChannelFactory<GlobalWeatherSoap>("GlobalWeatherSoap", weatherConfiguration, null);

GlobalWeatherSoap weatherClient = weatherChannelFactory.CreateChannel();

GetWeatherResponse weatherResponse = weatherClient.GetWeather(new GetWeatherRequest { Body = new GetWeatherRequestBody { CityName = "Paris", CountryName = "France" } });

Console.WriteLine(weatherResponse.Body.GetWeatherResult);

weatherChannelFactory.Close();

In this example, two separate client configuration files are located at C:\Temp\StockClient.config and C:\Temp\WeatherClient.config and we’re able to use both in the very same method! For each service, we first load up a configuration object, then pass that configuration object to the constructor for ConfigurationChannelFactory, and finally call the service and print out the results. It's that easy.

Comments

  • Anonymous
    February 28, 2011
    Good stuff.  Could you also indicate how this is to be used in conjunction with ClientBase<TChannel>, which svcutil-generated code uses?  Thanks.

  • Anonymous
    December 25, 2012
    If i give pass ExeConfigFilename as string,please find the code below Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(new ExeConfigurationFileMap() { ExeConfigFilename = path }, ConfigurationUserLevel.None); It throws error "An unexpected error occurred in 'ClientConfigurationHost::Init'." It work fine for the below code Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(new ExeConfigurationFileMap { ExeConfigFilename = @"D:test.config" }, ConfigurationUserLevel.None);

  • Anonymous
    September 03, 2013
    Do you also know of a way to have the <system.serviceModel><diagnostics><endToEndTracing .../>/>/> taken from somewhere other than app/web.config?  Our current project has an Excel plugin which calls out to our WCF service and I want to flow ActivityID across that call via propagateActivity="true", but I can't go creating/messing with Excel.exe.config.  So instead I want to enable this from a central config (like we have done using ConfigurationChannelFactory for the client/service config), or programmatically. Any suggesions?

  • Anonymous
    November 02, 2013
    This is very useful. I am writing in C#. I used your above code but am still having a problem when I call the newConfigurationChannelFactory: ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();            fileMap.ExeConfigFilename = "app.config";            Configuration newConfiguration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);            ConfigurationChannelFactory<IAlgorithm1> factory = new ConfigurationChannelFactory<IAlgorithm1>("WSHttpBinding_IAlgorithm1",                                    newConfiguration, new EndpointAddress("http://localhost:8000/TechnicalAnalysis/Algorithm1"));            IAlgorithm1 algo = factory.CreateChannel(); I get the error message when it gets to the factory code:    ConfigurationChannelFactory<IAlgorithm1> factory = new ConfigurationChannelFactory<IAlgorithm1>("WSHttpBinding_IAlgorithm1",                                    newConfiguration, new EndpointAddress("http://localhost:8000/TechnicalAnalysis/Algorithm1")); I get the following error: Could not find endpoint element with name 'WSHttpBinding_IAlgorithm1' and contract 'IAlgorithm1' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this name could be found in the client element. Am wondering whether the client generated code (which I originally generated with a config file using svcutil) needs to be changed. Any ideas? Thanks!

  • Anonymous
    October 06, 2014
    stackoverflow.com/.../convert-web-service-configuration-to-code