NHibernate + MVC

2010-03-21

NHibernate + MVC

博客分类: .net

载:http://www.cnblogs.com/wellsoho/archive/2009/09/11/1564880.html


在自己学习NHibernate+MVC时,吃了不少苦,开发中也总结了些问题。发表出来,以便新学者能有所借鉴少走些弯路。

Nhibernate 要求model实体类对于lazy="true" ,字段属性前需要加 virtual

sqlserver2005和oracle10g的hibernate.cfg.xml如何配置?
A:sqlserver2005配置如下
<!-- NHibernate sqlserver2005配置-->
<hibernate-configuration  xmlns="urn:nhibernate-configuration-2.2" >
  <session-factory name="db1">
    <!-- properties -->
    <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
    <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
    <property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
    <property name="connection.connection_string">
      Server=.;initial catalog=NhibernateTest;User Id=sa;Password=sa
    </property>
    <property name="use_outer_join">true</property>
    <property name="use_proxy_validator">true</property>
    <!--<property name="show_sql">false</property>-->
    <!--<property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property>-->
    <!-- mapping files -->
    <mapping assembly="Kang.Model" />
  </session-factory>
</hibernate-configuration>

Oracle10g配置如下:
<!-- NHibernate Oracle10g配置--> 
<hibernate-configuration  xmlns="urn:nhibernate-configuration-2.2" >
  <session-factory name="db1">
    <!-- properties -->
    <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
    <property name="connection.driver_class">NHibernate.Driver.OracleClientDriver&lt</property>
    <property name="dialect">NHibernate.Dialect.Oracle9Dialect&lt</property>
    <property name="connection.connection_string">
      data source=KANGSHI;User ID=huobj;Password=huobj
    </property>
    <property name="use_outer_join">true</property>
    <property name="use_proxy_validator">true</property>
    <!--<property name="show_sql">false</property>-->
    <!--<property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property>-->
    <!-- mapping files -->
    <mapping assembly="Kang.Model" />
  </session-factory>
</hibernate-configuration>


Q:无法将类型为“NHibernate.Dialect.MsSqlCeDialect”的对象强制转换为类型“NHibernate.Driver.IDriver”。 
A:当切换数据库时,相应的connection.driver_class属性是需要调整 
  oracle10g是NHibernate.Driver.OracleClientDriver
  MsSql2005是NHibernate.Driver.SqlClientDriver

Q:could not execute query
A:总的原则是,Nhibernate查询还是遵守sql原规则的。
1 字段名称不对,
2 字段格式不对,注意日期、数字和字符
3&lt;property type="string" length="50" name="RoleName" column="[RoleName]" /&gt;
oracle必须把RoleName的[]去掉。而sqlsever去不用去[]都行。
 

Q:The type System.Int32 can not be assigned to a property of type System.String setter of Kang.Model.Entities.USR_UserInfo.LoginID
A: 主键LoginID原定义的是int ,应该改成string

Q:Invalid Cast (check your mapping for property type mismatches); setter of Kang.Model.Entities.USR_UserInfo
A:length="80" 必须小于数据库表中字段的长度。另外,就是实体类中属性类的类型要和nhibernate-mapping 中的type同。

Q:数据库中的Date、DateTime和TimeStamp类型区别?
A:
DATETIME, DATE和TIMESTAMP类型是相关的。本文描述他们的特征,他们是如何类似的而又不同的。
DATETIME类型用在你需要同时包含日期和时间信息的值时。MySQL检索并且以'YYYY-MM-DD HH:MM:SS'格式显示DATETIME值,支持的范围是'1000-01-01 00:00:00'到'9999-12-31 23:59:59'。(“支持”意味着尽管更早的值可能工作,但不能保证他们可以。) 
DATE类型用在你仅需要日期值时,没有时间部分。MySQL检索并且以'YYYY-MM-DD'格式显示DATE值,支持的范围是'1000-01-01'到'9999-12-31'。
TIMESTAMP列类型提供一种类型,你可以使用它自动地用当前的日期和时间标记INSERT或UPDATE的操作。如果你有多个TIMESTAMP列,只有第一个自动更新。

SqlDateTime 溢出。必须介于 1/1/1753 12:00:00 AM 和 12/31/9999 11:59:59 PM 之间。
滴答数必须介于 DateTime.MinValue.Ticks 和 DateTime.MaxValue.Ticks 之间。
参数名: ticks 
A:实体类中这样定义就ok了  private DateTime _CreateDate = new DateTime(2009 - 9 - 9);

 

 
   Q:有的哥们这么写,但是问题是麻烦。
             var whitelist = new[] { "UserId", "UserName", "UserParssord", "UserMail" };
                UpdateModel(user, whitelist);
                uService.UpdateUserInfo(user); 
                return RedirectToAction("Index");
A:     可以这样写
               model = bll.GetModel(id);
                UpdateModel(model);
                bll.UpdateData(model);
                return RedirectToAction("Index")

父子表关联映射 ============================================== 
Q: 用户代码未处理 NHibernate.PropertyAccessException
  Message="Invalid Cast (check your mapping for property type mismatches); setter of Kang.Model.Entities.USR_UserInfo"
  Source="Kang.NHibernateHelper"
  A:<!--多对一关系:Users属于一个Role-->
  <many-to-one name="RoleID" column="RoleID" not-null="true" class="Kang.Model.Entities.RoleInfo" foreign-key="FK_RoleUsers" />

   <!--一对多关系:Role有一个或多个Users-->
    <set name="Users" table="`USR_UserInfo`" generic="true" inverse="true">
      <key column="RoleInfo" foreign-key="FK_RoleUsers"/>
      <one-to-many class="Kang.Model.Entities.USR_UserInfo"/>
    </set>
 
 Q:Duplicate property mapping of RoleID found in Kang.Model.Entities.USR_UserInfo
 A:有重复的属性定义。属性对象化,页面调用显示时可以再调用属性的属性,如:model.RoleID.RoleName

Q:Could not initialize proxy - the owning Session is disconnected
 A:对于父子关联表,把lazy="false"

 

 

 

 

 


(1)、Nhibernate错误”No persister for ”

          Nhibernate错误”No persister for <entity name>”

         例如:”No persister for DomainModel.Entities.User”

    1.检查hibernate.cfg.xml是否配置mapping 如:<mapping                                 assembly="”DomainModel”/">

    2.检查User.hbm.xml文件属性“生成操作”的值,从“内容”修改为“嵌入的资源”


(2)、Could not find the dialect in the configuration这个错误,

     这是数据库配置问题

     <hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">

    换成

    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">

(3)、The ProxyFactoryFactory was not configured 报错

     因为没有引用上面那个配置中的工厂类所以在引用下             Required_For_LazyLoading文件夹下的 LinFu下的NHibernate.ByteCode.LinFu.dll 当然也可以用 Castle 那要改下配置</hibernate-mapping></hibernate-mapping></mapping></entity>

(4)、Could not compile the mapping document

 解决办法:

  调试查看到InnerText为,不应该为<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">,然后我把改为

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">后,此问题解决.


(5)、NHibernate.InvalidProxyTypeException

        The following types may not be used as proxies: TestCleanSnow.BjkptOaxtCleanupsnow: method set_IsDeleted should be virtual TestCleanSnow.BjkptOaxtCleanupsnow: method set_IsChanged should be virtual TestCleanSnow.BjkptOaxtCleanupsnow: method Clone should be virtual TestCleanSnow.BjkptOaxtCleanupsnow: method get_IsChanged should be virtual TestCleanSnow.BjkptOaxtCleanupsnow: method get_IsDeleted should be virtual

解决办法: 在XML的 <class name="TestCleanSnow.BjkptOaxtCleanupsnow,TestCleanSnow" table="B_JKPT_OAXT_CLEANUPSNOW"> 添加  lazy="false" .

(6)、在执行 session.Save(cs);

时,出现could not get next sequence value[SQL: SQL not available] Nhibernate



解决办法:

把相应XML的

 <generator class="native" /> 改为 <generator class="assigned" />

以上我做Oracle时出现的错误,操作sqlserver的时候应该为 <generator class="native" />.



(7)、转载与: http://hi.baidu.com/zsea/blog/item/7d999e3d8a54c203baa1678d.html

一、Test.Model.Person.hbm.xml(2,2): XML validation error: 未能找到元素“urn:nhibernate-mapping-2.0:hibernate-mapping”的架构信息。

       将2.0改为2.2

二、 The following types may not be used as proxies:
         Test.Model.Person: method set_Id should be virtual
         Test.Model.Person: method get_Name should be virtual
         Test.Model.Person: method set_Name should be virtual
         Test.Model.Person: method get_Id should be virtual

         类配置文件中Class的Lazy改为false
         网上搜到的三种解决方案:
        1.   You can follow the advice of the exception and
add "virtual" to all of your properties, and make sure your class is non-sealed. Obviously you'll want to do this if you think you might want to take advantage of the lazy-initializing proxy feature.   However, changing your classes may not be practical or advisable if you have a legacy codebase, or it may just bother you that a "transparent" persistence framework is dictating how you design certain aspects of your value classes.   That's where Options 2 and 3 come in.   Both of those involve changing back to the old behavior.

          2.   To change the lazy-initialization proxy setting for a specific class , you can add a "lazy='false'" attribute to the <class> mapping element.   This might look something like:
<class
     name="NorthwindClasses.Category, NorthwindClasses"
     table="Categories"
  
   lazy ="false"
>
        3.   To change the lazy-initialization proxy setting for all classes in a given mapping file, you can add a "default-lazy='false'" attribute to the <hibernate-mapping> element, as follows:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0" default-lazy ="false" >
Unfortunately, Option 3 doesn't really help you much if you do one <class> mapping per <hibernate-mapping> file, a practice which I personally follow and recommend.   It's too bad, but there doesn't seem to be any way to set this default in the <nhibernate> global configuration.   But if you do happen to have all of your <class>'s in one .hbm.xml file, "default-lazy" can help you out.





 

面向对象的数据库开发框架NHibernate

 

近年来,越来越多的人认识到使用面向对象的企业应用开发框架来进行系统的开发有着诸多的好处。在项目设计阶段,使用UML建模语言设计业务域对象模型,从模型出发,定义业务域对象,运行时对业务域对象的属性进行操作,直接将业务域对象保存到数据库,或者从数据库加载,消除对面向数据集的Sql的依赖,这就是通常所说的OR Mapping,对象-关系映射方法。

在Java平台上,OR Mapping的开源框架的No.1就是Hibernate,Hibernate是一个轻量级的OR Mapping解决方案,一经推出就取得了巨大的成功,在刚刚发布的EJB3.0的草案中就吸收了大量的Hibernate中的特性。从2004年三月开始,SourceForge上发布了.Net版本的NHibernate的Alpha版本,目前NHibernate的开发进展非常顺利,平均每一个半月就会发布一个新的版本。

NHibernate具有以下特性:

对象持续性:能够管理.Net类到数据库表的映射,以对象的方式存取数据,支持复杂对象、复合对象,支持对象之间的关联,比如继承,聚合,关联。OR Mapping的定义都是基于XML,具有很好的扩展性和通用性。可以支持现有的数据库定义,很好地保护用户投资。

支持对象查询:提供了面向对象的查询语言(HQL和条件查询),可以根据条件查询复合对象以及对象集合。

支持事务:创建还必须支持悲观锁的事务,并提供了乐观锁的并发支持。

性能优化:允许用户使用定制的Sql来提高查询的性能,提供了多种SQL自动策略开关,使得框架生成的Sql语句具有非常优化的性能。提供了灵活的Cache缓冲机制,以及延迟加载,批量更新的策略,保证一般应用的性能不会低于相应的数据集应用。

数据库平台无关性:使用OR Mapping技术实现了数据库平台无关性,可以随时切换开发及数据库发布平台,方便移植。


 

NHibernate的体系结构示意图:

 

 

图中的Session对应于应用程序同持久层的一次对话,其中保存有必需的持久化对象的缓存,可以通过标识符查找持久对象。持久层同底层数据库之间的操作是通过ADO.Net来实现的。

 

包的介绍:

 

NHibernate.dll是核心的程序集

Log4net.dll是日志记录程序集

Iesi.Collections.dll是集合框架的程序集

Castle.DynameicProxy.dll控制反转的程序集 


编码步骤:

 

第一步:Web.Config/App.Config

第二步: 实体类

第三步:创建使用NHibernate的配置文件

 

     freetextbox是一款免费的asp.net网页编辑器,官方默认为英文版,可以设置文字样式、在线排版、图片上传等。
是一款非常好用,功能很强大的在线编辑器,尤其是能真正实现图片上传,目前网上流传的帮助都是针对老版本的,所以为大家整理一个针对新版本的帮助,希望对大家有用:

目录结构:
aspnet_client     freetextbox的外观文件,直接拷贝到你的工程的目录下就可以了。
docs              帮助文档
examples          官方例子,包括了各类应用的演示和实现过程,包括:功能设置、下拉显示、多语言(包括简体中文、繁体、英文等)切换、js调用、webparts应用、ajax无刷新交互等例子。
framework-2.0     适合.net freameork2.0使用的dll
framework-1.0     适合.net freameork1.1使用的dll
framework-1.0     适合.net freameork1.0使用的dll
使用方法: 
1 在web应用程序中添加引用freetextbox.dll,自动添加到bin 目录; 
  文件夹下有asp.net1.1/2.0/3.5各个环境下可以使用的freetextbox.dll;
  添加引用时要根据使用的framework版本来引用相应的dll。
2 把aspnet_client下的freetextbox文件夹及其所有内容都拷贝到web项目
3 在应用程序目录下建立images目录,此目录用做上传图片的图片库,上传的图片都保持在该文件夹下
4 在aspx中使用:
  页头添加


xml/html代码


    <%@ register tagprefix="ftb" namespace="freetextboxcontrols" assembly="freetextbox"  %>   


引入 控件 标签 
  添加<ftb:freetextbox>到 页面 中需要的位置。



xml/html代码

    <ftb:freetextbox id="freetextbox1" onsaveclick="savebutton_click"   language="zh-cn"    
       toolbarlayout="paragraphmenu,fontfacesmenu,fontsizesmenu,fontforecolorsmenu,fontforecolorpicker,fontbackcolorsmenu,fontbackcolorpicker|bold,italic,underline,strikethrough,superscript,subscript,removeformat|justifyleft,justifyright,justifycenter,justifyfull;bulletedlist,numberedlist,indent,outdent;createlink,unlink,insertimage|cut,copy,paste,delete;undo,redo,print,save|symbolsmenu,stylesmenu,inserthtmlmenu|insertrule,insertdate,inserttime|inserttable,edittable;inserttablerowafter,inserttablerowbefore,deletetablerow;inserttablecolumnafter,inserttablecolumnbefore,deletetablecolumn|insertform,inserttextbox,inserttextarea,insertradiobutton,insertcheckbox,insertdropdownlist,insertbutton|insertdiv,editstyle,insertimagefromgallery,preview,selectall,wordclean,netspell"   runat="server" designmode css ="designmode.css"/>  
        
    <asp:button id="savebutton" text="save" οnclick="savebutton_click" runat="server" />     
      



  
  常用属性:
  language="zh-cn" 把显示语言改为中文,默认为英文
  
  toolbarlayout: 说明在线编辑器提供的相应功能
  text: 提供默认值
  toolbarstyleconfiguration:换肤,取值包括notset office2000 officexp officemac office2003
  注意提交按钮和freetextbox的onclick事件使用同一个处理方法
5 如果要实现上传图片功能 ,必须把ftb.imagegallery.aspx文件,拷贝到使用该控件的aspx文件相同的文件夹下。
6 获取或者设置值: freetextbox1.text
this.freetextbox1.htmlstrippedtext 这个是将html标记去掉的文本
7 使用的页面中需要设置 validaterequest="false"
  否则会报错:从客户端.....中检测到有潜在危险的 request.form 值。说明: 请求 验证 过程检测到有潜在危险的客户端输入值,对请求的处理已经中止。该值可能指示危及应用  程序安全的尝试,如跨站点的脚本攻击。通过在 page 指令或配置节中设置 validaterequest=false 可以禁用请求验证
   解决 办法:
  web.config中<system.web>下添加一个配置 

  页面配置中添加validaterequest="false",即<%@ page ...... validaterequest="false"%>

下载 地址
http://freetextbox.com/
http://freetextbox.com/download/

 

2009-12-12

CKeditor

博客分类: .net

 首先介绍一下CKeditor的技术,其实CKeditor就是FCKeditor的升级版本,改名主要是与它公司的名字有关,这就是新出的版本Ckeditor3.0  官方网为:http://www.fckeditor.net/

 

  develops Guide 这个开发指南相当不错,一般我们学一样东西都是直接去看这个技术的开发指南,里面有一般的用法,让你迅速上手,而且很容易搞懂这些配置。首先下载FCKeditor2.6.5.zip包,这个包是必须的,而且与语言无关。第二个必须包是FCKeditor.net_2.6.3.zip包。下载完这两个包,马上就可以开始web开发了。

 

  当然首先你要看看Demo的东西,毕竟它是官方自带的例子,肯定值得我们去研究,而且里面的代码很有参考价值,到了这一步,我相信就很容易做了。 

 

 

 

 开发指南网址:http://docs.cksource.com/CKEditor_3.x/Developers_Guide


下面讲讲FCKeditor.Net编辑器在.net环境的配置方法。

第一步:解压缩FCKeditor_2.6.3.zip文件,并将解压缩得到的fckeditor文件夹复制到你想使用这个编辑器的网站的根目录下面。

第二步:把下载的FCKeditor.Net.zip随便解压缩到你硬盘的一个空目录,里面是FCKeditor.Net的源代码,可以对它进行再度开发,我这里讲直接应用,我们要使用到是其目录下的\bin\Debug目录中的FredCK.FCKeditorV2.dll文件。在你的网站里面把这个FredCK.FCKeditorV2.dll添加到bin目录下。

第三步:进入FCKeditor文件夹,编辑 fckconfig.js 文件,如下:

1、指定编辑器应用的编程环境,修改

var _FileBrowserLanguage = 'asp' ; // asp | aspx | cfm | lasso | perl | php | py

var _QuickUploadLanguage = 'asp' ; // asp | aspx | cfm | lasso | php

改为

var _FileBrowserLanguage = 'aspx' ; // asp | aspx | cfm | lasso | perl | php | py

var _QuickUploadLanguage = 'aspx' ; // asp | aspx | cfm | lasso | php

2、配置语言包。有英文、繁体中文等,这里我们使用简体中文。

修改

FCKConfig.DefaultLanguage = 'en' ;



FCKConfig.DefaultLanguage = 'zh-cn' ;

3、配置皮肤。有default、office2003、silver风格等,这里我们可以使用默认。

FCKConfig.SkinPath = FCKConfig.BasePath + 'skins/default/' ;

4、在编辑器域内可以使用Tab键。(1为是,0为否)

FCKConfig.TabSpaces = 0 ; 改为FCKConfig.TabSpaces = 1 ;

5、加上几种我们常用的字体的方法,例如:

修改

FCKConfig.FontNames = 'Arial;Comic Sans MS;Courier New;Tahoma;Times New Roman;Verdana' ;



FCKConfig.FontNames = '宋体;黑体;隶书;楷体_GB2312;Arial;Comic Sans MS;Courier New;Tahoma;Times New Roman;Verdana'

6、编辑器域内默认的显示字体为12px,想要修改可以通过修改样式表来达到要求,打开/editor/css/fck_editorarea.css,修改font-size属性即可。如font-size: 14px;

7、关于安全性。

如果你的编辑器用在网站前台的话,那就不得不考虑安全了,在前台千万不要使用Default的toolbar,要么自定义一下功能,要么就用系统已经定义好的Basic,也就是基本的toolbar,

修改

FCKConfig.ToolbarSets["Basic"] = [

['Bold','Italic','-','OrderedList','UnorderedList','-','Link','Unlink','-','About']



FCKConfig.ToolbarSets["Basic"] = [

['Bold','Italic','-','OrderedList','UnorderedList','-','Unlink','-','Style','FontSize','TextColor','BGColor','-','Smiley','SpecialChar','Replace','Preview']

] ;

第四步:在Web.Config文件里面添加,如下所示

1、配置WebConfig,在<appSettings>节点添加,如下所示:

如果你用的是默认的上传功能,则

<add key="FCKeditor:BasePath" value="~/fckeditor/"/>

<add key="FCKeditor:UserFilesPath" value="/网站名称/UploadFiles/"/>

第五步:在页面里应用FCKeditor编辑器

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" validateRequest="false" %>

<%@ Register Assembly="FredCK.FCKeditorV2" Namespace="FredCK.FCKeditorV2" TagPrefix="FCKeditorV2" %>

// 这里要主要两个参数

// 默认为<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

// 我们要添加一个参数 validateRequest=false,否则提交带html代码的内容会报错

// 从客户端(...)中检测到有潜在危险的 Request.Form 值。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

<title>无标题页</title>

</head>

<body>

<form id="form1" runat="server">

<div>

<FCKeditorV2:FCKeditor ID="FCKeditor1" runat="server">

</FCKeditorV2:FCKeditor>

&nbsp;</div>

</form>

</body>

</html>

如何获取其内容呢?读取FCKeditor1控件的Value属性值即可。

到这里基本OK了,但是我发现在使用图片上传功能的时候,会弹出一个阻止框,显示"this connector is disabled Please check the"editor/filemanager/connectors/aspx/config.aspx",解决这个错误的方法是打开editor/filemanager/connectors/aspx/config.ascx修改CheckAuthentication()方法,返回true

C# code

private bool CheckAuthentication()

{

// WARNING : DO NOT simply return "true". By doing so, you are allowing

// "anyone" to upload and list the files in your server. You must implement

// some kind of session validation here. Even something very simple as...

//

// return ( Session[ "IsAuthorized" ] != null && (bool)Session[ "IsAuthorized" ] == true );

//

// ... where Session[ "IsAuthorized" ] is set to "true" as soon as the

// user logs in your system.

return true;

}


下载地址:http://www.fckeditor.net/download

FCKeditor使用

一、配置

1、在www.fckeditor.net点击Download,下载FCKEditor_2.5.1.zip和FCKEditor.Net(ASP.NET Control to easily integrate FCKEditor on .Net Web pages.)

2、新建一项目,比如叫FCK。解压FCKEditor_2.5.1.zip,里面有个fckeditor目录。把该目录整个复制到新建的ASP.NET项目根目录下。打开fckeditor目录下的fckconfig.js,修改二项:

FCKConfig.DefaultLanguage = 'en' ;

改为

FCKConfig.DefaultLanguage = 'zh-cn' ;

-----------------------------------------------------

var _FileBrowserLanguage = 'php' ; // asp | aspx | cfm | lasso | perl | php | py

var _QuickUploadLanguage = 'php' ; // asp | aspx | cfm | lasso | perl | php | py

改为

var _FileBrowserLanguage = 'aspx' ; // asp | aspx | cfm | lasso | perl | php | py

var _QuickUploadLanguage = 'aspx' ; // asp | aspx | cfm | lasso | perl | php | py

3、在vs05/08的工具箱上新建一个名叫FCKEditor的Tab,然后在里面点右键,选择Choose Item,定位到解压FCKEditor.Net后生成的FCKEditor2.51\FCKeditor.Net_2.5\bin\Release\2.0目录下的FredCK.FCKEditorV2.dll。该Tab下就会生成一个FCKEditor的.net组件。在vs的Design模式下把该组件拖放到界面上。点击该组件,在属性面板上设置BashPath为/FCK/fckeditor/,注意这里的FCK就是你建的ASP.NET的项目名称,fckeditor为项目根目录下的目录名称。(注意:/FCK/fckeditor/前后的斜杠,少了一个都不会显示编辑器的)。Ctrl+F5!

其它次要配置(不影响使用):

* 可以把fckeditor目录及其子目录下所有下划下开头的范例、源文件删掉。

* 可以在fckeditor目录下只保留fckconfig.js、fckeditor.js和几个xml文件,其余全部删掉。

* fckeditor目录下的editor目录下有个filemanager目录,把该目录下的borswer\default\connectors目录中除aspx目录以外的全部目录删掉。

* 可以把editor\lang目录下除zh-cn.js、en.js、zh.js之外的全部删掉。

二、图片上传

FCKEditor支持图片上传。可以在ASP.NET项目根目录下添加一目录,起名为UploadFiles.

在web.config里的appSettings段里

<appSettings>

<add key="FCKEditor:BasePath" value="/FCK/fckeditor"/>

<add key="FCKeditor:UserFilesPath" value="/FCK/UploadFiles/" />

</appSettings>

注意UserFielsPath,这里设置的/FCK/UploadFiles/指定了要上传的目录。个人认为这里的FCK可以认为是服务器上的虚拟目录名。(另外发现如设为时不起作用)。

当上传图片时有可能遇到"this connector is disabled Please check the"editor/filemanager/connectors/aspx/config.aspx"的错误,这时可以更改fckeditor\editor\filemanager\connectors\aspx\config.ascx的CheckAuthentication()方法,返回true.

三、简单的FCKEditor存取数据库及显示

1、在项目里添加新项Sql Server Database, 文件名保留为Database.mdf。在里面新建一表MyTable,只有两个字段,一个int型自动增加的primary key, 另一个是text类型的MyContent. 我们要把FCKEditor1.Value值存到这个字段里。

2、先做个显示的页面。项目增加一个Show.aspx,拖一个SqlDataSource,设置一下返回MyTable的内容。再用Repeater显示。

//代码

<asp:Repeater ID="myRepeater" runat="server" DataSourceID="SqlDataSource1">

<HeaderTemplate>

<table>

</HeaderTemplate>

<ItemTemplate>

<tr>

<td>

<%# Eval("MyContent") %>

</td>

</tr>

</ItemTemplate>

<FooterTemplate>

</table>

</FooterTemplate>

</asp:Repeater>

<asp:SqlDataSource ID="SqlDataSource1" runat="server"

ConnectionString="<%nbsp;ConnectionStrings:ConnectionString %>"

SelectCommand="SELECT [OID], [MyContent] FROM [MyTable] ORDER BY [OID] DESC"></asp:SqlDataSource>

3、存入数据库

项目中引用System.Configuration(为了使用System.Web.WebConfigurationManager)

在FCKEditor界面上入一个按钮,然后

protected void Button1_Click(object sender, EventArgs e)

{

using (SqlConnection conn = new SqlConnection())

{

conn.ConnectionString = System.Web.Configuration.WebConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;

SqlCommand cmd = new SqlCommand();

cmd.Connection = conn;

cmd.CommandText = "insert into MyTable(MyContent) values(@FCKContent)";

cmd.Parameters.AddWithValue("FCKContent",FCKeditor1.Value);

conn.Open();

cmd.ExecuteNonQuery();

}

}
 

 

 

 

前言:

与ASP相比ASP.NET在Web应用开发上无疑更容易,更有效率。Web开发大部分还是围绕着数据操作,建立数据库存储数据,编写代码访问和修改数据,设计界面采集和呈现数据。走过Asp.net学习入门阶段后,真正开始着手开发一个Web项目时,才发现错综复杂的数据与关联根本就不是SqlDataSource和AccessDataSource数据源控件能简单解决的,而恰恰是被忽视了的一个ObjectDataSource数据源控件才是真正踏入开发门槛的关键,由此也对三层架构模式有了初步体验。

一.ASP.NET三层架构介绍

设计模式中的分层架构(可以参考一下J2EE中MVC模式)实现了各司其职,互不干涉,所以如果一旦哪一层的需求发生了变化,就只需要更改相应的层中的代码而不会影响到其它层中的代码。这样就能更好的实现开发中的分工,有利于组件的重用。所以这些年关于模式的研究有很多成果,应用也很广泛。一个好的模式在程序开发和后期维护中作用重大。

ASP.NET三层架构自底向上分为:数据访问层(DAL),业务逻辑层(BLL)和表示层(PL)。




数据访问层(DAL):使用了一个强类型的DataSet作为数据访问层,只是单纯的对数据进行增,删,改,查询和判断存在等等较通用的数据访问方法(由SQL语句来提供),不应该有“事务”存在。

业务逻辑层(BLL):业务逻辑层是在数据访问层和表示层之间进行数据交换的桥梁,按业务需求调用数据访问层中的方法组合,集合了各种业务规则到一个BLL中,例如通过条件进行判断的数据操作或“事务”处理。BLL都是以类库(Class Library)的形式来实现的。

表示层(PL):表示层是为客户提供用于交互的应用服务图形界面,帮助用户理解和高效地定位应用服务,呈现业务逻辑层中传递的数据,用ASP.NET页面来实现。

 

 二.三层架构应用实现

随着ASP.NET 的不断升级,可以很方便的使用ASP.NET 来构建B/S 三层架构的应用程序,下面以“教师业务信息管理系统”项目中的部分例子来演示如何使用ASP.NET 2.0 和SQL Server 2005数据库来构建一个三层架构的应用程序。

1.创建数据库

打开SQL Server 2005,新建一个数据库“TeacherDb”,建立如下所示结构的两个表“PersonInfo”和“JobInfo”。两表以PersonIDNumber作为关联字段,存储18位身份证号码。

 

 

 2.创建数据访问层

在开始创建数据访问层(DAL)之前,首先需要创建一个网站,配置好数据库链接。

第一步:创建一个Web项目,配置数据库连接

打开Visual Studio 2005(以下简称VS2005)集成开发环境, 首先创建一个C#语言的ASP.NET网站,并将其命名为WebSite,设置位置(Location)列表的选项为文件系统( File System),然后选这一个放置这个网站的文件夹,然后选择编程语言为C#。Visual Studio会为你生成一个新的网站,同时生成一个名为Default.aspx的网页,和一个App_Data文件夹。

 

 

 第二步:创建数据访问层,配置数据库连接

接下来创建数据访问层,添加一个强类型的DataSet。在解决方案管理器里的项目节点上按右鼠标,选择“添加新项”,在模板列单里选择“数据集”,将其命名为DataSet1.xsd。接下来会出现“TableAdpater”配置向导的窗口,选择数据库服务器,设置好各项参数,并按照提示逐步完成。需要注意:

1.指定连接的数据库字符串,并选择将连接字符串保存到web.config文件中去。

2.命令类型选择“使用SQL语句”,通过“高级选项”选择“生成Insert、Update和Delete语句”,通过“查询生成器”生成要装载数据的“Select语句”。并为方法命名。

 

 

 


SELECT ID, UserID, TrueName, PersonIDNumber, Sex, BirthDate, Nation, NativePlace,

Polity, JoinPolityTime, PersonImageUrl, Telephone, MobiePhone, Email

FROM EM_P_PersonInfo

针对项目需求对数据库中各表查询操作分别建立各种方法,完成后的可能如下图。

 

 

跟底层数据源相关的所有编码,比如建立到数据库的连接,发出SELECT,INSERT ,UPDATE和DELETE命令等的编码,都应该放置在DAL中。表现层不应该包含对这些数据访问编码的任何引用,而应该调用DAL中的编码处理所有的数据访问请求。数据访问层包含访问底层数据库数据的方法。至此,清晰构建出数据访问层,之后可在“业务逻辑层”和“表示层”通过调用自动生成的TableAdpater及相关类来操作数据。由于“数据集”是强类型,对于数据库中的NULL数据需要使用方法来判断,这些内容在后续内容中再详细描述。

 


3.创建业务逻辑层

数据访问层(DAL)将数据访问的细节从表示层中分离出来了,可它却不能处理任何的业务规则。比如判断数据的有效性。这些工作将由业务逻辑层(简称BLL)来承担,在以下应用程序中,将BLL实现为App_Code文件夹中的一系列的类。每一个BLL类都对应DAL中的一个TableAdapter,它们都从各自的TableAdapter中得到读取、插入、修改以及删除等方法以应用合适的业务规则。

第一步:创建BLL类
在App_Code文件夹中创建2个类文件。在解决方案浏览器(Solution Explorer)中右键点击App_Code文件夹,并选择新建项目(New Item),然后在弹出的对话框中选择“类”模板(Class template)就可以创建新的类文件了。将这2个文件分别命名为UserBLL以及JobBLL。

 


第二步:通过BLL类访问类型化数据集

为UserBLL和JobBLL类分别添加如下方法:

(1) UserBLL.css

l updateUser(string UserName, String PersonIDNumber, int SchoolID, string Password, string Sex, string TrueName, bool InPosition)

l updateUser(String PersonIDNumber, string TrueName, string BirthDate, string Nation, string NativePlace, string Polity, string JoinPolityTime, string Telephone, string MobiePhone, string Email)

l getPersons(int SchoolID,string TrueName)

l getPersonByPID(string PersonIDNumber)

l deleteUser(string UserName, String PersonIDNumber, int? SchoolID)

l addUser(string UserName, String PersonIDNumber, int SchoolID, string Password, string Sex, string TrueName, bool InPosition)

(2)JobBLL.css

l getPersonJob(string PersonIDNumber)

l updateUser(String PersonIDNumber, string Post1, string Post2, string JoinTime, int? CountryWorkedTime, string MasteSubject, string SecondSubject, string SchoolPhase, int? MotherClassTime)

以下为JobBLL.css的代码(UserBLL.css的代码太长,不列出)

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using TeacherTableAdapters;

/// <summary>
/// JobBLL 的摘要说明
/// </summary>

[System.ComponentModel.DataObject]
public class JobBLL
{
private JobInfoTableAdapter _JobAdapter = null;

public JobBLL()
{
//
// TODO: 在此处添加构造函数逻辑
//
}

protected JobInfoTableAdapter Adapter
{
get
{
if (_JobAdapter == null)
_JobAdapter = new JobInfoTableAdapter();

return _JobAdapter;
}
}

 


//select
[System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, false)]
public Teacher.JobInfoDataTable getPersonJob(string PersonIDNumber)
{
return Adapter.GetPersonJobByPID(PersonIDNumber);
}

//update
[System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Update, false)]
public bool updateUser(String PersonIDNumber, string Post1, string Post2, string JoinTime, int? CountryWorkedTime, string MasteSubject, string SecondSubject, string SchoolPhase, int? MotherClassTime)
{
if (string.IsNullOrEmpty(PersonIDNumber))
{
return false;
}

try
{

Teacher.JobInfoDataTable PersonJob = Adapter.GetPersonJobByPID(PersonIDNumber);
Teacher.JobInfoRow PersonJobPID;

if (PersonJob.Count == 1)
{
PersonJobPID = PersonJob[0];
}
else
{
return false;
}

if (!string.IsNullOrEmpty(Post1))
{
PersonJobPID.Post1 = Post1;
}
else
{
PersonJobPID.SetPost1Null();
}
if (!string.IsNullOrEmpty(Post2))
{
PersonJobPID.Post2 = Post2;
}
else
{
PersonJobPID.SetPost2Null();
}
if (!string.IsNullOrEmpty(MasteSubject))
{
PersonJobPID.MasteSubject = MasteSubject;
}
else
{
PersonJobPID.SetMasteSubjectNull();
}
if (!string.IsNullOrEmpty(SecondSubject))
{
PersonJobPID.SecondSubject = SecondSubject;
}
else
{
PersonJobPID.SetSecondSubjectNull();
}
if (!string.IsNullOrEmpty(SchoolPhase))
{
PersonJobPID.SchoolPhase = SchoolPhase;
}
else
{
PersonJobPID.SetSchoolPhaseNull();
}

if (!(CountryWorkedTime == null))
{
PersonJobPID.CountryWorkedTime = CountryWorkedTime.Value;
}
else
{
PersonJobPID.SetCountryWorkedTimeNull();
}
if (!(MotherClassTime == null))
{
PersonJobPID.MotherClassTime = MotherClassTime.Value;
}
else
{
PersonJobPID.SetMotherClassTimeNull();
}
if (!string.IsNullOrEmpty(JoinTime))
{
PersonJobPID.JoinTime = DateTime.Parse(JoinTime);
}
else
{
PersonJobPID.SetJoinTimeNull();
}

int rowAffect1 = Adapter.Update(PersonJobPID);
return (rowAffect1 == 1);
}
catch (System.Configuration.Provider.ProviderException e)
{
return false;
}
}
}

说明:

(1)using TeacherTableAdapters; 引用DAL层命名空间,自动生成,必须。否则无法使用类。

(2)JobInfoTableAdapter类,对应DAL中的TableAdapter适配器JobInfo,通过这个类来调用增、删及改等数据操作。

(3)使用JobInfoDataTable PersonJob来装载查询返回的数据,是DataSet中的强类型数据表,结构和数据类型由数据库定义。使用JobInfoRow PersonJobPID来载入表中的某一行。行字段访问用如下形式:Row变量.字段名(如PersonJobPID.Post1)。

Teacher.JobInfoDataTable PersonJob = Adapter.GetPersonJobByPID(PersonIDNumber);

Teacher.JobInfoRow PersonJobPID = PersonJob[0];

(4)数据库中某些表字段在设计时可能被允许空值(null),强类型DataTable中对字段的判空与赋空值不能采用以下形式:

l !string.IsNullOrEmpty(PersonJobPID.Post1)

l PersonJobPID.Post1 == null;

l PersonJobPID.Post1 = null;

正确的做法是采用行类型变量(Teacher.JobInfoRow PersonJobPID)为每个字段生成的“空值方法”操作:

l void PersonJobPID.SetPost1Null();

l bool PersonJobPID.IsPost1Null()

(5)JobInfoDataTable或JobInfoRow中数据存储在内存中,修改后的数据要反映到数据库中采用适配器方法Update().

int rowAffect1 = Adapter.Update(PersonJobPID);

至此业务逻辑层构建完成。

 

 4.表示层-使用ObjectDataSource展现数据

在完成应用程序架构后,我们可以实现多种报表展现。ASP.NET 2.0的数据源控件提供了一种新的方式,使用这些控件可以轻松的从创建的业务逻辑层中进行数据绑定,甚至不需要手写一行的代码。

ASP.NET 2.0提供了五种内置的数据源控件:SqlDataSource、AccessDataSource,、ObjectDataSource、XmlDataSource、和SiteMapDataSource。基于已有的业务逻辑类我们将使用ObjectDataSource。

ObjectDataSource充当别的对象的代理。通过配置ObjectDataSource,我们指定这些底层的对象,还有这些对象的方法如何映射到ObjectDataSource的Select、Insert、Update和Delete方法。一旦底层的对象被指定并且其方法映射到ObjectDataSource的方法后,我们就可以把ObjectDataSource绑定到页面上的Data Web服务器控件。ASP.NET提供了许多Data Web 服务器控件,包括GridView、DetailsView、RadioButtonList和DropDownList等等。在页面的生命周期中,Data Web 服务器控件可能需要访问它所绑定的数据,这将通过调用ObjectDataSource的Select方法来实现;如果这个Data Web 服务器控件还支持插入、更新或者删除,那么将调用ObjectDataSource的Insert、Update或者Delete方法。这些调用会通过ObjectDataSource被发送到适当的底层对象的方法。


第一步:添加和配置ObjectDataSource控件

(1)新建一个“Web窗体”模板文件(UserView.aspx),语言Visual C#,选择“将代码发在单独文件中”。

(2)拖入一个“GirdView”控件,点击智能标记中的“配置数据源”,选择“新建数据源…”,进入数据源配置向导来添加一个ObjectDataSource。

(3)进入数据源配置向导。首先给ObjectDataSource指定一个业务对象。如果勾选上“只显示数据组件”,那么下拉框中就仅仅显示出那些以[DataObject]特征修饰过的对象。可以不勾选“只显示数据组件”从而看见所有对象。从下拉列表中选择业务对象UserBLL 。

 

 

 

 根据页面设计的需要为SELECT,UPDATE,INSERT及DELETE操作指定相应的业务对象的方法。这些方法已经在业务逻辑层中定义。如果用GridView及DetailsView服务器控件呈现数据,SELECT操作是必须的。

 

 

 


第二步:配置GridView

从GridView的智能标记点选“编辑列”,为“选定的字段”指定标题名,格式,删除不需要的列,添加命令字段(Command Field)等。操作比较繁琐,看参考相关资料。完成后的样子类似下图:

 

 

 根据设计需求将页面设计完成。至此,表示层的搭建过程简单演示一下。

三.总结

用了几天时间将前段时间的学习和项目开发中的框架构建简单做了个总结,这不是一个教程类的文章,许多细节性的东西不可能面面俱到。程序开发是一件比较辛苦的事,过程可能很枯燥,不过对此感兴趣的人会在不断学习中体会到其中的乐趣。

  • 23:13
  • 评论 / 浏览 (0 / 2325)

基于UML和ASP.NET实现三层B/S结构系统开发

作者:胡颖辉 宁赛飞   来源:IBM


摘 要 进行良好的系统分析和设计是软件项目开发的关键,构架设计的合理与否往往决定了项目的成败。本文结合一个项目的开发,阐述了基于UML的系统建模过程和基于ASP.NET实现面向对象的三层结构应用系统的方法。

 关键词 ASP.NET; 三层结构; UML建模; 系统开发

架构设计是软件开发的基础,并往往决定一个项目的成败。三层结构是目前流行的架构设计模式,它是在由Buschmann等提出的“层模式”[1]基础上发展起来的,由表示层、业务逻辑层和数据访问层三个层次结构组成。它通过分解来管理问题的复杂性,同时还可以有效地重复使用业务逻辑并保留与昂贵资源(如数据库)的重要连接[2,3]。

 基于ASP.NET能够充分发挥其完全面向对象的技术特点,实现三层结构B/S系统架构,从而提高开发效率,增强系统的可维护性和扩展性。本文结合一个“学生成绩管理系统”的开发,研究如何基于UML进行三层B/S结构的系统建模,及其在ASP.NET下的应用实现。

 1 三层结构系统模型
 架构设计是非常高级的设计,也是系统设计的关键,主要是定义和说明包(子系统),以及包与包之间的相互依赖与通信机制。系统构架模型的合理与否将决定系统的可维护性、扩展性和开发效率。

 包通常所需要处理的是要么是一个具体的功能区域(业务逻辑),要么是一个具体的技术区域(技术逻辑)。业务逻辑主要考虑的是对系统业务功能的实现,而技术逻辑则是进一步考虑用户界面、数据库或通信机制等形成的技术方案。把技术逻辑和业务逻辑区分开来是极其重要的,这是为了当修改程序的某一部分时不会对另一部分产生影响,更加便于进行“复用”,同时易于应对来自业务逻辑的变更需求。

 三层结构是一种成熟、简单并得到普遍应用的应用程序架构,它将应用程序结构划分三层独立的包,包括用户表示层、业务逻辑层、数据访问层。其中将实现人机界面的所有表单和组件放在表示层,将所有业务规则和逻辑的实现封装在负责业务逻辑组件中,将所有和数据库的交互封装在数据访问组件中。其结构如下图1所示:


 图1 三层结构示意图

三层结构是一种严格分层方法,即数据访问层只能被业务逻辑层访问,业务逻辑层只能被表示层访问,用户通过表示层将请求传送给业务逻辑层,业务逻辑层完成相关业务规则和逻辑,并通过数据访问层访问数据库获得数据,然后按照相反的顺序依次返回将数据显示在表示层。

 2 三层B/S结构的学生管理系统开发
 下面通过一个学生管理系统的开发,说明三层B/S结构系统从UML建模到基于ASP.NET进行实现的完整开发过程,UML建模工具采用的是Rational Rose。

 2.1 需求分析
 软件需求分析是系统开发的第一步也是最重要的一个环节,其基本任务是准确地回答“系统做什么?”这个问题,这需要在对用户需求进行充分调研的基础上,深入理解并描述出软件的功能、性能、接口等方面的需求,可以使用UML建模作为需求分析和系统设计的有效方法。

 分析的目的是为了获得和描述系统中所有的要求,因此分析阶段是一种典型的与用户或客户合作的过程,通常由开发人员同用户或客户共同完成。在这个阶段,开发人员不应该考虑代码或程序实现的细节,而应该把精力放在对现有业务逻辑的理解上,通过与用户之间的充分沟通,逐步理解并描述出得到用户确认的系统模型,包括用例模型和领域(domain,系统中关键的类)模型。

 2.1.1 用例模型
 软件开发人员在对用户进行需求调研的过程中,用户往往并不能立即准确描述出未来系统应该提供一些什么样的功能。因此,需要开发人员理解和分析需求,并将系统应该具有的功能通过用例图直观的描述出来,方便用户理解并做出评判,开发人员从而可以根据用户的反馈不断调整用例模型,直至完全正确、充分描述清楚系统功能。

 用例建模主要是分离出系统的活动参与者(Actor)和用例(Use Case),用例是指对系统提供的功能的一种描述,而活动参与者是那些可能使用这些用例的人或外部系统,通过用例图可以描述出系统外部的执行者、系统的用例,以及它们之间的联系。本学生管理系统的用例图见图2。

 用例模型还需要进一步对每个用例进行详细描述,进一步说明用例的名称、基本事件流和备选事件流、前置条件和后置条件等,并形成文档。限于篇幅,这里就不多说了。
 
 图2 用例图

2.1.2 领域建模
 分析过程中还要详细地列举领域(domain ,系统中关键的类),为了进行领域分析,需要充分理解用例模型,也可以与用户及领域专家组织一次集体研讨会谈,尝试找出所有必须处理的关键概念以及它们之间的相互关系,并最终分析出域类图。下图3为本系统的域类图。

 需要强调的是:在本阶段,对领域进行分析的类图还是处于“草图”状态。定义的操作和属性不是最后的版本,只是在本阶段看来比较合适。后期将通过动态行为分析不断得出新的操作,这是一个逐步完善和发展的过程。

 2.2 系统设计
 系统设计的目的是产生一个可用的、完整的解决方案,并且能够比较容易地将方案转换成程序代码。这个阶段在三层结构的架构设计模型基础上,将考虑所有的实现技术问题,对分析阶段的模型进行扩展和细化,分析阶段定义的类进一步扩充,定义新的类来处理技术方面的问题,并形成最后的UML模型。

 推动不断进行详细设计的方法是对每个用例进行动态建模,描述如何通过类图中的对象协作实现用例中的功能,由于一开始对系统的认识是很不够的,前面建立的类往往随着动态建模的深入,发现存在缺陷或不够完整,需要对分析中得到的域类图进行不断修正和调整,扩展形成业务逻辑包。同时,随着对用户界面、数据库访问等技术实现的深入建模,不断建立新的用户界面类(如窗体、控件)和数据访问类,形成用户界面包和数据访问包。

 本学生管理系统经过详细设计后,在域类图基础上进行扩展后形成的业务逻辑包类图如下图4所示。
 
 图3 域类图


 图4 业务逻辑包类图

新建立的数据访问包类图如下图5所示。所有的数据访问类都定义了一个基类DBCommon,该基类包含属性DBConnectionString,通过该属性可以获得数据库连接字符串。还包括一个方法GetDataView,可以实现在数据库中执行查询获得一个DataView。这些属性和方法被所有的数据访问类继承,可以直接使用。



图5 数据访问包

关于用户界面包的类图比较简单,主要是通过界面设计,设计出窗体及控件等界面元素,并根据动态建模时需要涉及的用户界面访问动作,定义所引起的相关事件,这些方面都在窗体类中进行定义,并组成用户界面包,这里就不详细介绍。
动态建模通常采用的方法是使用UML中的时序图描述用例,一个时序图针对某个用例中的一个“场景”进行分析。所谓“场景”是指一个用例中事件发展的一条路线。根据活动参与者的不同输入或行为,通常一个用例会有多个“场景”,也就需要分析出多个时序图。通过时序图描述一个场景中各个对象之间所进行的通信,同时可以分析出系统中相应的类需要具备的操作,从而不断扩充和细化类的设计。如果需要进一步描述类的状态变化情况和操作流程,可以使用UML中的状态图和活动图。


 图6 登录场景

 动态建模时产生的时序图较多,这里无法一一阐述。图6给出了登录系统场景的时序图,在用户界面包中定义了一个LoginForm类,其对应的Web窗体为用户登录窗体页面Login.aspx,图6描述了在该窗体中实现用户登录的场景。

 2.3 基于ASP.NET的系统实现
 前面系统设计动态模型时,通过时序图已经对每个用例的各项功能所涉及的场景进行了详尽的描述,按照时序图的规定把每个用例都分别进行编码实现即可。下面结合学生管理系统中的“登录系统”用例,介绍基于ASP.NET进行系统实现的方法。
首先需要考虑分包,ASP.NET中包对应的就是命名空间。在本学生管理系统中,规定业务逻辑包的命名空间为ResultManage.BusinessRule,数据访问包的命名空间为ResultManage.DataAccess,而用户界面包的命名空间为ResultManage.Web。

 然后进行业务逻辑包和数据访问包中相关类的设计,对于“登录系统”用例,从上图6的登录场景时序图中可以看出,相关的类有业务逻辑包的Users类和数据访问包的UsersDB类,分别对这些类的属性和方法进行定义和实现,并设计一些测试用例或测试程序对其进行单元测试。

 最后按照用户界面包和上图6的登录场景时序图中的规定,对用户登录窗体页面Login.aspx进行设计实现,其实现登录的代码如下所示:
private void btnLogin_Click(object sender, System.EventArgs e)
{
//获得用户登录信息
string UserName = txbUserName.Text;
string Password = txbPassword.Text;
try
{
if (Users.Login(UserName , Password)) //检查用户登录信息
{
//创建身份验证票
FormsAuthentication.SetAuthCookie(UserName, false);
//显示欢迎信息
ShowWelcomeMessage(UserName);
}
else
{
Message.Text = "用户登录失败!";
}
}
catch (SqlException sqlexception)
{
//提示数据库操作错误信息
Response.Write(sqlexception.Message);
}
}
代码中对于业务的处理,通过调用业务逻辑包Users类的Login方法实现登录信息的检查,其代码如下:
public static bool Login(string UserName , string Password)
{
if (UserName == "")
{
return false;
}
else
{
//检查数据库中是否存在符合的用户
return UsersDB.CheckLogin(UserName , Password);
}
}


上述Users类的Login方法的代码中,首先进行业务逻辑检查,判断用户名是否为空,涉及数据库访问则通过数据访问类完成,通过数据访问包的UsersDB类的CheckLogin方法从数据库中检查是否存在符合相应登录信息的用户。

 前面已经提到,包括UsersDB类在内的数据访问层所有类都从一个基类DBCommon继承,该基类封装了所有数据库访问类公共的特性,其中包括定义了公共属性:数据连接字符串DBConnectionString。UsersDB类的CheckLogin方法中使用DBConnectionString进行数据库的连接,并调用数据库中存储过程CheckLogin查找用户登录信息是否正确。

 3 结束语
 本文介绍了三层B/S结构系统的UML建模和基于ASP.NET进行实现的过程和方法,实现的三层结构不仅程序逻辑上结构清晰,而且由于容易发生需求变更的业务逻辑部分实现了分离,因此具有更强的可扩展性和可维护性。同时这种系统在部署时具有很强的灵活性,可以将各个包分别编译成.NET组件,安装在多台服务器。较典型的是用户界面包安装在Web服务器,业务逻辑包安装在应用服务器,数据访问包安装在数据库服务器或进一步分离,从而实现多级分布的部署方式,实现更好的可伸缩性和安全性,满足大规模的企业级B/S应用系统的需求。

  • 22:54
  • 评论 / 浏览 (0 / 749)

一、数据库

/* DBMS name: Microsoft SQL Server 2000 */

if exists (select 1

from sysobjects

where id = object_id('newsContent')

and type = 'U')

drop table newsContent

go

/* Table: newsContent */

create table newsContent (

ID int identity(1,1) primary key,

Title nvarchar(50) not null,

Content ntext not null,

AddDate datetime not null,

CategoryID int not null

)

go

二、项目文件架构

实现步骤为:4-3-6-5-2-1


ID


项目


描述


用途


项目引用关系


实例所需文件


相关方法



1


Web


表现层


Web页和控件


引用BLL


WebUI.aspx

WebUI.aspx.cs



GetContent()



2


BLL


业务逻辑层


业务逻辑组件


引用 IDAL,Model,使用DALFactory创建实例


Content.cs


ContentInfo GetContentInfo(int id)



3


IDAL


数据访问层接口定义


每个DAL实现都要实现的一组接口


引用 Model


IContent.cs


ContentInfo GetContentInfo(int id)



4


Model


业务实体


传递各种数据的容器


无引用


ContentInfo.cs






5


DALFactory


数据层的抽象工厂


创建反射,用来确定加载哪一个数据库访问程序集的类


引用IDAL,通过读取web.config里设置的程序集,加载类的实例,返回给BLL使用。


Content.cs


IDAL.Icontent create()



6


SQLServerDAL


SQLServer数据访问层


Microsoft SQL Server特定的Pet Shop DAL实现,使用了IDAL接口


引用 Model和IDAL,被DALFactory加载的程序集,实现接口里的方法。


SqlHelper.cs




Content.cs


SqlDataReader ExecuteReader()

PrepareCommand()

ContentInfo GetContentInfo(int id)



OracleDAL


Oracle数据访问层



7


DBUtility


数据库访问组件基础类


GetSqlServerConnectionString得到数据库连接字符串,也可省去该项目,在SQLServerDAL.SqlHelper中用static readonly string SqlConnectionString代替。


无引用










实现步骤过程

1、创建Model,实现业务实体。

2、创建IDAL,实现接口。

3、创建SQLServerDAL,实现接口里的方法。

4、增加web.config里的配置信息,为SQLServerDAL的程序集。

5、创建DALFactory,返回程序集的指定类的实例。

6、创建BLL,调用DALFactory,得到程序集指定类的实例,完成数据操作方法。

7、创建WEB,调用BLL里的数据操作方法。

注意:

1、web.config里的程序集名称必须与SQLServerDAL里的输出程序集名称一致。

2、DALFactory里只需要一个DataAccess类,可以完成创建所有的程序集实例。

3、项目创建后,注意修改各项目的默认命名空间和程序集名称。

4、注意修改解决方案里的项目依赖。

5、注意在解决方案里增加各项目引用。

三、各间的访问过程

1、传入值,将值进行类型转换(为整型)。

2、创建BLL层的content.cs对象c,通过对象c访问BLL层的方法GetContentInfo(ID)调用BLL层。

3、BLL层方法GetContentInfo(ID)中取得数据访问层SQLServerDAL的实例,实例化IDAL层的接口对象dal,这个对象是由工厂层DALFactory创建的,然后返回IDAL层传入值所查找的内容的方法dal.GetContentInfo(id)。

4、数据工厂通过web.config配置文件中给定的webdal字串访问SQLServerDAL层,返回一个完整的调用SQLServerDAL层的路径给 BLL层。

5、到此要调用SQLServerDAL层,SQLServerDAL层完成赋值Model层的对象值为空,给定一个参数,调用SQLServerDAL层的SqlHelper的ExecuteReader方法,读出每个字段的数据赋值给以定义为空的Model层的对象。

6、SqlHelper执行sql命令,返回一个指定连接的数据库记录集,在这里需要引用参数类型,提供为打开连接命令执行做好准备PrepareCommand。

7、返回Model层把查询得到的一行记录值赋值给SQLServerDAL层的引入的Model层的对象ci,然后把这个对象返回给BLL。

8、回到Web层的BLL层的方法调用,把得到的对象值赋值给Lable标签,在前台显示给界面

四、项目中的文件清单

1、DBUtility项目

(1)connectionInfo.cs

using System;

using System.Configuration;

namespace Utility

{

/// <summary>

/// ConnectionInfo 的摘要说明。

/// </summary>

public class ConnectionInfo

{

public static string GetSqlServerConnectionString()

{

return ConfigurationSettings.AppSettings["SQLConnString"];

}

}

}

2、SQLServerDAL项目

(1)SqlHelper.cs抽象类

using System;

using System.Data;

using System.Data.SqlClient;

using DBUtility;

namespace SQLServerDAL

{

/// <summary>

/// SqlHelper 的摘要说明。

/// </summary>

public abstract class SqlHelper

{

public static readonly string CONN_STR = ConnectionInfo.GetSqlServerConnectionString();


/// <summary>

/// 用提供的函数,执行SQL命令,返回一个从指定连接的数据库记录集

/// </summary>

/// <remarks>

/// 例如:

/// SqlDataReader r = ExecuteReader(connString, CommandType.StoredProcedure, "PublishOrders", new SqlParameter("@prodid", 24));

/// </remarks>

/// <param name="connectionString">SqlConnection有效的SQL连接字符串</param>

/// <param name="commandType">CommandType:CommandType.Text、CommandType.StoredProcedure</param>

/// <param name="commandText">SQL语句或存储过程</param>

/// <param name="commandParameters">SqlParameter[]参数数组</param>

/// <returns>SqlDataReader:执行结果的记录集</returns>

public static SqlDataReader ExecuteReader(string connString, CommandType cmdType, string cmdText, params SqlParameter[] cmdParms)

{

SqlCommand cmd = new SqlCommand();

SqlConnection conn = new SqlConnection(connString);


// 我们在这里用 try/catch 是因为如果这个方法抛出异常,我们目的是关闭数据库连接,再抛出异常,

// 因为这时不会有DataReader存在,此后commandBehaviour.CloseConnection将不会工作。

try

{

PrepareCommand(cmd, conn, null, cmdType, cmdText, cmdParms);

SqlDataReader rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection);

cmd.Parameters.Clear();

return rdr;

}

catch

{

conn.Close();

throw;

}

}

/// <summary>

/// 为执行命令做好准备:打开数据库连接,命令语句,设置命令类型(SQL语句或存储过程),函数语取。

/// </summary>

/// <param name="cmd">SqlCommand 组件</param>

/// <param name="conn">SqlConnection 组件</param>

/// <param name="trans">SqlTransaction 组件,可以为null</param>

/// <param name="cmdType">语句类型:CommandType.Text、CommandType.StoredProcedure</param>

/// <param name="cmdText">SQL语句,可以为存储过程</param>

/// <param name="cmdParms">SQL参数数组</param>

private static void PrepareCommand(SqlCommand cmd, SqlConnection conn, SqlTransaction trans, CommandType cmdType, string cmdText, SqlParameter[] cmdParms)

{

if (conn.State != ConnectionState.Open)

conn.Open();


cmd.Connection = conn;

cmd.CommandText = cmdText;

if (trans != null)

cmd.Transaction = trans;

cmd.CommandType = cmdType;

if (cmdParms != null)

{

foreach (SqlParameter parm in cmdParms)

cmd.Parameters.Add(parm);

}

}

}

}

(2)Content.cs类

using System;

using System.Data;

using System.Data.SqlClient;

using Model;

using IDAL;


namespace SQLServerDAL

{

/// <summary>

/// Content 的摘要说明。

/// </summary>

public class Content:IContent

{

private const string PARM_ID = "@ID";

private const string SQL_SELECT_CONTENT = "Select ID, Title, Content, AddDate, CategoryID From newsContent Where ID = @ID";

public ContentInfo GetContentInfo(int id)

{

//创意文章内容类

ContentInfo ci = null;


//创建一个参数

SqlParameter parm = new SqlParameter(PARM_ID, SqlDbType.BigInt, 8);

//赋上ID值

parm.Value = id;

using(SqlDataReader sdr = SqlHelper.ExecuteReader(SqlHelper.CONN_STR, CommandType.Text, SQL_SELECT_CONTENT, parm))

{

if(sdr.Read())

{

ci = new ContentInfo(sdr.GetInt32(0),sdr.GetString(1), sdr.GetString(2),

sdr.GetDateTime(3), sdr.GetInt32(4), sdr.GetInt32(5), sdr.GetString(6));

}

}

return ci;

}

}

}

 

 


3、Model项目

(1)contentInfo.cs

using System;

namespace Model

{

/// <summary>

/// Class1 的摘要说明。

/// </summary>

public class ContentInfo

{

private int _ID;

private string _Content;

private string _Title;

private string _From;

private DateTime _AddDate;

private int _clsID;

private int _tmpID;

/// <summary>

/// 文章内容构造函数

/// </summary>

/// <param name="id">文章流水号ID</param>

/// <param name="content">文章内容</param>

/// <param name="title">文章标题</param>

/// <param name="from">文章来源</param>

/// <param name="clsid">文章的分类属性ID</param>

/// <param name="tmpid">文章的模板属性ID</param>

public ContentInfo(int id,string title,string content,string from,DateTime addDate,int clsid,int tmpid )

{

this._ID = id;

this._Content = content;

this._Title = title;

this._From = from;

this._AddDate = addDate;

this._clsID = clsid;

this._tmpID = tmpid;

}

//属性

public int ID

{

get { return _ID; }

}

public string Content

{

get { return _Content; }

}

public string Title

{

get { return _Title; }

}

public string From

{

get { return _From; }

}

public DateTime AddDate

{

get { return _AddDate; }

}

public int ClsID

{

get { return _clsID; }

}

public int TmpID

{

get { return _tmpID; }

}

}

}

4、IDAL项目

(1)Icontent.cs

using System;

using Model;

namespace IDAL

{

/// <summary>

/// 文章内容操作接口

/// </summary>

public interface IContent

{

/// <summary>

/// 取得文章的内容。

/// </summary>

/// <param name="id">文章的ID</param>

/// <returns></returns>

ContentInfo GetContentInfo(int id);

}

}

5、DALFactory项目

(1)Content.cs

using System;

using System.Reflection;

using System.Configuration;

using IDAL;

namespace DALFactory

{

/// <summary>

/// 工产模式实现文章接口。

/// </summary>

public class Content

{

public static IDAL.IContent Create()

{

// 这里可以查看 DAL 接口类。

string path = System.Configuration.ConfigurationSettings.AppSettings["WebDAL"].ToString();

string className = path+".Content";



// 用配置文件指定的类组合

return (IDAL.IContent)Assembly.Load(path).CreateInstance(className);

}

}

}

6、BLL项目

(1)Content.cs

using System;

using Model;

using IDAL;

namespace BLL

{

/// <summary>

/// Content 的摘要说明。

/// </summary>

public class Content

{

public ContentInfo GetContentInfo(int id)

{

// 取得从数据访问层取得一个文章内容实例

IContent dal = DALFactory.Content.Create();

// 用DAL查找文章内容

return dal.GetContentInfo(id);

}

}

}



7、Web项目

1、Web.config:

<appSettings>

<add key="SQLConnString" value="Data Source=localhost;Persist Security info=True;Initial Catalog=newsDB;User ID=sa;Password= " />

<add key="WebDAL" value="SQLServerDAL" />

</appSettings>


2、WebUI.aspx

<%@ Page language="c#" Codebehind="WebUI.aspx.cs" AutoEventWireup="false" Inherits="Web.WebUI" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >

<HTML>

<HEAD>

<title>WebUI</title>

<meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1">

<meta name="CODE_LANGUAGE" Content="C#">

<meta name="vs_defaultClientScript" content="JavaScript">

<meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">

</HEAD>

<body MS_POSITIONING="GridLayout">

<form id="Form1" method="post" runat="server">

<FONT">宋体"></FONT>

<table width="600" border="1">

<tr>

<td style="WIDTH: 173px">&nbsp;</td>

<td>&nbsp;

<asp:Label id="lblTitle" runat="server"></asp:Label></td>

</tr>

<tr>

<td style="WIDTH: 173px; HEIGHT: 22px">&nbsp;</td>

<td style="HEIGHT: 22px">&nbsp;

<asp:Label id="lblDataTime" runat="server"></asp:Label></td>

</tr>

<tr>

<td style="WIDTH: 173px">&nbsp;</td>

<td>&nbsp;

<asp:Label id="lblContent" runat="server"></asp:Label></td>

</tr>

<tr>

<td style="WIDTH: 173px">&nbsp;</td>

<td>&nbsp;</td>

</tr>

<tr>

<td style="WIDTH: 173px; HEIGHT: 23px">&nbsp;</td>

<td style="HEIGHT: 23px">&nbsp;</td>

</tr>

<tr>

<td style="WIDTH: 173px">&nbsp;</td>

<td>&nbsp;</td>

</tr>

<tr>

<td style="WIDTH: 173px">&nbsp;</td>

<td>&nbsp;</td>

</tr>

<tr>

<td style="WIDTH: 173px">&nbsp;</td>

<td>&nbsp;</td>

</tr>

<tr>

<td style="WIDTH: 173px">&nbsp;</td>

<td>&nbsp;

<asp:Label id="lblMsg" runat="server">Label</asp:Label></td>

</tr>

</table>

</form>

</body>

</HTML>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值