Sunday, July 26, 2009

N-Tier Design Revisit part 4 – Biz Layer

The Biz Layer Only handles Business logic, nothing more, noting less. It doesn't know or care where the data came from or where it's going, it only cares about manipulating the data to comply with business rules, this would include date validation, data filtering, and data processing.

  1. Validation: This can include checking to see if the data in an entity conforms to business rules, if the request from the UI is valid

       1: public bool AuthenticateUser(string user, string pass)
       2: {
       3:     bool success = false;
       4:     if (user.Trim().Length>0 && pass.Trim().Length>0)
       5:     {
       6:         success = AuthenticationRequestInterface.AuthenticateUser(user, pass);                
       7:     }
       8:     return success;
       9: }    

    in this case the username and password must both have something other then spaces. This could also include a validation api to handle validation requests from the UI, this way you can have consistent validation for every type app that might use it(win forum, win service, website, etc.) .

  2. Data Filtering: For the most part this is telling the DAL what data it needs, let the DAL figure out how to get it, an example of this would be if you have a collection of accounts and an account must have specific privileges to have access to some data then only request the data for the accounts in the collection that have these privileges

  3. Data processing: Basically any processing that is based on business rules. This can be as simple as requesting more data based on business rules to parsing text, like a log file, to get specific data, etc. One major advantage of doing N-Tier is if you have an application that is very process intensive it’s easy to scale out using something like wcf or old school web services and move all or part of your business layer to a farm and scale as much as you need from there. NTierLayout

This way you don’t need a bunch of beefy boxes for web servers, this is also nice if your setting this up as a client server app. If done right, you can use the adaptor pattern to spread your application to completely different servers. The point is to isolate functionality in your application, this makes it easy to test, maintain, and update.

Wednesday, July 22, 2009

N-Tier Design Revisit part 3 – Data Access Layer

The Data Access Layer abstracts your data requests away from the rest of your application and prevents your Biz Layer from needing to know where your data comes from.

In it’s simplest form a DAL is a class that pulls data from a data source(SqlServer, MySql, an XML File, a web service, the Cloud, etc.) populates a data entity and returns it to the Biz layer for some the DAL is simply a Object Relational Mapper like NHibernate or The Entity Framework, while this is fine, I would recommend against it for the simple reason that I want the Biz to know as little about where the data comes from as possible and if it’s talking directly to Entity Framework then it has more knowledge about how the system is setup then it should; and what happens if you have to change ORM Tools?  I think ORM tools are for the most part great, but I strongly feel you should abstract them away preferably using an interface this makes it much easier to swap of the underlying code if you have to, plus it makes it much easy to test. 

One type of ORM I would suggest you avoid are the code gen ORMs like subsonic, it’s quick and easy to pull your data entities, but your now very strongly tied to your database schema and database changes affect your entire application, also what if not all of your requests are to a database, at work we have several products that use 3rd party web services that tie into data from the database and are returned to the Biz Layer, that’s hard to do if your entities are being build for you by a code generator.   

Finally there are only 2 really solid rules for the DAL

1: Expose as little about your data sources as possible, this prevents them from being too tightly coupled to your data source.  Recently we switched data vendors for one of our products, as far as the rest of the application knew nothing had changed even though the underlying web service was completely different.

2: The only logic in the DAL is to filter data and map it to data entities, at this point all of your validation should be done (that’s the Biz layers job).

Technorati Tags: ,

Sunday, July 19, 2009

N-Tier Design Revisit part 2 – Data Entities

Entities are unique in N-Tier, they are the only thing that is used by every level. In my original N-Tier entry I stated that it’s was ok to put your entities in your Data Access Layer (DAL), this is a very common practice with a lot of Object Relational Mappers (ORMs), some will even generate your entities from your data base (subsonic, Entity framework, etc.). The reason I dislike this is you are making your DAL a dependency in every layer of your application, further more if your using something like subsonic to generate your data entities you are tightly coupling your database design to everything. I would strongly encourage you to place your data entities into a separate project, the main focuses here is to decouple your application, the less any one part of your app knows about any other part the better.

It is my firm belief that Data Entities should contain data and have very little too no logic, and what logic they do have should only relate to manipulating themselves they are dumb objects, THEY DO NOT CONTAIN BUSINESS LOGIC!, DATA ACCESS LOCIC, OR UI LOGIC. if they do you have a layer violation. The only function of a data entity is to hold data and be passed from one layer to the next nothing more! Here is a code sample for a data entity

   1: public class Customer
   2:     {
   3:         public int Id { get; set; }
   4:         public string FirstName{get; set;}
   5:         public string LastName { get; set; }
   6:         public string Company { get; set; }
   7:         public string Email { get; set; }
   8:         public string Phone { get; set; }
   9:     }

It’s really nothing more then a data structure, but what data you put into your entities is also important, if you have a property called company logo, that has a value like “/images/logos/customer12.png” you have a problem, now every layer has information about your UI, a better solution is to only store the “customer12.png” value and let the UI figure out how to display it.

For entities I usually create a collection object named the plural of the class it holds. The code looks something like this.


   1: public class Customers :Collection<Customer> {}
I personally like using generic collections as a base class, it makes a strongly typed, fast, and with only one line of code easy, collection object. I have everything I need baked in, with the possible exception of the ability to add collections, but with a little refactoring this is added

   1: public class Customers :Collection<Customer>
   2: {
   3:     public void Add(IEnumerable<Customer> newCustomers)
   4:     {
   5:         foreach (Customer customer in newCustomers)
   6:         {
   7:             Add(customer);
   8:         }
   9:     }
  10: }

if you noticed I use generic IEnumerable<Customer> this way I can add any collection that implements IEnumerable, this could include: another Customers object, a List<Customer> , etc. As with the single entity the collection should have limited logic and what logic it has should only deal with managing the items it holds.


Technorati Tags: ,,

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.