Introduction
In my first MVC series post, I discussed how to dynamically add items to a container using an MVC controller. Afterwards, I went through the process of unit testing the AccountController. The main purpose of this series was to explain some troublesome hiccups I ran into considering I did not come from a web development background. In this post I want to highlight a few of the minor issues while developing in MVC. One of them is not even related to MVC specifically, but it still caused enough of a headache that hopefully someone reading this can be spared the confusion.
HttpContext in Unit Tests
When I first started unit testing controllers, the HttpContext would return null when attempting to be accessed. The reason for this is because the controllers never assign the class on creation. Instead, controllers are typically created by the ControllerBuilder class. In my last post about unit testing the AccountController, I described a way to mock out the HttpContext, but in the beginning I wanted to try and keep my test project as lean as possible. Since I had not approached testing the AccountController yet and did not want to include a package to mock out an object I only needed to resolve NullReferenceExceptions, I found this clever post to quickly bypass this issue. By providing the HttpContext with a simple Url I no longer received an exception and was able to test the other components of a controller. I decided to wrap this functionality inside a class:
public class TestHttpContext : IDisposable { public TestHttpContext() { HttpContext.Current = new HttpContext( new HttpResponse( null ) ); } public void Dispose() { HttpContext.Current = null ; } } |
Since I am creating a new controller for each test, I needed the HttpContext to be recreated and destroyed each time. So, I went ahead and placed this inside a base test class that all controller tests will inherit:
public class TestBase { private TestHttpContext _testContext; [TestInitialize] public void Initialize() { _testContext = new TestHttpContext(); } [TestCleanup] public void TestCleanup() { _testContext.Dispose(); } } |
Mocking out the HttpContext would provide better unit testing standards, but my minimalist personality found this solution too good to pass for the time being.
DbContext Non-Thread Safe
After updating my project to use Unity, I decided to take better advantage of the dependency injection design pattern by making the DbContext a singleton to prevent having to constantly re-initialize the connection to our Azure database. Early on after this change it became apparent our website was very inconsistent when trying to write to the database. Since many changes were occurring during this time, I did not immediately presume the DbContext as a singleton was the cause until I ran into this post.
So it seems I could still gain a performance boost by only creating the DbContext once per thread call, but how could I do this implementation using dependency injection? “Fortunately”, a new version of Unity provides a LifetimeManager catered specifically to this calledPerRequestLifetimeManager.
This solution dramatically reduced my refactoring costs to close to zero, which was very desirable at this point in the project where time constraints were becoming out of reach. Later, I did a more thorough research into DbContext and you will notice this is why I put ‘Fortunately’ in quotes. As this MSDN post mentions, PerRequestLifetimeManager is bad practice to use when dealing with the DbContext. The reason is because it can lead to hard to track bugs and goes against the MVC principle of registering objects with Unity that will remain stateless. Although our application never ran into issues after implementing this LifetimeManager, in the future it is best to simply create and destroy the DbContext every time.
Ajax Caching in IE
This last problem is not so much an MVC issue, but a cross browser bug. And it is not so much a bug as it is more of understanding there are different specifications for each browser. As I mentioned in my post for creating Dynamic Items, I was using ajax calls to dynamically modify the DOM of a container. Throughout the project though we would intermittently hear bugs when attempting to add an item and trying to save. Each time the bug would re-occur, I would view the problem area, look stupefied at the cause of the issue, check in a fix, and the problem would go away, only to show up again a week later. What was going on here? Especially since the files in this area had been untouched for weeks!
The problem? Internet Explorer and its aggressive caching. The other browsers are not this adamant about caching ajax calls, at least when it comes to developing testing. And the solution to the problem was a bit more demoralizing:
$.ajax({ async: false , cache: false , url: '/Controller/Action' , }).success( function (partialView) { // do action }); |
One line of code solved weeks of headache Although any fairly seasoned web developer would probably speculate the browser being at fault, as someone who only ever has to deal with one set of specifications (.NET/WCF/EF/WPF/SQL) our team and I were not use to meticulously testing each new feature on every available browser. This meant although someone would find the bug in IE, but in retesting they may have coincidentally retested the feature in Chrome. Or, even worse, republishing the test caused the caching to reset so retesting the feature would get the pass the first time, but would not realize how broken it was until days later. All this means is we need to have a different method for testing web projects and to continue our understanding of how web development can act.
Summary
Working in MVC has been a great learning experience and helped continue my growth in developing in web. Despite my complaints and the hair-splitting, alcohol consuming problems I do enjoy the breadth and stability MVC provides to the web world. I will continue my progress in the realms of web development and hope these small roadblocks will become less frequent, at the very least for my sanity’s sake.