Rickie is back .... 人生·工作的结果=思维方式×热情×能力

今天比昨天更好,明天比今天更好,为此,不屈不挠地工作、勤勤恳恳地经营、孜孜不倦地修炼,我们人生的目的和价值就是这样确确实实地存在着。

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  397 随笔 :: 3 文章 :: 1310 评论 :: 129 引用

2011年7月19日 #

Windows Server AppFabric 扩展了 Windows Server 以为 Web 应用程序和中间层服务提供增强的托管、管理和缓存功能。 AppFabric 托管功能向 Internet 信息服务 (IIS)、Windows Process Activation Service (WAS) 和 .NET Framework 4 添加了服务管理扩展。其中包括托管服务和托管管理工具,这些工具使部署、配置和管理基于 Windows Communication Foundation (WCF) 和 Windows Workflow Foundation (WF) 的服务变得更加容易。

AppFabric 缓存功能向 Windows Server 添加了一个分布式的内存中对象缓存,它使扩展高性能 .NET 应用程序(特别是 ASP.NET 应用程序)变得更加容易。

关于Windows Server AppFabric 的相关技术文章:

    posted @ 2011-07-19 21:10 Rickie 阅读(287) 评论(0) 编辑

    2011年7月9日 #

    关于大型网站的架构设计,包括hardware和software等等,经常有朋友谈及这个问题。

    这里推荐两篇非常好的文章,如何随着业务/访问量的增长,升级或扩展现有的系统架构设计。

    大型网站的服务器架构设计-1

    大型网站的服务器架构设计-2

    === 节选内容 ===

    网站初始

    架设入门网站其实很容易,在基本的架构是安装一台Web Server 及一台 Database Server,这样的架构在流量不高的个人网站而言,的确已足够了。但其实风险很高,因为没有考虑日后的扩充性(Scalability),也没有考虑到系统容错及恢复能力(High Availability & Failover),因此只要流量一高,问题就接踵而至。

    商业化架构

    在筹到一笔资金后,网站就可以进行商业化架构设计,一般商业化的标准架构,如下图所示:

    posted @ 2011-07-09 10:35 Rickie 阅读(683) 评论(0) 编辑

    2011年5月16日 #

    如果你正在学习ASP.NET MVC 3HTML5jQuery和浏览器客户端交互技术,推荐你下载Mileage Stats 范例程序,可更好理解如何使用当前技术创建当前的web应用程序,尤其关注如何架构一个企业级的应用程序。关于Mileage Stats项目的初步介绍,请参考《Project Silk 基于ASP.NET MVC 3 的示例应用程序Mileage Stats》。


     

    EntLib.com Team 尝试从架构的角度对MileageStats项目进行分析和解读,并计划运用到实际的电子商务系统中,欢迎大家参与交流和分享。

     

    MileageStats RI 运行的主要界面:


     

    MileageStats RI 项目的当前架构图,主要有Web 表示层、业务逻辑层和数据访问层,如下图所示。

     


     

    简要看看MileageStats 包含的一些主要项目:


     

     

    创建数据模型(Data Model

    MileageStats.Model 项目包含数据模型(Data Model)。结构化和强类型的类描述了业务数据的数据类型、关系和约束。

     

    实现Repository Pattern

    Repository模式中,Repository是一组接口,实现了数据访问相关的方法。接口没有暴露任何特定数据存储相关的类型。

    MileageStats.Data 项目包含了Repository接口,MileageStats.Data.SqlCe 项目包含了接口的实现。如下是IReminderRepository 接口的示例代码:

    // contained in IReminderRepository.cs

    public interface IReminderRepository

    {

    void Create(int vehicleId, Reminder reminder);

    Reminder GetReminder(int reminderId);

    void Update(Reminder reminder);

    void Delete(int reminderId);

     

    IEnumerable<Reminder> GetRemindersForVehicle(int vehicleId);

    IEnumerable<Reminder> GetOverdueReminders(int vehicleId,

    DateTime forDate, int forOdometer);

     

    IEnumerable<Reminder> GetUpcomingReminders(int vehicleId,

    DateTime forStartDate, DateTime forEndDate,

    int odometer, int warningOdometer);

     

    IEnumerable<Reminder> GetFulfilledRemindersForVehicle(int vehicleId);

    }

     

    分解应用程序代码到ASP.NET MVC模式

    设计良好的MVC应用程序保持ControllerAction方法比较小,View比较简单。大部分的核心应用程序逻辑存放在Model中。在MVC应用程序创建时,保持DRYDon’t Repeat Yourself)原则比后期试图清理代码更容易。

     

    因为大部分应用程序逻辑在Model层中,因此很多MVC 应用程序包含不同类型的Model

    View models(视图模型) - 仅用于视图的数据绑定,这些Models包含于MVC 应用程序中,一般与ViewsPartial Views保持相同的构成结构。

    Application, domain, or service models(业务模型) - 基于实际业务需要建立的数据模型,可添加属性标注,或扩展支持应用功能,如数据验证、身份验证。因为这些Models易于往返于客户端浏览器,因此它们经常包含于View Models,并直接在HTML 表单进行数据绑定。

    Data models(数据模型) - 用于数据服务和存储,不会暴露在应用程序之外,经常封装在服务层。

     

    如下是MileageStats RI Solution中包含的3Model项目下图中选中的项目,分别在Web层、业务逻辑层和数据层:


     

    对于比较复杂或长期维护的应用程序,应该分离业务模型和数据模型。如果业务模型和数据模型的层级和接口差异很大,则创建完全分离的类。如业务模型和数据模型有匹配的层级和兼容的接口,则建议业务模型类继承数据模型类。如业务模型和数据模型有匹配的层级,但接口不兼容(如数据模型类接口不适合于业务模型类),则在业务模型类中通过聚集关系,包含数据模型类实例。


    在编写Controller Action方法时,应将一些复杂的方法包装为modelservice层的辅助方法或类中。优先采用action过滤器属性,如HttpPostAttribute,避免在每一个action方法中检测HttpContext,编写逻辑判断。此外,使用action过滤器进行横切关切点(Cross-cutting concern),如认证(AuthorizeAttribute)、错误处理(HandleErrorAttribute)等等。处理GET请求的方法应仅包含一些方法调用,而不必包含太多业务判断逻辑;处理POST 请求的方法应验证传入的数据,在数据合法的情况下,执行更新操作,并根据更新结果,返回对应视图。MileageStats RI 应用程序的如下范例显示2个版本的Add方法(分别为GETPOST版本):

            // GET: /Fillups/Add/1

            public ActionResult Add(int vehicleId)

            {

                var vehicles = this.businessServices.GetVehicles(this.User.MileageStatsIdentity().UserId);

                Vehicle vehicle = vehicles.First(v => v.VehicleId == vehicleId);

     

                var newFillupEntry = new FillupEntry()

                {

                    Odometer = vehicle.Odometer.HasValue ? vehicle.Odometer.Value : 0

                };

                var fillups = this.GetVehicleFillupsDescending(vehicleId);

     

                var model = new FillupViewModel()

                {

                    VehicleList = new VehicleListViewModel(vehicles, vehicle) { IsCollapsed = true },

                    Fillups = new SelectedItemList<FillupEntry>(fillups, newFillupEntry),

                    FillupEntry = newFillupEntry

                };

     

                this.ViewBag.IsFirstFillup = (fillups.Count == 0);

     

                return this.View(model);

            }

     

            //

            // POST: /Fillups/Add/5

            [HttpPost]

            [ValidateInput(false)]

            [ValidateAntiForgeryToken]

            public ActionResult Add(int vehicleId, FillupEntry model)

            {

                if (this.ModelState.IsValid)

                {

                    this.AddModelErrors(this.businessServices.CanAddFillup(this.CurrentUserId, vehicleId, model),

                                        "AddFillup");

     

                    if (this.ModelState.IsValid)

                    {

                        this.businessServices.AddFillupToVehicle(this.CurrentUserId, vehicleId, model);

                        this.TempData["LastActionMessage"] = Resources.VehicleController_AddFillupSuccessMessage;

                        return this.RedirectToAction("List", "Fillup", new { vehicleId = vehicleId });

                    }

                }

     

                var vehicles = this.businessServices.GetVehicles(this.CurrentUserId);

                Vehicle vehicle = vehicles.First(v => v.VehicleId == vehicleId);

                var fillups = this.GetVehicleFillupsDescending(vehicleId);

     

                var viewModel = new FillupViewModel()

                {

                    VehicleList = new VehicleListViewModel(vehicles, vehicle) { IsCollapsed = true },

                    Fillups = new SelectedItemList<FillupEntry>(fillups, model),

                    FillupEntry = model

                };

     

                this.ViewBag.IsFirstFillup = (fillups.Count == 0);

     

                return this.View(viewModel);

            }

     

     

    依赖注入 - Dependency Injection

    解耦应用程序的组件(Decoupling the application components)。关于Unity 2.0 依赖注入容器在ASP.NET MVC 3 项目的具体使用细节,可参考文章 - ASP.NET MVC 项目使用Unity 2.0实现依赖注入

     

    创建Business Service

    为了项目的可维护和支持不同类型的客户端,大型和复杂的应用程序经常需要额外的架构层 – Business Service Layer,将业务逻辑从数据访问层分离出来。

     

    本文参考和编译了如下文章部分内容:

    Project Silk 1.0 – Server-side Architecture

    Project Silk - http://silk.codeplex.com/


    posted @ 2011-05-16 08:12 Rickie 阅读(1689) 评论(5) 编辑

    2011年5月3日 #

    本文提供了一些代码设计准则,目标是帮助ASP.NET MVC 开发人员创建可靠的应用程序,当然,你可根据实际应用程序选择合适的标准。本文由EntLib.com 小组翻译,欢迎分享和交流ASP.NET MVC 项目开发设计思路。

     

    Model建议 - Model Recommendations

    Model是定义业务领域相关的对象,应该包含业务逻辑(对象如何动作和关联),验证逻辑(验证对象的有效值),数据逻辑(数据对象如何持久化),和会话逻辑(跟踪用户状态)。

     

    创建独立的Model项目,在ASP.NET MVC 项目中引用Model程序集。

     

    将所有业务逻辑放置在Model中。

    如将所有业务逻辑放置在Model项目中,可根据实际业务数据来生成ViewController。有如下好处:

    • 减少重复的业务逻辑。
    • View中减少业务逻辑,View易于理解。
    • 业务逻辑的测试仅仅和Model有关。

     

    例如,下面需要显示用户的用户名先显示Last Name,在View中代码如下:


    <% if (String.Compare((string)TempData["displayLastNameFirst"], "on"== 0)
           { 
    %>
            Welcome, 
    <%= Model.lastName%><%= Model.firstName%>
       
    <% }
          
    else
           { 
    %>
            Welcome, 
    <%= Model.firstName%> <%= Model.lastName%>
       
    <% } %>

     

    然而你需要在每一个地方重复这一逻辑。如将这一业务逻辑放置在Model中,可在Model中添加一个属性封装这一逻辑。


    public string combinedName
    {
       
    get
        {
           
    return (displayLastNameFirst ? lastName + " " + firstName : firstName + " " + lastName);
        }
       
    private set
        {
            ;
        }
    }

    这样,可大大简化视图代码:

    <% Welcome, <%= Model.combinedName %> %>

     

    将所有验证逻辑放置在Model

    所有输入验证应该在Model层,包括Client-side 验证。

    可使用ModelState 添加验证检查,代码如下所示:

    if (String.IsNullOrEmpty(userName))

    {

       ModelState.AddModelError("username", Resources.SignUp.UserNameError);

     

    不过,更好的办法是使用 System.ComponentModel.DataAnnotations,在Model类的属性上添加attribute,如下所示:

    public class User

    {

       [Required(ErrorMessageResourceName = "nameRequired", ErrorMessageResourceType = typeof(Resources.User))]

       public String userName { get; set; }

           ...

    }

     

    为数据访问定义接口

    接口用来暴露数据访问类的方法,强化ASP.NET MVC 的松散耦合设计。

    可考虑使用Entity Framework LINQ to SQL 创建对数据库的访问类,Entity Framework LINQ to SQL 都支持存储过程。

     

    将所有会话逻辑放置在Model中。

     

    View 建议 - View Recommendations

    View用来展示Model数据,Controller负责选择View。业务逻辑不属于ViewModel负责业务逻辑。View非常灵活,如ModelView可通过HTML显示,同样的Model也可通过XML 视图来呈现。

     

    HTML放置在ViewPartial View中(不要在Controller中)

    默认的ASP.NET视图引擎提供了如下视图文件:HTML View.aspx),Partial HTML View.ascx)和Master page.master

    如下视图演示了对partial view的调用:

    <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>

        Below is a list of items submitted by <b>

    <%= Html.Encode(ViewData["name"]) %></b>.

        <p>

       

        ...

        <div id="items">

            <% Html.RenderPartial("ItemsByName");%>

        </div>   

    </asp:content>

     

    Partial viewItemsByName.ascx)如下所示:

    <%@ Control Language="C#" %>

            <% foreach (Seller.Controllers.Items item in (IEnumerable)ViewData.Model)

               { %>

                <tr>

                    <td>

                        <%= Html.Encode(item.title)%>

                    </td>

                    <td>

                        <%= Html.Encode(item.price)%>

                    </td>              

                </tr>       

            <% } %>

            </table>

          <% } %>

    Partial View 是一个强大的扩展和重用机制。你可在不同的地方包含相同的View,不必编写重复的代码。

     

    View中使用ViewData访问数据

    ASP.NET 提供了如下机制在View模板中访问数据:

    ViewData.Model 对象Controlleraction方法中,在return语句中传入一个Model对象(return View(myModelObject))。

    ViewData Dictionary – action方法中存入数据(ViewData[“key”] = value),接着在View中方法相同的dictionary

    在可能的情况下,应该是一ViewData Model,而不是ViewData 来访问数据,因为Model 提供了类型安全。此外,你应在View模板中,使用数据访问机制,而不是Request / Session 来访问。

    如需要显示一个对象的多个属性,可使用ViewData.Model,并创建一个强类型View。针对seller详细页面,seller类有namephoneaddressemail等等属性,在呈现View之前,你可在Controller中对ViewData.Model 赋值seller对象实例。但是如果是一些零散的数据,如page#、用户名和current time,则一般使用ViewData字典。

     

    在使用模型绑定(Model bingding)时,避免在view中访问数据。

    Controller 中访问数据库,在执行View之前,将从数据库中检索的数据复制给轻量的View Model对象,这样,轻量的View Model对象不必在视图执行时检索数据。

     

    使用(自动生成)客户端验证

    ASP.NET MVC 2 开始,可以很容易添加客户端验证。

    (1) 如前所述,在Model层中添加数据验证逻辑;

    (2) 确保项目中Scripts目录有如下javascript 文件:MicrosoftAjax.js MicrosoftMvcValidation.js

    (3) 在表单提交页面,添加如下代码:

    <script src="<%= Url.Content("~/Scripts/MicrosoftAjax.js") %>" type="text/javascript"></script>

     

    <script src="<%= Url.Content("~/Scripts/MicrosoftMvcValidation.js") %>" type="text/javascript"></script>

     

    (4) 在表单中添加如下代码:

    <% Html.EnableClientValidation(); %>

     

    现在如果编辑表单内容,当输入值不合格时,客户端马上进行验证提醒。

     

    在模板中插入server-side 注释

    View模板中使用服务端注释,在HTML呈现时,会剔除。

    如下是server-side注释:

    <%-- This is a server side template comment --%>

     

    不要在View模板中使用HTML 注释,因为这些注释会呈现在web浏览器中,可被用户看到。

     

    使用HTMLHelper 扩展方法。

    System.Web.Mvc.Html 类中包含了很多有用的HTML 扩展方法。

    Form 表单生成(BeginForm

    输入字段生成(checkboxhiddenradio buttontextbox

    链接URL生成(ActionLink

    XSS保护(Encode

     

    尽可能使用这些HTML扩展方法,如下是使用route table创建一个链接:

    <%= Html.ActionLink(“Home page”, “Default”) %>


    后续相关文章,可参考如下链接:

     

    ASP.NET MVC 最佳开发实践(2)
    ASP.NET MVC 最佳开发实践(3)

     

     

    英文原文链接:
    Best Practices for ASP.NET MVC
    http://blogs.msdn.com/b/aspnetue/archive/2010/09/17/second_2d00_post.aspx

     

     

     

     

    posted @ 2011-05-03 21:05 Rickie 阅读(2462) 评论(8) 编辑

    2011年4月22日 #

    目前可使用的IoC(Inversion of Control,控制反转)容器有很多,如 Unity、Castle Windsor、Autofac、StructureMap等等。

    下面是 Autofac 容器的下载网址:

    http://code.google.com/p/autofac/

     

      
    posted @ 2011-04-22 15:44 Rickie 阅读(280) 评论(0) 编辑

    2011年4月21日 #

    摘要: 1. 先看下webformviewengine的构造函数: publicWebFormViewEngine(){base.MasterLocationFormats=newstring[]{"~/Views/{1}/{0}.master","~/Views/Shared/{0}.master"};base.ViewLocationFormats=newstring[]{"~/Views/{1}/{0}.aspx","~/Views/{1}/{0}.ascx","~/Views/Shared/{0}.asp阅读全文
    posted @ 2011-04-21 23:15 Rickie 阅读(181) 评论(0) 编辑

    2011年4月19日 #

    摘要: Html.RenderPartial与Html.RenderAction这两个方法都是用来在界面上嵌入用户控件的。 Html.RenderPartial是直接将用户控件嵌入到界面上: <%Html.RenderPartial("LogOnUserControl");%> 或 <%Html.RenderPartial("~/Areas/Comm/Views/Shared/LogOnUserControl.ascx");%> 注意:用第一种方法时,用户控件必须放在调用者同一目录下,也可以放在View/Shared中。 Html.Ren阅读全文
    posted @ 2011-04-19 22:16 Rickie 阅读(1295) 评论(1) 编辑

    2011年3月31日 #

    摘要: Setting Expires and Cache-Control: max-age headers for static resources in ASP.NET原文地址: http://www.stardeveloper.com/articles/expires-and-max-age-headers-in-aspnet/Real-World example of load time improvement using HTTP static resource caching原文地址: http://www.stardeveloper.com/articles/real-world-exa阅读全文
    posted @ 2011-03-31 21:13 Rickie 阅读(126) 评论(0) 编辑

    2011年3月25日 #

    摘要: 前端是庞大的,包括HTML、CSS、Javascript、Image、Flash等等各种各样的资源。前端优化是复杂的,针对方方面面的资源都有不同的方式。那么,前端优化的目的是什么?1. 从用户角度而言,优化能够让页面加载得更快、对用户的操作响应得更及时,能够给用户提供更为友好的体验。2. 从服务商角度而言,优化能够减少页面请求数、或者减小请求所占带宽,能够节省可观的资源。总之,恰当的优化不仅能够改善站点的用户体验并且能够节省相当的资源利用。前端优化的途径有很多,按粒度大致可以分为两类,第一类是页面级别的优 化,例如HTTP请求数、脚本的无阻塞加载、内联脚本的位置优化等;第二类则是代码级别的优化阅读全文
    posted @ 2011-03-25 08:16 Rickie 阅读(164) 评论(1) 编辑

    2011年3月22日 #

    摘要: ASP.NET Open Source Projectshttp://wiki.asp.net/page.aspx/388/aspnet-open-source-projects/有大量基于.NET Framework 开发的开源项目。 另外还推荐几个开源的ASP.NET MVC 项目:(1)Orchard 项目 http://orchard.codeplex.com/(2)The Beer House CMS and E-Commerce applicationhttp://thebeerhouse.codeplex.com/(3)mytrip.mvc 项目http://mytripmvc.阅读全文
    posted @ 2011-03-22 22:09 Rickie 阅读(183) 评论(0) 编辑