ASP.net MVC Routing Throws Exceptions as Normal Behavour? - asp.net-mvc

I was debugging my current project (ASP.net MVC 1.0 project)
and stumbled upon slightly disturbing behavour.
It seems that when the router is hunting for a referenced partial view
aka
<%Html.RenderPartial("AccountListControl", ViewData["AccountList"]); %>
It cycles through it's default locations until it finds the correct spot.
So it checks "Views\Shared\AccountListControl"
and checks "Views\Home\AccountListControl"
etc
Once it finds a match - all is good.
Bad locations are identified by the web exception thrown in each case.
Is there a significant performance cost for all of these exceptions?
Should I modify the code to be more explicit?

It seems that in Release mode there are no exceptions thrown and view locations are cached so there is no need to be more explicit.

Related

Logging 404 errors (with target and referrer URL fields)

I want to collect and analyze 404 data to address any real issues, in an ASP.NET MVC site (with ELMAH). The chief requirement is to store this information in a more specialized and dense but still queryable format, including the referring site/URL.
I can currently review 404's in ELMAH. However I do not want ELMAH collecting all my 404's (at least not in the default format), because these error logs get large too rapidly. Only about 1% of an ELMAH 404 log is typically relevant data, for example logging irrelevant exception details about mundane vulnerability scans. Then, finding real errors becomes very difficult, or even impossible if I have to truncate my ELMAH table weekly.
Also, even after collecting all that data in ELMAH, it does not offer specialized fields for the critical target and referer URL fields (to query or aggregate) that make managing 404's possible.
If there's a package (e.g. via NuGet) that is able to store to SQL, includes a presentation layer, can sort by most common errors or errors with actual referring sources, and even permits marking them seen/addressed so they do not show in future reports, that would be an ideal solution. Any solution providing a portion of that would be a great start.
In lieu of a recommendation, I will probably add a custom handler to ELMAH and log to SQL through my own data layer.
However, I'd prefer a packaged solution, and it need not leverage ELMAH. I can manually add a filter to ELMAH (Elmah reporting unwanted 404 errors, ELMAH - Filtering 404 Errors) if ELMAH is not part of the solution.
I'm one of the developers behind https://elmah.io. elmah.io offers some of the features you are looking for. You can search for errors by different key properties. Also the filter part can be implemented using our Rules option, where you can ignore errors from specific user agents and so on.
We are also creating a ErrorLog implementation for ELMAH, making it possible for you to store errors in Elasticsearch: https://github.com/elmahio/Elmah.Io.ElasticSearch. You could search and aggregate all of your 404's using a UI for Elasticsearch like Kibana.

MVC Mini-Profiler throws LockRecursionException when modifying RouteCollection

I am seeing a pretty crazy error crop up when using the MVC MiniProfiler. Intermittently, the site I'm working on enters a state where every request results in this exception being thrown:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
---> System.TypeInitializationException: The type initializer for 'MvcMiniProfiler.MiniProfiler' threw an exception.
---> System.Threading.LockRecursionException: Write lock may not be acquired with read lock held.
This pattern is prone to deadlocks. Please ensure that read locks are released before taking a write lock.
If an upgrade is necessary, use an upgrade lock in place of the read lock.
at System.Threading.ReaderWriterLockSlim.TryEnterWriteLockCore(Int32 millisecondsTimeout)
at System.Threading.ReaderWriterLockSlim.TryEnterWriteLock(Int32 millisecondsTimeout)
at System.Web.Routing.RouteCollection.GetWriteLock()
at MvcMiniProfiler.UI.MiniProfilerHandler.RegisterRoutes()
in C:\Users\sam\Desktop\mvc-mini-profiler\MvcMiniProfiler\UI\MiniProfilerHandler.cs:line 81
at MvcMiniProfiler.MiniProfiler..cctor()
in C:\Users\sam\Desktop\mvc-mini-profiler\MvcMiniProfiler\MiniProfiler.cs:line 241
— End of inner exception stack trace —
at MvcMiniProfiler.MiniProfiler.get_Current()
at TotallyNotOverDrive.Boom.MvcApplication.Application_EndRequest()
The error persists until the app pool is recycled. Looks like somehow a lock is being held which prevents the MiniProfiler from trying to register it's routes. This occurs for requests where I am not starting the MiniProfiler, but during Application_EndRequest I call MiniProfiler.Stop(), which seems to result in a MiniProfiler being created when the Current property is accessed. For a simple solution, I modified EndRequest to use the same logic for stopping the profiler as BeginRequest, so if the request is not using the profiler this error should be avoided completely. I would still like to resolve the actual problem before sending this code to production.
My route table is pretty simple, and is only added to within the Application_Start method. We are not using any other third-party code which might be modifying the route table after startup. The only suspect thing I've done with routing is add a custom Route to the table, but it's a pretty straightforward route, I just needed some more complicated pattern matching than a standard MVC route could accomplish.
I looked through the relevant MiniProfiler code and don't see anything that could be causing a lock to go unreleased, so I'm assuming it's a combination of ASP.NET and MiniProfiler conflicting when accessing the RouteTable. I can't reliably reproduce the problem, so I'm wondering if anyone else has had problems like this with routing. Thanks for any help you can offer.
I think I see what is happening, you need to get the routes registered earlier. You are registering them during EndRequest, at this point there may be other requests in the pipeline which are holding read locks on the route table.
The routes are registered in the static constructor of MiniProfiler. If you access any of the settings in MiniProfiler during Application_Start, this will kick off the static constructor that will register the routes.
For example, try adding something like this, just after registering your routes.
MiniProfiler.Settings.PopupMaxTracesToShow = 10;

How do I test that Asp.Net MVC Views are rendered without exceptions?

I have come up with a small issue in my application.
I changed the namespace of my main application to be from MyApp.Models to MyApp.ViewModels so that the namespaces were less confusing overall (since that namespace only has view models and no business models). I changed all the references I could find, including in my views, and I re-ran all my unit tests and went through the application, and all seemed fine.
A few days later I got a report that the registration page had an error when it was brought up. After looking it turns out I forgot to fix the namespace on the registration page, and thus it was failing to compile the view.
This worries me. The whole point of unit testing, and one of the biggest lures of Asp.Net MVC, is to be able to have confidence in your application by having everything tested individually automatically so that you know immediately when your modification breaks parts of the system. Views right now seem like a major hole in this.
To be clear, I am aware you are able to turn on pre-compiling a views. However, I do not like this option as it's not a good idea to have this on all the time (as it makes compiling a new build very, very slow), and having a separate configuration scheme for this means it's up to the user to remember to attempt to compile with that configuration scheme to check for view compile errors.
This also completely bypasses checking for runtime errors that may occur. For example, lets say you change the viewmodel that a strongly-typed view is expecting. You would then update the unit test to make sure that the Controller.Action() is returning a view result with the correct view model type, but that does nothing to make sure that the actual view was updated correctly for the new view, and yet this scenario will cause a run-time exception. This is an easy scenario to occur, especially since if the differences in the two view models are only seen in partials used within the view.
Other examples of code that can cause runtime exceptions in views are incorrect loops (possibly caused by changes in a view model), code that checks a user's role (so buttons are only shown for users with credentials), incorrect casts (e.g. for converting a collection into a select list), incorrect code to sort a collection (how a collection is sorted in the display can construed as a view concern, not a controller or view model concern), if strings used for locations of files don't work correctly (T4MVC doesn't integrate well with some things, such as Telerik's script registration system) etc...
The way I see it, there are many things that can cause an exception to occur in the process of rendering a view, and I can't seem to find any way to create unit or integration tests to determine when these occur. I would feel more comfortable if I did not have to check every page to make sure I missed a compile time or runtime error for something that a standard unit test should be able to catch.
What options do I have to do this?
I would prefer to stay away from WaTiN and other GUI testing tools, as for this I am not interested in the actual display of the page, I only want to know if the view renders or if an exception occurs and do not need the overhead of Watin running an IE instance for each test (I also think this will cause issues if I go with continuous integration at a later point).
If you don't want to use WaTIN and IE, how about firing up your web site in IIS Express, and then using HttpWebRequest over each of your Views' urls to check the result is 200 OK. This is a complete integration test.
Otherwise, you have to get the ViewResult from your controller, and call the ExecuteResult method passing in a ControllerContext containing a stubbed HttpContextBase. This gives more of a true unit test, and would be faster, but you've got a lot of mocking and stubbing to do before it will work.
mspec mvc extensions

How to do Specification Testing with ASP.NET MVC Error view

I'm doing BDD on an MVC3 project with SpecFlow. My current specification scenario says that:
Given a user is working on the system
When an error is raised
Then the user should be redirected to error page
And display a link to go back where he came from
How can I test a spec like this? I usually test the controller directly, however the Error view given by the standard MVC3 template has no controller, and no controller is used, because is redirected by the HandleError global filter.
In exceptional cases I use Watin to test that the behavior conforms to what the specification says, however to do that I need a view that raises an error, something that when everything is working i do not have.
Any ideas on testing scenarios like this?
I have a few thoughts on this scenario:
1.) "Given a user is working on the system" is a pretty vague step. What code would be found in the step definition? Unless you have a user class that has a WorkingOnSystem method, it might be worth taking this line out.
2.) Without having seen the rest of your code, I think the target of this feature should be the HandleError filter itself. By its very definition, you know that when it is invoked an error has occurred. All you need to do is instantiate the filter, call the appropriate method, and test the results.
Think about it this way: What does "When an error is raised" mean in your system? If your HandleError filter is not the place, then you probably don't have a place. In which case, you'll need to be more specific.
I think the awkwardness around this spec is due to ASP.Net MVC. When you're dealing with a framework of abstractions, you're sometimes left to "wrap" your specs around some part of it. We just can't go end-to-end easily when the parts of the application come from so many places.

Finding all use of session state

I'm looking for some smart ideas on how to quickly find all usage of session state within an existing asp.net (MVC) application.
The application in question was the subject of outsourced development, and has been running fine in production. But we recently realised that it's using InProc session state rather than (our preferred route) StateServer.
In a small scale test, we switched it over to StateServer, and all worked fine. However, when we deployed to production, we suddenly experienced a large number of errors. I'm not sure if these errors were caused by this change (they were actually complaining about database level problems), but removing the change allowed the application to function once again (this may have just been because it caused a recycle to occur).
So before I try switching it again, I'd like to perform a thorough audit of all objects being placed in the session (I'd previously taken a quick look at a couple of controllers, and they seemed fine). If I had full control over the code, this is the kind of place where I'd just comment out the class (to compile and find the various ways of reaching the session class), then comment out the accessors, hit compile, and visit each error. But I can't do that with built in .NET framework types.
So, any smart ideas on how to find each usage?
I decided to try using Reflector. I've analyzed the "Used By" for each of the following:
System.Web.HttpSessionStateBase.set_Item(String, Object) : Void
System.Web.SessionState.HttpSessionState.set_Item(String, Object) : Void
System.Web.SessionState.HttpSessionState.set_Item(Int32, Object) : Void
System.Web.HttpSessionStateBase.set_Item(Int32, Object) : Void
System.Web.HttpSessionStateBase.Add(String, Object) : Void
System.Web.SessionState.HttpSessionState.Add(String, Object) : Void
(and checked that we don't use TempData anywhere). Am I missing any other routes by which items can end up in the Session?
You can get the source for asp.net MVC. to look for use of Session
http://aspnet.codeplex.com/releases/view/58781 for MVC 3
http://aspnet.codeplex.com/releases/view/41742 for MVC 2
http://aspnet.codeplex.com/releases/view/24471 for MVC 1
I've actually found these quite useful to have laying around for when you need to find out why something is doing what it does.
MVC 2 won't run with Session switched off, so it may be using the session in ways not compatible with stateserver.
From the DB errors, sounds like nHibernate maybe doing something. You could get the source for that as well to have a look see, but I'm sure it's use of session will be documented.
Simon
I say do a solution wide search for "Session". Besides this if this is ASP.Net MVC application, then don't forget that TempData is also Session.

Resources