七天学会ASP.NET MVC (六)——线程问题、异常处理、自定义URL

6 篇文章 0 订阅

http://www.cnblogs.com/powertoolsteam/p/MVC_Six.html

系列文章
七天学会ASP.NET MVC (一)——深入理解ASP.NET MVC

七天学会ASP.NET MVC (二)——ASP.NET MVC 数据传递

七天学会ASP.NET MVC (三)——ASP.Net MVC 数据处理

七天学会ASP.NET MVC (四)——用户授权认证问题

七天学会ASP.NET MVC (五)——Layout页面使用和用户角色管理

七天学会ASP.NET MVC (六)——线程问题、异常处理、自定义URL

七天学会ASP.NET MVC(七)——创建单页应用

目录
实验27——添加批量上传选项

关于实验27

实验27存在的问题

解决方法

实验28——解决线程饥饿问题

实验29——异常处理—显示自定义错误页面

关于实验29

理解实验29中的限制

实验30—异常处理—日志异常

关于实验30

理解RouteTable

理解Asp.net MVC 请求周期

实验31—实现用户友好URLs

关于实验31

总结

实验27——添加批量上传选项
在实验27中,我们将提供一个选项,供用户选择上传Employee记录文件(CSV格式)。

我们会学习以下知识:

  1. 如何使用文件上传控件

  2. 异步控制器

  3. 创建 FileUploadViewModel

在ViewModels文件夹下新建类“FileUploadViewModel”,如下:

1: public class FileUploadViewModel: BaseViewModel
2: {
3: public HttpPostedFileBase fileUpload {get; set ;}
4: }
HttpPostedFileBase 将通过客户端提供上传文件的访问入口。

  1. 创建 BulkUploadController 和Index action 方法

新建 controller“BulkUploadController”,并实现Index Action 方法,如下:

1: public class BulkUploadController : Controller
2: {
3: [HeaderFooterFilter]
4: [AdminFilter]
5: public ActionResult Index()
6: {
7: return View(new FileUploadViewModel());
8: }
9: }
Index方法与 HeaderFooterFilter 和 AdminFilter属性绑定。HeaderFooterFilter会确保页眉和页脚数据能够正确传递到ViewModel中,AdminFilter限制非管理员用户的访问。
3.创建上传View

创建以上Action方法的View。View名称应为 index.cshtml,且存放在“~/Views/BulkUpload”文件夹下。

  1. 设计上传View

在View中输入以下内容:

1: @using WebApplication1.ViewModels
2: @model FileUploadViewModel
3: @{
4: Layout = “~/Views/Shared/MyLayout.cshtml”;
5: }
6:
7: @section TitleSection{
8: Bulk Upload
9: }
10: @section ContentBody{
11:


12: Back
13:
14: Select File :
15:
16:
17:

18: }
如上,FileUploadViewModel中属性名称与 input[type=”file”]的名称类似,都称为“fileUpload”。我们在Model Binder中已经讲述了名称属性的重要性,注意:在表单标签中,有一个额外的属性是加密的,会在实验结尾处讲解。

  1. 创建业务层上传方法

在 EmployeeBusinessLayer中新建方法 UploadEmployees,如下:

1: public void UploadEmployees(List employees)
2: {
3: SalesERPDAL salesDal = new SalesERPDAL();
4: salesDal.Employees.AddRange(employees);
5: salesDal.SaveChanges();
6: }
7:
6. 创建Upload Action 方法

创建Action 方法,并命名为 “BulkUploadController”,如下:

1: [AdminFilter]
2: public ActionResult Upload(FileUploadViewModel model)
3: {
4: List employees = GetEmployees(model);
5: EmployeeBusinessLayer bal = new EmployeeBusinessLayer();
6: bal.UploadEmployees(employees);
7: return RedirectToAction(“Index”,”Employee”);
8: }
9:
10: private List GetEmployees(FileUploadViewModel model)
11: {
12: List employees = new List();
13: StreamReader csvreader = new StreamReader(model.fileUpload.InputStream);
14: csvreader.ReadLine(); // Assuming first line is header
15: while (!csvreader.EndOfStream)
16: {
17: var line = csvreader.ReadLine();
18: var values = line.Split(‘,’);//Values are comma separated
19: Employee e = new Employee();
20: e.FirstName = values[0];
21: e.LastName = values[1];
22: e.Salary = int.Parse(values[2]);
23: employees.Add(e);
24: }
25: return employees;
26: }
AdminFilter会绑定到Upload action方法中,限制非管理员用户的访问。

  1. 创建BulkUpload链接

打开 “Views/Employee”文件夹下的 AddNewLink.cshtml 文件,输入BulkUpload链接,如下:

Add New

BulkUpload
8.运行

8.1 创建一个样本文件来测试,如图所示

8.2 运行,点击BulkUpload链接

选择文件并点击确认

关于实验 27

为什么在实验27中不需要验证?

在该选项中添加客户端和服务器端验证需要读者自行添加的,以下是添加验证的提示:

服务器端验证可使用Data Annotations。
客户端验证可利用客户端的数据解释和执行jQuery的验证。必须手动设置自定义数据属性,因为并没有将Htmlhelper 方法设置为文件输入。
客户端验证可编写JavaScript 代码,通过点击按钮来实现。这个方法并不是很难,由于文件输入是由输入控件完成,值可以在JavaScript中获取及验证 。
什么是 HttpPostedFileBase?

HttpPostedFileBase将通过客户端提供文件上传的访问入口,Model Binder 会在Post请求期间更新 FileUploadViewModel类中的所有属性值。我们在FileUploadViewModel内部只有一个属性,Model Binder会通过客户端设置它实现文件上传。

是否会提供多文件的输入控件?

是,有两种方法可以实现:

  1. 创建多文件输入控件,每个控件有唯一的名称,FileUploadViewModel类会为每个控件创建 HttpPostedFileBase类型的属性,每个属性名称应该与控件名称匹配。

  2. 创建多文件输入控件,每个控件有相同的名称,创建类型的List列表,代替创建多个HttpPostedFileBase类型的属性。

enctype=”multipart/form-data” 是用来做什么的?

该属性指定了post 数据的编码类型,默认属性值是”application/x-www-form-urlencoded“

例1—登录窗体会给服务器发送以下Post 请求

1: POST /Authentication/DoLogin HTTP/1.1
2: Host: localhost:8870
3: Connection: keep-alive
4: Content-Length: 44
5: Content-Type: application/x-www-form-urlencoded
6: …
7: …
8: UserName=Admin&Passsword=Admin&BtnSubmi=Login
所有输入值会被作为发送的值的一部分,以”key/value“的形式发送。

当 enctype=”multipart/form-data” 属性被加入Form标签中,以下post 请求会被发送到服务器。

1: POST /Authentication/DoLogin HTTP/1.1
2: Host: localhost:8870
3: Connection: keep-alive
4: Content-Length: 452
5: Content-Type: multipart/form-data; boundary=—-WebKitFormBoundarywHxplIF8cR8KNjeJ
6: …
7: …
8: ——WebKitFormBoundary7hciuLuSNglCR8WC
9: Content-Disposition: form-data; name=”UserName”
10:
11: Admin
12: ——WebKitFormBoundary7hciuLuSNglCR8WC
13: Content-Disposition: form-data; name=”Password”
14:
15: Admin
16: ——WebKitFormBoundary7hciuLuSNglCR8WC
17: Content-Disposition: form-data; name=”BtnSubmi”
18:
19: Login
20: ——WebKitFormBoundary7hciuLuSNglCR8WC–
如上所示,Form会在多部分post发送,每部分都是被分界线分割的,每部分包含单值。

如果form标签包含文件输入控件的话,enctype必须被设置为”multipart/form-data“。

为什么有时候需要设置 encType 为 “multipart/form-data”,而有时候不需要设置?

当encType 设置为”multipart/form-data“,将会实现Post数据和上传文件的功能,当然也会增加请求的size 增加,请求size 越大意味着性能越低。因此得出的最佳实践经验需要设置为默认的”application/x-www-form-urlencoded“。

为什么在实验27中创建ViewModel?

在View中已经有一个控件了,我们需要通过直接添加 HttpPostedFileBase类型的参数,并命名为”fileUpload“实现相同的结果,从而替代创建独立的ViewModel。

1: public ActionResult Upload(HttpPostedFileBase fileUpload)
2: {
3: }
创建 ViewModel是最好的方法,Controller应该以 ViewModel的形式给View发送数据,且数据必须来自Controller。

以上问题的解决方法

是否存在疑虑,当发送请求时,如何获取响应?

众人皆知的编程规则,程序中任何事件都是由线程执行的,请求事件也是。

Asp.net framework 维护线程池,每次当请求发送到webserver时,会从线程池中分配空闲的线程处理此请求。这种线程被称为worker线程。

当请求处理完成,该线程无法服务其他请求时,worker 线程会被阻塞。现在我们来了解什么是线程饥饿,如果一个应用程序接收到很多请求,且处理每个请求都非常耗时。在这种情况下,我们就必须指定一个点来结束请求,当有新的请求进入状态时,没有worker 线程可使用,这种现象称为线程饥饿。

在我们的示例程序中只包含2个员工记录,而在实际使用情况下,会包含成千上万的记录,这就意味着将耗费大量的时间来处理请求。这种情况就可能导致线程饥饿.

线程饥饿的解决方法:

截至现在我们讨论的请求类型都是同步请求。如果使用异步请求来代替同步请求,那么线程饥饿的问题就得到解决了。

异步请求的情况下,会分配worker线程来服务请求。
worker 线程初始化异步操作,并返回到线程池服务其他请求。异步操作可使用CLR 线程来继续执行。
存在的问题就是,CLR 线程无法返回响应,一旦它完成了异步操作,它会通知Asp.net。
Webserver 再次获取一个worker线程来处理剩余的请求,并返回响应。
上述使用场景中,会获取两次worker 线程,这两次获取的线程可能相同,也可能会不同。

文件读取是I/O操作,不需要使用worker 线程处理。因此最好将同步请求转换为异步。

同步请求的响应时间能提升吗?

不可以,响应时间是相同的,线程会被释放来服务其他请求。

实验28——解决线程饥饿问题
在Asp.net MVC中会通过将同步Action方法转换为异步Action方法,将同步请求转换为异步请求。

1. 创建异步控制器

在控制器中将基类 UploadController修改为 AsynController。

1: {
2: public class BulkUploadController : AsyncController
3: {
2. 转换同步Action方法

该功能通过两个关键字就可实现:“async “和” await”

1: [AdminFilter]
2: public async Task Upload(FileUploadViewModel model)
3: {
4: int t1 = Thread.CurrentThread.ManagedThreadId;
5: List employees = await Task.Factory.StartNew

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值