What went wrong: IDbConnection life cycle
When deploying this site for the first time and actually telling people to come here, I learned that I had made a pretty big mistake. Appropriately (or perhaps tragically), I made a mistake in one of the cross-cutting concerns of my own site.
I am using StructureMap to wire up all my dependencies, and 90% of these dependencies are just done WithDefaultConventions. But there is one dependency, IDbConnection which I wired up by hand, like so:
If you can spot the mistake here, then congratulations, you are officially a better developer than me (which is no high accolade). Here's what I should have done:
And then, in Application_EndRequest, I just call ReleaseAndDisposeAllHttpScopedObjects() on ObjectFactory. This means each of the SqlConnections will be bound to a request, and then disposed of when the request is complete. Because I wasn't doing that before, each of the connections would stay open. I didn't notice this when developing the site, because I was continually rebuilding and redeploying.
This may not be strictly speaking AOP, but it's certainly a cross-cutting concern, as almost every request makes use of the IDbConnection to use Dapper, and using StructureMap to manage that dependency saves me from writing a bunch of boilerplate "new SqlConnection" in all my repositories.
Lesson learned: if this site was actually mission critical to a business, I would've been in hot water. I should've been testing with a larger number of requests over a longer running application in an environment similar to production. Fortunately, since I didn't have a bunch of repetitive boilerplate, it was very easy for me to make the fix, once I figured out what the problem was.