Learning Dependency Injection

I recently accepted a new job, its one of those jobs where everything matches your skillset, technical interests, personal home/work balance requirements, and ethical requirements. I am super excited to be working here. While I have many of the skills required for the position they are doing some things I have never done before. One of them is that they use Dependency Injection (DI) with Unity and nHibernate. I have heard of them but never looked into them before. Here is the approach I took to learning this new skill set, I had 2-3 days to figure it out before the work would start rolling in.

Step 1: Talk to my co-worker who is the project guru
First I spoke to my coworker who gave me a general overview of the system and how things are laid out, setup, and interwoven. During the overview he mentioned that it would be good if I knew more about DI before getting to deep into the code.

Step 2: Google
My next stop was Google where I found the following blog posts and websites that had some information that helped. It wasn’t enough. Because I don’t understand the basics I was completely confused.
Dependency Injection and Inversion of Control with ASP.NET MVC
ASP.NET MVC 3 Service Location, Part 1: Introduction
MSDN: Appendix A – Dependency Injection with Unity
Microsoft patterns & practices: Unity
Microsoft patterns & practices: Inject Some Life into Your Applications—Getting to Know the Unity Application Block

Step3: StackOverflow
Next I went to StackOverflow to try again.  I started looking at the posts in the dependency-injection tag and found the following gems. 
Learning inversion of control through dependency injection in MVC3
Dependency Injection book recommendations
How to explain dependency injection to a 5 year old

Step 4: Resorted to a Technical Book
In a StackOverflow post I finally found a reference to the book “Dependency Injection .NET” by Mark Seeman. Luckily the publisher has the first chapter of the book available for free on their website. Things are finally beginning to make sense. 

Step5: Book – Dependency Injection .NET
I finally just broke down and purchased the book and started to read it.  Some of it makes perfect sense and some just makes my head hurt.  I am glad I got it and find it to be very useful.  I like that it has great examples and a section on patterns. 

Step 6: Talk to my co-worker who is the project guru
Now that I have read and understood enough of the book to get the basics I will be having my coworker go over the whole thing again, in more depth this time.  Hopefully I can hit the ground running.

Dynamically generate XML based on Class Properties

I recently came across a problem where I needed to dynamically generate data for a PDF file created using Adobe Livecycle Designer. Here are the main methods that I used to loop through the relevant classes and pull out the data for the file. I created a table in the DB containing a list of all the fields from the 3 main classes that need to be included in the XML data. This is done so that in the future we can add additional fields without needing to do a release to add them.

This method will return properly formed XML data that will then be attached to the PDF file. It generates the XML by looping through the PDF, Student, and Security object and retrieving the relevant data.

internal static string GetPDFDocXMLData(int pdfTemplateId, string studentId, SSO sso)
{
   var supportedFields = PDFDocData.GetListSupportedFields();
   using (var sdc = new StudentDataClient())
   using (var db = new DatabaseContainer())
   {
      var pdf = db.PDFForms.Single(f => f.Id == pdfTemplateId);
   
      FillSupportedFields("PDFTemplate", pdf, typeof(PDFForm), supportedFields);
      if (studentId != string.Empty)
      {
         var student = sdc.GetStudentInfo(Int32.Parse(studentId));
         FillSupportedFields("StudentInfo", student, typeof(StudentInfo), supportedFields);
      }
      FillSupportedFields("SSO", sso, typeof(SSO), supportedFields);
      return CreateXML(supportedFields);
   }
}

This method loops through all the properties in the indicated class object and loads any that match the list of valid supported fields. It adds the value of the field to the PDFDocData item.

private static void FillSupportedFields(string cName, object obj, IReflect type, IEnumerable<pdfdocdata> supportedFields)
{
   var props = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);

   foreach (var item in supportedFields.Where(sf => sf.ClassName == cName))
   {
      foreach (var propInfo in props.Where(f => f.Name == item.FieldName).ToList())
      {
         item.Value = propInfo.GetValue(obj, null).ToString();
      }
   }
}

This method generates the properly formed XML string that will be used.

private static string CreateXML(IEnumerable<pdfdocdata> supportedFields)
{
   var doc = new XmlDocument();

   var dec = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
   doc.AppendChild(dec);

   var root = doc.CreateElement("form1");
   doc.AppendChild(root);

   foreach (var item in supportedFields)
   {
      var element = doc.CreateElement(item.ClassName + item.FieldName);
      element.InnerText = item.Value;
      root.AppendChild(element);
   }
   return doc.OuterXml;
}

This class looks at the DataBase and pulls the list of supported fields and populates a list containing all the information about the fields except for the value which is populated in the FillSupportedFields method.

public class PDFDocData
{
   public string ClassName { get; set; }
   public string FieldName { get; set; }
   public string Description { get; set; }
   public string Value { get; set; }
   public static List<pdfdocdata> GetListSupportedFields()
   {
      using (var db = new DatabaseContainer())
      {
         return db.PDFSupportedFields.Select(s => new PDFDocData()
                                             {
                                                ClassName = s.ClassName,
                                                FieldName = s.FieldName,
                                                Description = s.Description
                                             }).ToList();
      }
   }
}

MVC Browser Detection

Task:

For a recent project I had to look at a users browser to determine if the
browser meets our requirements. We have multiple third party sites that
we interface with and some of them do not work with certain browser
versions. One of the requirements of the project was to make it flexible
enough that a person on the tech support team would maintain the list once
we finished with it. Here is the solution that we came up with, some more
tweaks are needed but for now this is what we have deployed.

Browser Requirements:

We created an XML file that lives in the site directory on the live server.
It is able to be edited by the tech support team as needed.

  1. Supported – Allow normal login
  2. Warning – Not fully supported, post warning message, allow login
  3. Blocked – Access denied, post message, do not allow login
        <?xml version="1.0" encoding="utf-8" ?>
        <supportedbrowsers>
          <supported>
            <IE
              displayName ="Internet Explorer" MachineType="Windows" MinVersion ="9.0" MaxVersion ="9.0"
              link="http://windows.microsoft.com/en-US/internet-explorer/downloads/ie-8"
              />
            <Firefox
              displayName ="Mozilla Firefox" MachineType="Windows, Mac" MinVersion ="7.0" MaxVersion ="9.1"
              link="http://www.mozilla.com/en-US/firefox/all-older.html"
              />
            <Chrome
              displayName ="Google Chrome" MachineType="Windows, Mac" MinVersion ="10.0" MaxVersion ="16.0"
              link="https://www.google.com/chrome"
              />
            <Safari
              displayName ="Safari" MachineType="Mac" MinVersion ="5.0" MaxVersion ="6.0"
              link="http://www.apple.com/safari/download/"
              />
          </supported>
          <warning>
            <ie      MachineType="Windows" MinVersion ="8.0" MaxVersion ="8.0" />
            <firefox MachineType="Windows, Mac" MinVersion ="3.6" MaxVersion ="7.9" />
            <firefox MachineType="Windows, Mac" MinVersion ="9.2" MaxVersion ="1000" /> <!--For future versions-->
            <chrome  MachineType="Windows, Mac" MinVersion ="10.0" MaxVersion ="14.9" />
            <chrome  MachineType="Windows, Mac" MinVersion ="16.1" MaxVersion ="1000" /> <!--For future versions-->
            <safari  MachineType="Mac" MinVersion ="4.0" MaxVersion ="4.9" />
            <safari  MachineType="Mac" MinVersion ="6.1" MaxVersion ="1000" /> <!--For future versions-->
          </warning>
          <blocked>
            <ie      MachineType="Windows" MinVersion ="0" MaxVersion ="7.9" />
            <firefox MachineType="Windows, Mac" MinVersion ="0" MaxVersion ="3.5" />
            <chrome  MachineType="Windows, Mac" MinVersion ="0" MaxVersion ="9.9" />
            <safari  MachineType="Mac" MinVersion ="0" MaxVersion ="3.9" />
            <safari  MachineType="Windows" MinVersion ="0" MaxVersion ="100" />  
          </blocked>
        </supportedbrowsers>

SupportedBrowser Class:

This class contains all the logic for determining the browser requirements
based on the data in the XML file.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Xml.Linq;

namespace SSO_UI.Models
{
    public enum SupportStatus
    {
        Unknown = 0,
        Supported = 1,
        Warning = 2,
        Blocked = 3
    }

    public class SupportedBrowsers
    {
        readonly string _path = ConfigurationManager.AppSettings["SupportedBrowserPath"];

        [DefaultValue("")]
        public string BrowserName { get; set; }
        [DefaultValue("")]
        public string MachineType { get; set; }
        [DefaultValue(0)]
        public double Version { get; set; }
        [DefaultValue(false)]
        public bool IsValid { get; set; }

        /// <summary>
        /// Retrieve the message to display to the users based on the browser settings.
        /// </summary>
        public string GetMessage()
        {
            var msg = string.Empty;
            switch (SupportStatus)
            {
                case SupportStatus.Warning:
                    msg =
                        String.Format(
                            "Your web browser, {0} v{1} for {2}, is not fully supported.  Please consider downloading one of the supported browsers listed for full functionality within CampusConnect.",
                            BrowserName,
                            Version,
                            MachineType
                            );
                    break;
                case SupportStatus.Blocked:
                    msg =
                        String.Format(
                            "Your web browser, {0} v{1} for {2}, is not supported at all.  Please download one of the supported browsers listed to use CampusConnect.",
                            BrowserName,
                            Version,
                            MachineType
                            );
                    break;
            }
            return msg;
        }

        public SupportStatus SupportStatus { get; set; }

        /// <summary>
        /// Constructor to seed the class with the relevant information
        /// </summary>
        public SupportedBrowsers(HttpBrowserCapabilitiesBase browser)
        {
            if (browser == null) return;

            BrowserName = browser.Browser;
            if (!GetMachineType()) return;
            if (!GetVersion(browser)) return;
            IsValid = GetSupportStatus();

        }

        /// <summary>
        /// Generate a list of supported browsers based on the machine type.
        /// </summary>
        /// <param name="machineType">
Windows, Mac</param>
/// <returns></returns>
        public List<string> GetList(string machineType)
        {
            const string li = "{0} {1} <a href='{2}' target='_blank'>Get {3}</a>";  
            // {0}: browserName
            // {1}: minVersion
            // {2}: link
            var list = new List<string>();

            var supported = XDocument.Load(_path).Descendants("supported").ToList();

            foreach (var el in supported.Descendants())
            {
                var elname = el.Name;
                var minVersionAtt = el.Attribute("MinVersion");
                var maxVersionAtt = el.Attribute("MaxVersion");
                var machineTypeAtt = el.Attribute("MachineType");
                var displayNameAtt = el.Attribute("displayName");
                var linkAtt = el.Attribute("link");

                if (minVersionAtt == null || maxVersionAtt == null || machineTypeAtt == null || displayNameAtt == null || linkAtt == null)
                    throw new Exception("Error in SupportedBrowsers.xml file.");

                try
                {
                    var version = minVersionAtt.Value == maxVersionAtt.Value
                                      ? "v" + maxVersionAtt.Value
                                      : "v" + minVersionAtt.Value + " - v" + maxVersionAtt.Value;
                    if (machineTypeAtt.Value.ToUpper().Contains(machineType.ToUpper()))
                        list.Add(string.Format(li,
                                               displayNameAtt.Value,
                                               version,
                                               linkAtt.Value,
                                               elname
                                               ));
                }
                catch (Exception)
                {
                    throw new Exception("Error in SupportedBrowsers.xml file.");

                }
            }

            return list;
        }

        /// <summary>
        /// Parse the machine type out of the UserAgent string.
        /// </summary>
        private bool GetMachineType()
        {
            var platform = HttpContext.Current.Request.UserAgent;
            if (platform == null)
                return false;
            if (platform.ToUpper().Contains("WINDOWS"))
            {
                MachineType = "Windows";
                return true;
            }
            if (platform.ToUpper().Contains("MACINTOSH"))
            {
                MachineType = "Mac";
                return true;
            }
            return false;
        }

        /// <summary>
        /// Get the browser version.  
        /// For IE we have temporarily hardcoded the version based on the Trident version in the UserAgent.
        /// ToDo: clean this up and make it work properly in the future.
        /// </summary>
        private bool GetVersion(HttpBrowserCapabilitiesBase browser)
        {
            double version;

            if (BrowserName == "IE")
            {
                var platform = HttpContext.Current.Request.UserAgent;
                if (platform != null && platform.Contains("Trident/5.0"))
                    Version = 9.0;
                else if (platform != null && platform.Contains("Trident/4.0"))
                    Version = 8.0;
                else if (double.TryParse(browser.Version, out version))
                    Version = version;
            } 
            else if (double.TryParse(browser.Version, out version))
                Version = version;
            else
                return false;
            return true;
        }

        /// <summary>
        /// Determine the level of support we have for this browser
        /// </summary>
        private bool GetSupportStatus()
        {
            var doc = XDocument.Load(_path);

            var supported = doc.Descendants("supported").Descendants(BrowserName).ToList();
            var warning = doc.Descendants("warning").Descendants(BrowserName).ToList();
            var blocked = doc.Descendants("blocked").Descendants(BrowserName).ToList();

            if (IsSupportedStatusInData(supported)) SupportStatus = SupportStatus.Supported;
            else if (IsSupportedStatusInData(warning)) SupportStatus = SupportStatus.Warning;
            else if (IsSupportedStatusInData(blocked)) SupportStatus = SupportStatus.Blocked;
            else
            {
                SupportStatus = SupportStatus.Blocked;
                return false;
            }

            return true;
        }

        /// <summary>
        /// Parses the actual XML Elements from the file and determines if it is supported.
        /// </summary>
        private bool IsSupportedStatusInData(IEnumerable<xelement> data)
        {
            foreach (var el in data)
            {
                var minVersionAtt = el.Attribute("MinVersion");
                var maxVersionAtt = el.Attribute("MaxVersion");
                var machineTypeAtt = el.Attribute("MachineType");

                if (minVersionAtt == null || maxVersionAtt == null || machineTypeAtt == null)
                    throw new Exception("Error in SupportedBrowsers.xml file.");

                try
                {
                    if (Version >= double.Parse(minVersionAtt.Value)
                        && Version <= double.Parse(maxVersionAtt.Value)
                        && machineTypeAtt.Value.ToUpper().Contains(MachineType.ToUpper()))
                        return true;
                }
                catch (Exception)
                {
                    throw new Exception("Error in SupportedBrowsers.xml file.");

                }
            }
            return false;
        }
    }
}

SupportedBrowser Partial View:

@{
    var windows = ViewBag.browser.GetList("Windows");
    var mac = ViewBag.browser.GetList("Mac");
}

@if (ViewBag.browser.SupportStatus == SupportStatus.Supported)
{
    return;
}

<div class="sysreq">
<h2>Supported Browsers</h2>
<h3>Windows</h3>
<ul class="bullets">
    @foreach (var li in windows)
    {
      <li> @Html.Raw(li.ToString())</li>
    }
</ul>
<h3>Mac</h3>
<ul class="bullets">
    @foreach (var li in mac)
    {
        <li> @Html.Raw(li.ToString())</li>
    }
</ul>
<p class="sysreq">More about <a href="http://students.msbcollege.edu/elearning/system-requirements/" target="_blank">System Requirements</a></p>
</div>

Login Page:

@model VMLogin

@{
    ViewBag.Title = "Log in ";
    Layout = "~/Views/Shared/_Login.cshtml";
}

<script language="javascript" type="text/javascript">
    window.onload = $(function () {
        $('#UserName').focus();
        var status = '@ViewBag.browser.SupportStatus';
        if (status == 'Blocked') //blocked
            $('#logindiv').addClass('hide');
    });
</script>

@Html.Image("loginimg", "login.jpg", "log in", 110, 25)
@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)
    
    if (!String.IsNullOrEmpty(Model.ErrorMsg))
    { 
    <div class="error-state">
        <label class="error">@Model.ErrorMsg</label>
    </div>
    }
    if (ViewBag.browser.SupportStatus != SupportStatus.Supported)
    { 
        <div class="error-state">
            <label class="error">@ViewBag.browser.GetMessage()</label>
        </div>
    }
    <div id="logindiv">
        <fieldset>
            <div>
                @Html.LabelFor(model => model.UserName, new { @class = "textlabel" })
            </div>
            <div>
                @Html.TextBoxFor(model => model.UserName, new { @class = "textbox" })
                @Html.ValidationMessageFor(model => model.UserName)
            </div>
            <div>
                @Html.LabelFor(model => model.Password, new { @class = "textlabel" })
            </div>
            <div>
                @Html.PasswordFor(model => model.Password, new { @class = "textbox" })
                @Html.ValidationMessageFor(model => model.Password)
            </div>
        </fieldset>

        <input type="submit" value="Submit" class="button-1" name="navigation" />
    </div>
}

Learning/Mastering jQuery

These days most of my projects are done in .Net with MVC.  In order to get the pages to work properly I need to write a lot of javascript and jQuery.  I decided to take a course from  Benchmark Learning to help me improve my skills with it.  Here is a list of the resources I am using to improve my skills.

Benchmark course: Mastering jQuery

Official jQuery website

Html reference at W3Schools

Tutorials from the jQuery website

Free online fundamentals book by Rebecca Murphey

Hottest questions about jQuery on StackOverflow

John Resign video

CSS Selectors

In CSS, selectors are patterns used to select the element(s) you want to style.
The “CSS” column indicates in which CSS version the property is defined (CSS1, CSS2, or CSS3).

Selector Example Example description CSS
.class .intro Selects all elements with 1
#id #firstname Selects the element with id=”firstname” 1
* * Selects all elements 2
element p Selects all

elements

1
element,element div,p Selects all

elements and all

elements

1
element element div p Selects all

elements inside

elements
1

JavaScript/jQuery Notes

I suck at writing JavaScript and jQuery and I need to change that.  Most of my career was Windows forms development and I kind of fell into web development.  Now I am playing catch-up and trying to learn as I go.  That means that I am writing alot of bad cut and paste code.  Here are a few webpages and code snippits that I found that were written well and I can use for reference.

Here is some proper jQuery that does a series of actions on a single item.  It came from here:

$('.nav a').click(function(e) {
var anchor = $(this);

anchor
.hide()
.css('color', 'red')
.show();

alert('something else');

anchor.hide();
e.preventDefault();
});

Jeremy McPeak wrote an interesting article on the nesting of JavaScript functions that got me thinking about how little I actually know about JavaScript.  Now I am off to look at JavaScript: The Good Parts by Douglas Crockford that I heard about on HanselMinutes a while back.

Fonts and Bill Hill

Today started with listening to a podcast on Typography from “This Developers Life”.  It was fantastic and not at all what I expected.  I ended up with an interesting lesson on who Bill Hill is.  I spent some time exploring his website and blog and was pleasantly surprised by what I learned.  It inspired me to spend a bit of time focusing on a personal website that I have had floating around in my head for a while.  I decided I wanted to play around with fonts and found Google Web Fonts which gives me a simple place to start.  Hopefully I can find some more time to focus on my site and eventually some day I will get it up and running.