Click here to Skip to main content
Click here to Skip to main content

Integrating Spring.NET with ASP.NET Web Site

, 27 Jan 2008
Rate this:
Please Sign up or sign in to vote.
This article describes how to integrate Spring.NET enterprise Framework with ASP.NET

Introduction

Developing software applications is hard enough even with good tools and technologies. It is said by Spring.NET developers that Spring provides a lightweight solution for building enterprise-ready applications. Spring provides a consistent and transparent means to configure your application and integrate Aspect-Oriented Programming (AOP) into your software. Highlights of Spring's functionality are providing declarative transaction management for your middle tier as well as a full-featured ASP.NET Framework.

According to them, Spring.NET is an application Framework that provides comprehensive infrastructural support for developing enterprise .NET applications. It allows you to remove incidental complexity when using the base class libraries which makes best practices, such as test driven development, easy practices. Spring.NET is created, supported and sustained by SpringSource.

Environment Setup

First download Spring.NET from Sourceforge Spring.NET download page. While writing this article, the latest version was 1.1. Install it at default location.

The ASP.NET Web Site

To start with Spring.NET, let us create a new Web site. We have a Default.aspx page. Now we need to create sections in Web.Config files.

<configuration>    
    <configSections>
     <!--<span class="code-comment"> Spring --></span>
      <sectionGroup name="spring">
      <section name="context" 
    type="Spring.Context.Support.WebContextHandler, Spring.Web"/>
      <section name="objects" 
    type="Spring.Context.Support.DefaultSectionHandler, Spring.Core"/>
      <section name="parsers" 
    type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core"/>
      </sectionGroup>
    </configSections>
    
    <!--<span class="code-comment"> Spring --></span>
    <spring>        
    <parsers>
    </parsers>
        
    <context>
       <resource uri="config://spring/objects"/>
    </context>                
        
        <objects xmlns="http://www.springframework.net" 
        xmlns:db="http://www.springframework.net/database">        
          <!--<span class="code-comment"> Pages --></span>
          <object type="Default.aspx">
          </object>        
                    
        </objects>     
    </spring>   
        
    <sysyem.web>
    <httpHandlers>
       <!--<span class="code-comment"> Spring Handler --></span>
       <add verb="*" path="*.aspx" 
       type="Spring.Web.Support.PageHandlerFactory, Spring.Web"/>
        </httpHandlers>
        
        <httpModules>
            <add name="SpringModule" 
            type="Spring.Context.Support.WebSupportModule, Spring.Web"/>
        </httpModules>    
    </sysyem.web>

</configuration>    

We have now added a new HTTP handler for *.aspx pages that is a Spring.NET provided handler. Now Spring.NET manages all our ASP.NET pages. We'll be able to use Spring.NET features for the ASP.NET pages after this configuration.

Now we have to add a reference to the site. We need a reference to Spring.Core and Spring.Web assembly located in the Spring.NET installation folder. We can now run the application to see our page. We'll go to the next step if everything is OK.

Dependency Injection

DI is a very interesting thing. You can make your design totally decoupled with concrete implementations. To see this in effect, let us create a new string type property in our page's code named Message with a private variable message. And in the Page_Load method, add the following line:

Response.Write(message);

Here we do not set the value of the message variable. We'll set it through the Web.Config file. We now change the object definition for Default.aspx:

<object type="Default.aspx">
    <property name="Message" value="Hello from Web.Config"/>
</object>    

Now we have supplied a value outside of the page using the configuration file. We have set a string type value here. We can also set an object type value. To do that, let us define a class Math with one method:

public class Math
{
    public int add(int x, int y)
    {
        return x+y;
    }
}

Now let us add a new property Math in the Default.aspx code file like we did for message. In the Page_Load method, we add code:

Response.Write(math.add(30, 50));

In Web.Config we now add new object definition just above object for Default.aspx. So our spring section becomes:

<spring>
    <parsers>
    </parsers>
    <context>
      <resource uri="config://spring/objects"/>
    </context>

    <objects xmlns=http://www.springframework.net 
        xmlns:db="http://www.springframework.net/database">          

    <object name="MyMathObj"  type="Math, App_code" />

    <!--<span class="code-comment"> Pages --></span>
    <object type="Default.aspx">
        <property name="Message" value="Hello from Web.Config"/>
            <property name="Math" ref="MyMathObj"/>        
    </object>

    </objects>
</spring>   

Working with Data

Now we want to deal with data. To deal with data, Spring.NET natively provides NHibernate and ADO.NET support. Here we use NHibernate - as it handles all dirty things about database and lets us work in the object world only. In the Spring.NET installation folder in /bin and in /lib directory, we have the required NHibernate binaries. Here I use NHibernate 1.2 assemblies. For hibernate we define a table in the database named person, create a new class named Person and a NHibernate mapping file (Person.hbm.xml):

The Person Table

Column Type Modifiers
Id Number not null, primary key
VersionNumber Number -
Name nvarchar(16) not null

The Person Class

public class Person
{
    private long id;
    private string name;
    private int versionNumber;
    //These methods should be virtual for NHibernate Mapping
    public virtual long Id
    {
        get { return id; }
        set { id = value; }
    }

    public virtual int VersionNumber
    {
        get { return versionNumber; }
        set { versionNumber = value; }
    }

    public virtual string Name
    {
        get { return name; }
        set { name = value; }
    }
}

The NHibernate Mapping File

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
    namespace="CodeProject.DAO" assembly=""CodeProject.DAO">

    <class name="Person" table="Person">
        <id name="Id">
            <column name="Id" not-null="true"/>
            <generator class="increment"/>
        </id>
        <version column="VersionNumber" name="VersionNumber" />

        <property name="Name">
            <column name="Name" length="16" not-null="true" />
        </property>
    </class>

</hibernate-mapping>

Please note that the mapping file should have the extension .hbm.xml and should be set to Embedded Resource for Build Action property of the file.

The BaseDAO Class

We want a base class that implements basic functionality of database like LoadALL, SaveOrUpdate etc. We define an Interface and implement that for our use:

public interface IBaseDAO<EntityT, idT>
{
    IList LoadAll();
    EntityT LoadByID(idT id);
    IList Load(string hsqlQuery, object[] values);
    void Save(EntityT fine);
    void SaveOrUpdate(EntityT fine);
    NHibernate.ISessionFactory SessionFactory { set; }
}

public abstract class BaseDAO<EntityT, idT>: IBaseDAO<EntityT, idT>
{
    protected HibernateTemplate hibernateTemplate;

    public ISessionFactory SessionFactory
    {
        set
        {
            hibernateTemplate = new HibernateTemplate(value);
            hibernateTemplate.TemplateFlushMode = TemplateFlushMode.Auto;
        }
    }

    public BaseDAO()
    {
    }

    public virtual EntityT LoadByID(idT id)
    {
        EntityT entity = (EntityT)hibernateTemplate.Load(typeof(EntityT), id);
        return entity;
    }

    public virtual IList LoadAll()
    {
        return hibernateTemplate.LoadAll(typeof(EntityT));
    }

    public virtual IList Load(string hsqlQuery, object[] values)
    {
        return hibernateTemplate.Find(hsqlQuery, values);
    }

    public virtual void Save(EntityT fine)
    {
        hibernateTemplate.Save(fine);
    }

    public virtual void SaveOrUpdate(EntityT fine)
    {
        hibernateTemplate.SaveOrUpdate(fine);
    }
}

The PersonDAO Class

This class is inherited from BaseDAO that is responsible for the Person class's load/save operation:

public interface IPersonDAO : IBaseDAO<Person, long>
{
}

public class PersonDAO : BaseDAO<Person, long>, IPersonDAO
{
}

Please note that this time we define the class with Person type for Object type and use long for Id type.

Using the PersonDAO Object

Now we add a new property to Default.aspx code file named personDAO. Please note here that you must use the interface of DAO class here.

IPersonDAO personDAO;
public IPersonDAO PersonDAO
{
    get{return personDAO;}
    set{personDAO=value;}
}

And add the following line in the Page_Load method:

Person p = new Person();
p.Name = "Maruf";
personDAO.Save(p);
Person p1 = personDAO.LoadByID(1); 

You may do whatever you want with the Person object you get.

Configuration for NHibernate

Now we need some configuration work in Web.Config file.

<?xml version="1.0"?>

<configuration>

  <configSections>
    <!--<span class="code-comment"> Spring --></span>
    <sectionGroup name="spring">
      <section name="context" 
    type="Spring.Context.Support.WebContextHandler, Spring.Web"/>
      <section name="objects" 
    type="Spring.Context.Support.DefaultSectionHandler, Spring.Core"/>
      <section name="parsers" 
    type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core"/>
    </sectionGroup>
  </configSections>

  <!--<span class="code-comment"> Spring --></span>
  <spring>

    <parsers>
      <parser type="Spring.Data.Config.DatabaseNamespaceParser, Spring.Data"/>
    </parsers>

    <context>
      <resource uri="config://spring/objects"/>
    </context>

    <objects xmlns=http://www.springframework.net 
        xmlns:db="http://www.springframework.net/database">

      <db:provider id="DbProviderMySQL" provider="MySql" 
        connectionString="Server=localhost;....;"/>
      
      <object type="Spring.Objects.Factory.Config.PropertyPlaceholderConfigurer,
             Spring.Core">
        <property name="ConfigSections" value="databaseSettings"/>
      </object>

      <object id="SessionFactory" 
        type="Spring.Data.NHibernate.LocalSessionFactoryObject, 
            Spring.Data.NHibernate12">
        <property name="DbProvider" ref="DbProviderMySQL"/>
        <property name="MappingAssemblies">
          <list>
            <value>CodeProject.DAO</value>
          </list>
        </property>
        <property name="HibernateProperties">
          <dictionary>
            <entry key="hibernate.connection.provider" 
        value="NHibernate.Connection.DriverConnectionProvider"/>
            <entry key="hibernate.dialect" 
        value="NHibernate.Dialect.MySQLDialect"/>
            <entry key="hibernate.connection.driver_class" 
        value="NHibernate.Driver.MySqlDataDriver"/>
          </dictionary>
        </property>
      </object>

      <object name="MyMathObj"  type="Math, App_code" />
      <object id="PersonDAO" type="CodeProject.DAO.PersonDAO, CodeProject.DAO">
        <property name="SessionFactory" ref="SessionFactory"/>
      </object>

      <!--<span class="code-comment"> Pages --></span>
      <object type="Default.aspx">
        <property name="Message" value="Hello from Web.Config"/>
        <property name="Math" ref="MyMathObj"/>
        <property name="PersonDAO" ref="PersonDAO"/>
      </object>

    </objects>
  </spring>

  <appSettings/>
    <connectionStrings/>
    <system.web>        
        <compilation debug="true"/>
        <authentication mode="Windows"/>

    <httpHandlers>
      <!--<span class="code-comment"> Spring Handler --></span>
      <add verb="*" path="*.aspx" 
        type="Spring.Web.Support.PageHandlerFactory, Spring.Web"/>
    </httpHandlers>

    <httpModules>
      <add name="SpringModule" 
        type="Spring.Context.Support.WebSupportModule, Spring.Web"/>
      <!--<span class="code-comment"> Required for managing NHibernate session between http requests--></span>
      <add name="OpenSessionInView" 
    type="Spring.Data.NHibernate.Support.OpenSessionInViewModule, 
            Spring.Data.NHibernate12"/>
    </httpModules>

  </system.web>
</configuration>

Declarative Transaction Management

It keeps transaction management out of business logic, and is not difficult to configure in Spring. We want our certain operation be under transaction. We do not need to manage that in code. We simply configure that from Web.Config file. Let us assume we want Save, SaveOrUpdate, Delete, Query etc. method in PersonDAO to be in atomic database operation and rollback entire operation on any exception. We create PersonDAOTx object in our config file and set it to the Deafult.aspx pages' PersonDAO property.

<!--<span class="code-comment"> TxManager --></span>
<object id="HibernateTransactionManager" 
    type="Spring.Data.NHibernate.HibernateTransactionManager, 
            Spring.Data.NHibernate12">
  <property name="DbProvider" ref="DbProviderMySQL"/>
  <property name="SessionFactory" ref="SessionFactory"/>
</object>

<object id="PersonDAOTx" 
    type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject, Spring.Data">
    <property name="PlatformTransactionManager" ref="HibernateTransactionManager"/>
    <property name="Target" ref="PersonDAO"/>
    <property name="TransactionAttributes">
    <name-values>
        <add key="Save*" value="PROPAGATION_REQUIRES_NEW"/>
        <add key="SaveO*" value="PROPAGATION_REQUIRES_NEW"/>
        <add key="Delete*" value="PROPAGATION_REQUIRED"/>
        <add key="Update*" value="PROPAGATION_REQUIRED"/>
        <add key="Query*" value="PROPAGATION_REQUIRED"/>
    </name-values>
    </property>
</object> 
<!--<span class="code-comment"> Pages --></span> 
<object type="Default.aspx">
    <property name="Message" value="Hello from Web.Config"/> 
    <property name="Math" ref="MyMathObj"/> 
  <property name="PersonDAO" ref="PersonDAOTx"/> 
</object>

Please note that we can use a new transaction or an inherited transaction from the caller. While using inherited transaction, a new transaction is automatically created if none exists from the caller.

Web Service

Spring introduces very flexible Web service support. It can export any class that implements a public interface. WebService attribute is not required at all. Let us define a plain interface and implement it in a plain class:

public interface IFirstService
{
    string GetMessage();
}

public class FirstService : IFirstService
{
    private string message;

    public string Message
    {
        get { return message; }
        set { message = value; }
    }

    public string GetMessage()
    {
        return message;
    }
}  

That's it. We can now export this class by just adding a few lines in the Web.Config file. We can also inject its dependency (the Message property) from web.config. Please note the new httpHandlers entry to handle.asmx page.

<object id="FirstServiceImpl" type="CodeProject.DAO.FirstService, CodeProject.DAO">
    <property name="Message" value="Test Message" />
</object>
<!--<span class="code-comment">Web Services--></span>
<object id="FirstService" type="Spring.Web.Services.WebServiceExporter, Spring.Web">
    <property name="TargetName" value="FirstServiceImpl"/>
    <property name="Namespace" value="http://myCompany/services"/>
    <property name="Description" value="My First web service"/>
</object>

<system.web>
<httpHandlers>
    <!--<span class="code-comment"> Spring --></span>
    <add verb="*" path="*.aspx" type="Spring.Web.Support.PageHandlerFactory, 
        Spring.Web"/>
    <add verb="*" path="*.asmx" type="Spring.Web.Services.WebServiceHandlerFactory, 
        Spring.Web"/>
</httpHandlers>
</system.web>

That's it. We can access the service at /FirstService.asmx path.

By now we can create ASPX pages, Web services without [WebService] attribute from virtually any class, inject dependency from configuration file - making the application highly configurable, work with database and totally separate the transaction management from business logic. I expect it will help to quickstart using Spring.NET and develop a scalable application. For beginners, when you use Spring.NET for the first time you'll be surprised how much it helps by reducing most of the redundant work. Please excuse for language - my first language is Bangla. I'll be happy to hear from you.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Maruf Maniruzzaman
Software Developer KAZ Software Ltd. Bangladesh.
Bangladesh Bangladesh
Have completed BSc in Computer Science & Engineering from Shah Jalal University of Science & Technology, Sylhet, Bangladesh (SUST).
 
Story books (specially Masud Rana series), tourism, songs and programming is most favorite.
 
Blog:
Maruf Notes
http://blog.kuashaonline.com
 
Working on small project for 2 factor authentication auth2.com

Comments and Discussions

 
GeneralQuestion about IPersonDAO [modified] PinmemberMember 351511223-Nov-10 11:37 
Generalgot it working for the message from web.config but... Pinmemberbevans19758-Mar-10 11:54 
GeneralRe: got it working for the message from web.config but... PinmemberMaruf Maniruzzaman8-Mar-10 14:33 
GeneralRe: got it working for the message from web.config but... Pinmemberbevans19759-Mar-10 3:36 
GeneralNice work PinmemberDecoupledRoma12-Jan-10 19:42 
GeneralOriginal article PinmemberEnrique Albert15-Apr-09 3:52 
The original article is good and describes in detail why to use Exporters and also an easier way to declare WebServices from classes with annotations.
GeneralRe: Original article PinmemberMaruf Maniruzzaman11-Sep-09 20:23 
GeneralSorry why in web.config property "Message"/"Math" - take them out app should still work Pinmemberdevvvy15-Jan-09 17:17 
GeneralRe: Sorry why in web.config property "Message"/"Math" - take them out app should still work PinmemberMaruf Maniruzzaman18-Jan-09 12:53 
GeneralGood Article Pinmembersoftty23-May-08 0:45 
GeneralExcellent article PinmemberHolomerlin21-May-08 11:29 
QuestionProblem Invalid token Pinmemberjvhow16-Apr-08 22:04 
GeneralNice and comprehensive PinmemberMember 29789579-Feb-08 20:38 
Generalgreat work Pinmembermssadik9-Feb-08 19:46 
GeneralEasy to Implement PinmemberNadim Saker9-Feb-08 18:40 
GeneralInteresting Reading PinmemberPaul Conrad27-Jan-08 6:54 
GeneralNice & Clean PinmemberShahriar Hyder26-Jan-08 17:51 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140721.1 | Last Updated 28 Jan 2008
Article Copyright 2008 by Maruf Maniruzzaman
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid