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.

More js plugin fun, this time with with google maps

by MikeHogg 6. September 2012 09:40

I don't believe I've written this up anywhere and it might be useful to refer to in the future...  I did a rather extensive page in vb aspnet webforms that included mapping several markers on a google map.  Several lessons learned throughout.  Here is the mature code...

 

I was told to use a ListView control, and they wanted paging, so I hooked up the DataPager control to that, but they wanted the map to show everything in the list, not just the displayed page, so I just included a separate hidden listview, with my required data elements (all of them), no paging.  The data is a list of cars, each with a zip code as the sole location data.  I was to use this limited info to create markers for each car on the map.   Oh and the data was in a foreign language  :)  Everything else about the List should be standard here...

 

Added to the bottom of the html in this case...

<script language="javascript" type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=AIsomething&sensor=false"></script>
 <!-- deploy this script AFTER the maps api-->
 <script language="javascript" src="../_scripts/google-maps-3-vs-1-0.js" type="text/javascript"></script>
 <script language="javascript" type="text/javascript">
  var map; 
  var cars;
  var infowindow;
  var rollovers = [];
  var latlngprocessed = [];
  
  function init() {
   var mapOptions = {
    center: new google.maps.LatLng(51.55, 4.28), // default center
    zoom: 7,
    mapTypeId: google.maps.MapTypeId.ROADMAP
   };
               
   map = new google.maps.Map($("#CVMap")[0], mapOptions); 
 
   cars = getAllCars();
 
   $(cars).each(function () {
       if (!latLngAlreadyProcessed(this)) {                
           //  it's likely there exists more than one car at a particular latlng           
           var allmatches = getAllMatches(this);
 
           var image = new google.maps.MarkerImage('../_css/img/org_dwn_arrow.png',
                      new google.maps.Size(17, 19),
                      new google.maps.Point(0, 0),
                      new google.maps.Point(0, 19));
           var shadow = new google.maps.MarkerImage('../_css/img/org_dwn_arrow.png',
                      new google.maps.Size(40, 19),
                      new google.maps.Point(0, 0),
                      new google.maps.Point(0, 19));
           var shape = { coord: [1, 1, 1, 17, 19, 17, 19, 1],  type: 'poly' };
 
           var marker = new google.maps.Marker({
               map: map,
               position: getGoogleLatLng(this),
               shadow: shadow,
               icon: image,
               shape: shape,
               title: allmatches.length > 1 ? (allmatches.length) + ' cars' : this.titlelink.text
           });
 
           centerMap(allmatches);
           createInfoWindow();
 
           var $rollovercontent = $('<div class="carrollover" id="CarRollover"><h1></h1><ul></ul></div>');
           $.each(allmatches, function (idx, val) {
               var $item = $('<li></li>').html($(val.titlelink).clone())
        , $title = $('h1', $rollovercontent);
               if ($title.text() == '') {
                   $title.text('Cars in ' + val.location);
               }
               $('ul', $rollovercontent).append($item);
           });
 
           // closure and a separate array of rollovercontent needed here, because there is only one infowindow per map
           var i = rollovers.length; // get before push so we have index for closure below
           rollovers.push(getStringFromJqueryObject($rollovercontent));
 
           google.maps.event.addListener(marker, 'mouseover', (function (mark, idx) {
               return function () {
                   infowindow.setContent(rollovers[idx]);
                   infowindow.open(map, mark);
                   $('#CarRollover').parent().css('overflow-x', 'hidden');
                   setTimeout(function () {
                       $fix = $('#CarRollover').parent().parent();
                       $fix.css({'top' : '28px'});
                   }, 200);
               };
           })(marker, i));
       }
   });
  }

 

The closure is nothing more than creating distinct function instances on the fly for each rollover, since google maps only have one InfoWindow, we need to replace the content of it with that particular marker's info.  Also we merge info so a marker with several cars sharing the same zip code would show as a list of links.

The rest is just some standard helper jQuery-fu functions.

 

function centerMap(allmatches) { // to first in resultslist
      if ($.grep(allmatches, function (v) { return v.index == 0; }).length > 0) {
          map.setCenter(getGoogleLatLng(allmatches[0]));
      }
  }
 
  function createInfoWindow() {  // if not already created (google says only one per map)
      if (!infowindow) {
          infowindow = new google.maps.InfoWindow({
              maxWidth: 400
          });
      }
  }
  function getAllCars() {  
      var titlelinks = $("#hiddenformap .nameformap");
      var descriptions = $("#hiddenformap .shortdescriptionformap").map(function () { return $(this).text(); }).get();
      var locations = $(".hiddenlocationformap").map(function () { return $(this).text(); }).get();
      var latlngs = $(".hiddenlatlngformap").map(function () { return $(this).text(); }).get(); 
      var result = [];
      $.each(latlngs, function (idx, val) {
          if (val != '') {
              result.push({  
                        'index': idx,
                  'location': locations[idx],
                  'latlng': val,
                  'titlelink': titlelinks[idx],
                  'description': descriptions[idx]   });
          }
      });
   return result;
  }
 
  function getAllMatches(car) {
      return $.merge($.grep(cars, function (c) { return car.latlng == c.latlng && c != car; }), [car]);
  }
 
  function getGoogleLatLng(car) {
      return new google.maps.LatLng(car.latlng.split(",")[0], car.latlng.split(",")[1]);
  }
 
  function getStringFromJqueryObject(obj) {
      return $('<div>').append($(obj).clone()).html();
  }
 
        function latLngAlreadyProcessed(car) {
            var result = $.grep(latlngprocessed, function (ll) {
                return ll == car.latlng;
            }).length > 0;
            if (result == false) { latlngprocessed.push(car.latlng); }
            return result;
        }
One other thing to mention was that I was querying google for latitude and longitude and storing it server side, so as not to pound their geolocation service, as they requested in terms of service and by applying a few different limits.  So rather than sending zipcode (if you read the code above notice it should not send zip) it sends latlng which it already has.  Here is the server side code for google's geo service (note my XML library calls, which I now replace with 3.5 xml literals [yay] since I just found out about them)...

 

 

Private Function GetGoogleLatLng(ByVal c As Car, ByVal trynumber As Int16) As String
        Dim url As String = String.Format("http://maps.googleapis.com/maps/api/geocode/xml?sensor=false&address={0}", HttpUtility.HtmlEncode(j.FunctionLocationPostalCode))
        Dim x As XDocument = XDocument.Load(url)
        Dim s As XElement = x.Descendants("status")(0)
        If s Is Nothing Then
            'Logging.Log.
            Return String.Empty
        End If
 
        If s.Value = "OVER_QUERY_LIMIT" And trynumber < 4 Then
            System.Threading.Thread.Sleep(500) ' this sucks but what else can I do, actually it works well with google
            trynumber += 1
            Return GetGoogleLatLng(c, trynumber)
        End If
 
        Dim e As XElement = x.Descendants("geometry").Elements("location")(0)
        If Not e Is Nothing Then
            Return String.Format("{0},{1}", Xml.GetField(e, "lat", 25), Xml.GetField(e, "lng", 25))
        Else : Return String.Empty
        End If
 
    End Function 

 

 

BTW PS...

 

Want intellisense for your google. namespace?

 

I added this to the top of my usercontrol above

 

<%-- 
<% #if (false) %>
 <script src="../_scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
<% #endif %>
--%>
 

Tags:

Javascript | JQuery

Urls are not strings

by MikeHogg 2. September 2012 09:39

The idea occurred to me recently, that in a web project, if I do a ctrl F for "http://" and find anything that wasn't a third party link, then I might want to take a look at the way I perceive Urls.  There are two main concepts that occur to me at the same time.  The first is that my web project should be able to replicate every feature on every environment (with blue moon exceptions) including on my local machine in debug mode.  So easy stuff like every link should work, and I shouldn't have to worry about clicking any links in special places that might take me to, for instance, the production version of the site.  The Second premise for this, is that I remember reading through some .net framework intellisense, and finding that Uri is a full fledged class (not just another string), so the capability exists to do much more with it, and in web/mvc projects, links seem to me to be more than just strings, they are like... method calls if you will, on controller actions.

 

How would I go about using this idea?  On Application Startup, set a static HOSTNAME, PORT, SCHEME, whatever you intend to do with links, from webconfig (post transform), and then craft your Uris with that, handling specific ports (are you setting Cassini to use the same port on debug? there is a use for that).  the UriBuilder let's you craft every part of the url dynamically, instead of having to use one long hard coded string over and over. Wrap the specific functionality you need in a static class (one or two methods like GetSSLUrl(pathname) and GetNonSSLUrl(pathname)) and you can go back to writing one liners for your links, and even use them in razor templates. There is just so much in the Uri class that you should be able to handle all kinds of situations, with strong typed code, and have everything testable, 'inside the box', meaning write it once and never have to worry about it again.  "Will those links work on that page?"  "Will they work on that server?"  "when I change X, when I turn on SSL, when I send them in an email, when I publish to a new build server?"  Promote your hardcoded links to Uri's and - write it once and never have to worry about it again.

 

Migrating to your UAT host should be painless and all the links will now magically point to httporhttpsScheme://myuathost/:optionalport/urlstringhere.whatever.ext and migrating to your production host should be the same.  Want to set up a third environment to test some branch?  Just add the transforms.

Tags:

Architecture

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