Archives

Archives / 2007 / October
  • Loading the WCF configuration from different files on the client side

    A common problem in WCF that many people face is the impossibility of loading the client configuration from different configuration files. This is a common scenario  when the developer wants to deploy some binaries with along with an independent configuration file (Which may be in a resource file also) to avoid modifying the main configuration file. A weeks ago, I described a easy workaround to use the external configuration files through the use of the configSource attribute (A mechanism provided by .NET). However, that approach requires several configuration files to configure an entire WCF channel, at least three files (client section, bindings and behaviors).

    Another approach, which is less common and I will describe in this post, requires some custom code to extend the ChannelFactory<T> class.

    The ChannelFactory<T> provides a virtual method "CreateDescription" that can be overridden to create a ServiceEndpoint.

     

    //

    // Summary:

    //    Creates a description of the service endpoint.

    //

    // Returns:

    //    The System.ServiceModel.Description.ServiceEndpoint of the service.

    //

    // Exceptions:

    //   System.InvalidOperatorException:

    //    The callback contract is null but the service endpoint requires one that

    //    is non-null.

    protected override ServiceEndpoint CreateDescription();

    The default implementation of this method basically tries to load the endpoint configuration from the default configuration file (The file configured for the default AppDomain). So, the workaround here is to override that method and load the configuration from another file. It seems to be pretty easy to do at first glance, but as you will see next, it requires a lot of plumbing code to make it work.

    The first step is to derive our custom channel class from the ChannelFactory<T> class and add an argument in the constructor to specify a different configuration file.

    /// <summary>

    /// Custom client channel. Allows to specify a different configuration file

    /// </summary>

    /// <typeparam name="T"></typeparam>

    public class CustomClientChannel<T> : ChannelFactory<T>

    {

      string configurationPath;

     

      /// <summary>

      /// Constructor

      /// </summary>

      /// <param name="configurationPath"></param>

      public CustomClientChannel(string configurationPath) : base(typeof(T))

      {

        this.configurationPath = configurationPath;

        base.InitializeEndpoint((string)null, null);

      }

    As you can see, a call to the method InitialiazeEndpoint of the base class is required. That method will automatically call to our CreateDescription method to configure the service endpoint.

    /// <summary>

    /// Loads the serviceEndpoint description from the specified configuration file

    /// </summary>

    /// <returns></returns>

    protected override ServiceEndpoint CreateDescription()

    {

       ServiceEndpoint serviceEndpoint = base.CreateDescription();

     

       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)

          {

            selectedEndpoint = endpoint;

            break;

          }

        }

     

        if (selectedEndpoint != null)

        {

          if (serviceEndpoint.Binding == null)

          {

            serviceEndpoint.Binding = CreateBinding(selectedEndpoint.Binding, group);

          }

     

          if (serviceEndpoint.Address == null)

          {

            serviceEndpoint.Address = new EndpointAddress(selectedEndpoint.Address, GetIdentity(selectedEndpoint.Identity), selectedEndpoint.Headers.Headers);

          }

     

          if (serviceEndpoint.Behaviors.Count == 0 && selectedEndpoint.BehaviorConfiguration != null)

          {

            AddBehaviors(selectedEndpoint.BehaviorConfiguration, serviceEndpoint, group);

          }

     

          serviceEndpoint.Name = selectedEndpoint.Contract;

        }

     

        return serviceEndpoint;

     

    }

     

    CreateDescription is the core method where we create the service endpoint using the configuration file specified in the constructor method.

    And the last step, is to use our custom channel in the client application instead of the base channel provided by WCF.

    CustomClientChannel<ICalculator> channel = new CustomClientChannel<ICalculator>("OtherConfig.config");

    ICalculator client = channel.CreateChannel();

    The code below uses the ICalculator contract  that comes with the WCF sdk samples.

    You can download the complete sample here

     

     

     

    Read more...

  • Clarius is Hiring!!!

    Want to work at a growing, high energy services-software company? Clarius Consulting is looking for the candidates to help us fill the following positions:

    At Clarius we do all kind of interesting and exciting work. We help customers get up to speed with .Net by providing superb training, mentoring and consulting. We also write a lot of code. We present @ several conferences (locally and worldwide) and we write articles and books.

    Senior Software Developers.

    The position is based in Buenos Aires, Argentina (Local candidates only). Selected candidates should possess experience in many of the following disciplines:

    ASP.NET, ADO.NET
    Winforms .NET development (C#, preferably; MDI-based applications) and Webforms
    XML-related standards
    SQL Server 2000-2005
    Explicit/Implicit stored procedures.
    Web Services / .NET remoting / WCF
    COM+ / .NET interoperability
    Migration from COM+ to .NET

    If you are interested, drop me a line with your resume (pci at clariusconsulting DOT net)

    Thanks!!!.

    Read more...

  • Certificate Access Error for WCF hosted services

    The problem appears when a WCF Service hosted in an IIS tries to load a certificate from the Windows Certificates Store with the account of the Application Pool where the service runs, and the account’s profile is not previously loaded. When a user logs on interactively, the system automatically loads the user's profile. If a service or an application impersonates a user, the system does not load the user's profile. Therefore, the service or application should load the user's profile with LoadUserProfile.

    When this happens the operation throws the following exception:

    System.Security.Cryptography.CryptographicException: The system cannot find the file specified. [VIA Mariano Sanches Blog]

     

    The problem is basically related to the method that WCF uses to encrypt the Secure conversation cookie. By default, WCF encrypts the cookie using DPAPI (Current User), so the user profile should be loaded in order to use that encryption method.

    Mariano mentioned one of the workarounds, which requires to load the user's profile of the account configured in the IIS Application pool using some windows API's.

    Another workaround is to change the method used by WCF to encrypt the SCT cookie and eliminate the DPAPI dependency. An advantage of this method is that it works fine for Web Farm scenarios.

    Fortunately, WCF provides an extension to change the method used to encrypt and serialize the SCT Cookie. This extension is a SecurityStateEncoder and it can be plugged-in by code in the service host:

    serviceHost.Credentials.SecureConversationAuthentication.SecurityStateEncoder

    You can find an excellent example about how to implement a custom SecurityStateEncoder here, (WCF.Netfx3.com web site, WS-SC With State Encoder)

    Read more...

  • NullTransport for WCF

    As usual, Roman Kiss continues doing great stuffs for WCF. He has recently published a new NullTransport for WCF in CodeProject.

    This transport is really useful for In-Process communication when the client and the service run on the same windows process. Before having this transport, the recommended transport for scenario was Named pipes.

    Read more about this transport in the article he published here http://www.codeproject.com/WCF/NullTransportForWCF.asp

    Enjoy!!.

    Read more...