Changing WCF Service reference URL based on environment

10,610

Solution 1

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.

Solution 2

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.

Solution 3

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

Share:
10,610
Richard Ev
Author by

Richard Ev

Creator of things Learner of stuff Helper of others Once fended off an elephant with a laptop * * my laptop, not the elephant's

Updated on June 13, 2022

Comments

  • Richard Ev
    Richard Ev almost 2 years

    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
  • Richard Ev
    Richard Ev about 15 years
    I really need an option that requires zero config file changes between environments...
  • Richard Ev
    Richard Ev about 15 years
    Do you use any WCF Services that require X509 certificates?
  • Bigtoe
    Bigtoe about 15 years
    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.