Friday, July 17, 2009

N-Tier Design Revisit part 1 – Over View

Back in March I did the blog entry The value of N-Tier Design, I didn’t provide any code, it was just a simple here is why N-Tier is good. After some reflection I have decided to revisit the subject and go a little more into detail.

The primary focuses of N-Tier is to provide a separation of concerns that will make your code more testable and more importantly maintainable, remember the code you write today, is the code you maintain tomorrow. Most of what I’m going to cover are some simple suggestions to make your life easier by putting in a little extra work up front, they may not be applicable in all situations, like a small one time use app for parsing a log file, some good rules of thumb are, if you can rewrite the application in less then 4 hours or it’s a proof of concept for a specific technology, it’s a little over kill for that.

The basic layers of N-Tier are

  1. UI Layer – Contains the logic for interacting with your user, this could be a web form, web service, command-line application, Winform, etc.
  2. Biz Layer – Contains business logic like data validation, manipulation, etc.  Basically any logic that deals with business rules belongs in the Biz
  3. Data Access Layer – Getting the Data and mapping it to Entities.  this could be from a Data Base, a 3rd party web service, an xml File, etc.
  4. Data Entities – Are not a layer, but how data is passed from one layer to another

Layer can consist of a single class or a set of classes that perform different tasks as long as they are doing what that layer is tasked with.

The basic rules for N-Tier are simple

  1. Layers can only talk to the layer right next to it, the UI layer can only talk to the Biz layer, the Biz can talk to the UI layer and the Data Access but the Data Access layer can only talk to the Biz Layer
  2. A Layer should have no internal knowledge of any of the other layers, A Biz class should have no understanding of how the DAL gets the data that it gives the it, The data could come from a Database, an XML File, or be randomly generated. Getting the data isn’t the Biz layers job so it shouldn’t care where it comes from, this becomes more important when you start using dependency injection and the underlying code may change completely.
  3. The layers should be decoupled and use interfaces to communicate with each other, this makes it easier to swap out code, use dependency injection , etc. you should be able to completely change a layer and as long as it keeps the same interface.

Sunday, July 12, 2009

Using WMI for building better applications

There was a couple of stack overflow question the other day that got my attention: How to find out if a user has administer privileges? and How to programmatically discover mapped network drives on system and their server names? My fist thought was WMI, and it got me thinking about how little WMI is discussed, I’ve never seen a conference session about it, or a session at code camp on it. Yet if your doing any serious system development it’s almost required.

For starters what is WMI?

According to Microsoft Technet “Windows Management Instrumentation (WMI) is the primary management technology for Microsoft® Windows® operating systems. It enables consistent and uniform management, control, and monitoring of systems throughout your enterprise….” see Microsoft Technet

So what dose this mean for a .NET developer?

You can access WMI though the System.Management namespace and can be used for finding out just about anything you want to know about your computer and Microsoft network. For example what drives do you have mapped?

   1: using System;
   2: using System.Management;
   3: using System.Windows.Forms;
   4:  
   5: namespace WMISample
   6: {
   7:     public class MyWMIQuery
   8:     {
   9:         public static void Main()
  10:         {
  11:             try
  12:             {
  13:                 ManagementObjectSearcher searcher = 
  14:                     new ManagementObjectSearcher("root\\CIMV2", 
  15:                     "SELECT * FROM Win32_MappedLogicalDisk"); 
  16:  
  17:                 foreach (ManagementObject queryObj in searcher.Get())
  18:                 {
  19:                     Console.WriteLine("-----------------------------------");
  20:                     Console.WriteLine("Win32_MappedLogicalDisk instance");
  21:                     Console.WriteLine("-----------------------------------");
  22:                     Console.WriteLine("Access: {0}", queryObj["Access"]);
  23:                     Console.WriteLine("Availability: {0}", queryObj["Availability"]);
  24:                     Console.WriteLine("BlockSize: {0}", queryObj["BlockSize"]);
  25:                     Console.WriteLine("Caption: {0}", queryObj["Caption"]);
  26:                     Console.WriteLine("Compressed: {0}", queryObj["Compressed"]);
  27:                     Console.WriteLine("ConfigManagerErrorCode: {0}", queryObj["ConfigManagerErrorCode"]);
  28:                     Console.WriteLine("ConfigManagerUserConfig: {0}", queryObj["ConfigManagerUserConfig"]);
  29:                     Console.WriteLine("CreationClassName: {0}", queryObj["CreationClassName"]);
  30:                     Console.WriteLine("Description: {0}", queryObj["Description"]);
  31:                     Console.WriteLine("DeviceID: {0}", queryObj["DeviceID"]);
  32:                     Console.WriteLine("ErrorCleared: {0}", queryObj["ErrorCleared"]);
  33:                     Console.WriteLine("ErrorDescription: {0}", queryObj["ErrorDescription"]);
  34:                     Console.WriteLine("ErrorMethodology: {0}", queryObj["ErrorMethodology"]);
  35:                     Console.WriteLine("FileSystem: {0}", queryObj["FileSystem"]);
  36:                     Console.WriteLine("FreeSpace: {0}", queryObj["FreeSpace"]);
  37:                     Console.WriteLine("InstallDate: {0}", queryObj["InstallDate"]);
  38:                     Console.WriteLine("LastErrorCode: {0}", queryObj["LastErrorCode"]);
  39:                     Console.WriteLine("MaximumComponentLength: {0}", queryObj["MaximumComponentLength"]);
  40:                     Console.WriteLine("Name: {0}", queryObj["Name"]);
  41:                     Console.WriteLine("NumberOfBlocks: {0}", queryObj["NumberOfBlocks"]);
  42:                     Console.WriteLine("PNPDeviceID: {0}", queryObj["PNPDeviceID"]);
  43:  
  44:                     if(queryObj["PowerManagementCapabilities"] == null)
  45:                         Console.WriteLine("PowerManagementCapabilities: {0}", queryObj["PowerManagementCapabilities"]);
  46:                     else
  47:                     {
  48:                         UInt16[] arrPowerManagementCapabilities = (UInt16[])(queryObj["PowerManagementCapabilities"]);
  49:                         foreach (UInt16 arrValue in arrPowerManagementCapabilities)
  50:                         {
  51:                             Console.WriteLine("PowerManagementCapabilities: {0}", arrValue);
  52:                         }
  53:                     }
  54:                     Console.WriteLine("PowerManagementSupported: {0}", queryObj["PowerManagementSupported"]);
  55:                     Console.WriteLine("ProviderName: {0}", queryObj["ProviderName"]);
  56:                     Console.WriteLine("Purpose: {0}", queryObj["Purpose"]);
  57:                     Console.WriteLine("QuotasDisabled: {0}", queryObj["QuotasDisabled"]);
  58:                     Console.WriteLine("QuotasIncomplete: {0}", queryObj["QuotasIncomplete"]);
  59:                     Console.WriteLine("QuotasRebuilding: {0}", queryObj["QuotasRebuilding"]);
  60:                     Console.WriteLine("SessionID: {0}", queryObj["SessionID"]);
  61:                     Console.WriteLine("Size: {0}", queryObj["Size"]);
  62:                     Console.WriteLine("Status: {0}", queryObj["Status"]);
  63:                     Console.WriteLine("StatusInfo: {0}", queryObj["StatusInfo"]);
  64:                     Console.WriteLine("SupportsDiskQuotas: {0}", queryObj["SupportsDiskQuotas"]);
  65:                     Console.WriteLine("SupportsFileBasedCompression: {0}", queryObj["SupportsFileBasedCompression"]);
  66:                     Console.WriteLine("SystemCreationClassName: {0}", queryObj["SystemCreationClassName"]);
  67:                     Console.WriteLine("SystemName: {0}", queryObj["SystemName"]);
  68:                     Console.WriteLine("VolumeName: {0}", queryObj["VolumeName"]);
  69:                     Console.WriteLine("VolumeSerialNumber: {0}", queryObj["VolumeSerialNumber"]);
  70:                 }
  71:             }
  72:             catch (ManagementException e)
  73:             {
  74:                 MessageBox.Show("An error occurred while querying for WMI data: " + e.Message);
  75:             }
  76:         }
  77:     }
  78: }

for a lot of developers this doesn't mater one way or another, for most winform or WPF apps you don’t need it, if your doing web development their is almost never going to be a reason to touch WMI.

One exception to this is if your working on an intranet application. How many time have you seen internal application that use a database to manage employees, there roles, etc. and then manage there active directory separately, why not just use active directory to do both?

If this seems a little obscure don’t worry there is a tool to do most of the heavy lifting for you.

The WMI Code Creator v1.0

WMI

It builds WMI queries, execute them, browse the local computers namespace, etc. for more information see the product overview.

Wednesday, July 8, 2009

Using Live Writer

Technorati Tags: ,

Watching Scott Hanselman’s presentation on how to make your blog not suck he talked about a tool for writing blogs called live writer that also has a plug-in for doing syntax highlighting, so I thought I would give it a try.

So far so good, installation was simple and on your first startup it asked what your blogging engine is (blogspot.com this case) your user name and password and it set up the interface to auto post to your blog.

The editor includes all the basic edit and formatting tools (bold, Italic, underline, etc.) and dose auto spell checking.  Some of the other features are the ability to insert pictures, videos, tables, hyperlinks, maps, etc. all of which appear to work fairly well with the exception of the map, when I enter a location it just hangs, I guess you can’t have everything. 

One of the major selling points is having a plug-in that gives you an integrated syntax highlighter

   1: public class RequestFactory : IRequestFactory
   2: {
   3:     public static readonly IRequestFactory Instance = new RequestFactory();
   4:  
   5:     private RequestFactory()
   6:     {
   7:         
   8:     }
   9:  
  10:     public IAuthenticationRequests GetAuthenticationRequests()
  11:     {
  12:         IAuthenticationRequests myRequests = new AuthenticationRequests();
  13:         return myRequests;
  14:     }
  15: }

vs. the old method where I would copy my code into a web form that would parse the syntax and give me my code formatted with html styles, plus I think it formats it a lot better, with one minor bug, if you use the default xhtml for your content the syntax highlighting is messed up, once you set it to html it works great.


The preview mode for looking at your post as it would appear in blog before you post your entry is fairly accurate with some minor problems with spacing.


Finally the ability to browse and update old posts with ease makes it much easier to manage your old posts, update content, fix formatting issues, etc.


With some small exceptions Live writer is a solid tool, that makes it a lot easier to blog, I give it an 8 out of 10.

Monday, June 22, 2009

The Simple Fundamentals we Forget

A little while ago a frustrated co-worker asked me for some help, he was working on consuming a web service and needed to add an array of strings to the request based on user input and he couldn't figure out how to add a new item to the array. He could find lots of examples of how to create the array, and how to populate it at initialization, etc. but he couldn't find out how to just add a new item. When i explained to him that you couldn't he was a little shocked, all of the other collection type let you add new items, why wouldn't an array? In his defense he came from a dynamic language background, where an array is more like an ArrayList in c#.

This got me thinking about some of the simple fundamentals and basic language features that I don't remember exactly how to use, mostly because I never use them. A good example would be the Conditional Operator
   1: string fileName = tempFileName != null ? tempFileName : "Untitled";
it's purely a personal preference, but I don't like the way they look in code and I think they make it harder to debug, having said that they are a fundamental part of the language and as a good developer I should know how to use them. This is got me thinking about how I should use parts of language/framework that I don't normally use just to keep in practice.

I think this could be beneficial in a couple of ways, primarily it would require me to look for things I'm not using and force me to think about how to use them. Second it would make me think why I don't use them. A prime example is an abstract classes, I know how to use them I just don't like to. Maybe if I forced myself to use them on occasion I would find a place where they are better suited then an interface or I'm just going to prove why I like interfaces better, but the important part is that I reaffirm why I like interfaces more then abstract classes.

At times I think the hardest part of learning new things is not forgetting what I already know, maybe I need to take some time to write some practice code or proof of concepts just for the practice.

Wednesday, June 3, 2009

An elegant solution that was completely unnecessary

Working on a web form that would email someone when it was submitted, one of the methods looked like it could use a little refactoring.
   1: private string BuildMessageBody()
   2: {
   3:     StringBuilder messageBuilder = new StringBuilder();
   4:     messageBuilder.Append("Account Number: ");
   5:     messageBuilder.Append(textAccountNumber.Text);
   6:     messageBuilder.Append("\n");
   7: }
It looks kind of ugly and takes up a fair amount of space, I could do string concatenation,


   1: private string BuildMessageBody()
   2: {
   3:     messageBuilder.Append("Account Number: " + textAccountNumber.Text + "\n"
   4: );
but that can get ugly fast and in my opinion it's hard to maintain. So I came up with a brilliant and elegant solution, I would use an extension method!


   1: public static void AppendLine(this StringBuilder builder, string title, string value)
   2: { 
   3:     builder.Append(title); 
   4:     builder.Append(value); 
   5:     builder.Append("\n");        
   6: }

and now my could would look something like this



   1: private string BuildMessageBody()
   2: {
   3:     StringBuilder messageBuilder = new StringBuilder(); 
   4:     messageBuilder.AppendLine("Account Number: ", textAccountNumber.Text);
   5: }

and just as I was thinking how cool Extender methods are it hit me? I could just use StringBuilder.AppendFormat to do basically the same thing like this



   1: private string BuildMessageBody()
   2: {
   3:     StringBuilder messageBuilder = new StringBuilder();
   4:     messageBuilder.AppendFormat("Account Number: {0}\n", textAccountNumber.Text);  
   5: }

Oh well, but just proves that sometimes a cool new way to handle a problem isn't always the right way, and this was a reminder for me to look at existing functionality before I try to create my own.