Wednesday, June 23, 2010

Refactoring ASP MVC 2 to use Dependecy Injection (part1)

In my previous post named ASP.NET MVC 2.0 - Master Detail Views I wanted to show how to retreive data from several tables move this into objects and then present this in a view in a master-detail format.

My comment specifically with regards to the controller was "Since this controller was created to illustrate as simple as possible how to build a master-detail view in ASP.NET MVC,
I have not focused on proper architecture using Depedency Injection, Repository Patterns etc... (read more here and here)."

I would now like to go through the steps needed to refactor the solution to take advantage of Dependency Injection. The scenario we are facing is that my fictual boss has requested that we move the implementation so it is running on mono on top of a CentOS/Redhat linux distribution on Amazon Elastic Compute Cloud. We will have to switch the database to MySQL.

Now since I have chosen to NOT use NHibernate or another similar database agnostic ORM (which I could have) I will instead do this manually. The ultimate goal is that we can swap the database from Microsoft SQL Server to MySQL server but we want to allow the client (my fickle fictive boss) to go back to Microsoft SQL Server as his temper changes.
As a matter of fact I would also like to allow implementations of another view front end in Silverlight 4.0 or WPF.

I will in this post not actually implement the MySQL DAL or the Silverlight GUI but make sure that my applications allows it.

First we need to look at if we need to change anything at all?

public ActionResult Details(Guid id)
{
    Guid project_id = id;   // needed due to conflicting variables 
    ReverseAuctionDBDataContext db = new ReverseAuctionDBDataContext(); 

    var projects = from p in db.projects
                   where p.id == project_id
                   join u in db.users on p.owner_user_id equals u.id
                   select
                   new ProjectViewModel
                   {
                       Name = p.name,
                       Description = p.description,
                       BiddingStartDate = p.bidding_start_date,
                       BiddingEndDate = p.bidding_end_date,
                       ProjectLauchDate = p.project_start_date,
                       ProjectDeadline = p.project_deadline,
                       Owner = new SimpleUserViewModel 
                       { 
                           ID = u.id, 
                           Username = u.user_name 
                       }
                   };

    var bids = from b in db.project_bids
               where b.project_id == project_id
               join u in db.users on b.user_id equals u.id
               select new ProjectBidViewModel 
               { 
                   BidAmount = b.bid_amount, 
                   BidDate = b.bid_date, 
                   Bidder = new SimpleUserViewModel 
                   { 
                       ID = u.id, 
                       Username = u.user_name 
                   } 
               };

    ProjectViewModel project = projects.Single<ProjectViewModel>();
    project.ProjectBids = bids.ToList<ProjectBidViewModel>();
    return View(project);
} 

If we have a look at line 04 - line 37 we have intimate knowledge of the database in this code. Basically since we are directly using the generated LINQ classes we might as well hardcode SQL Server in the controller.


Now lets first of all try to move the LINQ classes to a new assembly.


So let us move the LINQ classes to a new project and change the name to reflect that this generated set of classes is for MSSQL.



Updated the dependency / reference
using Appinux.ReverseAuction.Data.Mssql;

Updated the class we work with
public ActionResult Details(Guid id)
        {
            Guid project_id = id;   // needed due to conflicting variables 
            ReverseAuctionDBMssqlDataContext db = new ReverseAuctionDBMssqlDataContext(); 

            var projects = from p in db.projects
...

Has this changed anything at all for the better? No, it has not since we are still depending on the concrete classes in ReverseAuctionDBMssql.dbml which now are just located in another assembly.

I would like to split the refactoring into 3 different pieces

  1. Seperating the DataLayer (LINQ classes) from the controller and views by introducing a domain layer
  2. Refactoring to adhere to Single Responsibility Principle
  3. Abstracting away the actual Respositories and Operations from the controller and domain setting the stage for DI
  4. Introducing the Composition Root and Windsor Lightweight Container

UPDATE

I have added a series of postings that talk about ASP.NET MVC ,Dependency Injection and Inversion of control.

They are available here:

Refactoring ASP MVC 2 to use Dependecy Injection (part1) (this posting)
Refactoring ASP MVC 2 to use Dependecy Injection (part2)

2 comments:

Anonymous said...

Nice post...Thank you for sharing some good things!!

Kenneth Thorman said...

Thank you for the nice feedback

/Kenneth Thorman