65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 NHibernate 和 Spring.NET 构建中间层组件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.50/5 (20投票s)

2006 年 5 月 10 日

CPOL

8分钟阅读

viewsIcon

164177

downloadIcon

2492

使用 NHibernate 和 Spring.Net 构建高度可插拔的中间层组件。

Screenshot

更新于 2009 年 1 月 29 日

Spring.NET 近期变化很大,与本文使用的版本相比。因此,附件代码与当前 Spring.NET 版本不兼容。Spring.NET 项目经理 Mark Pollack 帮助我更新了本文的源代码。因此,建议将他的代码库作为示例,了解 Spring.NET 目前如何使用 NHibernate。这是 Mark 编写的代码库:此处

引言

在职业生涯中,我花费了大量时间使用 Visual C++、Java,最近也使用了 .NET 技术。我曾使用过流行的 Spring 框架和 Java 中的 Hibernate。现在,我最近发现这两种技术在 .NET 中也可用。但 Java 中的 Spring 框架比 Spring.NET 功能更丰富。特别是,我喜欢 Spring 与 Hibernate 的集成(*spring.orm.Jar*)。这使得以面向对象的方式操作数据变得非常容易。

背景

与 Java 的 Spring 框架不同,Spring.Net 没有与任何 ORM 技术集成。我的意思是,找不到任何 ORM 集成。至少,到现在为止,我还没有发现任何。对于 Spring.Net,声明式事务划分是通过 COM+ 服务编写的。对于那些熟悉 Java Spring 框架的人来说,我认为他们不会愿意使用 COM+ 服务。编写专业软件时,COM+ 需要高级知识。此外,COM+ 要求包含服务组件的程序集具有强名称。

因此,我尝试实现这种集成,以便无需使用 COM+ 服务即可轻松编写业务层组件。

在实现集成代码时,我借鉴了 Java 的 Spring 框架(一个开源框架)的整个概念。在实现时,我尝试为类和接口保留相同的名称。但我修改了许多方法。我还改变了一些类的行为。因此,我不能声称我的实现是 Java Spring 框架的精确副本。我只是实现了 *Spring.Orm.dll* 作为 NHibernate 和 Spring.Net 之间的集成,就像 Java 世界中的 *spring.orm.jar* 一样。

文章目标

这是我的第一次投稿,请尽量避免非建设性的批评。我对反馈持完全开放的态度,我不自称无所不知,也不自称拥有实现各种目标的最佳方法。在接下来的系列文章中,我想演示一些利用 NHibernate 和 Spring.NET 的 n 层框架。

入门

在开始之前,我将假设读者对以下内容有一些基本了解:

  • NHibernate 是什么?如何配置和使用它?请从此处学习。
  • 什么是控制反转?请从此处学习。
  • 如何使用 Spring 作为 IOC 容器?请从此处学习。

您可能知道,NHibernate 可以通过配置与任何关系型数据库一起使用。在此场合,我使用了 Oracle 9i 数据库作为数据源。当然,您可以通过在 *App.Config* 文件中进行配置,将其更改为任何其他数据库。

从下一节开始,我们将使用 *Spring.Orm.dll* 构建中间层组件,您将看到它有多么简单。而且设计真正具有可插拔性和优雅性。

这是我们的服务器组件的抽象设计

UML

分步指南

首先,启动 Visual Studio .NET。创建一个新的控制台应用程序。为您的业务平台命名。在本教程中,我使用的是“SpringClient”。

将以下程序集引用添加到本文提供的二进制分发版中:

  • castle.dynamicproxy
  • hashcodeprovider
  • iesi.collections
  • log4net
  • nhibernate
  • nunit.framework
  • spring.aop
  • spring.core

当然,还要添加对以下程序的引用:

  • spring.orm

现在,向项目中添加一个 *App.Config* 文件。并写入以下内容:

<?xml version="1.0"encoding="utf-8" ?> 
  <configuration>
    <configSections> 
       <sectionGroup name="spring">
         <section name="context" 
           type ="Spring.Context.Support.ContextHandler, Spring.Core"/>
         <section name="objects" 
           type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
       </sectionGroup>
       <section name="nhibernate" 
          type="System.Configuration.NameValueSectionHandler, System, 
                Version=1.0.5000.0,Culture=neutral, 
                PublicKeyToken=b77a5c561934e089" />
       <section name="log4net" 
         type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
    </configSections>
    <spring>
      <context><resource uri="config://spring/objects"/></context>
      <objects>              
        <!—WRITE YOUR SPRING CONFIGURATION HERE-->    
      </objects>      
    </spring>
      <nhibernate> 
        <add key="hibernate.show_sql" value="true"/>
        <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="Server=localhost;initial 
                       catalog=nhibernate;Integrated Security=SSPI" />
          -->         
          <!-- This is the System.Data.OracleClient.dll 
                  provider for Oracle from MS --> 
        <add key="hibernate.dialect" 
                value="NHibernate.Dialect.Oracle9Dialect" /> 
        <add key="hibernate.connection.driver_class" 
                value="NHibernate.Driver.OracleClientDriver" />  
        <add key="hibernate.connection.connection_string" 
                value="Data Source=ihis;User ID=system;Password=manager;" />
      </nhibernate> 
          <!-- This section contains the log4net configuration settings -->  
      <log4net> 
          <!-- Define some output appenders -->      
        <appender name="rollingFile" 
                 type="log4net.Appender.ConsoleAppender,log4net" >
         <param name="File" value="log.txt" />
         <param name="AppendToFile" value="true" />
         <param name="RollingStyle" value="Date" />
         <param name="DatePattern" value="yyyy.MM.dd" />
         <param name="StaticLogFileName" value="true" />
         <layout type="log4net.Layout.PatternLayout,log4net">
           <param name="ConversionPattern" 
                     value="%d [%t] %-5p %c [%x] <%X{auth}> - %m%n" />
         </layout>
        </appender> 
           <!-- Setup the root Category, add the
                   appenders and set the default priority -->
        <root>
         <priority value="DEBUG" />
         <appender-ref ref="rollingFile" />
        </root>
      </log4net> 
</configuration>

太多 XML 了!吓到了吗?

不用怕。我来解释一下。在这个配置文件中,我们已经配置了 Spring 的 IOC 容器、NHibernate 以及用于日志记录的 Log4net。

在 XML 中找到注释“在此处编写您的 Spring 配置”。在该区域,您将配置由 Spring IOC 加载的对象。如果这对您来说太复杂,请不要放弃。继续,您将能够在不了解 IOC 细节的情况下进行操作。您需要更改数据库配置块中的 DSN(在此示例中,我使用了 DSN 名称“ihis”)、用户名和密码。

向项目中添加一个名为“*hibernate.cfg.xml*”的 XML 文件。NHibernate 将使用它。将此文件的生成操作设置为**嵌入式资源**。

将以下配置插入该文件:

<?xml version="1.0" encoding="utf-8"?>
  <hibernate-configuration xmlns="urn:nhibernate-configuration-2.0">
    <session-factory name="NHibernate.Test"/>
  </hibernate-configuration>

我们的业务逻辑层将利用声明式事务划分的便利性。所以我们需要一个事务管理器。目前,我们使用 NHibernate 进行 ORM,并将使用 *Spring.Orm* 程序集中的 `Spring.Orm.Hibernate.HibernateTransactionManager` 作为事务管理器。

现在让我们配置事务管理器。将以下配置块插入我用注释标记的点:

<object id="myTransactionManager" 
        type="Spring.Orm.Hibernate.HibernateTransactionManager, Spring.Orm">
 <property name="SessionFactory">
   <ref object="mySessionFactory"/> 
  </property> 
</object>

在本例中,我们暂时实现一个业务对象。我将其命名为 `Product`。因此,创建一个名为 `SpringClient.Utility.Product.UProductDTO` 的类。后缀 DTO 代表“数据传输对象”。插入以下代码:

using System;

namespace SpringClient.Utility.Product
{
    /// 
    /// 
    /// The Data transfer object for the Product entity.
    /// 
    ///  Moim Hossain
    /// 
    [Serializable()]
    public class UProductDTO
    {
        /// 
        /// Constructor Method
        /// 
        public UProductDTO()
        {
        }    
        /// 
        /// The Version Number for the Entity.
        /// Hibernate will use this version number for ensuring the atomicity
        /// of single data object. 
        /// 
        private int versionNumber;
        /// 
        /// Get or set the Data Version Number
        /// 
        public int VersionNumber
        {
            get
            {
                return versionNumber;
            }
            set
            {
                versionNumber = value;
            }
        }
        /// 
        /// The Name of the Product
        /// 
        private string name;
        /// 
        /// Get or set the name of the Product
        /// 
        public string Name
        {
            get
            {
                return name;
            }
            set
            {
                name = value;
            }
        }
        /// 
        /// The ID [PRIMATY KEY] for the product object
        /// 
        private long id;
        /// 
        /// Get or set the Product ID
        /// 
        public long ID
        {
            get
            {
                return id;
            }
            set
            {
                id = value;
            }
        }
    }
}

现在,由于我们将把 `Product` 实例持久化到数据存储中,因此我们需要为该类提供 Hibernate 映射文件。在同一命名空间中添加一个 XML 文件,名为“*UProductDTO.hbm.xml*”。并将此 XML 资源的生成操作设置为嵌入式资源。Spring 框架始终建议“面向接口编程”的编码实践。我们也不例外。所以,让我们为 `Product` 编写一个数据访问对象接口:

using System;

namespace SpringClient.Utility.Product
{
    /// 
    /// The Interface for accessing the Data Store for the Product 
    /// The Suffix DAO is for Data Access Object. 
    /// 
    /// This is a typical interface for
    /// the Data Access Layer of an Application
    /// 
    /// Declares the CRUD for Product Object
    /// 
    ///  Moim Hossain
    /// 
    public interface IUProductDAO
    {
        /// 
        /// Create a Product. 
        /// 
        /// The Product That will be Persisted
        /// The Product The has saved to the Data Store.
        /// Contains the ID (Generated by datastore)
        UProductDTO Create(UProductDTO Product);
        /// 
        /// Retrive a Product from the Data Store by ID
        /// 
        /// The ID that will be searched into the Data store
        /// The Retrived Data Object
        UProductDTO Retrive( long ProductID );
        /// 
        /// Update a product Object
        /// 
        /// The Product Instance that should be Updated
        void Update( UProductDTO Product );
        /// 
        /// Deletes a product
        /// 
        /// The product that will be Deleted
        void Delete( UProductDTO Product );
        /// 
        /// Search for some object by matching a criteria
        /// 
        /// The Hibernate Query string
        /// The parameter values for the query
        /// The List of UProducts that has a match for the given query
        UProductDTO[]FindProducts( string queryString , 
                                   object[]Parameters );
    }
}

现在我们将实现该接口

using System;
using System.Collections;
using Spring.Orm.Hibernate.Support;

namespace SpringClient.Utility.Product
{
    /// 
    /// The Implementation of the IUProductDAO.
    /// 
    /// This is a concrete Data Access Object for the Product object.
    /// 
    /// Implemented all the methods remains in  DAO interface.
    /// 
    /// Inherited from  for
    /// the Data Acccess support provided by the Hibernate ORM.
    /// 
    ///  Moim Hossain
    /// 
    public class UProductDAO : HibernateDaoSupport, IUProductDAO
    {
        /// 
        /// Constructor
        /// 
        public UProductDAO()
        {
        }

        #region IUProductDAO Members
        /// 
        /// Create a Product. 
        /// 
        /// The Product That will be Persisted
        /// The Product The has saved to the Data Store.
        /// Contains the ID (Generated by datastore)
        public UProductDTO Create(UProductDTO Product)
        {
            HibernateTemplate.Save( Product ) ;

            return Product;
        }
        /// 
        /// Retrive a Product from the Data Store by ID
        /// 
        /// The ID that will be searched into the Data store
        /// The Retrived Data Object
        public UProductDTO Retrive( long ProductID )
        {
            return HibernateTemplate.Load( typeof( UProductDTO ) , 
                   ProductID ) as UProductDTO;
        }
        /// 
        /// Update a product Object
        /// 
        /// The Product Instance that should be Updated
        public void Update( UProductDTO Product )
        {
            HibernateTemplate.Update( Product );
        }
        /// 
        /// Deletes a product
        /// 
        /// The product that will be Deleted
        public void Delete( UProductDTO Product )
        {
            HibernateTemplate.Delete( Product );
        }
        /// 
        /// Search for some object by matching a criteria
        /// 
        /// The Hibernate Query string
        /// The parameter values for the query
        /// The List of UProducts that has a match for the given query
        public UProductDTO[]FindProducts( string queryString , 
                                          object[]Parameters )
        {
            IList resultList = 
              HibernateTemplate.Find( queryString , 
              Parameters ) as IList;

            if( null != resultList )
            {
                UProductDTO[]products = 
                  new UProductDTO[resultList.Count];

                resultList.CopyTo( products , 0 );

                return products;
            }
            return null;
        }
        #endregion
    }
}

请注意,我们的数据访问类继承自 `Spring.Orm.Hibernate.Support.HibernateDaoSupport`,以便通过 `HibernateTemplate` 轻松访问 NHibernate 方法。现在是时候编写业务逻辑层了。让我们为我们的产品业务逻辑层编写一个接口:

using System;

namespace SpringClient.Utility.Product
{
    /// 
    /// The Interface for the Product Service.
    /// This is a interface for the Business Logic
    /// Layer of Product Object.
    /// 
    /// Contains all the methods that are related
    /// to the business issues of Product entity.
    /// 
    /// When Implemented, Concrete objects
    /// will implement the Business Logic for the interaction
    /// with product object.
    /// 
    ///  Moim Hossain
    /// 
    public interface IUProductService
    {
        /// 
        /// Get or set the Data Access Object for the Product object.
        /// 
        IUProductDAO ProductDAO
        {
            get;
            set;
        }
        /// 
        /// Save a Product
        /// 
        /// The Product to be persisted
        /// Saved product
        UProductDTO SaveProduct( UProductDTO Product );
        /// 
        /// Retrives a product from a data store
        /// 
        /// The ID of the product to be retrived
        /// The retrived product
        UProductDTO RetriveProduct( long ProductID );
        /// 
        /// Update a Product Instance
        /// 
        /// The Product to be Updated
        void UpdateProduct( UProductDTO Product );
        /// 
        /// Deletes a product
        /// 
        /// The product to be deleted
        void DeleteProduct( UProductDTO Product );
        /// 
        /// Search for some object by matching a criteria
        /// 
        /// The Hibernate Query string
        /// The parameter values for the query
        /// The List of UProducts that has a match for the given query
        UProductDTO[]FindProducts( string queryString , 
                                   object[]Parameters );
    }
}

现在我将提供实现

using System;

namespace SpringClient.Utility.Product
{
    /// 
    /// The Concrete Business Logic layer for the product Object.
    /// 
    /// Implemented the  inteface.
    /// 
    /// Invoke by the service class for the Product Entity.
    /// 
    ///  Moim Hossain
    /// 
    public class UProductServiceImpl : IUProductService
    {
        /// 
        /// Constructor
        /// 
        public UProductServiceImpl()
        {
        }
        /// 
        /// The Product DAO Interface
        ///     
        private IUProductDAO productDAO;
    
        #region IUProductService Members
        /// 
        /// Get or set the Data Access Object for the Product object.
        /// 
        public IUProductDAO ProductDAO
        {
            get
            {
                return productDAO;
            }
            set
            {
                productDAO = value;
            }
        }
        /// 
        /// Save a Product
        /// 
        /// The Product to be persisted
        /// Saved product
        public UProductDTO SaveProduct(UProductDTO Product)
        {
            return productDAO.Create( Product );
        }
        /// 
        /// Retrives a product from a data store
        /// 
        /// The ID of the product to be retrived
        /// The retrived product
        public UProductDTO RetriveProduct( long ProductID )
        {
            return productDAO.Retrive( ProductID );
        }
        /// 
        /// Update a Product Instance
        /// 
        /// The Product to be Updated
        public void UpdateProduct( UProductDTO Product )
        {
            productDAO.Update( Product );
        }
        /// 
        /// Deletes a product
        /// 
        /// The product to be deleted
        public void DeleteProduct( UProductDTO Product )
        {
            productDAO.Delete( Product );
        }
        /// 
        /// Search for some object by matching a criteria
        /// 
        /// The Hibernate Query string
        /// The parameter values for the query
        /// The List of UProducts that has a match for the given query
        public UProductDTO[]FindProducts( string queryString , 
                                          object[]Parameters )
        {
            return productDAO.FindProducts( queryString , Parameters );
        }
        #endregion
    }
}

请注意,`UProductServiceImpl` 不继承任何 Spring 特定类,但此类有能力在方法上传播事务。这是与 COM+ 的关键区别。在 COM+ 中,您的业务类必须继承 `ServicedComponent` 类。此时,我们已完成业务组件的开发。现在,我们将为我们的业务类配置 Spring 事务支持。将以下 XML 插入 *AppConfig.xml* 中,位于您之前插入的事务管理器配置块正下方:

<object id="mySessionFactory" 
  type="Spring.Orm.Hibernate.LocalSessionFactoryObject, Spring.Orm">
    <property name="MappingResources">
        <list>
            <value>SpringClient.Utility.Product.UProductDTO, SpringClient</value>
        </list>
    </property>
    <property name="ExportSchema" value="true"/>
</object>

这里我们正在构建 Session Factory 对象。这只是 NHibernate Session factory 的一个代理。`ExportSchema` 属性设置为 true,以便在运行服务器时,将为您创建所需的数据库表。将其设置为 false 可阻止表创建。现在,添加以下 XML 片段:

<!--UProduct Hibernate+ Spring conf -->
<object id="UProductTarget" 
        type="SpringClient.Utility.Product.UProductServiceImpl, SpringClient"> 
    <property name="ProductDAO">
        <ref object="ProductDAO"/>
    </property>
</object>
<object id="UProductService" 
           type="Spring.Transaction.Interceptor.
                 TransactionProxyFactoryObject, Spring.Orm">
    <property name="TransactionManager">
        <ref object="myTransactionManager">
    </property>
    <property name="Target">
        <ref object="UProductTarget">
    </property>
    <property name="TransactionAttributes">
        <name-values>
            <add key="Save*" value="PROPAGATION_REQUIRES_NEW"/>
            <add key="Update*" value="PROPAGATION_REQUIRED"/>
            <add key="Delete*" value="PROPAGATION_REQUIRED"/>
        </name-values>
    </property>
</object>

这是什么?首先,我们为业务类配置了一个提供事务支持的代理。在这里,我们还指定了事务传播。我们向 Spring 指定,我们需要为“`Save`”方法提供“Requires New”传播,为“`Update`”和“`Delete`”方法提供“Required”传播模式。请注意,您可以使用正则表达式指定方法名称。

现在,是时候考虑如何建立客户端应用程序和业务类之间的通信了?这完全取决于您的选择。您可以选择 Web 服务、Remoting - 任何您喜欢的方式。为了简单起见,我使用了 .NET Remoting 实现了一个示例。因此,让我们编写一个用于公开 Remoting 对象的类。此类还充当 IOC 加载对象的 fachada。

using System;
using Spring.Context;
using Spring.Context.Support;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;

namespace SpringClient.Service
{
    /// 
    /// A Service factory used to resolve
    /// and provide the service for a service name.
    /// This class is tightly coupled with Spring Ioc.
    /// 
    /// Responsible for Constructing
    /// the Spring Context and retains a static instance 
    /// of the spring context.
    /// 
    ///  Moim Hossain
    /// 
    public class ServiceFactory
    {
        /// 
        /// preventing the Out side world from
        /// creating an instance of this class.
        /// 
        private ServiceFactory()
        {
            
        }
        /// 
        /// Expose the Services
        /// 
        public static void ExposeServices( params Type[]services)
        {
            HttpServerChannel channel = new HttpServerChannel(8080);
    
            ChannelServices.RegisterChannel( channel );
            
            foreach( System.Type service in services )
            {    // Iterate through all the services
                System.Runtime.Remoting.RemotingConfiguration.
                       RegisterWellKnownServiceType(
                    service , "ProductService",
                    System.Runtime.Remoting.
                           WellKnownObjectMode.SingleCall 
                    );
            }
        }
        /// 
        /// Provide the service object by the name.
        /// 
        /// The Service Name to be resolved
        /// The Service Object
        public static object ProvideService( string serviceName )
        {
            if( null == m_AppContext )
              throw new ApplicationException(
                    "Spring not initialized yet.", null );
            // return the service
            return m_AppContext[serviceName];
        }
        /// 
        /// The Spring Context reference
        /// 
        private static IApplicationContext m_AppContext = null;
        /// 
        /// Constructs the Spring Container
        /// 
        public static void BuildSpringContext( )
        {
            // Make this method work as Single-ton fashion.
            if( null != m_AppContext ) return ;
            // No need to Build again

            try
            {    // Get the Handler for the spring Context
                m_AppContext = ContextRegistry.GetContext();

                if( null != m_AppContext )
                {    // Success !
                    System.Console.WriteLine("Spring" + 
                           " Initialized Successfully.");
                }
            }
            catch(Exception ex )
            {                
                System.Console.WriteLine( "Failed to" + 
                   " Initialize the Spring context." );

                System.Diagnostics.Trace.WriteLine( ex.Message );
            }
        }
    }
}

让我们编写一个服务类,它将业务访问接口暴露给外部世界

using System;
using System.Web.Services;
using SpringClient.Service;

namespace SpringClient.Utility.Product
{
    /// 
    /// This the class with which the client will interact. 
    /// For the Sake of Simplicity
    /// I have made this class as a simple C# Class.
    /// 
    /// But when implemented in a enterprise
    /// level software, this class will be implemented as a 
    /// Remoting Server, derived from .
    /// Or, as a Web service contains some web method.
    /// 
    ///  Moim Hossain
    /// 
    public class RpcUProductService : MarshalByRefObject
    {
        /// 
        /// Constructor
        /// 
        public RpcUProductService()
        {
        }
        
        /// 
        /// The Service Name that will be used
        /// to resolve the Business Service Interface.
        /// 
        private string SERVICE_NAME = "UProductService";
        /// 
        /// Save a product
        /// 
        /// The product to be saved.
        /// The Saved product.
        /// Thows if any error occured while
        public UProductDTO SaveProduct( UProductDTO Product )
        {
            return ( ServiceFactory.ProvideService(SERVICE_NAME) 
                     as IUProductService ).SaveProduct( Product );
        }
        /// 
        /// Retrive a product by the id
        /// 
        /// The Id of the product
        /// the product
        /// Thows if any error occured while
        public UProductDTO RetriveProduct( long ProductID )
        {
            return ( ServiceFactory.ProvideService(SERVICE_NAME) 
                     as IUProductService ).RetriveProduct( ProductID );
        }
        /// 
        /// Update a product
        /// 
        /// The product to be updated
        /// Thows if any error occured while
        public void UpdateProduct( UProductDTO Product )
        {
            ( ServiceFactory.ProvideService(SERVICE_NAME) 
              as IUProductService ).UpdateProduct( Product );
        }
        /// 
        /// Delete a product
        /// 
        /// The product to be deleted
        /// Thows if any error occured while
        public void DeleteProduct( UProductDTO Product )
        {
            ( ServiceFactory.ProvideService(SERVICE_NAME) 
              as IUProductService ).DeleteProduct( Product );
        }
        /// 
        /// Search for some object by matching a criteria.
        /// 
        /// This method is tightly coupled
        /// with Hibernate specific query string.
        /// But You can easily provide some
        /// strong type method to encapsulate the
        /// hibernate specific code inside your service layer.
        /// 
        /// The Hibernate Query string
        /// The parameter values for the query
        /// The List of UProducts that has a match for the given query
        ///         /// 
        ///        
        ///            // I am Searching Only those
        ///            // objects that matchs with a given ID
        ///            // For More Inforamtion about writing
        ///            // Hibernate Query string and about Hibernate
        ///            // please search at http://nhibernate.sourceforge.net/.
        ///            string QueryString = "select UProduct from" + 
        ///            " UProduct in class UProductDTO where UProduct.ID = ?";
        ///            // The Given ID is 1.
        ///            object[]Parameters = new Object[]{ Convert.ToInt64(1) };
        ///            
        ///            UProductDTO[]Results =
        ///            new RpcUProductService().FindProducts(
        ///            QueryString , Parameters );        ///            
        ///        
        /// 
        public UProductDTO[]FindProducts( string queryString , 
                                          object[]parameters )
        {
            return ( ServiceFactory.ProvideService( SERVICE_NAME ) 
                     as IUProductService ).FindProducts( queryString, 
                     parameters );
        }
    }
}

现在,将您应用程序的 Main 方法更改为:

using System;
using SpringClient.Service;
using SpringClient.Utility.Product;

namespace SpringClient
{
    /// 
    /// The Test Class
    /// 
    ///  Moim Hossain
    /// 
    public class MainClass
    {
        /// 
        /// The main entry point for the application.
        /// 
        [STAThread]
        static void Main(string[] args)
        {
        //    log4net.Config.XmlConfigurator.Configure();

            ServiceFactory.BuildSpringContext();

            ServiceFactory.ExposeServices( typeof(
               SpringClient.Utility.Product.RpcUProductService) );

            System.Console.WriteLine("Service Exported. " + 
                                     "Server is running.");

            System.Console.ReadLine();
        }    
    }
}

完成了。您已经使用声明式事务功能完成了业务层。在这里,我提供了我的项目结构的截图。

编写一个客户端来测试我们的服务器

让我们创建一个名为 RemoteClient 的 Windows 应用程序。为 Remoting 组件创建 Web 引用。从“项目”菜单中选择“添加 Web 引用”,然后在 URL 框中输入:*https://:8080/ProductService?WSDL*。我假设您在同一台机器上运行服务器程序。否则,请在 `localhost` 处插入服务器机器的 IP 地址。为此示例,我已将其命名为“ProductService”。

现在,您可以像这样调用您在产品服务中编写的方法:

try
{
    RemoteClient.ProductService.RpcUProductServiceService rpc = 
      new RemoteClient.ProductService.RpcUProductServiceService();
    
    UProductDTO product = new UProductDTO();
    
    product.name = "MyProduct";
            
    rpc.SaveProduct( product );    // Saved !!!
}
catch(Exception Ex )
{
    Console.WriteLine( Ex.Message );
}

就这样。很简单,不是吗?

未来开发的关注点

Java 的 Spring 框架提供了一些我在此版本中未实现但更吸引人的功能,例如保存点管理、将 Hibernate 特定异常转换为 Spring 的通用数据访问异常,以及其他一些非常重要的功能。不过,我希望将来有机会实现这些部分。

结论

我已阅读并尝试在编写本文时遵循 Java Spring 框架的设计。但在许多方面,由于语言不一致和其他原因,我不得不打破常规。不过,感谢 Spring 框架团队。

为了执行业务组件,您需要包含 Spring 和 NHibernate 模块的程序集。虽然我已将这些程序集与本文一起提供,但您也可以从以下链接下载:

  • 此处下载 NHibernate 相关文档。
  • 此处下载 Spring.NET 相关文档。

希望您喜欢这篇文章。我将非常感谢任何人的建议和提议。谢谢。

© . All rights reserved.