Click here to Skip to main content
15,881,687 members
Articles / Web Development / ASP.NET

MVP in ASP.NET with .NET Remoting

Rate me:
Please Sign up or sign in to vote.
3.40/5 (8 votes)
28 Aug 2006CPOL4 min read 45.6K   538   44   2
.NET Remoting and ASP.NET MVP. Extending Billy McCafferty's "Model View Presenter with ASP.NET".

MVP with ASP.NET and .NET Remoting

Introduction

This article is an extension to Billy McCafferty’s great "Model View Presenter with ASP.NET". I’ll try to go with a solution provided by Billy a little bit deeper into "enterprise". I’ll discuss the situation where you have to host the site for internet (as opposite for intranet) and you cannot place the database server inside the DMZ. Demilitarized Zone is a concept of secure zone that divides the company "safe" inside with the war that is going on outside (in internet). So for security reasons, you have to place your database somewhere – apart from your website. This solution is something half way between SOA and tight data access and presentation layer integration. With this solution, you will not have to introduce one more layer to your architecture (no need for a separate service layer) but you will hat a clean physical separation of layers (see picture).

Please make sure that you have read and understood Billy’s article before you go further with my text.

You have to keep in mind that using this solution, you lose one of the prime NHibernate features: "lazy loading". Working over boundaries, every call to a remote service means a new NHibernate session, that means no easy way to load things "on demand".

Extending MVP

We will abstract the DAOs (Data Access Objects) further more to make them work over .NET Remoting. First, cut the inline DAOs definition form NHibernateDaoFacotry and paste it to its own file, say NHibernateDoas. The DAOs definitions from this class will by used with both scenarios remotely and locally.

C#
public class CustomerDaoNHibernate : 
       GenericNHibernateDao<Customer, string>, ICustomerDao { }

public class OrderDaoNHibernate : 
       GenericNHibernateDao<Order, long>, IOrderDao { }

To make these classes to work outside the normal boundaries, you have to make them inherit from MarshalByRefObject. To make it simple, we will inherit only the base class for all DAOs: GenericNHibernateDao.

Now you have to write the remote DAO factory class. Let’s name it NHibernateRemoteDaoFactory. It will look like this:

C#
public class NHibernateRemoteDaoFactory : IDaoFactory
{
    /// <summary>
    /// Static contructor loads the remoting
    /// configuration form configuration file.
    /// </summary>
    static NHibernateRemoteDaoFactory()
    {
        RemotingConfiguration.Configure(
           AppDomain.CurrentDomain.SetupInformation.ConfigurationFile, 
           false);
    }

    #region IDaoFactory Members

    public ICustomerDao GetCustomerDao()
    {
        NHibernateDaos.CustomerDaoNHibernate dao = 
          (NHibernateDaos.CustomerDaoNHibernate)
          Activator.CreateInstance(typeof(
          NHibernateDaos.CustomerDaoNHibernate));
        return dao;
    }

    public IOrderDao GetOrderDao()
    {
        NHibernateDaos.OrderDaoNHibernate dao = 
            (NHibernateDaos.OrderDaoNHibernate)
            Activator.CreateInstance(typeof(
            NHibernateDaos.OrderDaoNHibernate));
        return dao;
    }

    #endregion
}

Configuring .NET Remoting

Believe it or not, but we are done with programming here! Really, from now on, you won’t have to code. The rest will by done by configuring and customizing.

Let's configure the server. I’ll use IIS to make it simple and plain. We will use the binary formatter and HTTP channel. Please create a virtual directory and place all the MvpSample.Data DLLs in its bin subdirectory. To make IIS understand what you want to serialize, you have to place the web.config file inside. It will look like this:

XML
<configuration>
  <configSections>
        <section name="nhibernate" 
          type="System.Configuration.NameValueSectionHandler, System, 
                Version=1.0.1.0, Culture=neutral, 
                PublicKeyToken=b77a5c561934e089"/>
    </configSections>

  <appSettings>
        <add key="HBM_ASSEMBLY" value="MvpSample.Core"/>
    </appSettings>

  <nhibernate>
    <add key="hibernate.connection.provider" 
       value="NHibernate.Connection.DriverConnectionProvider"/>
    <add key="hibernate.dialect" 
       value="NHibernate.Dialect.MsSql2000Dialect"/>
    <add key="hibernate.connection.driver_class" 
       value="NHibernate.Driver.SqlClientDriver"/>
    <add key="hibernate.connection.connection_string"
            value="Data Source=mk-r52;Database=testdb;Trusted_Connection=True;" />
    <add key="hibernate.connection.isolation" value="ReadCommitted"/>
  </nhibernate>

  <system.runtime.remoting>
        <application>
            <channels>
                <serverProviders>
                    <formatter ref="binary"/>
                </serverProviders>
                <channel ref="http">
                </channel>
            </channels>
            <service>
                <wellknown mode="SingleCall"
               type="MvpSample.Data.CustomerDaoNHibernate,MvpSample.Data"
               objectUri="CustomerDao.rem"/>
                <wellknown mode="SingleCall"
               type="MvpSample.Data.OrderDaoNHibernate,MvpSample.Data"
               objectUri="OrderDao.rem"/>
            </service>
        </application>
    </system.runtime.remoting>
    
  <system.web>
        <customErrors mode="Off">
        </customErrors>
        <compilation>
            <assemblies>
                <add assembly="System.Runtime.Remoting, Version=2.0.0.0, 
                               Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
      </assemblies>
    </compilation>
  </system.web>
</configuration>

You probably already know the first part that configures NHibernate form Billy's article. The rest configures .NET Remoting. First, you are specifying the channel and then the services you want to host. We will make the calls to be of SingleCall type (so no state, very much like an ordinary Web Service). We will be hosting CustomerDaoNHibernate under the name CustomerDao.rem and OrderDaoNHibernate under OrderDao.rem. If your virtual directory name is MvpSampleRemoteDao, then you can try calling the WSDL for each service like this:

  • http://localhost/MvpSampleRemoteDao/OrderDao.rem?wsdl
  • http://localhost/MvpSampleRemoteDao/CustomerDao.rem?wsdl
XML
<system.runtime.remoting>
    <application>
      <channels>
        <channel ref="http">
          <clientProviders>
            <formatter ref="binary" />
          </clientProviders>
        </channel>
      </channels>
      <client>
        <wellknown type="MvpSample.Data.CustomerDaoNHibernate,MvpSample.Data"
                    url="http://localhost/MvpSampleRemoteDao/CustomerDao.rem" />
        <wellknown type="MvpSample.Data.OrderDaoNHibernate,MvpSample.Data"
          url="http://localhost/MvpSampleRemoteDao/OrderDao.rem" />
      </client>
    </application>
</system.runtime.remoting>

Congratulations, you are done. From now on, you can switch between remoting / no remoting by editing the Windsor Container configuration file Config\CastleComponents.config.

XML
<configuration>
  <components>
    <component id="daoFactory" 
      type="OFS.ORM.Data.NHibernateDaoFactory, OFS.ORM.Data" 
      service="OFS.ORM.Core.DataInterfaces.IDaoFactory, OFS.ORM.Core" />
    <!--component id="daoFactory" 
       type="OFS.ORM.Data.NHibernateRemoteDaoFactory, OFS.ORM.Data" 
       service="OFS.ORM.Core.DataInterfaces.IDaoFactory, OFS.ORM.Core" /-->
  </components>
</configuration>

Points of Interest

There are some things you have to keep in mind while working with this architecture:

  1. All the classes you intend to work over the boundaries have to by serializable.
  2. After you compile the Data project, you have to transfer somehow the DLL to the IIS virtual directory. You could configure the Data project to output the DLLs into the bin subdirectory and make the Data project folder by the virtual directory. You can also write an AfterBuild task in your prj file to deploy the DLLs to a local/remote server; there are a lot of possibilities. For the time being, you have a folder MvpSampleWeb in the zip file provided with this article. You have to make it a virtual directory in your IIS.
  3. In his original article, Billy came up with a great idea of an HTTPModule that opens the NHibernate session on every page served. You won't need it while working with remote objects. So you can turn this part of web.config off:
  4. XML
    <httpModules>
      <add name="NHibernateSessionModule" 
             type="MvpSample.Web.NHibernateSessionModule"/>
    </httpModules>
  5. There is a question whether you need special tests for your remote DAOs. Surely, yes!
  6. Oh and yes, I’m deploying the same assembly to the remoting server and client. I’m not working with interfaces as a contract between the client and server. Well, that approach serves a little bit of work and after all, it is server software, you don’t have to be afraid of someone else peeping into your code, right!

I hope this article will help you set up a great enterprise application with ASP.NET and .NET Remoting!

P.S.: Take a look at Advancing the Model-View-Presenter Pattern - Fixing the Common Problems by Acuostic - it's another great extension of Billy’s solution.

License

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


Written By
Web Developer
Poland Poland
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralSome Additions Pin
Bill Pierce21-Aug-06 9:23
Bill Pierce21-Aug-06 9:23 
Hey Marcin,
You might want to update your article to point out you can't use Lazy Loading for entities when using remoting. Since you use Windsor Container (I'm a big fan) you might want to discuss a little about the built in Remoting Facility rather than setting up the remoting yourself.

-Bill
GeneralRe: Some Additions Pin
Marcin Kawalerowicz21-Aug-06 21:49
Marcin Kawalerowicz21-Aug-06 21:49 

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

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