Gunnar Peipman's ASP.NET blog

ASP.NET, C#, SharePoint, SQL Server and general software development topics.

Sponsors

News

 
 
 
DZone MVB

Links

Social

June 2011 - Posts

ASP.NET MVC: Moving code from controller action to service layer

I fixed one controller action in my application that doesn’t seemed good enough for me. It wasn’t big move I did but worth to show to beginners how nice code you can write when using correct layering in your application. As an example I use code from my posting ASP.NET MVC: How to implement invitation codes support.

Problematic controller action

Although my controller action works well I don’t like how it looks. It is too much for controller action in my opinion.


[HttpPost]

public ActionResult GetAccess(string accessCode)

{

    if(string.IsNullOrEmpty(accessCode.Trim()))

    {

        ModelState.AddModelError("accessCode", "Insert invitation code!");

        return View();

    }

 

    Guid accessGuid;

 

    try

    {

        accessGuid = Guid.Parse(accessCode);

    }

    catch

    {

        ModelState.AddModelError("accessCode", "Incorrect format of invitation code!");

        return View();               

    }

 

    using(var ctx = new EventsEntities())

    {

        var user = ctx.GetNewUserByAccessCode(accessGuid);

        if(user == null)

        {

            ModelState.AddModelError("accessCode", "Cannot find account with given invitation code!");

            return View();

        }

 

        user.UserToken = User.Identity.GetUserToken();

        ctx.SaveChanges();

    }

 

    Session["UserId"] = accessGuid;

 

    return Redirect("~/admin");

}


Looking at this code my first idea is that all this access code stuff must be located somewhere else. We have working functionality in wrong place and we should do something about it.

Service layer

I add layers to my application very carefully because I don’t like to use hand grenade to kill a fly. When I see real need for some layer and it doesn’t add too much complexity I will add new layer. Right now it is good time to add service layer to my small application. After that it is time to move code to service layer and inject service class to controller.


public interface IUserService

{

    bool ClaimAccessCode(string accessCode, string userToken,
                         out string errorMessage);

 

    // Other methods of user service

}


I need this interface when writing unit tests because I need fake service that doesn’t communicate with database and other external sources.


public class UserService : IUserService

{

    private readonly IDataContext _context;

 

    public UserService(IDataContext context)

    {

        _context = context;

    }

 

    public bool ClaimAccessCode(string accessCode, string userToken, out string errorMessage)

    {

        if (string.IsNullOrEmpty(accessCode.Trim()))

        {

            errorMessage = "Insert invitation code!";

            return false;

        }

 

        Guid accessGuid;

        if (!Guid.TryParse(accessCode, out accessGuid))

        {

            errorMessage = "Incorrect format of invitation code!";

            return false;

        }

 

        var user = _context.GetNewUserByAccessCode(accessGuid);

        if (user == null)

        {

            errorMessage = "Cannot find account with given invitation code!";

            return false;

        }

 

        user.UserToken = userToken;

        _context.SaveChanges();

 

        errorMessage = string.Empty;

        return true;

    }

}


Right now I used simple solution for errors and made access code claiming method to follow usual TrySomething() methods pattern. This way I can keep error messages and their retrieval away from controller and in controller I just mediate error message from service to view.

Controller

Now all the code is moved to service layer and we need also some modifications to controller code so it makes use of users service. I don’t show here DI/IoC details about how to give service instance to controller. GetAccess() action of controller looks like this right now.


[HttpPost]

public ActionResult GetAccess(string accessCode)

{

    var userToken = User.Identity.GetUserToken();

    string errorMessage;

 

    if (!_userService.ClaimAccessCode(accessCode, userToken,
                                     
out errorMessage))

    {              

        ModelState.AddModelError("accessCode", errorMessage);

        return View();

    }

 

    Session["UserId"] = Guid.Parse(accessCode);

    return Redirect("~/admin");

}


It’s short and nice now and it deals with web site part of access code claiming. In the case of error user is shown access code claiming view with error message that ClaimAccessCode() method returns as output parameter. If everything goes fine then access code is reserved for current user and user is authenticated.

Conclusion

When controller action grows big you have to move code to layers it actually belongs. In this posting I showed you how I moved access code claiming functionality from controller action to user service class that belongs to service layer of my application. As the result I have controller action that coordinates the user interaction when going through access code claiming process. Controller communicates with service layer and gets information about how access code claiming succeeded.

DiscountASP–Winner of my daily WTF today

Today I tried to put up simple ASP.NET MVC application to DiscountASP shared hosting. It all started well but ended with most strange security and server architecture I’ve ever seen. I don’t want to insult them but it is really shocking and unexpected when some of top hosting providers just spits on web security.

Okay, I uploaded my ASP.NET MVC application to server using WebDeploy – it works fine, no problems at all. It was also very easy to put my database and get application running. Public side of application works fine and it was time to log in to admin area. Now that’s the point where things started to stink bad.

Windows Identity Foundation happens today

Well… as I don’t like to invent the wheels and I don’t like easy to break security solutions like classic username and password stuff I’m using Windows Identity Foundation and Windows Azure AppFabric Access Control Services to authenticate administrators. It’s all damn easy to set up and configure and it all works like charm. What’s best – Windows Identity Foundation provides way better and stronger security than all those homemade pieces of crap that people love to use.

If you want to find out more about WIF then I can suggest you some of my resources:

This is what Microsoft offers for better and safe web.

After short discussion with DiscountASP technical staff it turned out that on their shared hosting service it is impossible to follow these simple steps that make WIF work:

  • Open IIS Manager.
  • Find out what AppPool your application is using by selecting your App, right-click on it, and Select Manage Application -> Advanced Settings.
  • After that, on the top left hand side, select Applications Pools, and go ahead and select the App Pool used by your app.
  • Right-click on the App Pool, and select Advanced Settings, Go to the Process Model Section and Find the "Load User Profile" Option and set it to true.

On their web I didn’t saw warning saying that please only legacy systems…

Let’s do it DiscountASP way

As DiscountASP cannot help me with their service I started thinking how looks secure web application in DiscountASP world. The best (and it is really stupid) way to do secure things on their hosting is here (although I’m not sure about security of the link between custom box and MSSQL).

Secure web DiscountASP way

Site is hosted in DiscountASP servers and copy of site runs on some custom box that is able to run IIS 7.5. This custom box serves admin interface to administrators. This box can be everywhere – even in your home under your table if you have good connection. And this custom box extends DiscountASP legacy hosting with todays secure web mechanisms. Cool? :)

Where to go next?

Seems like it’s not wise to make bets on top providers as they have stuck to mainstream and have no will to improve their services. I think Windows Azure will be the next place to  stop with all my public systems as there I have lot more control over my technical environment although I have only very small wishes. Also it seems to me that new services have less legacy to carry on and they are more interested in keeping users they get.

MiniProfiler: Lightweight profiler for ASP.NET web applications

I found very cool small profiler that can also be used on production sites to quickly detect bottle necks in web application code. The profiler is called MiniProfiler and in this posting I will introduce you how to use it in your code.

As a first thing you must have some web application. Although profiler name in Google repository refers to MVC you can use it with any other web application type. I suppose you have ASP.NET MVC application.

NB! Sam Saffron wrote very good story about MiniProfiler. You can find it from his blog and it is titled as Profiling your website like a true Ninja. I really suggest you to read it.

Adding profiler to project

As a first thing you should add library package reference to MiniProfiler like shown on the following screenshot fragment.

MiniProfiler: Add package reference

After you added reference it’s time to start and stop profiler. We do it in BeginRequest and EndRequest events of our application class. Open global.asax and paste the following code there.


protected void Application_BeginRequest()

{

    if (Request.IsLocal)

    {

        MiniProfiler.Start();

    }

}

 

protected void Application_EndRequest()

{

    MiniProfiler.Stop();

}


It’s time to add some profiling code now.


public ActionResult Index(int page = 1)

{

    var profiler = MiniProfiler.Current;

    using (profiler.Step("Load events"))

    {

        PagedResult<Event> events = _context.ListPublicEvents(page);

        return View(events);

    }

}


And here’s how we can show profile on our pages. Just add MiniProfiler call to the head of your master page.


<head>
    @MvcMiniProfiler.MiniProfiler
.RenderIncludes()
</head>

That’s it. Let’s take look now what it produces.

Viewing profiler output

When we run our application and open the page with profiled code we can see the following result when we click on profiler timing icon.

MiniProfiler: Profiler output popup

You can also share profile trace with your friends by clicking share link on trace popup.

MiniProfiler: Profiler output as shareable page

Of course, if you have more profiling messages you will see longer list.

I tried but my code looks awful…

Well… it seems like you have to move some code out from your controller methods. If your controller actions code gets messy and complex when using profiling messages there is good chance that you have to move some to some other layers (maybe add some new service classes etc).

If your controller code has no multiple responsibilities then it has practically simple flow and adding MiniProfiler profiling messages doesn’t make it look like mess.

Conclusion

MiniProfiler is small and very promising web applications profiling tool that adds no remarkable overhead to applications. It is easy to use and it generates nice profiling output that you also can share with your colleagues. If your controller actions are coded well then MiniProfiler adds no overhead to your code and it doesn’t make it look like mess. You can use MiniProfiler also to catch database queries generated by Linq To SQL and Entity Framework.

More Posts