Thursday, November 01, 2007 3:19 AM
I need to be able to initialise a ServiceHost that uses two different binding configurations; one for normal network operation and one for standalone demo operation. Essentially I need to be able to run our application on a laptop for demonstration purposes. But it normally uses Windows authentication and therefore needs to be on a domain. I would like to be able to startup the client and server with a "/standalone" switch that would select alternative binding configurations that do not use Windows auth.
On the client, this is easy as I can specify an alternative binding endpoint configuration name that uses a different binding configuration when creating the proxy.
I haven't found a way to do this on the server when creating the ServiceHost. I would like to create a ServiceHost and specify which endpoint configuration to use from App.config. I want to leave the endpoint and behaviour configuration in the App.config file rather than code it
Is this possible?
Thursday, November 01, 2007 2:42 PM
The easy way to do this is to have the /standalone option parsed before the ServiceModel host comes up. Assuming the following services config,Code Block
This code will setup things correctly for your application (I recommend putting this as the first thing that happens in your Main method):Code Block
Configurationconfig = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
ServiceModelSectionGroupsectionGroup = ServiceModelSectionGroup.GetSectionGroup(config);
stringregularServiceName = typeof(TestService).FullName;
stringintegratedServiceName = regularServiceName + ".Integrated";
stringstandaloneServiceName = regularServiceName + ".Standalone";
// First, normalize the name in config.
sectionGroup.Services.Services[regularServiceName].Name = standaloneServiceName;
}else if (sectionGroup.Services.Services.ContainsKey(standaloneServiceName))
sectionGroup.Services.Services[regularServiceName].Name = integratedServiceName;
}// else, we have never changed the name, so we are OK.
if(args.Length > 0 && string.Compare(args, "/standalone") == 0)
sectionGroup.Services.Services[standaloneServiceName].Name = regularServiceName;
sectionGroup.Services.Services[integratedServiceName].Name = regularServiceName;
Monday, November 12, 2007 4:02 AM
So your solution is basically modifying the config file before it is actually used. Neat but a little scary!
Is the config.Save() necessary? Would this actually write out any config changes? I know it will write user settings which is ok
Monday, November 12, 2007 12:46 PMThe Save is necessary and does write out config changes. The Configuration object has its own copy of the config file which is NOT shared with the ConfigurationManager.GetSection(string) method/infrastructure.
Monday, November 12, 2007 5:32 PM
- another option for your solution is to create one more config file for your demo. In order having this configuration from this file, the method ApplyConfiguration in the ServiceHost must be overrided. The following code snippet is an example of this implementation:Code Block
protected override void ApplyConfiguration()
// workaround for passing a custom configFilename
string configFilename = (string)CallContext.GetData("_config");
ExeConfigurationFileMap filemap = new ExeConfigurationFileMap();
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile : configFilename;
Configuration config =
ServiceModelSectionGroup serviceModel = ServiceModelSectionGroup.GetSectionGroup(config);
foreach (ServiceElement se in serviceModel.Services.Services)
if (se.Name == this.Description.ConfigurationName)
throw new ArgumentException("ServiceElement doesn't exist");
Note, the ServiceHost is calling an override method (what is not a good pattern) in the constructor, therefore the value of the custom config path is passed via the thread context. If the context doesn't exist, the default application config file is used.
Other option to avoid using the thread context is using a hard coded extension for your second config file, for instance .democonfig.