随笔-6  评论-1  文章-0  trackbacks-1
  2006年5月24日

        目前,软件分层的思想已经得到普及,在我所做过的项目中也得到了很好的效果。但是也有明显的缺点,应付从下而上的变化时,往往需要级连修改,尤其是数据库结构发生变化,另外如果采用了NHibernate之类ORM平台,这方面好好一些。
        在复杂的业务逻辑层,往往对象的粒度很小,在表现层使用起来不太方便,会产生重复代码(例如常规的初始化,数据访问数等),加大了表现层开发人员的学习难度和开发工作量。此时往往是为业务逻辑层增加服务层(包装层),减少重复代码和不必要的复杂度。
        增加服务层的缺点也是明显的:减少了灵活性。
        本例使用了服务层包装业务逻辑,简化了表现层开发。服务层包装类需要数据库连接参数等,为此将采用单件模式,使用静态属性进一步封装服务层对象,并考虑了多线程的情景。这种情况下,以后服务层接口的变更仅需要修改服务层包装类。

        // 服务层包装类
        public class MyUserService
        {
                 public MyUserService(string strConn)
                 {
                      // ......
                 }
                // ......
        }
        ......
        public class BusinewwWapper
        {
                private static MyUserService m_User;
                private static string m_StrConn;

             static BusinewwWapper()
             {
              // 必要的初始化
                    m_StrConn =......;
             }

                private static void SetUser()
                {
                        lock(typeof(SmWFM))
                        {
                                 if(m_User == null )
                                         m_User = new MyUserService(m_StrConn );
                        }
                }

                public static MyUserService User
                {
                        get
                        {
                                 if(m_User == null )
                                         SetUser();
                                return m_User;
                        }
                }
                // ......
        }
        
        其实,有了Spring.NET这样的框架,这样做就没必要了。

posted @ 2006-05-24 15:16 快乐尘埃 阅读(319) 评论(0) 编辑
  2006年5月23日

        目前ASP.NET中的数据绑定是单向的,即允许开发人员将数据模型帮定到页面控件上显示,提交表单的时候,必须再次将页面控件值绑定到数据模型。大家都不太喜欢写这样的代码。
        通过自定义特性,
Spring.Web提供了控件与数据模型的双向绑定的功能,减少了代码量。
        双向绑定使用起来很方便,但页面类需要从Spring.Web.UI.Page类继承。

        public class UserRegistration : Spring.Web.UI.Page
        {
                [Binding("Text", "UserInfo.Email")]
                protected TextBox email;
                // ……
                // 此属性即数据模型
                private User m_User; 
                public User UserInfo
                {
                    get { return m_User; }
                    set { m_User = value; }
                }   
        }

        Binding特性有可选参数OneWay(第三个参数),如果为true,退化为单向绑定,即不再更新模型数据,对只读的数据或者通过计算得到的只读数据特别有用。另一个可选参数为Format,用于指定绑定值的显示格式,通常和OneWay联合使用,提供日期或数值自定义格式,支持String.Format方法支持的格式表达式。
        类型转换,绑定时,Spring.Web试图进行数据转换,如果指定Format参数,Spring.Web将使用此参数将数据模型值转为String,否则,使用.NET的类型转换机制。
        数据绑定事件,Spring.Web的页面基类在.NET页面的生命周期加入两个事件:DataBoundDataUnboundDataBound事件在控件值被更新后激发,在PreRender事件之前。事件发生顺序为:Load――>DataBound――>PreRender,这样是合适的,在Load事件处理代码中对数据模型做出修改,能反映在控件上。DataUnbound事件在数据模型被更新后激发,在Load事件之后,此时是回发。

参考:spring-net-reference.pdf。

很遗憾,使用Spring.NET 1.1 Preview 2没有测试成功,。我会继续跟踪,新版本或许能解决问题。

posted @ 2006-05-23 14:09 快乐尘埃 阅读(875) 评论(0) 编辑
 

NAnt 是一个Visual Studio .Net应用程序的连编工具,对大而负责的工程而言,使用NAnt很方便。

1.      安装

http://nant.sourceforge.net上可以下载源代码或者编译好的二进制文件,一般下载nant-bin.zip,解压,注册系统环境变量后,就可以使用nant命令了。

2.      Build文件

XML格式,每个build文件包含一个projectproject有若干target,每个target包含若干taskTask不被包含在target中,即直接包含在project中。

Ø       Projects(工程)

三个特性,name、设置工程名称,default、设置默认target,和basedir、如果不设置,默认为build文件的父目录。

执行nant时,可以知道targets,如果未指定,执行默认得target,如果build文件中未指定默认得target,仅仅执行全局的task(全局的task总是执行),如果没有全局的task,那就什么都不执行了。

Ø       Targets(目标、对象)

有五个特性,name、指定名称,depends、此target所依赖的targets(多个用“,”隔开),if、如果条件为true执行此targetunless、如果条件为true跳过此targetdescription、功能的简短描述。其中name必须指定。

执行某个target时,首先执行此target所依赖的targets。一个target可能被depends多次,仅执行一次,但是通过<call>任务(task)执行一个target时,此target及其所依赖的targets要重新执行一次。另外,当target的名称被设置为“*”时,称为wild target,一个build文件仅仅有一个wild target,在目前的build文件中,当且仅当被调用的target不存在时,才执行wild target,主要用来处理无效的请求。

Ø       Task(任务)

一块可执行的代码,一个task可有多个特性和参数。特性的值可包含对属性的引用,在task执行前,这些引用会被解释出来。

Ø       Properties(属性)

一个project可有很多属性,这些属性可以通过<property任务设置在build文件中,也可以设置在Nant外。一个属性有一个name和一个value,可用于task的特性中,也可用于表达式,用在task的特性中时,使用${property name}格式。Nant有很多内建属性(与nant有关的,与框架有关的,与平台有关的等)。

<property>任务有readonlyoverwrite等特性,readonly指定属性是否是只读到,默认falseoverwirte指定如果属性已经存在,属性值是否可以重写,默认true,对于只读属性,是不能被重写的。注意:在Nant命令行指定的属性,先于在build文件中指定的属性,并且这些属性往往是只读的。

另外可以在NAnt.exe.config文件中定义全局属性。

Ø       Loggers & Listeners

Nant 通过LoggersListeners来监控连编过程。Listeners记录了build startedbuild finishedtarget startedtarget finishedtask startedtask finishedmessage logged事件,Loggers扩展了Listeners,可以按-quiet(静态的,平稳的), -verbose(详细的), -debug三个层次记录连编信息,可输出到控制台或者文件中。Nant内建了三个类:NAnt.Core.DefaultLoggerNAnt.Core.MailLoggerNAnt.Core.XmlLogger。使用时:-logger:类 -logfile:文件名。可以是普通道文本文件或者XML文件。

Ø       Expressions(表达式)

表达式是一种简单而强大的机制,允许写高级的公式,用于task的参数和条件式中,这样就可以控制连编过程了。表达式能够访问project的属性、调用内建的或者用户定义的functions

表达式通过${…}符号,可用于task的参数中。也可以使用标准的算术、逻辑和关系运算符。通过prefix::function-name(argument1, ..., argumentN)语法调用函数。访问属性,仅需指定其name${…}

例子:

访问属性

<property name="build.version" value="3" />

<echo message="The current date is: ${build.version}" />

调用函数

<echo message="The current date is: ${datetime::now()}" />

表达式结果存储

<property name="autoexec-present" value="${file::exists('c:\autoexec.bat')}" />

Real-life expression use

<property name="myprj.basedir" value="c:\" />

<property name="filename" value="${path::combine(myprj.basedir,'version.txt')}" />

 

<if test="${not file::exists(filename) or file::get-length(filename) = 0}">

    <echo message="The version file ${filename} doesn't exist or is empty!" />

</if>

有条件执行task

<property name="myprj.basedir" value="c:\" unless="property::exists('myprj.basedir')" />

<csc target="library" output="out.dll" ...

     if="${datetime::now() - file::get-last-write-time('out.dll')) > timespan::from-hours(1)}">

...

</csc>

Functions

Nant提供了操作字符串、日期时间和路径名字的函数,还提供读取文件或者目录属性,访问目前的连编信息等函数。

调用函数语法prefix::function-name(argument1, ..., argumentN),需要的情况下会进行参数类型转换,如果转换有误,会报告错误。

自定义函数可以使用任何.Net语言实现,此外还可以通过<script>任务实现。

3.      运行Nant

命令Nant,此外还可以指定build文件名、targetsproperties等。

Nant

NAnt -buildfile:..\fileName.build

NAnt clean

NAnt -D:debug=false clean dist

posted @ 2006-05-23 08:48 快乐尘埃 阅读(1790) 评论(2) 编辑
  2006年5月22日

      最近升级部分业务模块以支持Oracle数据库,碰到了一些微妙的问题。
      1. OleDbConnection连接字符串如果provider为msdaora时,用户名和密码是不能简写的,为sqloledb时,是可以简写的。
      使用ADO.Net时,连接字符串可以将user id 简写为uid,password简写为pwd。但是会引起一些微妙的错误。当我将provider改为msdaora时,发现数据库连接打不开,异常为System.Data.OleDb.OleDbException描述为"ORA-12560: TNS: 协议适配器错误"。很是郁闷,我们知道引起这个异常有很多原因。试了很多次都不成功,最后修改了连接字符串,不在使用简写。成功了。
       最后我试了试OracleConnection,是支持简写的。

      2. 字符串空格
       在sql语句中,select .... where const_code='UrgenceDegree ',也不知道以前的哥们怎么回事,'UrgenceDegree '末尾多了个空格。以前连sqlserver数据库时,是可以取出数据的。现在连oracle数据库时,可就不行了。这种手误是非常害人的。另外对字符串的大小写,不同的数据库也是不同的。
    3. Oracle中处理bool类型的方式就和SQL Server不同
    sqlserver中,有bit类型,而oracle没有,在程序中编码不当,会引起微妙的问题。
    dataReader[0]在sqlserver
    if(dataReader[0].ToString().ToUpper() == "FALSE")
    {
    ......
    }
    这种判断方法在处理bit数据时,在Sql Server下是没问题的。Oracle下就不行了。
    if(Convert.ToInt16(dataReader[0]) == "0")
    {
    ......
    }
    这样写,两种数据库下都可以用了。

posted @ 2006-05-22 17:48 快乐尘埃 阅读(199) 评论(0) 编辑
  2006年2月22日

        目前在维护一个Web应用,用户提出一些对我来说要求比较高的需求,摸索了一下,终于解决了。和大家分享一下:
        问题:一般DataGrid中会有部分选择列,例如:
        <asp:ButtonColumn DataTextField="CaseName" HeaderText="......" CommandName="Select">
                <ItemStyle Height="20px" Width="170px"></ItemStyle>
        </asp:ButtonColumn>
        对于这些列,在ItemDataBound事件中,需要对选择列显示的文本的颜色根据绑定的数据进行处理。使用e.Item.Cells[0].Style.Add("color", "#993300")进行处理。运行时,查看页面代码,发现此属性也加到<TD Style="..."></TD>中了,就是颜色显示不出来。非常郁闷,试了很多方法,都不行。
        仔细看看这个单元格,原来结构如下:<TD Style="..."><A ...>文本</A></TD>。我想应该通过e.Item.Cells[2].Controls[0]将控件取出来,跟了一下代码,.Net将其定义为WebControls.DataGridLinkButton类型。可是此类型在.Net中访问权限受控制。进行e.Item.Cells[2].Controls[0] as WebControls.DataGridLinkButton这样的转型也宣告失败。想想WebControls.DataGridLinkButton肯定是从WebControl继承过来的。于是进行了如下处理:
         WebControl ctr = e.Item.Cells[0].Controls[0] as WebControl;
         ctr.Style.Add("color", "#993300");
        正好可以解决此问题。

 

posted @ 2006-02-22 18:07 快乐尘埃 阅读(544) 评论(0) 编辑
  2006年2月15日
        目前在维护一个Web应用,感觉做页面间的导航确实麻烦,特别是页面间参数的传递,如果写的不好,看起来很是头疼。
         正好有个机会,经理让把有些页面做成模式页面,打开模式页面仅仅能传递一个参数,当然这个参数可以是对象。但是如果为了传递参数就去构造很多类,又感觉太麻烦。
        灵机一动,想了如下方法,目前运行良好,和大家分享。有不合适的地方,请批评指正。
        此方法是为要打开的页面类添加个静态方法,例如有MsgInfo.aspx页面:
          public static void Open(ParaType1 para1, (ParaType2 para2, string msgInfoUrl, Page thePage)
          {
                   // 打开页面
          }
        其中前两个是传递的页面参数(当然多个也行了),第三个是要打开MsgInfo.aspx页面的页面相对于MsgInfo.aspx的相对url。如果在同一目录下,直接写MsgInfo.aspx就行了,第四个参数为要打开MsgInfo.aspx页面的页面Page对象。
优点:
         使用方便,直接使用MsgInfo.Open(..)方法就行了。
         可以传递任意多个参数,很适合打开模式页面。
         传递的参数是强类型的,避免很多不必要的麻烦。
posted @ 2006-02-15 17:41 快乐尘埃 阅读(263) 评论(0) 编辑
昵称:快乐尘埃
园龄:6年3个月
粉丝:0
关注:0
<2012年2月>
2930311234
567891011
12131415161718
19202122232425
26272829123
45678910

搜索

 
 

常用链接

随笔分类

随笔档案

文章分类

最新评论

阅读排行榜

评论排行榜

推荐排行榜