views:

1976

answers:

3

I have a web application that uses a number of WCF Services. I deploy my web application in various environments (dev, UAT, production etc). The URL of each WCF Service is different for each environment. I am using .NET 3.5 andbasicHttpBindings

The web application uses a framework to support machine-specific settings in my web.config file. When instantiating an instance of a WCF Service client I call a function that creates the instance of the WCF Service client using the constructor overload that takes the arguments:

System.ServiceModel.Channels.Binding binding,
System.ServiceModel.EndpointAddress remoteAddress

In essence the <system.serviceModel><bindings><basicHttpBinding><binding> configuration in web.config has been replicated in C# code.

This approach works well.

However, I now have to enhance this approach to work with a WCF service that uses an X509 certificate. This means that I have to replicate the following additional settings in web.config in C# code:

<!-- inside the binding section -->
<security mode="Message">
  <transport clientCredentialType="None" proxyCredentialType="None" realm="" />
  <message clientCredentialType="Certificate" algorithmSuite="Default" />
</security>


<behaviors>
  <endpointBehaviors>
    <behavior name="MyServiceBehaviour">
      <clientCredentials>
        <clientCertificate storeLocation="LocalMachine" storeName="My"
          x509FindType="FindByThumbprint" findValue="1234abcd" />
        <serviceCertificate>
          <defaultCertificate storeLocation="LocalMachine" storeName="My"
            x509FindType="FindByThumbprint" findValue="5678efgh" />
          <authentication trustedStoreLocation="LocalMachine"
            certificateValidationMode="None" />
        </serviceCertificate>
      </clientCredentials>
    </behavior>
  </endpointBehaviors>
</behaviors>

I am having some difficulty figuring out how to code this configuration in C#.

Two questions

  • Can anyone recommend a better approach for managing WCF Service reference URLs across multiple environments?
  • Alternatively, any suggestions on how to replicate the above web.config section in C# will be welcomed
+2  A: 

One possible approach would be to "externalize" certain parts of your <system.serviceModel> configuration into external files, one per environment.

E.g. we have "bindings.dev.config" and "bindings.test.config", which we then reference in our main web.config like this:

<system.serviceModel>
  <bindings configSource="bindings.dev.config" />
</system.serviceModel>

That way, all you need to change from DEV to PROD is this one line of config XML.

Basically, in .NET 2.0 config, any configuration element can be "externalized". You cannot however externalize configGroups (such as "system.serviceModel") directly - you have to be on the "configuration element" level.

Marc

EDIT: OK, so NO config edit changes to switch between environments..... In that case, you probably have to dream up a naming scheme, e.g. name your bindings, behaviors and endpoints in such a way, that you can distinguish them at runtime.

Something like:

<bindings>
  <binding name="Default_DEV">
    .....
  </binding>
  <binding name="Default_PROD">
    .....
  </binding>
</bindings>

that way, you could build up the name of the element you want (e.g. binding "Default_PROD") from your code and the environment you're running in, and then grab the according config from the config file which contains all the config settings for all environments.

marc_s
I really need an option that requires zero config file changes between environments...
Richard Ev
A: 

We don't use web.config files at all, we specify everything programitically and load all configuration from a centralised database.

Bigtoe
Do you use any WCF Services that require X509 certificates?
Richard Ev
Sorry no, but we do have varying options and types of bindings we support net.tcp, basicHttp, WS*). Depending on the URL, we lookup different configurations in the database and dynamically configure as appropriate. It's relatively straight forward and does away with loads of configuration. We can also deploy to a web-farm environment and allow it to be configured centrally.
Bigtoe
No problem - sounds like a good approach
Richard Ev
+1  A: 

The following code replicates the configuration in my original question:

myClient.ClientCredentials.ClientCertificate.SetCertificate(
    StoreLocation.LocalMachine,
    StoreName.My,
    X509FindType.FindByThumbprint,
    "1234abcd");

myClient.ClientCredentials.ServiceCertificate.SetDefaultCertificate(
    StoreLocation.LocalMachine,
    StoreName.My,
    X509FindType.FindByThumbprint,
    "5678efgh");

myClient.ClientCredentials.ServiceCertificate.Authentication.TrustedStoreLocation = StoreLocation.LocalMachine;
myClient.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;

In the production code the two thumbprint values are stored in appSettings in the web.config file.

Richard Ev