Using ErrorHandlers and singletons in WCF

by MikeHogg 19. September 2012 20:16

I had a COM wrapper that I wrote for a third party interface.  I knew I was going to use it not only in a desktop application, but also in our web application and our vendor’s web application, and also possibly further down the road in a mobile application, so I wrote a WCF web service that implemented my wrapper’s functionality rather than drop that project in multiple solutions. 

Writing the web service is easy enough.  For years in Visual Studio you can just create a WCF Project and figure out some options and add some classes.  For options you choose between NetTcp or Http binding. I have used NetTcp in intranet scenarios, but in this case I needed HttpBinding, so I could choose WS or Basic.  As WS doesn’t easily work with non .Net clients I chose Basic for this case, although I later found out this didn’t help me with my mobile client as I expected. 

The other option you usually always have to figure out is your authentication.  In this case I used basic forms authentication over https, so my service model was really simple.  I have set up services that implemented X509 client certificates, but it can be complicated and this project didn’t need that layer of security. 

 <system.serviceModel>
    <extensions>
      <behaviorExtensions>
        <add name="ErrorLogging" type="My.lib.WCF.ErrorHandlerBehavior, Mylib" />
      </behaviorExtensions>
    </extensions>
    
    <services>
      <service name="SomeSN.SomeService">
        <endpoint  binding="basicHttpBinding"
          bindingConfiguration="SSWebBinding" contract="SomeSN.ISomeService"/>
      </service>
    </services>
    <bindings>
      <basicHttpBinding>
        <binding name="SSWebBinding" sendTimeout="00:02:00">
          <security mode="TransportWithMessageCredential">
            <message clientCredentialType="UserName"/>
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <ErrorLogging/>
          <serviceCredentials>
            <userNameAuthentication userNamePasswordValidationMode="Custom"
              customUserNamePasswordValidatorType="Some.CustomPasswordValidator, Some" />
          </serviceCredentials>
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
If I remember right I needed to make MultipleSiteBindingsEnabled in this case for our IIS servers having other webs running. 

 

You will see at the bottom I added my ErrorHandling behavior, and my custom password validator, which was basically my password interface, in this case pointing just to the config files.

    class CustomPasswordValidator : System.IdentityModel.Selectors.UserNamePasswordValidator
    {
        public override void Validate(string userName, string password)
        {
            string[] serviceusernames = My.lib.ConfigHelper.GetAppSetting("SOME_USER", (string)null).Split(new char[]{ ';'});  //  quick solution to user mgmt assuming we only ever have two users (our website and our vendor's website) and they can share a password
            string servicepassword = My.lib.ConfigHelper.GetAppSetting("SOMe_PASS", (string)null);
            if ( !serviceusernames.Contains(userName) || String.IsNullOrEmpty(password) || !password.Equals(servicepassword) )
                throw new System.ServiceModel.FaultException("Authentication failed."); // this will just get wrapped by a messagesecurityexception an kick em out
        }
    }

 

The ErrorHandler was an interesting case, as it came up in my testing.  My COM component would fail occasionally, and it was expected to pass meaningful error messages.  I built the wrapper to fail also and pass these messages as exceptions, but when the Web Service would throw exceptions, it would just replace my meaningful messages with a general SOAP exception, and then freeze up the server to more incoming requests, which was very bad.  So I had to figure out a way to preserve those messages (easy if I turn them into messages instead of exceptions but my stack was built to use these exceptions already and this would mean lots of extra code for what I really intended to be exceptional) and not break the service, which wasn’t easy (don’t throw SOAPExceptions).  Here I just implement the Interfaces and the important part is in returning true in HandleError and in creating my MessageFault from my wrapper exceptions in ProvideFault…

    public class ErrorHandler : IErrorHandler, IServiceBehavior
    {
        public bool HandleError(Exception error)
        {
            // Logger.LogError(error);  
            return true;
        }
        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
            FaultException faultException = new FaultException(error.Message);
            MessageFault messageFault = faultException.CreateMessageFault();
            fault = Message.CreateMessage(version, messageFault, faultException.Action);
        }
        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<System.ServiceModel.Description.ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        { 
        }
        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            IErrorHandler errorHandler = new ErrorHandler();
            foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
            {
                ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
                channelDispatcher.ErrorHandlers.Add(errorHandler);
            }
        }
        public void Validate(System.ServiceModel.Description.ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
        { 
        }
    }
    class ErrorHandlerBehavior : System.ServiceModel.Configuration.BehaviorExtensionElement
    {
        public override Type BehaviorType
        {
            get
            {
                return typeof(ErrorHandler);
            }
        }
        protected override object CreateBehavior()
        {
            return new ErrorHandler();
        }
    }

With that I could now leave my exceptions as exceptions, and my stack would bubble up as expected, even across WCF to the client, with my meaningful messages, without freezing my channels.

The rest of my Service was simple also, a handful of OperationContracts, not even passing complex classes, except one IEnumerable<MyCustomType>.  And my Server class was also too simple to even post, since it was just a call to my COM wrapper for each web service method.  But the instantiation and initialization of the COM component and the wrapper was time intensive.  It took a few to ten seconds to create it and get it ready for use. So I wanted a way to create the wrapper once, and then use it over and over for each request, so I used a singleton pattern…

    // This class is so we can spin up one instance to handle a number of requests at once.  
    // In practice, it appears IIS will keep it in memory for a short length of time, like for several calls on one page, 
    // but it seems to dispose of it after a few minutes.... would like to investigate further...
    public sealed class MySingletonWrapper
    {
        MyWrapperClient.AdaptorClient _client; 
        static MySingletonWrapper _client = null;
        static readonly object padlock = new object();
        public static MySingletonWrapper Client
        {
            get
            {
                lock (padlock)
                {
                    if (_client == null)
                    {
                        _client = new MySingletonWrapper();
                    }
                    return _client;
                }
            }
        }
        MySingletonWrapper()
        {
            _client = GetMyWrapperClient(); 
        }
        /// <summary>
        /// initializes and prepares for transactions using properties from config file
        /// </summary>
        /// <returns></returns>
        MyWrapperClient.AdaptorClient GetMyWrapperClient(string somewireid = null, string anotherid = null, string anybodyskeyid = null)
        {
            string primary = My.lib.ConfigHelper.GetAppSetting("SS_PrimaryUrl", "https://somedomain.com/urlforsomething");
			string secondary = My.lib.ConfigHelper.GetAppSetting("SS_SecondaryUrl", "https://somedomain.com/urlforsomething");
            string whatid = My.lib.ConfigHelper.GetAppSetting("SS_MerchantId", "2323232323232323");
            if (String.IsNullOrEmpty(anotherid)) terminalid = My.lib.ConfigHelper.GetAppSetting("SS_TerminalId", "00000000001");
            if (String.IsNullOrEmpty(somewireid)) datawireid = My.lib.ConfigHelper.GetAppSetting("SS_SomeWireId", "12121212121212121212");
            if (String.IsNullOrEmpty(anybodyskeyid)) merchantkeyid = My.lib.ConfigHelper.GetAppSetting("SS_AnybodyskeyId", "2222222");
            string arefnum = My.lib.ConfigHelper.GetAppSetting("SS_ARefNum", "55555555"); 
            string whatkingkey = My.lib.ConfigHelper.GetAppSetting("SS_WhatKingKey", "88883333888833333888883333338888888333333");
            return new MyWrapperClient.AdaptorClient(primary, secondary, whatidid, anotherid, arefnum, somewireid, anybodyskeyid, WhatKingkey);
        }
        public IEnumerable<Transaction> GetTransHistory(string cardnumber, string pin)
        {
            List<Transaction> result = new List<Transaction>();
            foreach (MyWrapperClient.FSSransaction t in _client.GetTransactionHistory(cardnumber, pin)) result.Add(new Transaction(t)); }
            return result;
        }

 

This sped up my requests to sub-second times, although note where I found in IIS 7.5 there was some automatic memory management going on… something to look into for next time.

Exception Handling and Canceling Background Threads

by MikeHogg 11. March 2009 13:08

I read once the idea that Exceptions should only be caught if you can handle them, and this makes sense to me.  Besides a Top level, uncaught exception handler for client facing applications, I usually avoid the try catch blocks unless I am going to do something specific at that point in the code.  I wrote  a database monitor that was used to continually run in a Windows Service and involved several factors that called for robust program recovery- database timeouts, file I/O, multi threaded operations. So there were specific failures that I knew about and could write around.  Here are some of the routines:

}
                else
                {
                    myTimer.Dispose();
                    e.Result = filename;
                }
                try
                { 
                    DataTable myTable = new DataTable();
                    myTable.ExtendedProperties["filename"] = filename;
                    myAdp.Fill(myTable);
                    e.Result = myTable;
                    if (bw.CancellationPending)
                    {
                        e.Result = filename;
                        e.Cancel = true;
                        myTimer.Dispose();
                    }
                }
                catch (OracleException ex)
                {
                    logThis(ex.ToString(), EventLogEntryType.Warning);
                    e.Result = filename;  //move on
                }
                catch (Exception ex)
                {
                    logThis(ex.ToString(), EventLogEntryType.Error);
                    throw;
                }
                finally
                {
                    if (myAdp.SelectCommand.Connection.State == ConnectionState.Open)
                    {
                        myAdp.Dispose();
                    }
                    myTimer.Dispose();
                }

In this case we are pinging a database batch process every few minutes, and occasionally we might get a timeout, but we don’t want to bring the whole Service down, because it also monitors other data sources, and we can try again in a few minutes and find the same database is now responsive.  The end result of a timeout might be a blip on a graph or chart, or a yellow light on a status gauge, that turns green if the database comes back and turns red the longer it has been since the database was responsive.

Here we are storing our ping result info in local xml files.  In retrospect, there may have been easier options, but this allows us to add monitored sources dynamically, and manage the XML files dynamically, rather than have to create them in a database ahead of time.  I wrote in a level of tolerance for concurrent file access Reads and Writes just using sleep and loops and it works perfectly for this case.  Once again, we don’t need a perfect level of detail since we are running every few minutes.   An occasional lost entry does not get noticed.

        private void saveXML(XElement myRoot, string filename)
        {
            int retrySave = 10;
            while (retrySave > 0)
            {
                try
                {
                    myRoot.Save(filename);
                }
                catch (IOException exIO)
                {
                    Thread.Sleep(1000);
                    retrySave--;
                    continue;
                }
                break;
            } 
        }
        private XElement loadXML(string filename)
        {
            XElement myRoot = null;
            using (FileStream myStream =
                new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                int retryLoad = 10;
                while (retryLoad > 0)
                {
                    try
                    {
                        using (XmlReader xr = XmlReader.Create(myStream))
                        {
                            myRoot = XElement.Load(xr);
                        }
                    }
                    catch (XmlException x)
                    {
                        // we expect some rootElement is missing ... from other threads
                        retryLoad--;
                        Thread.Sleep(1000);
                        continue;
                    }
                    break;
                }
            }
            return myRoot;
        }

One of the other features of this monitor, was that we would run against an unknown number of data sources, and they weren’t related.  Each source was separate, and so threading out the pings was simple, but some datasources acted differently than others.  Oracle TNS Listener would simply not return if there was no database endpoint, and so we had to run another thread using the Timer to cancel our thread in case this happened. I think at the time I put this together, a parallel concurrency library had just come out, but wasn’t officially part of .Net, or it wasn’t out and so up to this point most of the threading projects I did and I researched were all done with BackgroundWorkers.

private void dbMonStart(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker bw = sender as BackgroundWorker;
            String db = e.Argument.ToString();
            // set a watch timer to cancel thread on sql timeout (used more for dev when taken offline not prod
            System.Threading.Timer myTimer = new System.Threading.Timer(cancelMyThread, bw, 30000, System.Threading.Timeout.Infinite);
            using (OracleDataAdapter myAdp = new OracleDataAdapter())
            {
                myAdp.SelectCommand = cmd;
                myAdp.SelectCommand.Connection = new OracleConnection(conn);
                try
                {
                    DataTable myTable = new DataTable();
                    myTable.ExtendedProperties["dbname"] = db;
                    myAdp.Fill(myTable);
                    e.Result = myTable;
                    if (bw.CancellationPending)
                    {
                        e.Result = db;
                        e.Cancel = true;
                        myTimer.Dispose();
                    }
                }

 

CancelMyThread is simple enough:

private void cancelMyThread(object myThread)
        {
            BackgroundWorker bw = myThread as BackgroundWorker;
            if (bw.IsBusy) { bw.CancelAsync(); }

 

and that’s it.

About Mike Hogg

Mike Hogg is a c# developer in Brooklyn.

More Here

Favorite Books

This book had the most influence on my coding style. It drastically changed the way I write code and turned me on to test driven development even if I don't always use it. It made me write clearer, functional-style code using more principles such as DRY, encapsulation, single responsibility, and more. amazon.com

This book opened my eyes to a methodical and systematic approach to upgrading legacy codebases step by step. Incrementally transforming code blocks into testable code before making improvements. amazon.com

More Here