nhibernate session created on every web request in asp.net MVC2 - asp.net

I have an ASP.net MVC2 application that is using NHibernate for data access. On every request, even static file requests (images, javascript), a new session is getting created. So for a single view where I'm returning a list, I'm creating around 15 session that don't load anything.
is there way to only create sessions when they are required?
I'm currently using Castle.Windsor to inject the session into my Controllers.
Is there a way to filter out static file requests?

It sounds like you need to exclude those paths in your routing:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// add these lines
routes.IgnoreRoute("{resource}.jpg");
routes.IgnoreRoute("{resource}.js");
}
Although if you ask me, a request for a static file shouldn't be instantiating a controller. You might want to take a look at your code and figure out why it's doing that.

Also I figured it out that this isn't a configuration with NHibernate or MVC. It is that ASP.net development server services every request through ASP.net. IIS will not send static file requests through ASP.net unless configured.
From Here (http://www.asp.net/hosting/tutorials/core-differences-between-iis-and-the-asp-net-development-server-cs)
Another core difference between IIS
and the ASP.NET Development Server is
how they handle requests for static
content. Every request that comes into
the ASP.NET Development Server,
whether for an ASP.NET page, an image,
or a JavaScript file, is processed by
the ASP.NET runtime. By default, IIS
only invokes the ASP.NET runtime when
a request comes in for an ASP.NET
resource, such as an ASP.NET web page,
a Web Service, and so forth. Requests
for static content - images, CSS
files, JavaScript files, PDF files,
ZIP files, and the like - are
retrieved by IIS without the
involvement of the ASP.NET runtime.

how are you creating the session, as the .jpg should not ask for an instance of ISession, therefor castle will not create one (from my understanding), could you post the castle setup, and how have you implemented it as a factory?
things to look out for
Make sure your session factory is a singleton
Create a session as PerWebRequest, using the OpenSession from the SessionFactory
//Setup the Hibernate dependencies
container.AddFacility<FactorySupportFacility>().Register(
Component.For<ISessionFactory>().LifeStyle.Singleton
.Instance(NHibernateHelper.GetSessionFactory()),
Component.For<ISession>().LifeStyle.PerWebRequest
.UsingFactoryMethod(kernel => kernel.Resolve<ISessionFactory>().OpenSession())
);
once you have registerd castle with MVC as a controller factory, it should only create a single session PerWebRequest and only if the controller, or its dependants are dependent on it
I have a sample app if it helps

I use Spring.NET, not Castle Windsor, but I assume the concepts are the same. The scope of your ISession should be defined as per request, and shouldn't actually be created until asked for, as dbones says. While MVC handles every request, asking for a .jpg shouldn't hit a controller which depends on ISession.
Is Castle Windsor eagerly creating per request objects instead of on demand? That may be a configuration issue. Or do you have a custom module, handler or a Global.asax application method that is asking Windsor for an ISession?

Related

ASP.NET/ServiceStack Root URL at startup

I'm trying to setup a ServiceStack template loosely based on the existing ASP.NET with razor template. The services to be created using this will be hosted in a variety of locations. What I would like is for them to be able to register themselves with a central server.
What I was hoping to do was to add some code to Application_start (or apphost) which would perform the registration however I can't find any way of getting the root url of the application. The normal method of using the request object doesn't work as there isn't a request object at that point.
If I can't get this from asp.net I'm wondering if there is a servicestack call I can make which can give me what I need
The URL for where an ASP.NET Web Application is hosted at is only available at runtime, inferred from the incoming are Request URL, so you won't be able retrieve it at Startup.

How does the .Net CLR identify which .DLL is the primary (startup) DLL in a web application?

I would like to know how the CLR finds the entry point / primary DLL of a web application. How does the CLR know which DLL out of the many that exist in my bin directory, is the DLL for my website?
There is no identifying information in my web.config that specifies one assembly as my "primary" assembly, so how does this selection process occur?
How does this selection / initialization process work?
That depends entirely on if you are using Web Forms, or MVC. The CLR itself does nothing to support this, it's the ASP.NET runtime and IIS that is doing all the leg work.
Web Form
In web forms, your .aspx and "code behind" use class inheritance to define that relationship. The #Page directive has an Inherits attribute defining what class the ASPX will inherit from. The ASPX itself is compiled into a class on-the-fly (or precompiled with aspnet_compiler.exe) that inherits that type.
When IIS hits an ASPX page, it passes that to the PageHandlerFactory either through the Integrated handler, or via the aspnet_isapi handler.
In this case, there is no "startup" DLL, it uses the DLL that the ASPX was compiled against.
MVC
When a request hits the ASP.NET runtime, it looks to see if there is a controller that matches the route. It then uses the DefaultControllerFactory to try and map the route to a controller. That eventually will call GetControllerType to try and find the type for the Controller, which further digs into an internal type called ControllerTypeCache.
ControllerTypeCache does most of the magic. It initialized with the EnsureInitialized, whos job is to populate the list of all types from all assemblies that are referenced using BuildManager.GetReferencedAssemblies. It then crawls each assembly looking for types that match a controller, such as implementing IController, being public, etc.
How does .NET know to fire up the MVC runtime
The MVC runtime is an HttpHandler. Either IIS directly passes it to the MVC handler automatically (newer versions of the framework and IIS do that) or you have to put the MVC handler in the httpHandlers section in the web.config.
In older versions of MVC you had to manually register the MvcHttpHandler. Starting in ASP.NET 4.0, a lot of the URL Routing guts were moved into the ASP.NET framework itself, so it now has this handler out of the box.
The closest thing to a 'startup' DLL in an ASP.Net web app is that assembly that contains `global.asax' (if you have one). See ASP.NET Application Life Cycle Overview for IIS 7.0 for details of what happens when a web app spins up.
You should also bear in mind that there can be a whole stack of HttpModule instances sitting on top of your web app. And your web app can add its own to the stack. The request is handed down through the stack of HttpModules and each of them gets the opportunity to intercept, handle, tamper with your request, etc. And once a response has been made, each module above it in the stack gets the same opportunity to monkey with the response.
I was going to comment on your comment to #VCJones excellent explanation (this stuff usually one just assumes so it's a great learning moment - so kudos to your question as well!).
How then, do we even get into the MVC runtime in the first place?
It's my understanding from reading this MSDN doc that file matching happens first on the requested resource, then route matching (and it's handler - MVC/Web API)
Your question pushed me to tinker :) and fired up a new MVC application with default scaffolding, created a controller for About:
public ActionResult About()
{
return View();
}
and also created a physical file named About.cshtml in the root of the application. I fiddled with the route config so that the controller name wouldn't be part of the route - e.g. http://localhost:123/about (not http://localhost:123/home/about). So now I have
About view
About.cshtml physical file in app root (not the one in /Views/Home/)
Test: http://localhost:123/About
First result: The MVC Controller fired. Wait, I thought it was file matching first?
Then if I navigate to http://localhost:123/About.cshtml a wierd exception is raised: The type of page you have requested is not served because it has been explicitly forbidden. The extension '.cshtml' may be incorrect. What?? Don't I have a ton of cshtml views?
Then I saw this setting in web.config:
<add key="webpages:Enabled" value="false"/> - what if i changed this to true?
Result:
Exception gone (no longer forbidden), and now I can see the behavior as described in the MSDN doc. I can't raise the About view at this point (http://localhost:123/about), because a file exists (and is the response), and I don't get into route matching (so the MVC handler isn't fired).
This is my understanding , so if I'm wrong, I'm sure someone here will point it out and another learning moment will occur :)

Running a part of MVC application separately under webforms application

I have a working MVC3 application with different modules. I want to use one of those modules as a separate application under IIS, this separate application will be under an already running WebForms application.
e.g.
My MVC application is running at http://mymvcappdomain.com/
There is a feature under this called "MyFeature" which runs at http://mymvcappdomain.com/MyFeature
I want another site (WebForms application) http://mywebformssitedomain/ to display exactly as http://mymvcappdomain.com/MyFeature when I browse to http://mywebformssitedomain/MyFeature
Is it possible? If so, how?
What I have already tried is dynamically registering selected number of routes based on the URL. I thought it'd work but as per the stackoverflow topic (http://stackoverflow.com/questions/2518057/request-is-not-available-in-this-context), I am not allowed to access the request object in the global.asax for registering routes.
Many thanks in advance!
Actually I was able to achieve what I wanted by changing the home controller. But it was purely because my requirements were not too complicated. The part of the MVC app I wanted to run was kind of standalone without any interference from other modules. But I guess the approach should work in resolving the issue.
public ActionResult Index()
{
if (URL is different to your normal MVC App URL)
{
return RedirectToRoute("YourCustomRouteForModule");
}
return View();
}

Use System.Web.Mvc in non MVC ASP.NET Web Forms Application

We are developing an ASP.NET Web Forms application with REST modelled URL, for which we are using Route tables in global.asax. However, recently we came over a problem where the WebResource.axd and ScriptResource.axd files were getting routed as well. We wanted to use the RouteCollection.IgnoreRoute function. However, since it in System.Web.Mvc, it would mean that we would need to reference that dll in a non MVC Web Forms application.
Is it safe for us to continue with the approach. If anyone has a better way to ignore routes from within the Web Forms application please do share. Please also note that the application has been extensively developed in Web Forms and moving to MVC at the current stage is not feasible.
For web forms you need to use System.Web.Routing
Put this is Global.asax
void RegisterRoutes(System.Web.Routing.RouteCollection routes)
{
routes.Ignore("{resource}.axd/{*pathInfo}");
routes.MapPageRoute(
"Home", // Route name
"WWWWWW", // Route URL
"~/Default.aspx" // Web page to handle route
);
}
Did you know you could safely run an ASP.NET Web Forms and MVC application combined? Here are some links:
http://www.hanselman.com/blog/IntegratingASPNETMVC3IntoExistingUpgradedASPNET4WebFormsApplications.aspx
http://www.packtpub.com/article/mixing-aspnet-webforms-and-aspnet-mvc
Also, you can just use URL routing in ASP.NET 4 applications, as Registered User pointed out above. Read more about it here: http://weblogs.asp.net/scottgu/archive/2009/10/13/url-routing-with-asp-net-4-web-forms-vs-2010-and-net-4-0-series.aspx

BeginRequest fires for static files in ASP.NET MVC app

I was under the impression that static files (CSS, images, #font-face files, etc) bypassed ASP.NET completely, and were served directly by IIS.
However, my BeginRequest event handler is being called for every HTTP request, including those for static files. This concerns me because I'm creating an Entity Framework data context to be used for the lifetime of each request in that event handler. I don't want to create those contexts if they're never going to be used.
I'm using IIS 7 on Windows 7 Ultimate with no special handler mappings defined. Do I have it wrong? Should these events be firing?
I believe a default ASP.NET MVC site has this set in the web.config.
<modules runAllManagedModulesForAllRequests="true" />
This means every .NET module will be loaded for every IIS request. This is required for ASP.NET MVC to handle extension-less routing. It's essentially a wildcard mapping that you would write in IIS that would match everything and route it to ASP.NET that lives in the web.config.
Read more here, including a way to disable the behavior if you aren't using .NET 4.0. It is nasty, but it's the cleanest solution for sites that can't deal with the overhead of having static files served by asp.net.
BeginRequest will be triggered for all requests (including static content) if:
You're using Visual Studio's development web server.
You've configured IIS to do so.
Please take a look at:
http://forums.asp.net/t/1220664.aspx
In addition to fixing the issue for your static files, you could use Lazy initialization Lazy<T> for your ObjectContext: http://msdn.microsoft.com/en-us/library/dd997286.aspx
The integrated mode in IIS 7 works differently than it was before.
You could switch to classic mode if desired.
Alternatively you can define your custom route handler and do the context initialization there. That way it's only done for specific routes.

Resources