PDA

View Full Version : Storing the web application context


Anonymous
02-22-2005, 02:01 PM
What is a proper way to store the web application context in an ASP.NET application so that I can be sure that there is only one copy alive in the whole application? I am no .NET (or Spring) guru so I am a little bit confused.

For example, if I get hold of the web app context like this:


ctx = ConfigurationSettings.GetConfig("spring/context") as IApplicationContext;


Where should I be storing the context? Does that guarantee that there will never be another spring context created, because I am finding out by logging and by inspecting memory dumps that there are numerous spring context objects created inside one asp.net application during its life time. There are no refreshes of web.config, no new dlls etc.

I was reading that asp.net creates copies of the application domain and pools them and selects one for each request from the pool. What seems to be happening is that each domain effectively has a spring context loaded meaning that you can not have singletons configured in your web.config without causing memory leaks. My server stays up about one day and eats up 1GB memory just from this behaviour.

Maybe I don't know what I am talking about :) but I am just wondering if there is a way to do it, either by configuring IIS or by programming things properly.

Thanks.

Aleks Seovic
02-22-2005, 06:45 PM
Hi,

There is no need to load context manually in ASP.Net applications. If you register our PageHandlerFactory to load your pages, contexts are gonna be loaded automatically as requests are processed.

The reason I'm saying "contexts" is that ASP.Net application supports hierarchy of contexts by using multiple Web.config files within application folder hirarchy. Contexts on the lower level have context defined in the root Web.config as a parent, which allows for easy componentization of the application.

Basically, this allows you to define all you common objects (services, DAOs, etc.) in the root config, and reference them from component configs, that would normally contain page definitions. Component context uses fallback rules to find object definitions -- if it doesn't find one locally, it searches its parent hierarchy.

I'll post something on wiki that describes how to set up ASP.Net application and add link to that here in a bit.

-- Aleks

Anonymous
02-22-2005, 07:20 PM
Thanks, that would be a great help. Anything, even brief tutorial would clarify things a lot. 1) how to configure Spring for asp.net, 2) how to get hold of the spring context in your controls etc.

Aleks Seovic
02-23-2005, 03:31 AM
Hi,

I just added few pages to wiki that provide some background info about Spring.Web and describe how to set everything up. I also started describing various features that Spring.Web implements, and will try to complete the rest of pages later tonight and tomorrow.

http://opensource.atlassian.com/confluence/spring/display/NET/Spring.Web

Regards,

Aleks

thusted
03-18-2005, 11:30 AM
If you can't use the Spring.Web from CVS (recommended), another approach is to define a singleton. This is a singleton that we were using the load the configuration both for tests and also for the code-behind.

{code:c#}
public class ObjectsLoader
{
private ObjectsLoader ()
{
// private constructor prevents instantiation.
}

private static string _rootDirectory = AppDomain.CurrentDomain.BaseDirectory.Replace (@"\bin", "").Replace (@"\Debug", "").Replace (@"\Release", "");
private static volatile IApplicationContext _Factory = null;

public static IApplicationContext Factory ()
{
if (_Factory == null)
{
lock (typeof (XmlObjectFactory))
{
if (_Factory == null) // double-check
_Factory = new XmlApplicationContext ("file://" + _rootDirectory + "/Resources/Objects.xml");
}
}
return _Factory;
}
}
{code}

You'd want to change the references to "Objects.xml" with whatever is appropriate for your application.

-Ted.

rich
07-13-2005, 12:53 AM
Hi,

There is no need to load context manually in ASP.Net applications. If you register our PageHandlerFactory to load your pages, contexts are gonna be loaded automatically as requests are processed.

-- Aleks


I think i'm a bit confused. If not manually, can you give an example of *not* loading the contect manually and then accessing the object in the pages code behind? The examples seem to loading the context manually, but perhaps, as I've indicated, i'm confused :) Using the wiki example:

<objects>

<object id="masterPage" type="~/Master.aspx" />

<object id="basePage" abstract="true">
<property name="Master">
<ref object="masterPage" />
</property>
</object>

<object type="Login.aspx">
<property name="Authenticator">
<ref object="authenticationService"/>
</property>
</object>

<object type="Default.aspx" parent="basePage"/>

</objects>

How would you access the authenticationService? Do you just expose a property in the class named Authenticator and access if from there?

Rick Evans
07-13-2005, 10:28 AM
Hi Rich

How would you access the authenticationService? Do you just expose a property in the class named Authenticator and access if from there?

In a word... yes.

Find below the very simplest configuration that demonstrates automatically and transparently accessing an application context. Everything is done via configuration, with not a single line of Spring.NET specific API code.

This is the content of my Web.config file (with comments)...

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<!--
These handlers are standard Spring.NET configuration sections; the meat of the configuration
is done below in the actual sections themselves.
-->
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
</sectionGroup>
</configSections>
<spring>
<!--
This is the meat; in answer to your post, this is where Spring.NET transparently instantiates
and configures an application context for you 'behind the scenes' as it were...
-->
<context type="Spring.Context.Support.WebApplicationContext, Spring.Web">

<resource uri="config://spring/objects" />
</context>
<!--
This is where we configure all of your pages, services, objects, etc...
This single page definition has a property called 'Greeting' that is set when the page is created
(by Spring.NET's PageHandlerFactory -- see below).
-->
<objects xmlns="http://www.springframework.net">
<object type="Bacon.aspx">
<property name="Greeting" value="Rich" />
</object>
</objects>
</spring>
<system.web>
<!--
Don't forget this important line... it sets it up so that Spring.NET can handle the resolution of pages
(and inject dependencies into them if they require any).
-->
<httpHandlers>
<add verb="*" path="*.aspx" type="Spring.Web.Support.PageHandlerFactory, Spring.Web" />
</httpHandlers>

<compilation defaultLanguage="c#" debug="true" />
<customErrors mode="RemoteOnly" />
<authentication mode="Windows" />
<authorization>
<allow users="*" />
</authorization>
<trace enabled="false" requestLimit="10" pageOutput="false" traceMode="SortByTime" localOnly="true" />
<sessionState mode="InProc" stateConnectionString="tcpip=127.0.0.1:42424" sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes"
cookieless="false" timeout="20" />
<globalization requestEncoding="utf-8" responseEncoding="utf-8" />
</system.web>
</configuration>

This is the HTML for the Bacon.aspx page; it simply uses a scriptlet (ah!) to output the value of the injected Greeting property.

<%@ Page language="c#" Codebehind="Bacon.aspx.cs" AutoEventWireup="false" Inherits="WebBed.BaconForm" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<html>
<head>
<title>The Index of Bacon</title>
<meta name="vs_defaultClientScript" content="JavaScript">
<meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
</head>
<body MS_POSITIONING="GridLayout">
<form id="form" method="post" runat="server">
<% Response.Write("Hello " + Greeting); %>
</form>
</body>
</html>


And this is the codebehind class for the Bacon.aspx page; this page is as plain vanilla as they come... it exposes a single bog standard .NET property called Greeting on this page. Note that the page itself does not extend any Spring.NET specific base page, not does it import any Spring.NET specific classes. Of course, in the real world one would replace the Greeting property with something useful such as the authenticator from your post, or perhaps some service that your page uses, etc.

You simply use the page... Spring.NET will supply any needed properties, all without you having to manually instantiate an appliction context or indeed manually pull objects from an application context. I hope this answers your post... and I do appreciate the fact that the example (a Hello World style variant) is trivial. If this post does not answer your post satisfactorily, just bang away on that 'Post Reply' button... I can mail you the entire project base if you wish.

using System;
using System.Web.UI;

namespace WebBed
{
public class BaconForm : Page
{
private string _greeting;

public string Greeting
{
get { return _greeting; }
set { _greeting = value; }
}

protected override void OnInit(EventArgs e)
{
InitializeComponent();
base.OnInit(e);
}

private void InitializeComponent()
{
}
}
}

And that's it...

Please be advised that the documentation that is currently on the wiki will be significantly reworked (no doubt rewritten from the ground up) prior to the Spring.Web library being officially released (due in the 1.1 timeframe). You have the dubious honor of being an early adopter :D

Ciao
Rick

rich
07-13-2005, 01:45 PM
ahh, this is really cool stuff!! Let me pick your brain a little if you don't mind. I've got an application that's several years old, and admittedly not the picture of what a best practice web app should look like. But be that as it may, it still runs quite well and gets the job done. It's becoming harder to manage tho' and I'd like to 'springify' it, if for no other reason than to become more familiar with Spring, but also to hopefully facilitate a gradual rewrite of the app altogether. So with that in mind, I'd like to approach this with the mindset of incorporating some of the functionality Spring offers while not totally re-writing this thing.

I've got lots of what I call handlers in my data access tier. They're just classes that handle everything for a particular entity. For example, my productHandler is just holds list of methods, all returning sqlDataReaders used in my .aspx files. And in my code behind, I'll just instantiate it and call whatever methods I need to get the job done. So I'm not dealing with object collections or anything like that when I'm returning aggregate records and for the time being I'd just assume keep it as is.

So throughout this app, I make use of a variety of these object handlers and they are static, so what would you recommend in terms of making them available site wide and via Spring? Would you recommend loading them into application scope? How would I do that with spring tho and still not have to access application context?

... I can mail you the entire project base if you wish.

Absolutely, I'd be very interested in any project you'd be willing to share!

Rick Evans
07-13-2005, 02:53 PM
Hi Rich

Mmm... well, from what I can infer from your post, there should still not be any need to access the application context explicitly. My inference about your code may be wrong so feel free to correct me.

You say that you simply instantiate these handler objects to do their stuff... later on though you say that these handlers are 'static'. Are the methods static? If so, then why are you instantiating objects simply to then call static methods? If the methods are not static, then well, do these handler objects retain any state? Are your handler objects 'classic' singletons? So many questions...

So let me assume you have a page that lists a set of products. This page (perhaps one of many pages that does so) directly uses the services of the ProductHandler class from your data tier. Putting issues regarding architecture to one side, consider...

public class ProductHandler
{
public SqlDataReader GetAllProducts()
{
// do your data access logic here, I'm just stubbing it...
return null;
}

// lots of other data access methods...
}

The codebehind for your page might look a little like this then...

public class ProductListForm : Page
{
protected System.Web.UI.WebControls.Button _listProductsButton;
private ProductHandler _productHandler;

public ProductHandler ProductHandler
{
get { return _productHandler; }
set { _productHandler = value; }
}

protected override void OnInit(EventArgs e)
{
InitializeComponent();
base.OnInit(e);
}

private void InitializeComponent()
{
this._listProductsButton.Click += new System.EventHandler(this._listProductsButton_Click );


}

private void _listProductsButton_Click(object sender, EventArgs e)
{
using (SqlDataReader reader = ProductHandler.GetAllProducts())
{
// display the products, etc...
}
}
}

The configuration looks like so (this is just the relevant snippet, the rest is the same as before). This will result in one shared, singleton instance of the ProductHandler class being injected into the ProductList page (and indeed any other page or object that references it).

<spring>
<context type="Spring.Context.Support.WebApplicationContext, Spring.Web">
<resource uri="config://spring/objects" />
</context>
<objects xmlns="http://www.springframework.net">
<object type="ProductList.aspx">
<property name="ProductHandler" ref="productHandler" />
</object>
<object id="productHandler" type="WebBed.ProductHandler"/>
</objects>
</spring>

If you wanted each hit to the ProductList page to get its own distinct instance of the ProductHandler class, simply add the 'singleton="false"' attribute' to your 'productHandler' definition, like so...

<spring>
<context type="Spring.Context.Support.WebApplicationContext, Spring.Web">
<resource uri="config://spring/objects" />
</context>
<objects xmlns="http://www.springframework.net">
<object type="ProductList.aspx">
<property name="ProductHandler" ref="productHandler" />
</object>
<object id="productHandler" type="WebBed.ProductHandler" singleton="false"/>
</objects>
</spring>

So... you can do this 'refactoring (of sorts) to Spring.NET' incrementally, one page at a time, which is a good idea. Again, if I have inferred something incorrectly, just bang on that 'Post Reply' button.

Ciao
Rick

rich
07-13-2005, 03:42 PM
You say that you simply instantiate these handler objects to do their stuff... later on though you say that these handlers are 'static'. Are the methods static? If so, then why are you instantiating objects simply to then call static methods? If the methods are not static, then well, do these handler objects retain any state? Are your handler objects 'classic' singletons? So many questions...

good question! :) Everything (in most of the handlers) is static.. the instantiation issue is a result of someone who was very new to OO a ways back. That's another issue to fix..

Thanks a ton for the example code, Rick. It will be very helpful moving forward!! I'll post back with any questions in regard to the code you provided should any issues arise.