ASP.NET MVC Unit Testing and HttpContext - asp.net-mvc

ASP.NET MVC has come a long way (compared to webforms) in becoming a unit testable framework. However, we are often faced with some remaining pigs like FormsAuthentication, which I usually wrap in some type of UserSession object to keep it clean and testable. The other day I realized I was using Server.MapPath in my controller action, and while things like MvcContrib make it easy(ish) to mock the current request, I found myself going down the path of creating a FileSystemService class to wrap operations with the file system. The benefits are that you get a tight API exposing just the methods you need, and it's easy to stub/mock in tests. The downside is that it is yet another constructor dependency.
What does the SO community thing about this situation? Where do you draw the line when trying to make your controllers as light and flexible as possible?

I would generally draw the line at the point where you need to actually get something done (i.e. somebody wants to use the code you're writing). If it takes another half a day to write your service etc. and your deadline is looming, then some things are best left...

Bear in mind that ASP.NET MVC has already replaced the sealed HttpContext with more test-friendly HttpContextBase, which you can mock to provide your tests with your chosen implementations of Server.*, Request.*, Response.*, etc.
You just need to set the controller's ControllerContext to provide your test context:
controllerUnderTest.ControllerContext = new ControllerContext( testHttpContext, new RouteData(), controllerUnderTest );

This is a great question! I do the same thing you do - wrap HttpContext dependencies so they can be visible, inverted, and mocked.
I draw the controller line at validating the post values and saving or passing the call off to a task layer. So if I have to validate, save some data, send an email to marketing if a preferred customer makes a purchase, log something, etc., that's too much. I'd put that in a task layer and have my controller call that task layer. Most of the dependencies then float to the task layer constructors and come out of the controller.
My general rule of thumb is this: If you were asked to create a Silverlight or some other UI on your app, would you be totally rewriting it? Controllers should stick to presentation logic. If you can scrape off the presentation layer and put another one on, I think that gives you the best future proofing.
Of course, where you draw the line is up to you and your app. See Who Can Help Me, which is based on Sharp Architecture, for more about the task layer and skinny controllers.

There are also these wrappers around things like HttpContext to make testing easier:
http://www.codethinked.com/post/2008/12/04/Using-SystemWebAbstractions-in-Your-WebForms-Apps.aspx
So to sum it up:
Get System.Web.Abstractions
Use HttpContext base as a parameter, not HttpContext:
public void SomeMethod(HttpContextBase context)
{
}
Call the method wrapping your real http context
HttpContextBase contextBase = new HttpContextWrapper(context);
SomeMethod(contextBase);
You can provide fakes like so (example using Moq):
var context = new Mock<HttpContextBase>();
context.Setup(x => x.Request.QueryString).Returns(new NameValueCollection { { "Id", "5" } });

Related

Working with helpers in the dotnetcore DI world

I like to have static helper classes in my apps for common plumbing stuff, like checking roles, or Razor Html helpers and stuff... but how do you do this in the DI world?
Like lets say I want an extension helper to check if a user is an admin
public static async Task<bool> IsAdmin(this ApplicationUser user)
...
if(user.IsAdmin()){...}
So pre-core I could just ignore DI and create a UserManager all inside IsAdmin do whatever I need to do. But now is there no way to get the UserManager in these helpers to just use? The only way I can see is to inject it into the Controller, then pass along into the method (which I find ugly). Then there's the issue of trying to do user.IsAdmin() in the Razor view, would I need to add the UserManager to the ViewData collection to get it into the view markup?
Am I just missing something here?
Thanks,
Steve
First of all if you just asked how to use static class with di, i would say that your question is duplicate of How to use DI inside a static Method in Asp.net Core rc1
But as i see, you have some other question?
But now is there no way to get the UserManager in these helpers to
just use?
Yes there is a way : Service Locator pattern. But it is an anti pattern (see this article) . As far as possible you should avoid to use this pattern. Also see discussion in github.
The only way I can see is to inject it into the Controller, then pass
along into the method (which I find ugly)
I think this way is better than you want. I would prefer this.
Then there's the issue of trying to do user.IsAdmin() in the Razor
view, would I need to add the UserManager to the ViewData collection
to get it into the view markup?
In Aspnet core you can inject a dependency into a view, so you don't need to use ViewData. Simply you can inject UserManager into your view and then pass it as parameter to method. Take a look at official docs
Well you are talking about a cross-cutting concern here and one way how I've seen cross cutting concerns solved in ASP.NET Core MVC is with attributes (like [Authorize] for example). Which I think is an elegant solution.
So, if I understand your question correctly I think you can solve this with an Action Filter. Damien Bod described a few days ago how to use ActionFilters: https://damienbod.com/2016/09/09/asp-net-core-action-arguments-validation-using-an-actionfilter/.
So in short, you inherit from ActionFilterAttribute and make your own curstom filter called MyCustomFilter or whatever. Have this MyCustomFilter request UserManager in its constructor via DI. Then above any action method in a controller you say:
ServiceFilter[typeof(MyCustomFilter)]
And in MyCustomFilter you ofcourse have logic to check if User is IsAdmin and then take action accordingly.
Now, I've always used Microsoft's Unity to handle cross cutting concerns via interception (you can read more about that here: https://dannyvanderkraan.wordpress.com/2015/09/30/real-world-example-of-adding-auditing-with-dependency-injections-interception/. But last time I checked there is no Unity container for asp.net core yet. But this guy has a great article about porting it to core: https://dzimchuk.net/post/bring-your-own-di-container-to-aspnet-5-unity. I would really like my Interception back! Very elegant solution to cross cutting concerns. They are working on it though: https://github.com/unitycontainer/unity/issues/66. Fingers crossed...

Castle.Windsor and HttpContextWrapper

HttpContextWrapper and HttpContextBase, as explained here, were introduced to make HttpContext more mockable/testable.
I'm trying to use it with S#arp Architecture, and hitting some problems.
My MVC Controllers are set up to accept an HttpContextBase argument in the constructor, and during Application_Start, HttpContextBase is registered with Castle.Windor as follows:
container.Register(Component.For<HttpContextBase>().UsingFactoryMethod(
() => new HttpContextWrapper(HttpContext.Current)));
This seemed to work OK for a bit, but then I realised Castle is only running that Factory method once, so all requests get the original HttpContextWrapper. Really it needs to be re-created for every request. The Castle.Windsor command for that would be:
container.Register(Component.For<HttpContextBase().
LifeStyle.PerWebRequest.UsingFactoryMethod(
() => new HttpContextWrapper(HttpContext.Current)));
... but it turns out that Castle.Windsor doesn't allow LifeStyle.PerWebRequest to be used within Application_Start (as explained here)
What should I be doing? Is there an easy way round this or should I give up on HttpContextWrapper and inject my own factory to make new ones as needed?
My MVC Controllers are set up to accept an HttpContextBase argument in the constructor
You gotta be doing something extremely wrong here, so stop before it's too late and damage has been caused (material, moral and human casualties :-)). You already have the HttpContext inside the controller.
Don't register any HttpContexts in your DI framework. The HttpContext handling is the job of ASP.NET.
As Darin noted, it makes no sense to inject an HttpContext into an MVC controller. However, if you need it for other kind of services and also need it in Application_Start(), use an hybrid perwebrequest-transient lifestyle. Or, since it's trivial to build, just make it transient.
As others have stated - you are doing it wrong. My big question is:
What are you doing that requires you to inject HttpContextBase in your controller? It might be more helpful to people wanting to help you if you would provide us more context about what you are really trying to do. Lets take Castle out of it and get down to what your controller is doing.
BTW, your controller already has a reference to HttpContext. If you are doing this for testability, there is nothing you need to do at the controller level. You would just need to mock the HttpContextBase object as needed in your controller tests.

keeping asp.net mvc controller size down

I have a Controller. "OrderController". Currently it's 1800 lines. I like to reduce the size. I'm using static helper methods which is fine but i'm using ninject to call my repositories so don't have access to the repositories in the static methods without passing the properties in.
What are some good approaches for reducing controller noise?
How to get a Thin Controller
Refactor reusable functionalities that can apply to multiple types of output to ActionFilters. Consequence: Less repetitive code, thinner Controller actions, quicker future development
Refactor reusable functionalities that apply to a specific type of output to a custom ActionResult. Consequence: Less repetitive code, thinner Controller actions, quicker future development
Leverage ModelBinders to bind your input values to complex objects that are injected into your Controller action. Consequence: You don't need to handle the actual HTTP input (RouteData, Form values, querystring parameters) at all in your controller. You can also handle data validation in your model binder.
Implement Dependency Injection via a custom ControllerFactory. Consequence: You don't need to construct services in your Controller.
Refactor single Controllers with an excessive amount of Controller actions into multiple Controllers. Consequences: Your code becomes more maintainable.
Move your static helper methods to static classes. Consequence: Your methods become reusable by multiple controllers and you have less bloated code in the Controller, so it is easier to maintain and make changes to your app.
Other Notes
Plenty of open source resources exist to help accomplish these tasks. I definitely suggest looking into the MvcContrib project. They have a FluentController base class that was designed with building thin Controllers in mind. Also, I upvoted Darin because the video he recommended is helpful, so check it out
No way should there be that much code in your controller. I suspect you haven't separated your concerns.
I would have a look and a think at the answer to this SO question:
ASP.NET MVC Patterns
In short:
Put the complexity into Service classes that perform a clear cut purpose, ie, to deliver what the controller needs.
The controller should just have the application logic, ie, it should just be acting as a kind of air traffic, uhmm, controller, sending requests this way and that based on app logic. That is pretty much its function in a nutshell. Other stuff doesn't belong in a controller.
My controllers look like:
[Authorize(Roles="Admin, Tutor, Pupil")]
public partial class CourseController : Controller
{
ICourseDisplayService service;
public CourseController(ICourseDisplayService service)
{
this.service = service;
}
public virtual ActionResult Browse(int CourseId, string PupilName, string TutorName)
{
service.Initialize(CourseId, 1, PupilName, TutorName, User);
service.CurrentStepOrder = service.ActiveStepIndex;
if (Request.IsAjaxRequest())
{
return PartialView(MVC.Courses.Course.Views._Display, service.ViewModel);
}
else
{
return View(MVC.Courses.Course.Views.Display, service.ViewModel);
}
}
note the service instantiation in the controller's constructor and the calls to service in the actions.
1800 lines!!!!!!!!! Holy mother of God. I would recommend you watching the following video about putting your controllers on a diet.

CQS and ASP.NET MVC Actions

Those who have read about CQS principle know that:
CQS states that every method should
either be a command that performs an
action, or a query that returns data
to the caller, but not both.
Speaking of ASP.NET MVC Actions, does CQS indicate that we shouldn't have an Action like this?
public PartialView InsertOrder(Order order)
{
OrderService.InsertOrder(order);
return PartialView("OrderDetails", order);
}
This method is changing the state of the system and returning the current state. If CQS is applied here, we should have 2 separate Actions: one for inserting a new order and one for getting the system of the system (which should be called from the client if the first Action was completed successfully). However, this complicates programming.
I'd like to know your opinions on this.
Mosh
A common example of Command/Query Separation on the web is Post/Redirect/Get.
In ASP.NET MVC, this is usually implemented in the simplest way as
[HttpPost]
public ActionResult UpdateOrder(Order order){
UpdateOrder(order);
return RedirectToAction("ViewOrder", new { order.OrderId });
}
[HttpGet]
public ActionResult ViewOrder(int orderId){
return View(GetOrder(orderId));
}
For AJAX, and a partial view, this might not be the best strategy, since the problems that Post/Redirect/Get solves aren't really relevant, and the redirect can be tricky.
CQS is only concerned with command and queries to the same object. Since a OrderView the Order are not the same object (I guess from your implementation) the principle does not apply, so your code is not counter the principle neither in favor :)
I've never heard of CQS, but if you are doing ASP.NET MVC (MVC pattern) the action you wrote is perfectly fine (assuming this OrderService there is an abstraction to the real service). The controller manipulates the model and decides which view to render and passes this model to the view.
I had a vague recollection of this term from the eiffel days (which if followed all the way back, actually predates most current oop principles by a good decade or so (late 80's i think). I'd suggest that this term and/or principle may well be outmoded now and superceded by actionresults in mvc (be that asp or codeignitor etc, etc). I actually think that in terms of the definition (which i just looked up now), this separation is concerned with the logic that performs the action i.e. OrderService.InsertOrder(order) in your example. So, in a way, mvc as performed in your action is actually loosley following this pattern (InsertOrder doesn't attempt to present any stateful info, purely process the order object).
I'd suggest that you look at best practice for asp.net mvc which is fundementally based on returning an actionresult (or partial, contentresult etc, etc). this pattern was designed to simplify the paradigm to facilitate productivity in a uniform and universally accepted fashion.
of course, you could use your action return values to generate a success or fail for the insert/update/delete scenarios and then request partial views based on those return value. However, i personally don't think i'd leverage too much value from that approach bearing in mind the fact that the controller in MVC is concerned with stearing the logic of which view should be returned as the result of an action.
hope this helps
jim

Asp.Net MVC Beta: Previous RouteData overrides current RouteData?

I have something similar to the following method:
public ActionResult Details(int id)
{
var viewData = new DetailsViewData
{
Booth = BoothRepository.Find(id),
Category = ItemType.HotBuy
};
return View(viewData);
}
and the following Route:
routes.MapRoute("shows","shows/{controller}/{action}/{id}", new {id = 0});
Everything worked fine before the Beta, when I had Preview 3. Now the method will fill the id correctly the first time I execute the action. However the second time the controller's ModelState contains the last-use id value. This causes the ActionInvoker to use it in the method's parameter instead of the Route value.
So if I call the action twice on two different entities the results are such:
www.mysite.com/shows/Booth/Details/1 => Details(1)
www.mysite.com/shows/Booth/Details/2 => Details(1) //from ModelState["id"]
From my quick scan with Reflector it seems it first binds parameters to the ModelState then to Routes. However, I never even posted anything from the model. As far as I can tell the ModelState should not contain anything.
Is this a bug in the Beta, possibly a bug somewhere in my code, or is there some design feature that I am ignorant of? Any insight into the nature of ModelState and why this happens is appreciated.
EDIT:
I discovered that this issue is actually a symptom of what appears to be a bug with the DefaultValueProvider if you instantiate a Controller from an IoC container that exists for the lifetime of the Asp.Net application.What happens is that the DefaultValueProvider uses the first ControllerContext given to the Controller and never updates it until the controller is recreated. This causes old RouteData to be used for method parameters instead of the current RouteData.
It's hard for me to tell what you expect to happen and what is happening from your post. Is it possible there's an error in your BoothRepository.Find method such that it returns the same thing every time?
ModelBinder should not be affecting this method because the parameter to the action method is a simple type, int.
Were both of these requests GET requests? If you still are having problems, can you try and create the simplest repro possible and email it to philha - microsoft dot com?
EDIT: The problem ended up being that the developer was attempting to re-use the valueprovider across requests (by having Castle Windsor manage the lifecycle of Controllers). Right now, there's no support for re-using controller instances across requests like you would with IHttpHandler which has a IsReusable property. So in general, reusing controllers across requests requires doing a lot more work on your end. :)
The problem is the LifeStyle, I completetly overlooked the fact it was being defined, which means by default the controllers will use the Singleton lifestyle. Setting the LifeStyle to Transient for all controllers will sort this problem.
if you use spring.net modify
Controller's singleton to "false"
This is a common issue when using Singleton behavior with a IoC container such as Spring.NET or Windsor. Controllers should not have singleton behavior because the ControllerContext is per request, much like HttpContext.

Resources