代码不再重复:MVC与Windows工作流集成开发(上)

日期: 2009-09-22 作者:朱先忠 来源:TechTarget中国 英文

  无论是系统架构师还是普通程序员在构建应用程序时都期望系统的业务逻辑层构建得灵活而易于维护。因此,尽可能消除代码重复几乎成为传统软件开发过程中的金科玉律。为此,人们付出巨大的努力,包括投入大量的时间来研究如何设计出适当的模式以适合开发需求。当然,视选择的开发平台的不同,人们为之付出的努力程度也存在不同程度的差异。

  微软于2008年正式推出的ASP.NET MVC框架正是适合上述需求的平台之一。借助于这个框架,我们得以能够最小的努力来创建灵活和易于维护的应用程序。特别是,它还提供的功能能够帮助我们最大程度地避免代码重复。

  在本文中,我们将构建一个简单的新用户注册的ASP.NET 3.5 Web网站示例。通过这个例子,我们的主旨在于探讨如何能够通过把ASP.NET MVC框架和微软Windows工作流(Windows Workflow Foundation)架构结合到一起来开发出极富弹性的用户界面型工作流应用程序。具体地说,此示例应用程序将演示如何避免校验逻辑以及如何最大程度地实现应用程序本身与工作流业务逻辑部分的解耦。

  一 数据持久性考虑

  在编写多步骤用户界面工作流程应用程序方面,存在多种可选方案可用于实现用户输入数据的持久性存储。下面给出了多种可选方案的列表,以及它们各自存在的优缺点。

  方案1  把每个步骤中的数据存储到服务器端数据库中。

  优点:如果用户在操作过程中因为某种中断(可能因连接掉线或浏览器崩溃等原因所致)突然离开,那么,在下次回来时他还可以继续之前的操作—这将明显地提高系统的可靠性。【注意】这种方案的一个局限性是,通常这种类型的方法需要使用由客户端会话ID或MAC地址构造的Cookie结构。然而,如果用户下一次从另一台不同的机器访问网站时,他将无法继续操作。对此,我们有一种解决方法是,在第一步中就要求用户提供凭证数据—我们可以使用此数据来识别用户的下一次系统进入。

  缺点:①在正式提交前耗费服务器内存存储用户不必要的数据—有可能需要定期刷新数据库中储存的数据,以防用户永远不会回来;②需要服务器回寄支持(但我们可以通过AJAX调用来克服之)。

  方案2  在浏览器会话(Session)中存储每个步骤的数据,成功验证后,最后再一起储存到服务器端数据库中。

  优点:由于数据没有存储到数据库中,所以不必要创建独立的进程实现一次性存储所有不必要的数据。

  缺点:①提高了服务器端内存消耗;②在用户不启用会话(多种原因:浏览器崩溃,会话超时,应用程序池循环利用等)时导致不可靠性。

  方案3  先序列化页面的数据,成功验证后,最后再一起存储到服务器端数据库中。

  优点:由于数据没有存储到后台数据库中,所以不必要创建独立的进程实现一次性存储所有不必要的数据。

  缺点:单个网页的尺寸可能会因之急剧膨胀,因而会影响系统的响应时间。

  方案4  在同一个页面中的多个面板(对于jQuery框架来是指Div元素)中存储每个步骤的数据,成功验证后,最后再一起存储存到数据库中。

  优点:①用户界面响应性能好;②不需要服务器回寄,因而最有利于提高服务器资源和数据库的利用率。

  缺点:①在客户端浏览器崩溃时用户并不总是有释放数据的机会;②重新安排页面顺序以及改变相应的操作流程的可能性很小。

  值得注意的是,选择上述任何方案之一最终还将取决于系统功能和具体的业务逻辑需求。本文中将构建的示例应用程序将采取上表中的第3种存储方案。

  本文中将构建的示例应用程序极其简单—它将展示一个简单的使用三个步骤的界面来实现新雇员注册的工作流程。

  二 模型绑定

  模型绑定是ASP.NET MVC框架提供的极其强大的可定制功能。借助于模型绑定,在HTTP请求中传入的数据将被自动填充到模型类中。作为开发人员,我们没有必要担心提取Forms集合或querystring中数值所可能需要付出的大量编码的任务。基本上,存在两种类型的模型绑定支持:显式绑定和隐式绑定。通过调用TryUpdateModel方法,我们可以显式地触发绑定过程。通过把动作(Action)方法的参数设置为与模型类属性一样的名字,或通过把模型类自身作为动作(Action)方法的参数,我们可以隐式地取得HTTP请求中提供的数值并使之可用。

  在本文示例应用程序中,“Employee”承担模型类的任务。我们在OnActionExecuting事件中调用了TryUpdateModel方法,以便Employee模型类对象能够使用用户输入的数据得以自动填充。

  三 基于模型状态进行客户端校验

  常规的校验方法通常是在客户端使用Javascript脚本语言来执行数据输入的验证。有时候,我们还可能需要使用JavaScript在客户端进行业务规则的验证。仅当客户端验证不可靠时,才使用服务器端验证。显然,服务器端验证是被安排在类似C#这样的服务器端语言代码实现中。这种方法存在一个明显的问题是,在一段时间内,我们很有可能需要重复地使用数据以及业务规则验证逻辑等。

  为了解决上面这样的问题,我们可以在模型中加入方法,交由它来维护和强制执行所有的验证工作。这样一来,当需要改变验证逻辑时,仅需要在模型部分执行相应的改变逻辑,但却能够自动影响到系统中所有相关内容。

  ASP.NET MVC框架提供给我们许多种方案来执行校验逻辑任务,而这些工作仅需要使用我们所熟悉的C#编码即可。这样一来,校验规则被交由HTTP请求管道进行处理,从而使我们可以在客户端向用户提供校验相关的提示信息。

  ASP.NET MVC中使用一个临时存储区,命名为“ModelState”,用于存储所有的绑定操作模式期间发生的验证错误。调用方法ModelState.IsValid可以确定模型绑定操作是否发生了任何验证错误。如果有任何错误,则此方法将返回false。另外,ASP.NET MVC框架也提供了相应的机制用于向终端用户展示ModelState中存储的错误信息。为使模型部分(即C#类)使用此功能,模型应该实现IDataErrorInfo接口。

  在我们的示例应用程序中,模型“Employee”需要实现如下的接口:
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Web;
  using System.ComponentModel;

  namespace WizardTypeUITwo.Models
  {
    [Serializable]
    public class Employee : IDataErrorInfo
    {  
        //个人信息
        public string Name { get; set; }
        public int? Age { get; set; }
        //职业信息
        public string CurrentEmplrName { get; set; }
        public int? Salary { get; set; }
        //联系信息
        public string Email { get; set; }
        public int? Mobile { get; set; }
        public string this[string columnName]
        {
            get
            {
                if ((columnName == “Name”) && string.IsNullOrEmpty(Name))
                    return “Please enter a name”;
                if ((columnName == “Age”) && !Age.HasValue)
                    return “Please enter a numeric age”;

                if ((columnName == “CurrentEmplrName”) && string.IsNullOrEmpty(
                    CurrentEmplrName))
                    return “Please enter current employer name”;
                if ((columnName == “Salary”) && !Salary.HasValue)
                    return “Please enter salary”;

                if ((columnName == “Email”) && !IsValidEmailAddress(Email))
                    return “Please enter a valid email address”;
                if ((columnName == “Mobile”) && !Mobile.HasValue)
                    return “Please enter mobile number”;

                return null;
            }
        }
        private static bool IsValidEmailAddress(string email)
        {
            //请根据您的具体情况进一步改进这里的逻辑
            return (email != null) && (email.IndexOf(“@”) > 0);
        }
        //遵循默认编译规则
        public string Error { get { return null; } }
     }
  }

  在本文雇员注册示例程序中,页面Step1.aspx对应于第一个视图。借助于HTML辅助方法,我们会及时地通知用户相应的验证错误信息。

  <%= Html.ValidationSummary(“Please correct the errors and try again.”) %>
    <label for=”Name”>Name:</label>
    <%= Html.TextBox(“Name”, Model.Name) %>
    <%= Html.ValidationMessage(“Name”, “*”) %>

  通过在服务器端执行任何操作之前调用ModelState.IsValid方法,我们可以限制用户进入到系统注册流程中的下一个界面。在本文示例应用程序中,只有在填充适当的信息之后,才允许用户进入到下一个步(页面Step2.aspx)。

我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

我原创,你原创,我们的内容世界才会更加精彩!

【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

相关推荐