Thursday, February 14, 2013

WCF. Fighting your way through a proxy.

Recently I discovered that my desktop tool for memorizing English words doesn't work when a client is behind a proxy.

The problem was pretty common and I quickly found this awesome answer on stackoverflow. But still there were a few things to deal with:
1. Move all those hardcoded strings to config files.
2. Define proxy usage per binding.
3. Test the application.

First might be easily accomplished using ConfigurationManager class. Here is the code I got:

using System;
using System.Configuration;
using System.Net;
using log4net;

namespace VX.Desktop.Infrastructure
{
    public class CustomProxy : IWebProxy
    {
        private const string CustomProxyAddressKey = "CustomProxyAddress";
        private const string CustomProxyUserKey = "CustomProxyUser";
        private const string CustomProxyPassword = "CustomProxyPassword";

        private readonly ILog logger = LogManager.GetLogger(typeof (CustomProxy));
        
        public Uri GetProxy(Uri destination)
        {
            var proxyAddress = ConfigurationManager.AppSettings[CustomProxyAddressKey];
            if (string.IsNullOrEmpty(proxyAddress))
            {
                logger.Error("Error retrieving CustomProxyAddress from configuration file. Make sure you have a corresponding key in appSettings section of application config file.");
                return null;
            }
            
            logger.InfoFormat("Proxy address: {0}", proxyAddress);
            return new Uri(proxyAddress);
        }

        public bool IsBypassed(Uri host)
        {
            logger.InfoFormat("IsBypassed for host: {0} is false", host);
            return false;
        }

        public ICredentials Credentials
        {
            get
            {
                logger.InfoFormat("Getting proxy credentials");
                string userName = ConfigurationManager.AppSettings[CustomProxyUserKey];
                string password = ConfigurationManager.AppSettings[CustomProxyPassword];
                logger.InfoFormat("Done. {0}", userName);
                if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password))
                {
                    logger.Error(
                        "Error retrieving proxy credentials from configuration file. Make sure you have corresponding keys in appSettings section of application config file.");
                }

                return new NetworkCredential(userName, password);
            }
            set { }
        }
    }
}

Nice ways of addressing the second and the third issues are described here.
So we should use something like:

<bindings>
    <basicHttpBinding>
        <binding name="myBindingWithProxy" useDefaultWebProxy="true" />
    </basicHttpBinding>
</bindings>
instead of
<defaultProxy enabled="true" useDefaultCredentials="false">
  <module type = "SomeNameSpace.MyProxy, SomeAssembly" />
</defaultProxy>

Now we can use other bindings without any proxies. And to test all this stuff we can use a great tool - Fiddler. Just check the Rules -> Require Proxy Authentication option and you're done.

No comments:

Post a Comment