Posted by: Cirilo Meggiolaro | 05/8/2009

Tip of the day #206 – ASP.NET MVC – Architecture best practices – Service layer

It’s usually a good idea to keep concerns separated between layers. Maintenance and scalability are just two of many benefits of doing that.

When developing an ASP.NET MVC web application this is not different. You not only keep the concerns separated via the model, view and controller classes but is important to keep in mind that if you need to reuse some of the operations exposed via the model classes in another application, you cannot tie your code to any application or application type specific feature.

Actually the model is the only part of the MVC design pattern that is free of application type. You cannot develop either a controller or a view without referencing an ASP.NET MVC assembly. So, when you are designing your model classes you can (and you should) keep it completely decoupled from your controller classes.

Scenario

You work as a developer for a financial company that provides stock operations to its clients. The company operates by phone where the clients can talk to an analyst and either buy or sell stocks. The analysts use a .NET windows client application for all related tasks.

The company wants to develop an application where the clients can log on and check their investments and request transactions directly from it. An ASP.NET MVC web application was chosen as the application type and you are responsible for designing it.

Basically all operations, business logic and data access related to the investment transactions are available on the windows client application in a separated assembly from the UI. How can you reuse the code from your ASP.NET MVC application?

How to

We are going to create a service layer that will expose all the necessary operations to both the windows client and the ASP.NET MVC web application.

Our first task is to create an interface where all operations we need to use are defined. If you have a class with the methods you need you can use the Extract Interface feature from Visual Studio 2008 by right-clicking the class and selecting Refactor > Extract Interface. The process is pretty straightforward. Give a name to the new interface, the physical file name and select the methods you want to include in your interface. When it’s done, just click the OK button.

I am not a stock specialist so I am going to add simple methods to our interface just to illustrate:

public interface IStockService
{
    bool BuyStock(int clientID, int quantity, string stockCode, decimal unitPrice);
    bool SellStock(int clientID, int quantity, string stockCode, decimal unitPrice);
    List<Stock> GetAll();
    List<Stock> GetAllByClient(int clientID);
    Stock GetDefinition(string stockCode);
    Stock GetDefinition(string userName, string stockCode);
}

If you have made the refactor of your current application to extract an interface you will notice that the interface keyword has been added to the class definition. You have the first concrete implementation of your interface. Just to illustrate, a simple code:

public class ClientStockService : IStockService
{
    public bool BuyStock(string userName, int quantity, string stockCode)
    {
        /// Code removed for brevity
    }

    public bool SellStock(string userName, int quantity, string stockCode)
    {
        /// Code removed for brevity
    }

    public List<Stock> GetAll()
    {
        /// Code removed for brevity
    }

    public List<Stock> GetAllByClient(string userName)
    {
        /// Code removed for brevity
    }

    public Stock GetDefinition(string stockCode)
    {
        /// Code removed for brevity
    }

    public Stock GetDefinition(string userName, string stockCode)
    {
        /// Code removed for brevity
    }
}

Create a new ASP.NET MVC web application;

Add a reference to the assembly where both the concrete class and the interface are defined;

Right-click the Controllers folder and select Add > Controller;

From the dialog, name it StockController, make sure that the checkbox is not checked and click Add;

Picture 1 - Add Controller Dialog

Picture 1 - Add Controller Dialog

Open the StockController class. We are going to create the methods necessary to buy and sell stocks, get a list of stocks and a list of all stocks that the client has. The code is available below:

public class StockController : Controller
{
    IStockService _stockService;

    public StockController()
        : this(new ClientStockService())
    { }

    public StockController(IStockService service)
    {
        this._stockService = service;
    }

    public ActionResult Index()
    {
        return View(_stockService.GetAll());
    }

    [Authorize]
    public ActionResult MyOptions()
    {
        return View(_stockService.GetAllByClient(this.User.Identity.Name));
    }

    [Authorize]
    public ActionResult Buy(string stockCode)
    {
        return View(_stockService.GetDefinition(stockCode));
    }

    [AcceptVerbs(HttpVerbs.Post), Authorize]
    public ActionResult Buy(int quantity, string stockCode)
    {
        if (!_stockService.BuyStock(this.User.Identity.Name, quantity, stockCode))
            return View(“Error”);

        return RedirectToAction(“Index”);
    }

    [Authorize]
    public ActionResult Sell(string stockCode)
    {
        return View(_stockService.GetDefinition(this.User.Identity.Name, stockCode));
    }

    [AcceptVerbs(HttpVerbs.Post), Authorize]
    public ActionResult Sell(int quantity, string stockCode)
    {
        if (!_stockService.SellStock(this.User.Identity.Name, quantity, stockCode))
            return View(“Error”);

        return RedirectToAction(“Index”);
    }
}

You may have noticed that we are coding against an interface instead of the concrete class. As the same way than the data access we saw on Tip #205 we keep the layers separated. If you develop a new concrete service layer class, you just need to change the instantiation type on the controller class. Thanks to polymorphism!!!!

Tomorrow we are going to improve the code we have seen today to add the validation on the service layer and make it interact with the controller class dictionary.

Stay tuned!


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: