Home MVC Storefront

ASP.NET MVC: Using Helper Classes And Services

This question has come up many times in the forums:

I have an application that needs functionality X, but I need it everywhere - including my Master Page. Where should I put this stuff?

 

This kind of issue is pretty common using MVC, where logic is piped along some clearly defined paths. Often, however, you find that you need to have some special logic - some "horizontal" logic - that extends across your "vertical" controller pipes. A typical "horizontal" bit of logic might be statistics, security, logging, or email - common application functionality that transcends your application's MVC implementation.

My thoughts below are one of a few ways that you can address this. The goal is to reduce duplication (DRY) and keep it as centralized as you can.

One of the ways I've been recommending people deal with these issues is to create a "Service" class, and put it in a folder called "Services". These classes contain very specific logic, and are made up by (usually) a set of static methods.

With the MVC forums that I've been creating, I have the following Service classes in my Services folder:

  • Gravatar
  • Akismet (anti-spam)
  • Search (post/thread search)
  • TextSterilizer (cleans out bad words and blocked expressions)
  • BBCodeFormatter (encodes using BB Code replacement)
  • CSharpFormatter (Manoli CSharpFormat)
  • UserStats (posts, last post, last login, points, etc)

You can see how each of these can be used all over a forums application - thus their "horizontal" service nature. In fact if my application had a service tray - each of these might have an icon in there.

 

But What About UI?
If your service has a UI component, you can expose it using a UserControl, and then render it out using the MVC Toolkit's RenderUserControl() method:

<%=Html.RenderUserControl("~/Gravatar/GravatarImage.ascx")%>

 

Helper Classes
Another post came in where the user asked (paraphrased):

On my model I have a property which I am exposing using an enum. I want the user to be able to read this information properly so what should I do - add a property to my model, or format it using CodeBehind? I'm being told not to use CodeBehind - what should I do?

It's not fair to say "don't use CodeBehind" - it does come in handy for View-specific logic that you don't want to "clutter" the page. But mostly, if you have to doctor some data for your view, you can expand on it some and probably reuse it somewhere in your application.

This is where "Helper" classes come in - they contain UI code that know nothing of a Controller or Model information - they simply do the "heavy lifting" of diplaying data to your view. You can watch a Rails-cast on this (Rails uses Helpers extensively) that shows some great UI refactoring.

In this case the user wanted to output the enum value as a string, which you can do this way:

 
<%=Enum.GetName(typeof(Product.SomeEnum),ViewData.Product.MyEnum)%>

 

But this is a tad messy in the UI. You can indeed add a property to your model, but this ties UI logic to your model, which isn't always the best option (but it does work).

The thing to do here, in my mind, is to create a Helper class for your Controller, and have it handle the formatting.

If we're using Northwind, we can create a ProductHelper class that outputs the enum's value:

public static class ProductHelper{

   public static string EnumToString(object en){
       return Enum.GetName(typeof(en),en);
   }

}

This works, but in looking at this you can see that there's more we can do with it. Specifically - it's highly reusable code, and the entire application (not just the Product-related views) can use it.

Given this, let's take this "up-scope" and create a site-wide UI Helper class, with a little more love:

public static class AppHelper{

   public static string EnumToReadable(object en){
       string result=string.Empty;
       result= Enum.GetName(typeof(en),en);
       //make it human readable
       return SubSonic.Sugar.Strings.ParseCamelToProper(result);
   }

}

You can also create this as an extension method and put it in your UI library - like we did with SubSonic!

Adam Tybor avatar
Adam Tybor says:
Friday, December 28, 2007
>>It’s not fair to say “don’t use CodeBehind” - it does come in handy for View-specific logic that you don’t want to “clutter” the page. I think I might have been the one who said this and I have to stand by my statement. CodeBehind is for webforms not mvc. You were able to easily solve the problem without code behind so why advocate CodeBehind? I do not want to "clutter" my pages but I also do not want to "deceive" my developers by occasionally using CodeBehind. "Give them an inch and they will take a mile" How do you prevent abuses of CodeBehind?

Casey avatar
Casey says:
Friday, December 28, 2007
Two things I immediately identify as code smells are classes with the words 'Service' or 'Helper' in them ... it indicates a class that you really couldn't think of a better name for and ended up dumping it there ... 'Manager' is another good indicator of a code smell.

mike avatar
mike says:
Friday, December 28, 2007
@Adam Tybor You can have a war on code behind if you like, but it's useless. Code behind is just a way to separate some code from the markup in a different file. The only bad thing about code behind is the bad thing someone writes in it. So in _no_ way is the concept of code behind bad, it only becomes bad when someone writes bad code. If you really dislike the concept of code behind, you should have a coding standard to prevent it. Use code blocks in the .aspx-files instead. It will not solve anything, because the bad code is still bad code. Here's an example. I need a tree on one page in my application. The markup for it is generated by calling a method recursively. This method writes out HTML, so it's not on my Model objects (it does use the model object to get the data). Because it's needed in ONE page, I declare the method in the page. Where? In the code behind of course. I could put it in a script block on the .aspx-file but I like the fact that the method declaration is in a separate file. After that, it can be refactored as needed using the advice given in this post, but until that time, I am perfectly happy with code behind.

Steve avatar
Steve says:
Friday, December 28, 2007
I also dislike 'code behind', this is a webform concept. I think the controller should be the code. Any UI logic can be done via the view template code and kept clean. I'd even like to see the 'databind' calls move into the controller. If you want webform code behind, then use webforms. If you want MVC, then use your controller properly. As far as cross-cutting concerns - AOP is one good solution. ie. Windsor supports interception. It's clean way to implement what Rob is talking about. Utilizing a IoC container to facilitate AOP is very powerful

Michael avatar
Michael says:
Friday, December 28, 2007
@Steve & Adam Putting business logic and data logic in the code-behind IS a webforms concept, but the code-behind itself is not a bad idea. I can think of multiple ways that code-behind can make cleaner code and remain true to the view logic. Why is code-behind a webforms concept? I do not understand the reasoning behind that. Can you explain please?

Steven Harman avatar
Steven Harman says:
Friday, December 28, 2007
@Casey, Can you provide an example of how you would solve this same issue w/o the 'helper', 'service', and/or 'manager' classes stinking up the place?

Steve avatar
Steve says:
Friday, December 28, 2007
Code behind implies logic in the view. It tightly couples that logic to the view. It stems from webforms to handle page related events with it's page controller model. Outside of 'binding' I fail to see the value of it in a mvc architecture. Personally I'd be implementing javascript on the page to handle view related events. Outside of that it would be post/gets with the form to determine controller events.

Michael avatar
Michael says:
Friday, December 28, 2007
Event-handling isn't inherently associated to code-behind. Event-handling and such is a Webforms feature and necessity. Just because you have the ability to write bad code, doesn't make the whole thing bad. Besides, you can do all the things that are bad with code-behind without using code-behind at all.

Rob Conery avatar
Rob Conery says:
Friday, December 28, 2007
>>Two things I immediately identify as code smells are classes with the words ‘Service’ or ‘Helper’ in them … it indicates a class that you really couldn’t think of a better name for and ended up dumping it there … ‘Manager’ is another good indicator of a code smell.<< Fair point - but you have to remember that we're not necessarily talking OO here, and moreover these things are indeed helpers and services. It's a bit of a buzzword ("Code Smell") and I know the article that you're referring to (Angry Coder). In the sense where you have a "DataManager"and a "UserManager" - well that makes sense (what do they do?). But if you have a folder called "Services" with a class called "Gravatar" - to me that's fairly clear. That said - your point is very well taken. Naming issues are pretty huge and I would offer that whatever works for you and your team is what you should implement. For the enum example, I would probably implement it in an Extension for enums - I'd call that class "EnumExtensions" and I'd drop it in a folder called "Extensions" :). @Others: Code Behind is a preference, purely. I might offer @mike that the sample you gave can be handled much better by slicing it up into re-usable chunks. For instance - you can have a routine that recursively builds a List<> based on a self-referencing join, and another method that takes that List<> and applies a format to it (in the way that we have ToFormattedString() in the MVC Toolkit). This is off the top of my head, but at the very least you may want to consider that the "one" tree you're working on won't be your last, and you might want to take some time to make it generic ;).

Steve avatar
Steve says:
Friday, December 28, 2007
Michael - in a MVC environment, there is no need for code-behind, that is what the controller is handling. It's a front controller vs. a page controller. If you want 'code-behind' then use the webform page controller architecture. Certainly anyone can write bad code, but having code-behind in the mvc environment simple makes no sense to me. I'm sure this debate will continue, so I won't respond again but I'd rather put my static function in my controller as a 'helper' vs. putting it in a code behind. To me it creates confusion by even having it available. I've worked with the Monorail MVC and there was never a need for 'code behind'. If anything, we can add some form helpers for databinding as well and remove this code-behind page controller method out of the front controller model.

Ryan_k avatar
Ryan_k says:
Friday, December 28, 2007
I would agree that there is a definite lack of "code smell" when specifically naming a class "TextSterilizer" and putting it into your services folder. However, I can see the argument to give an inch and have the developer take a mile. The same can be said for code-behind files, great code can be written in code-behinds but it doesn't "fit" the pattern. But where does this all go? At the end of the day, if a developer is thrashing trying to fit into a model that they are not comfortable with, is a code-behind addition an answer? Of course it is! I think it is very easy to get caught up in the patterns and architecture, but when will it be allowable to just utilize just a snippet of the ASP .NET framework over convention if it fits the bill?

Alexey Kouzmitch avatar
Alexey Kouzmitch says:
Friday, December 28, 2007
Aside from the fact that I disagree with you regarding Service/Helper static methods (oh man do I hate the ubiquitous Utility class), I would like to point out that the Enum.ToString() method actually returns the string representation of the enum value. So even if someone DOES create static helper methods, they should be aware that they may be creating straight code bloat (with methods such as EnumToString(...)). I've seen too many mehtods along the lines of: ... public static XmlDocument LoadXmlDocument(string fileName) { XmlDocument doc = new XmlDocument(); doc.Load(fileName); return doc; } ... I would also think that, in the C# 3.0 land, EnumToReadable(...) should be an extension method on the String class.

tgmdbm avatar
tgmdbm says:
Friday, December 28, 2007
I love mvc. 95% of my code behind files are empty. I'm simply using them to define the strongly typed view data. 5% however, contain a few simple methods for formatting HTML where putting that code inside the view would make it untidy and unreadable. AND only in the case when that code is _specific_ to that view. If it's generic i'll consider putting it in an extension method for HtmlHelper. But now i'm cluttering up HtmlHelper. I wouldn't say code behind is bad, i definitely wouldn't suggest removing it from mvc projects. I would, however, suggest providing an @page directive for specifying the strong type of the viewdata so that you don't NEED code behind (i'm sure the team is already thinking the same thing! ;) Then the "war" will inevitably become about whether to include code behind "by default" or not. (its deja vu all over again :)

Vijay Santhanam avatar
Vijay Santhanam says:
Friday, December 28, 2007
I dig the RenderUserControl method. I implemented something similar using Scott Gu's cool ViewManager pre MVC times. I'm so glad its going to be part of ASP.NET. I still don't get how you pass user control specific to the user control with having each TViewData contain/encapsulate the data needed for the user control. i agree with tgmdbm about page directives, but i heard you need to specify them in weirdo clr syntax, like Company.MyNameSpace.GenType`1[System.Object]

Jeffrey Palermo avatar
Jeffrey Palermo says:
Saturday, December 29, 2007
@Rob, Regarding having service classes full of static methods. . . I strongly dislike this approach because of the tight coupling that occurs upon using these static methods. There need to be a good reason to create a global function. Much of the industry has gotten past the "avoid globals" best practice, but it also applies to functions. There is absolutely no way I can test-drive a controller action if I can't fake a dependency and assert we interacted with the dependency correctly. If the interesting code is inside a static method, there is no way to fake this out for the unit test. If we worked on a project together, I would take the actual cross-cutting concerns (like logging and getting the system time) and make the static method merely a wrapper and a line of code that resolved the dependency from my IoC container and then called the appropriate method. Then, in controllers, I'd make the dependency explicit by requiring it in the constructor, but, where necessary, I could use the static method knowing that it will delegate to my interface anyway. This will become especially useful in integration testing where I want to run code up to a certain point and then fake out the hard dependency that doesn't work well in an automated test. For workflow code, the system clock is the most common dependency that needs to be faked out for testing because we have to test that notifications go out on the proper schedule. Static methods are particularly heinous when it comes to coupling, so I generally avoid them. Regards, Jeffrey Palermo

Casey avatar
Casey says:
Saturday, December 29, 2007
Well, EnumToReadable appears to be a formatting function - so it shouldn't be in something generically called a Helper ... perhaps it should sit in a Formatter class? But the class name should really depend on the applciation context and domain language being used, I just find that Helper, Manager, and Service are all signs that not enough thought may have gone in ... Essentially, if the functions have meaningful uses, they probably should have meaningful names ... You could pretty much add 'Service' or 'Helper' onto 90% of classes in an applciation and alter their meaning little. For example: What is the difference between OrderHelper, OrderService, or OrderManager? They could probably all be for functions related to Orders, or for saving and loading Orders, or for storing Orders ... I just find those suffixes to be concerns. Incidentally ... if I do use a similar structure, it is the namespace that holds the 'Service' or 'Helper' bit ... So the following would sit more comfortably with me (including the class name being more meaningful): namespace Application.Presentation.Helpers { public FormatEnumForHtmlUse {} } The fact that the methods are also static just add to the concern, as Jeffrey said, the lack of tesability or replacement is a concern to me.

Rob Conery avatar
Rob Conery says:
Tuesday, January 01, 2008
@Alexey: If you disagree with me RE Helpers/Services, it would help if you pointed out why. I wasn't suggesting these classes are Utility by any stretch. Helpers handle UI logic in a central place, Services handle things that don't necessarily plug in "vertically" to your site. @Jeffrey: >> If the interesting code is inside a static method, there is no way to fake this out for the unit test.<< Agreed. But what is it you'd be testing here? And why? If we're discussing "horizontals" like logging and email - would you want this as part of your test? If you did - why not use the actual class? How do you "mock" a successful SMTP anyway? Your point, however, is well-taken in general however I think there's a lot more latitude for what you can ignore in terms of app-wide "services". >>I would take the actual cross-cutting concerns (like logging and getting the system time) and make the static method merely a wrapper and a line of code that resolved the dependency from my IoC container and then called the appropriate method. Then, in controllers, I’d make the dependency explicit by requiring it in the constructor, but, where necessary, I could use the static method knowing that it will delegate to my interface anyway. This will become especially useful in integration testing where I want to run code up to a certain point and then fake out the hard dependency that doesn’t work well in an automated test.<< This would be an excellent way to test your call, but at the cost of cruft (in my opinion). I had a good time the other day poking fun at Harman cause he spends more energy and inspiration on testing than he does on actual coding :):):). All fun aside - I see what you mean technically, but in my opinion it seems like that's an awful lot to go through for "logging and getting the system time". I don't think I'd last on that project :). Your comment's appreciated though! Thanks!

Tim Peel avatar
Tim Peel says:
Wednesday, January 02, 2008
Although this is slightly off topic for the post, I am interested in the static or not static debate ... would anyone have any more information or relevant blog posts/articles discussing it? @Casey: How would you go about using the example you put forward? Thanks


Search Me
Subscribe

Index Of MVC Screencasts

You can watch all of the MVC Screencasts up at ASP.NET, and even leave comments if you like.

Popular Posts
 
My Tweets
  • @haacked must.... resist... assimilation...
  • Dinner at the Haacks. How did Phil get such a cute kid? Evidently Phil's in the doghouse though...
  • @shanselman dude turn off twitter and drive! that's gotta be illegal!
  • For D'Arcy and Justice... Scottgu goes Canuck! http://twitpic.com/mfz1
  • Working in ScottGu's office with @shanselman. Wearing an Orange Polo and saying "go ahead" a lot for some reason.
  About Me



Hi! My name is Rob Conery and I work at Microsoft. I am the Creator of SubSonic and was the Chief Architect of the Commerce Starter Kit (a free, Open Source eCommerce platform for .NET)

I live in Kauai, HI with my family, and when my clients aren't looking, I sometimes write things on my blog (giving away secrets of incalculable value).