MVC执行流程
Model的建议
Model是用于定义特定于域的对象。 这些定义应包括业务逻辑 (对象的行为)、验证逻辑、数据逻辑和会话逻辑 (跟踪应用程序的用户状态)。
做模型自己的项目使用分隔不同的程序集。
大型复杂模型的应用程序最好创建一个单独的Model程序集,以减少耦合。 然后,可以在 ASP.NET MVC 项目中引用Model的程序集。
把所有的业务逻辑放在模型中。
如果你把所有的业务逻辑模型中, 你还获得以下好处:
- 减少重复的业务逻辑。
- 视图易于阅读,不存在的业务逻辑。
- 测试业务规则是独立的。
例如:
<% if (String.Compare((string)TempData["displayLastNameFirst"], "on") == 0)
{ %>
Welcome, <%= Model.lastName%>, <%= Model.firstName%>
<% }
else
{ %>
Welcome, <%= Model.firstName%> <%= Model.lastName%>
<% } %>
如果很多地方需要这样的逻辑,就是有在视图中写这样的代码,如果放在Model中:
public string combinedName
{
get
{
return (displayLastNameFirst ? lastName + " " + firstName : firstName + " " + lastName);
}
private set
{
;
}
}
这将极大地简化视图,如图所示:
<% Welcome, <%= Model.combinedName %> %>
把所有的验证逻辑放在Model中。
所有输入的验证应该放在Model中,包括客户机端验证。
可以使用 ModelState 来添加验证检查。 下面的示例显示了如何将有明确的 ModelState 添加验证检查:
if (String.IsNullOrEmpty(userName))
{
ModelState.AddModelError("username", Resources.SignUp.UserNameError);
}
.net 框架提供的 System.ComponentModel.DataAnnotations 应该是验证的首选的方法。比如:
public class User
{
[Required(ErrorMessageResourceName = "nameRequired", ErrorMessageResourceType = typeof(Resources.User))]
public String userName { get; set; }
…
}
定义数据访问接口
接口用于公开数据访问提供程序的方法, 这能增强 ASP.NET MVC 的松散耦合的组件的设计。
请考虑使用实体框架或 LINQ to SQL 创建到数据库的调用wrappers。
View建议
把 HTML 放在View和Partial Views中(而不是在一个Controller)。
对于默认视图引擎 ASP.NET 提供了几种文件类型: 完全 HTML 视图 (.aspx),部分 HTML 视图 (.ascx) 和母版页(.master)。 母版页使您能够指定一个整体布局的视图。 母版页可以嵌套几次创建的可用的布局类型层次结构。如果是Razor视图没有后缀名区别。
下面的示例显示了调用局部视图的方式:
<%@ 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>
局部视图 (ItemsByName.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>
<% } %>
局部视图是一个功能强大的可扩展性和重用机制。
访问视图使用ViewData。
ASP.NET 提供了以下的机制访问视图模板中的数据:
- ViewData.Model
- ViewData 字典
推荐使用ViewModel,ViewModel是强类型,能保证类型安全。
使用自动生成客户端验证。
在模板中插入服务器端注释。
下面的行演示了服务器端注释:
< %--这是一个服务器端的模板评论 -- %>
不要视图模板中使用 HTML 注释,因为他们会呈现到 web 浏览器,可被潜在的恶意的用户查看。
使用 HTMLHelper 扩展方法。
常用方法:
- 表单生成 (BeginForm)
- 输入的字段生成复选 (框,隐藏,单选按钮文本框)
- 链接代 (ActionLink)
- XSS 保护 (编码)
Controller的建议
在Action方法显示指定view 名称。
可以直接return view();
如果这样,MVC框架首先查找 /Views/Products/List.aspx。如果不存在,查找 /Views/Products/List.ascx,如果还没找到,查找 /Views/Shared/List.aspx 然后是/Views/Shared/List.ascx. 从上分析 /Views/Shared 这个目录的文件可以跨controller共享,为避免混淆和性能考虑,推荐使用显示指定view名称的方式。
。
当提交表单时,使用post/redirect/get (PRG)。
根据 HTTP POST 和 GET 动词的定义:
- HTTP GET 用于非更改您的模型 (幂等) 数据。
- HTTP POST 用来更改您的模型的数据。
如图在标准的回发中使用同一个 url create.aspx进行 GET 和 POST, 这是一个问题,当网站的用户获取窗体发布到完成没有耐心等待,如果他们点了浏览器的刷新按钮,可能导致的重复数据。使用后Redirect 获取模式可以解决这个问题。
使用 HandleError或者在Web.config自定义错误处理
路由的建议
路由用于在 ASP.NET MVC url 直接映射到一个的控制器,而不是特定的文件。 这是以提高可读性,可以更好被搜索引擎收录。
使用定制路由时使用从具体到一般路线。
定制路由遵从具体到一般的路线。
考虑下面的示例。 假设有一个如下列形式的 url 的产品目录:
- http://sellmyproducts/
- http://sellmyproducts/Page#
- http://sellmyproducts/category
- http://sellmyproducts/category/Page#
提供以下列表方法的签名 (ProductsController 类):
public ViewResult List(string category, int page)
定制路由:
routes.MapRoute(
null,
"",
new { controller = "Products", action = "List", category = (string)null, page = 1 }
);
routes.MapRoute(
null,
"Page{page}",
new { controller = "Products", action = "List", category = (string)null },
new { page = @"\d+" }
);
routes.MapRoute(
null,
"{category}",
new { controller = "Products", action = "List", page = 1}
);
routes.MapRoute(
null,
"{category}/Page{page}",
new { controller = "Products", action = "List"},
new { page = @"\d+" }
);
使用命名的路由机制,避免多义性的路由。
例如以下命名的路由:
routes.MapRoute(
"Default",
"",
new { controller = "Products", action = "List", category = (string)null, page = 1 }
);
routes.MapRoute(
"PageRoute",
"Page{page}",
new { controller = "Products", action = "List", category = (string)null },
new { page = @"\d+" }
);
使用这些路由定义,您可以创建链接,将解析为"PageRoute",如下所示:
<%= Html.RouteLink("Next", "PageRoute",
new RouteValueDictionary( new { page = i + 1 } )); %>
可扩展性的建议
ASP.NET MVC 框架内有很多扩展点。 可以替换的任何一个部分的列表,其中包括以下的核心组件:
- 路由引擎 (MvcRouteHandler)
- 控制器厂 (IControllerFactory)
- 视图引擎 (IViewEngine)
可以通过在filters添加自定义行为扩展框架,比如一些包含在框架的标准筛选器: OutputCache,HandleError,和Authorize。
使用filters添加行为
这些筛选器可以实现轻量级的请求处理管线的可扩展性。
例如假设要添加记录为每个请求调试问题的 HTTP 标头信息的功能。 下面的代码定义了从 ActionFilterAttribute 类派生的类。
public class LogHeadersFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
foreach (string header in
filterContext.HttpContext.Request.Headers.AllKeys)
{
Debug.WriteLine("Header " + header);
Debug.WriteLine("Value " +
filterContext.HttpContext.Request.Headers.Get(header));
}
base.OnActionExecuting(filterContext);
}
}
给定的操作方法中添加此筛选器,只要将 LogHeadersFilter 属性放在要筛选的Action(或Controller) 的顶部。
可测试性建议
MVC 模式的主要优势之一是改进可测试性设计,解耦。
编写单元测试。
ASP.NET MVC 提供了一个灵活的体系结构,允许简单测试。可以采用MS的单元测试工具或第三方工具来编写单元测试。
关于单元测试 ASP.NET MVC 的应用程序的详细信息,请参阅 。
安全建议
安全是任何现代软件开发项目的一个重要方面。 虽然没有框架可以提供完善的安全,但是还是有很多方面你可以帮助保护你的 ASP.NET MVC 应用程序。
防止常见的攻击。
网站安全需要所有 web 开发人员的关注,常见攻击方式:
- 跨站点脚本 (XSS) 攻击
- SQL 注入
- 跨站点请求伪造文件 (XSRF)
为防止跨站点脚本 (XSS) 攻击:
- 禁用请求验证通过使用 ValidateInput 属性。 此属性将拒绝错误的 HTML 输入。
- 将显示的所有用户输入数据都添加 Html.Encode,不管是立即呈现的数据还是从数据库取出要显示的数据。
- cookie 设置 HttpOnly 标志。 防止JavaScript阅读和发送 cookie。
为防止 SQL 注入:
- 始终使用参数化的 SQL 查询。
- 不要将原始 SQL 传递到数据库中。
- 使用 (例如,可以完全消除的 SQL 语句在应用程序代码需要的实体架构的对象关系映射 (ORM)。
为防止跨站点请求伪造 (XSRF):
- 在窗体中使用 Html.AntiForgeryToken 类可防止伪造跨站点请求。
- 在需要保证的Action方法上增加ValidateAntiForgeryToken 属性
进行身份验证和授权来保护内容的用户。
使用 < %: %> (.NET 4),以防止 XSS 攻击。
前,.net 4.0 开发人员将必须那里确保 HTML 编码通过使用类似于下面的代码:
<%= Html.Encode(ViewData["name"]) %>
此代码被要防止 XSS 跨站点脚本攻击。
如果使用的.net 4 不要使用上述语法。 请使用以下语法。
<%: Html.Encode(ViewData["name"] )%>
本地化和全球化建议
全球化是使一个产品多语言本地化在哪里的适应特定语言和国家的全球产品过程的过程。 要开发一个 web 应用程序,它支持全球化和本地化,请记住至少一个规则。 在视图中不使用硬编码字符串。
不要使用 ASP.NET 特殊资源文件夹和资源文件。
添加 ASP.NET 项目文件夹全球化内容 (App_GlobalResources) 和给定的视图 (App_LocalResources) 的本地化内容。 在每个这些文件夹应添加一个资源 (.resx) 文件,应根据该控制器的名称命名。如果控制器被命名为 SubmissionPipeline,资源文件应被命名为 SubmissionPipeline.resx。
visual Studio 将此文本映射类转换为全球的类,可以调用使用下面的语法:
Resources.<resource_filename>.<string_name>
然后将访问此类视图中的资源:
<%= Resources.SubmissionPipeline.continueButton %>
得到翻译的资源文件时应使用以下格式命名每个文件: <filename>. <language>.resx。
例如将命名资源文件的德语版的: SubmissionPipeline.de.resx。
性能的建议
可能会影响 web 站点性能的瓶颈包括:
- 数据库
- 低效的查询
- 不正确地放置索引
- 非规范化设计
- 带宽问题
- 请求大小 (大图像、.css、.js、.html、 等)。
- 引用了其他项目的多个脚本,CSS 或图像文件的内容
- 慢速连接
- 处理能力
- 服务器: 费时的操作
- 客户端: 糟糕的 javascript
考虑减少带宽使用 AJAX 的部分页更新。
使用Javascript AJAX 异步来处理部分页更新的请求来减轻涉及服务器处理压力是的解决性能问题的一种方法。 ASP.NET MVC 有内置的 AJAX 支持,可减少处理服务器必须执行呈现的请求和减少的 HTML 片段大小。
下面的示例说明了如何使用 AJAX 的部分页更新:
1. 创建PartialView test.cshtml。
@model MVC.Test.Site.Models.UserView <div id="items"> username: @if (Model != null) { @Model.UserName }
</div>
2. 在Action.cshtml中添加
@{Html.RenderPartial("test", ViewData["user"]);}
3. Home/Login代码
public ActionResult Login(UserView user) { ViewData["user"] = user; return PartialView("Action", user); }
不要过度使用会话,而是使用 TempData存储。
创建网站将对象添加到 会话 的对象,以便它们随时可用时,看起来很好,但是将这些对象放在 Session 对象中的问题是它可能给服务器造成负担,因为只是redirect的时候用到。 在重定向存储这些临时变量的正确方法是使用 TempData 词典。
例如假设收到一个 POST 登录时的表单数据。 初始化过程可能是下面的操作方法:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult LogIn(Seller person)
{
...
TempData["name"] = person.Name;
return RedirectToAction("ItemUpload");
}
重定向到 ItemUpload 的操作方法之前将person.name放置在 TempData 词典中。 ItemUpload 操作方法从 TempData 词典中检索,并放在自己的ViewData中,以便它可以在视图中引用。
public ActionResult ItemUpload()
{
string name = TempData["name"] as string;
ViewData["name"] = name;
return View();
}
使用OutputCache 。
OutputCache 属性用于不频繁更新的数据 , 主要是用于首页。 对于 HTML 和 JSON 数据类型,可以使用这种技术。 当使用它,只指定缓存配置文件的名称 ; 不指定任何其他。使用 Web.config 文件配置output cache section。
例如 OutputCache 属性附加到在以下代码中的控制板操作方法。
[AcceptVerbs(HttpVerbs.Get), OutputCache(CacheProfile = "Dashboard")]
public ActionResult Dashboard(string userName, StoryListTab tab, OrderBy orderBy, int? page)
{
...
}
考虑使用异步控制器长时间运行的请求。
ASP.net 线程池的默认限制为每个 CPU 12 并发工作线程。 当请求过载处理这些请求的服务器的能力时,队列是建立的请求。 例如任何请求,需要大量的时间等待外部资源如数据库或较大的文件操作。 这些外部请求阻止他们占用整个等待时间的线程。 当此队列获取太大 (5000 请求挂起) 时,在服务器启动 503 (服务器太忙) 错误响应。
在 ASP.NET 4 的并发线程数设置默认情况下,5000。 虽然可能增加默认限制有更好的方法,以减轻长时间运行的请求占用了修改异步运行的长时间运行请求的线程。 ASP.NET MVC 使您可以为此目的实现异步控制器。 有关如何实现一个异步控制器的详细信息,请参阅 。