1. 程式人生 > >Spring.NET教程(十九)整合NHibernate和ASP.NET MVC(基礎篇)

Spring.NET教程(十九)整合NHibernate和ASP.NET MVC(基礎篇)

contains sar occurs false port company param soft stat

今天帶給大家的就是期待以久的ASP.net MVC與Spring.NET和NHibernate的組合,視圖打造.NET版的SSH(Spring-Struts-Hibernate)。是不是聽到名字都很興奮?我認為目前的ASP.NET MVC比Struts在某些功能上要好用的多,而且代碼量要少,這就是我一直熱衷於ASP.NET MVC的原因。

我們接著昨天的例子學習。昨天我們成功測試了帶事務的業務層。接下來就是將業務層的對象註入到Controller中。我們先在Controller中寫好要註入的屬性。

HomeController

public class HomeController : Controller

{

public ICompanyManager CompanyManager { get; set; }

public IUserManager UserManager { get; set; }

public ActionResult Index()

{

ViewData["Message"] = "Welcome to ASP.NET MVC!";

ViewData["Company"] = CompanyManager.LoadAll();

return View();

}

 }

我們知道,對Controller依賴註入需要新建一個ControllerFactory。我們實現System.Web.Mvc.IControllerFactory接口即可。實際上就是替換現有的ControllerFactory,讓Spring.NET容器管理Controller。包含Spring.NET容器配置的Controller使用新建的ControllerFactory,沒有包含Spring.NET容器配置的Controller使用原有的DefaultControllerFactory。

SpringControllerFactory

 * www.cnblogs.com/GoodHelper

 */

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using Spring.Context;

using Spring.Context.Support;

using System.Web.MVC;

namespace Controllers

{

/// <summary>

/// Spring.net ControllerFacotry

/// </summary>

public class SpringControllerFactory : IControllerFactory

{

/// <summary>

/// Default ControllerFactory

/// </summary>

private static DefaultControllerFactory defalutf = null;

public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)

{

//get spring context

WebApplicationContext ctx = ContextReGIStry.GetContext() as WebApplicationContext;

string controller = controllerName + "Controller";

//查找是否配置該Controller

if (ctx.ContainsObject(controller))

{

object controllerf = ctx.GetObject(controller);

return (IController)controllerf;

}

else

{

if (defalutf == null)

{

defalutf = new DefaultControllerFactory();

}

return defalutf.CreateController(requestContext, controllerName);

}

}

public void ReleaseController(IController controller)

{

//get spring context

IApplicationContext ctx = ContextRegistry.GetContext();

if (!ctx.ContainsObject(controller.GetType().Name))

{

if (defalutf == null)

{

defalutf = new DefaultControllerFactory();

}

defalutf.ReleaseController(controller);

}

}

}

}

在Global.asax.cs的Application_Start方法下增加一些代碼,註冊SpringControllerFactory類。

Global.asax.cs

protected void Application_Start()

{

log4net.Config.XMLConfigurator.Configure();

ControllerBuilder.Current.SetControllerFactory(typeof(Controllers.SpringControllerFactory));

ReGISterRoutes(RouteTable.Routes);

}

然後我們以HomeController為例,增加一些方法。

HomeController

public class HomeController : Controller

{

public ICompanyManager CompanyManager { get; set; }

public IUserManager UserManager { get; set; }

public ActionResult Index()

{

ViewData["Message"] = "Welcome to ASP.net MVC!";

ViewData["Company"] = CompanyManager.LoadAll();

return View();

}

[AcceptVerbs(HttpVerbs.Post)]

public ActionResult SaveUser(User user)

{

user.CurrentCompany = CompanyManager.Get(user.CurrentCompany.CompanyID);

UserManager.Save(user);

return RedirectToAction("GetCompany", "Home", new { id = user.CurrentCompany.CompanyID });

}

[AcceptVerbs(HttpVerbs.Post)]

public ActionResult SaveCompany(Company company)

{

CompanyManager.Save(company);

return RedirectToAction("Index", "Home");

}

public ActionResult GetCompany(int id)

{

ViewData["Company"] = CompanyManager.Get(id);

return View();

}

public ActionResult About()

{

return View();

}

Controllers.XML

<?XML version="1.0" encoding="utf-8" ?>

<objects xmlns="http://www.springFramework.net">

<object id="HomeController" type="Controllers.HomeController, Controllers" singleton="false">

<property name="CompanyManager" ref="CompanyManager"/>

<property name="UserManager" ref="UserManager"/>

</object>

</objects>

這裏的HomeController我們部署了非singleton模式。

最後我們配置Web.config。我總結了一下,有兩個要註意的地方:

1.需要在appSettings節點處配置SessionFactory的id

2.需要配置httpModules,因為這關系到SessionFactory的作用域,直接影響對象的“延遲加載”等一系列問題。實際上SessionFactory的開關有Spring.Data.NHibernate.LocalSessionFactoryObject來控制。實現原理是Spring.NET會在HttpApplication.BeginRequest的事件中註冊打開SessionScope的動作,並在HttpApplication.EndRequest的事件中註冊關閉SessionScope的動作。這就意味著SessionFactory完全由Spring.NET來管理,我們不需要使用using語句來強制關閉Session。

Web.config

<?xml version="1.0"?>

<!-- 

Note: As an alternative to hand editing this file you can use the 

web admin tool to configure settings for your application. Use

the Website->ASP.Net Configuration option in Visual Studio.

A full list of settings and comments can be found in 

machine.config.comments usually located in 

\Windows\Microsoft.Net\Framework\v2.x\Config 

-->

<configuration>

<configSections>

<sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">

<sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">

<section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>

<sectionGroup name="WebServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">

<section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="Everywhere"/>

<section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>

<section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>

<section name="roleService" type="System.Web.Configuration.ScriptingRoleServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>

</sectionGroup>

</sectionGroup>

</sectionGroup>

<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />

<sectionGroup name="common">

<section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" />

</sectionGroup>

<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>

<section name="databaseSettings" type="System.Configuration.NameValueSectionHandler"/>

</configSections>

<log4net debug="true">

<appender name="LogFileAppender" type="log4net.Appender.FileAppender">

<param name="File" value="Logs\Application.log.txt" />

<param name="datePattern" value="MM-dd HH:mm" />

<param name="AppendToFile" value="true" />

<layout type="log4net.Layout.PatternLayout">

<param name="ConversionPattern" value="%d [%t] %-5p %c [%x] - %m%n" />

</layout>

</appender>

<appender name="HttpTraceAppender" type="log4net.Appender.ASPNetTraceAppender">

<layout type="log4net.Layout.PatternLayout">

<param name="ConversionPattern" value="%d [%t] %-5p %c [%x] - %m%n" />

</layout>

</appender>

<appender name="EventLogAppender" type="log4net.Appender.EventLogAppender">

<layout type="log4net.Layout.PatternLayout">

<param name="ConversionPattern" value="%d [%t] %-5p %c [%x] - %m%n" />

</layout>

</appender>

<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">

<param name="File" value="Logs/Log.txt" />

<param name="AppendToFile" value="true" />

<param name="MaxSizeRollBackups" value="10" />

<param name="MaximumFileSize" value="100K" />

<param name="RollingStyle" value="Size" />

<param name="StaticLogFileName" value="true" />

<layout type="log4net.Layout.PatternLayout">

<param name="ConversionPattern" value="%d [%t] %-5p %c [%x] - %m%n" />

</layout>

</appender>

<root>

<level value="ALL" />

<appender-ref ref="RollingLogFileAppender" />

</root>

</log4net>

<spring>

<parsers>

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

<parser type="Spring.Transaction.Config.TxNamespaceParser, Spring.Data" />

</parsers>

<context>

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

<resource uri="assembly://Repository/Repository/Repository.xml" />

<resource uri="assembly://Manager/Manager/Manager.xml" />

<resource uri="assembly://Controllers/Controllers/Controllers.xml"/>

</context>

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

</spring>

<!--數據庫連接字符串-->

<databaseSettings>

<add key="db.datasource" value="." />

<add key="db.user" value="sa" />

<add key="db.password" value="" />

<add key="db.database" value="SpringNet_Lesson18" />

</databaseSettings>

<!--很重要-->

<appSettings>

<add key="Spring.Data.NHibernate.Support.OpenSessionInViewModule.SessionFactoryObjectName" value="NHibernateSessionFactory" />

</appSettings>

<connectionStrings/>

<system.web>

<!-- 

Set compilation debug="true" to insert debugging 

symbols into the compiled page. Because this 

affects performance, set this value to true only 

during development.

-->

<compilation debug="true">

<assemblies>

<add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>

<add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

<add assembly="System.Web.Abstractions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

<add assembly="System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

<add assembly="System.Web.MVC, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

<add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>

<add assembly="System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>

<add assembly="System.Data.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>

<add assembly="MvcContrib"/>

</assemblies>

</compilation>

<!--

The <authentication> section enables configuration 

of the security authentication mode used by 

ASP.NET to identify an incoming user. 

-->

<authentication mode="Forms">

<forms loginUrl="~/Account/LogOn" timeout="2880"/>

</authentication>

<membership>

<providers>

<clear/>

<add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="ApplicationServices" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" passwordStrengthRegularExpression="" applicationName="/"/>

</providers>

</membership>

<profile>

<providers>

<clear/>

<add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="ApplicationServices" applicationName="/"/>

</providers>

</profile>

<roleManager enabled="false">

<providers>

<clear/>

<add connectionStringName="ApplicationServices" applicationName="/" name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>

<add applicationName="/" name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>

</providers>

</roleManager>

<!--

The <customErrors> section enables configuration 

of what to do if/when an unhandled error occurs 

during the execution of a request. Specifically, 

it enables developers to configure html error pages 

to be displayed in place of a error stack trace.

<customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">

<error statusCode="403" redirect="NoAccess.htm" />

<error statusCode="404" redirect="FileNotFound.htm" />

</customErrors>

-->

<pages>

<controls>

<add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

<add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

</controls>

<namespaces>

<add namespace="System.Web.Mvc"/>

<add namespace="System.Web.Mvc.Ajax"/>

<add namespace="System.Web.Mvc.Html"/>

<add namespace="System.Web.Routing"/>

<add namespace="System.Linq"/>

<add namespace="System.Collections.Generic"/>

<add namespace="MvcContrib.UI.Tags"/>

<add namespace="MvcContrib.UI"/>

<add namespace="MvcContrib.UI.Html"/>

<add namespace="MvcContrib.UI.Html.Grid"/>

<add namespace="MvcContrib"/>

</namespaces>

</pages>

<httpHandlers>

<remove verb="*" path="*.asmx"/>

<add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

<add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

<add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false"/>

<add verb="*" path="*.mvc" validate="false" type="System.Web.Mvc.MvcHttpHandler, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

</httpHandlers>

<httpModules>

<add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

<!--很重要-->

<add name="OpenSessionInView" type="Spring.Data.NHibernate.Support.OpenSessionInViewModule, Spring.Data.NHibernate21"/>

<add name="Spring" type="Spring.Context.Support.WebSupportModule, Spring.Web" />

</httpModules>

</system.web>

<system.codedom>

<compilers>

<compiler language="C#;cs;csharp" extension=".cs" warningLevel="4" type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">

<providerOption name="CompilerVersion" value="v3.5"/>

<providerOption name="WarnAsError" value="false"/>

</compiler>

<compiler language="VB;vbs;visualbasic;VBScript" extension=".vb" warningLevel="4" type="Microsoft.VisualBasic.VBCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">

<providerOption name="CompilerVersion" value="v3.5"/>

<providerOption name="OptionInfer" value="true"/>

<providerOption name="WarnAsError" value="false"/>

</compiler>

</compilers>

</system.codedom>

<system.web.extensions/>

<!-- 

The system.webServer section is required for running ASP.NET AJAX under Internet

Information Services 7.0.It is not necessary for previous version of IIS.

-->

<system.webServer>

<validation validateIntegratedModeConfiguration="false"/>

<modules runAllManagedModulesForAllRequests="true">

<remove name="ScriptModule"/>

<remove name="UrlRoutingModule"/>

<add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

</modules>

<handlers>

<remove name="WebServiceHandlerFactory-Integrated"/>

<remove name="ScriptHandlerFactory"/>

<remove name="ScriptHandlerFactoryAppServices"/>

<remove name="ScriptResource"/>

<remove name="MvcHttpHandler"/>

<remove name="UrlRoutingHandler"/>

<add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

<add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

<add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

<add name="MvcHttpHandler" preCondition="integratedMode" verb="*" path="*.mvc" type="System.Web.Mvc.MvcHttpHandler, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

<add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" path="UrlRouting.axd" type="System.Web.HttpForbiddenHandler, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>

</handlers>

</system.webServer>

</configuration>

我們運行一下程序。

技術分享圖片

技術分享圖片

我個人認為Spring.NET在SessionFactory和事務控制上對Nhibernate支持的很好,減少了我們的代碼量和增加了擴增性,這就是為什麽Nhibernate與Spring.NET能成為一對很好組合的原因。

Spring.NET教程(十九)整合NHibernate和ASP.NET MVC(基礎篇)