How to code business layer in ASP.NET MVC (part 5 of series)

Hi everyone,

In this series of articles I made a rant about recommended software templates and techniques (A rant about Microsoft’s ASP.NET MVC templates). In the last article (Rewrite of ASP.NET MVC’s controller (part 4)) I proposed how to make a proper controller base class from which you can derive your controllers that have repeatable mechanisms to control and protect view and inject business actions.

In this article I’m gonna address another requirement:

How to create a business layer for ASP.NET MVC ??

Like in previous articles we can asume that business classes share some logic so we immediatelly start from building base class, an abstract one, from which you can derive your real classes. But first let’s put it in some context. This is how one of controller’s actions was created.

 [HttpPost, ActionName(CancelActionName)]
        [ValidateAntiForgeryToken]
        public ActionResult CancelConfirmed(int id)
        {
            Order order = repo.Get(id);
            BusinessLayer.OrderBL orderBL = new BusinessLayer.OrderBL(repo, order, Helpers.UserHelper.GetRoles(HttpContext).ToList());

            var viewBuilder = ViewBuilder.Initialize(this)
               .SetActionName(Order.Actions.Cancel.ToString())
               .SetMode(ViewBuilder.HttpModes.Post)
               .SetItemId(order.OrderId)
               .SetItemPermission(IsActionAvailable)
               .SetBusinessFunc(orderBL.PerformAction)
               .SetGetModel(() => repo.Get(order.OrderId))
               .SetRedirectAction(Order.Actions.Index.ToString())
               .Build();
            return viewBuilder.View;
        }

It included creation of OrderBL object, which then was used to PerformAction in ViewBuilder. As you can see OrderBL is initialized with repository object (repo), entity object (order) and a list of roles that current user has in the system (GetRoles).

OrderBL object is then used to set business function for ViewBuilder: SetBusinessFunc(orderBL.PerformAction). We are going to concentrate ourselves on PerformAction method. It should look like this:

 public void PerformAction(String ActionName)

The reason why you don’t see ActionName parameter in SetBusinessFunc invocation is because ActionName is being set at earlier stage of setting up ViewBuilder:

.SetActionName(Order.Actions.Cancel.ToString())

ActionName is then used automatically in ViewBuilder’s View method:

builder.BusinessFunc?.Invoke(builder.ActionName);

So we have to build an abstract business layer class that is aware what is the type of business entity that we want to work on, the type of repository class we will be using and permission system we use to check if an action can be performed for this entity instance:

 public abstract class BlBase<ModelType, ActionEnum, RolePermission,   Repository>
 where ModelType : IModel 
 where RolePermission : IRolePermission
 where Repository : IRepo<ModelType>

You can use this abstract to define real world class of OrderBL:

 public class OrderBL : BlBase<Order, Order.Actions, OrderRolePermission, IOrderRepo>

In base class we should have a common PerformAction method that is used across all business layer classes:

public void PerformAction(String ActionName)
{
    try
    {
        RolePermission perm = Activator.CreateInstance();
        if (!perm.IsActionAvailable(roles, item, ActionName))
            throw new MyActionNotAllowedException(ActionName, typeof(ModelType).GetType().Name);

        var method = GetMethod(ActionName);
        if (method == null)
            throw new ActionMissingException(ActionName, typeof(ModelType).GetType().Name);
        method.Invoke(this, new object[] { });
    }
    catch (DbEntityValidationException dbve)
    {
        throw new MyValidationException(dbve);
    }
}

It creates an instance of permission class and initializes it, and then asks it if current action can be performed for this item and with these user roles. If so, it tries to search our business class for method marked with a custom attribute and invokes it if it finds one, for example the Cancel action method (located in OrderBL class):

[BusinessAction(Order.Actions.Cancel)]
void Cancel()
{
    item.StatusEnum = Order.Statuses.Cancelled;
    repo.Update(item);
}

The reason I use attributes with action enum as a parameter instead of searching for method names is because I like to use same action naming across entire ASP.NET application, and the only valid list of action names is Actions enum defined in Order class. This way you avoid any mistakes in naming, upper/lower case, and gramatical errors. Also by using attribs and Reflection you don’t have to use switch/case to link action name with business functions which is lame.

And that’s it ! We’ve just created a perfect business layer that makes it supereasy to create new business action methods.

In the next article I’m going to address the problem of using ViewBag in standard Microsoft’s templates by changing from Order model to Order ViewModel.

Thanks for reading ?

Dominik Steinhauf

CEO, .Net developer, software architect at Creative Yellow Solutions (formerly Indesys)

If you need help with your software project, or need customized software for your company, contact me at: dominik.steinhauf ( at) cys.biz.pl

Leave a Reply

Your email address will not be published. Required fields are marked *