目录

  • 第 1 天

  • 第 2 天

  • 第 3 天

  • 第 4 天

  • 第 5 天

  • 第 6 天

  • 第 7 天

0. 前言

欢迎来到第六天的 MVC 系列学习中。希望你在阅读此篇文章的时候,已经学习了前五天的内容,这也是第六天学习的前提条件。

1. Lab 27 — 添加批量上传选项

在这个实验中,我们将会创建一个选项,用于从 CSV 文件中上传多个 Employees。

我们将会做两件事。
1. 学会如何运用文件上传控件。

  1. 异步控制器。

第一步:创建 FileUploadViewModel

在 ViewModels 文件夹下创建一个类,命名为 FileUploadViewModel。

  1. publicclassFileUploadViewModel:BaseViewModel

  2. {

  3. publicHttpPostedFileBase fileUpload {get;set;}

  4. }

HttpPostedFileBase 将会通过客户端提供上传文件的访问入口。

第二步:创建 BulkUploadController 和 Index 行为方法

创建一个新的控制器,命名为 BulkUploadController,以及一个行为方法,命名为 Index。

  1. publicclassBulkUploadController:Controller

  2. {

  3. [HeaderFooterFilter]

  4. [AdminFilter]

  5. publicActionResultIndex()

  6. {

  7. returnView(newFileUploadViewModel());

  8. }

  9. }

正 如你所看见的,Index 行为方法附上了 HeaderFooterFilter 和 AdminFilter 属性。HeaderFooterFilter 确保了正确了页眉和页脚数据传输到 ViewModel,AdminFilter 限制了 Non-Admin 用户访问行为方法。

第三步:创建上传视图

为上述行为方法创建一个视图。

需要注意的是,视图的名称应该为 Index.cshtml,并且应该放置在「~/Views/BulkUpload」文件夹下。

第四步:设计上传视图

在视图中放置如下内容。

  1. @usingWebApplication1.ViewModels

  2. @modelFileUploadViewModel

  3. @{

  4. Layout="~/Views/Shared/MyLayout.cshtml";

  5. }


  6. @sectionTitleSection{

  7. BulkUpload

  8. }

  9. @sectionContentBody{

  10. <a href="/Employee/Index">Backa>

  11. <form action="/BulkUpload/Upload" method="post" enctype="multipart/form-data">

  12. SelectFile:<input type="file" name="fileUpload" value=""/>

  13. <input type="submit" name="name" value="Upload"/>

  14. form>

  15. div>

  16. }

正如你所看见的,在 FileUploadViewModel 中,属性的名称和 input[type="file"] 的名称是一样的,都是「FileUpload」。我们在 Model Binder 实验中已经讲述了名称属性的重要性。

注意:在 Form 标签中,有一个额外的指定加密属性,我们将会在实验结尾处讨论它。

第五步:创建业务层上传方法

在 EmployeeBusinessLayer 中创建一个新的方法,命名为 UploadEmployees。

  1. publicvoidUploadEmployees(List<Employee> employees)

  2. {

  3. SalesERPDAL salesDal =newSalesERPDAL();

  4. salesDal.Employees.AddRange(employees);

  5. salesDal.SaveChanges();

  6. }

第六步:创建上传行为方法

在 BulkUploadController 中创建一个新的行为方法,命名为 Upload。

  1. [AdminFilter]

  2. publicActionResultUpload(FileUploadViewModel model)

  3. {

  4. List<Employee> employees =GetEmployees(model);

  5. EmployeeBusinessLayer bal =newEmployeeBusinessLayer();

  6. bal.UploadEmployees(employees);

  7. returnRedirectToAction("Index","Employee");

  8. }


  9. privateList<Employee>GetEmployees(FileUploadViewModel model)

  10. {

  11. List<Employee> employees =newList<Employee>();

  12. StreamReader csvreader =newStreamReader(model.fileUpload.InputStream);

  13. csvreader.ReadLine();// Assuming first line is header

  14. while(!csvreader.EndOfStream)

  15. {

  16. var line = csvreader.ReadLine();

  17. var values = line.Split(',');//Values are comma separated

  18. Employee e =newEmployee();

  19. e.FirstName= values[0];

  20. e.LastName= values[1];

  21. e.Salary=int.Parse(values[2]);

  22. employees.Add(e);

  23. }

  24. return employees;

  25. }

在 Upload 中附上 AdminFilter 是用于限制 Non-Admin 用户访问。

第七步:为 BulkUpload 创建链接

在「Views/Employee」文件夹下打开 AddNewLink.cshtml 文件,为 BulkUpload 附上链接。

  1. href="/Employee/AddNew">Add New

  2.  

  3.  

  4. href="/BulkUpload/Index">BulkUpload

第八步:执行并测试

为测试创建一个简单的文件

创建一个简单的文件如下,然后将其保存在电脑中。

执行并测试

按下 F5,然后执行应用。完成登录操作,然后通过点击链接导航到 BulkUpload 选项。

选择一个文件,然后点击上传。

注意:在上述的例子中,我们没有在视图中用到任何客户端或者服务器端的认证。它也许会导致如下的错误。

「Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.」

为了发现这个错误的确切原因,只需要在异常发生的时候添加如下的表达式。

((System.Data.Entity.Validation.DbEntityValidationException)$exception).EntityValidationErrors。

表达式「$exception」呈现了任何从当前上下文中抛出的错误,即使它没有被捕获或者支配到一个变量中。

Lab 27 的 Q&A

为什么我们没有在这里用到认证?

为选项增加客户端和服务器端的认证将会留给读者完成,我在这里给出一些暗示。

  • 运用 Data Annotations 来进行服务器端的认证。

  • 你可以运用 Data Annotations 或者实现 JQuery Unobtrusive Validation 来实现客户端认证。明显的是,这一次你需要手动设置自定义数据属性,因为我们没有为文件输入创建 HtmlHelper 方法。

  • 对于客户端的认证,你可以写一些自定义的 JavaScript,然后通过点击安全触发它。这并不是很难,因为文件输入是一个输入控件,值可以通过在 JavaScript 中获取并认证。

什么是HttpPostedFileBase?

HttpPostedFileBase 可以通过客户端提供文件上传的访问接口。Model Binder 将会在发送 Post 请求时更新所有 FileUploadViewModel 类的属性值。现在 FileUploadViewModel 里只有一个属性值,Model Binder 将会通过客户端来设置这个属性值,实现文件上传。

提供多个文件输入控件是否可行?

答案是肯定的。我们可以通过两种方式实现它。

  1. 创 建多个文件输入控件。每一个控件都需要有唯一的名字。在 FileUploadViewModel 类中为每个控件创建一个 HttpPostedFileBase 的类型属性。每一个属性的名称应该与控件的名称相匹配。剩下的工作会由 ModelBinder 来处理。

  2. 创建多个文件输入控件。每一个控件都需要有唯一的名字。这次不是创建多个 HttpPostedFileBase 的属性,而是创建一个类型 List。
    注意:上述的情形对于所有控件都可行。当你拥有多个相同名称的控件时,如果要更新的属性值是一个简单参数,Model Binder 将会更新第一个控件的属性值。如果更新的属性值是一个 List,Model Binder 会将每一个属性值设置到控件中。

enctype="multipart/form-data"是用于做什么的?

这个对知道与否并不重要,但是知道确实会好一点。

这个属性指定了编码类型,在传输数据时使用。属性的默认值是「application/x-www-form-urlencoded」。

例如,我们的登录表单将会随着 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

当 enctype="multipart/form-data"属性被添加到表单标签时,随着 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. Admin

  11. ------WebKitFormBoundary7hciuLuSNglCR8WC

  12. Content-Disposition: form-data; name="Password"


  13. Admin

  14. ------WebKitFormBoundary7hciuLuSNglCR8WC

  15. Content-Disposition: form-data; name="BtnSubmi"


  16. Login

  17. ------WebKitFormBoundary7hciuLuSNglCR8WC

正如你所看见的,表单以多个部分被发送。每一个部分都通过 Content-Type 被一条边界线所分隔,并且每一个部分都包含一个值。

如果表单标签中包含文件输入控件时,编码类型需要设定为「multipart/form-data」。

注意:每一次请求发生时,边界线会随机生成。你可能会看到不同的边界线。

为什么我们不总是将 EncTyp 设置为「multipart/form-data」?

当 EncTyp 被设置为「multipart/form-data」,它将会做两件事,Post 数据以及上传文件。这就是为什么我们不总是将其设置为「multipart/form-data」。

答案就是,这样会增加请求的总体大小。请求的大小越大,意味着性能越差。因为最佳实践应该是将其设置为默认的值,即「application/x-www-form-urlencoded」。

为什么我们需要创建 ViewModel?

在我们的视图中有一个控件。我们可以通过直接向 HttpPostedFileBase 类型增加一个参数来实现同样的结果,这里我们需要在上传方法中命名为 「fileUpload」,而不是创建一个单独的 ViewModel。代码如下所示。

  1. publicActionResultUpload(HttpPostedFileBase fileUpload)

  2. {

  3. }

创建 ViewModel 是最佳实践。Controller 应该总是向视图发送以 ViewModel 为格式的数据,并且来自视图的数据应该以 ViewModel 发送给 Controller。

2. 上述解决方案的问题

你是否想知道,当你发送一个请求时,如何获得响应的?

现在不要去说,是通过行为方法接到请求然后怎样怎样的。尽管这是正确的答案,我仍然期望一些不同的答案。我的问题是在最开始的时候发生了什么。

一个简单的编程规则,程序中所有都通过线程执行,尽管是请求。

在 Web 服务器上的 ASP.NET,.NET Framework 维护着线程池。每一次请求发送到 Web 服务器上时,就会把一个线程池中一个空闲的线程分配给服务器,用于处理请求。这个线程被称为 Worker 线程。

Worker 线程在请求正常处理的过程中处于阻塞状态,并且不能处理其它请求。

现 在来假设一种场景,一个应用接收到了很多请求,并且每个请求都会花费许多时间来处理进程。在这种情形下,没有 Worker 线程可用于服务器请求,所以当新的请求想要获取该线程进行处理状态时,我们可能需要在这时候终止它。这个我们称之为 Thread Starvation(线程饥饿)。

在我们的例子样本文件中,只存在了两个雇员记录,而在真实场景中,可能存在成千上万的记录,这意味着请求也许会花费大量时间来完成进程。这样会导致线程饥饿。

解决方案

迄今为止我们所讨论的请求都是同步请求类型。

如果客户端发出的是异步请求,而不是同步请求,那么线程饥饿的问题就解决了。

  • 在异步请求的情形下,请求将会从线程池分配中获得通常的 Worker 线程,用于服务请求。

  • Worker 线程将会初始化异步操作,然后返回线程池来服务其它请求。异步操作将会继续被 CLR 线程处理。

  • 现在的问题是,CLR 线程不能返回响应,所以一旦当完成异步操作后,它就会通知 ASP.NET。

  • Web 服务器将会再一次从线程池中得到 Worker 线程,用于处理剩余的请求和响应。

在上述的完整的场景中,两个 Worker 线程从线程池中获取。这两个 Worker 线程也许是同一个,也许不是。

在我们的例子中,文件读取是通过 I/O 操作的,这个操作不需要 Worker 线程来处理。所以最好是将同步请求转换为异步请求。

异步请求会提升响应时间吗?

答案是否定的。响应时间是相同的。这里线程将会被释放,用于服务其它请求。

3. Lab 28 — 解决线程饥饿问题

在 ASP.NET MVC 中,我们可以通过转换同步行为方法到异步行为方法,来将同步请求转换为异步请求。

第一步:创建异步控制器

将 UploadController 的基类改为AsynController。

  1. publicclassBulkUploadController:AsyncController

  2. {

第二步:转换同步行为方法到异步行为方法

通过关键字,「async」和「await」,可以很容易做这件事。

  1. [AdminFilter]

  2. public async Task<ActionResult>Upload(FileUploadViewModel model)

  3. {

  4. int t1 =Thread.CurrentThread.ManagedThreadId;

  5. List<Employee> employees = await Task.Factory.StartNew<List<Employee>>

  6. (()=>GetEmployees(model));

  7. int t2 =Thread.CurrentThread.ManagedThreadId;

  8. EmployeeBusinessLayer bal =newEmployeeBusinessLayer();

  9. bal.UploadEmployees(employees);

  10. returnRedirectToAction("Index","Employee");

  11. }

正如你所看见的,我们在行为方法的开始和结束的地方将线程 ID 存储在变量中。

现在让我理解下代码。

  • 当客户端点击上传按钮时,一个新的请求将被发送到服务器。

  • Webserver 从线程池中获取一个 Worker 线程,然后将其分配给请求用于服务。

  • Worker 线程使得行为方法用于执行。

  • Worker 方法通过 Task.Factory.StartNew 方法执行异步操作。

  • 正如你所看见的,行为方法通过关键字 Async被标记为异步的,这将会确保一旦异步方法操作开始执行,Worker 线程就会得到释放。这个时候逻辑的异步操作将会通过独立的 CLR 线程继续在后台执行。

  • 现在异步操作调用将被标记为 Await 关键字。这将会确保接下来的代码行不会被执行,除非异步操作完成。

  • 一旦异步操作完成了,接下来的行为方法中的代码就需要被执行。因此又要需要一个 Worker 线程。因此 Webserver 将会从线程池中取出一个空闲线程,然后将其分配给剩余的请求用于服务,并返回响应。

第三步:执行并测试

执行应用。导航到 BulkUpload 选项。

在你做任何操作之前,先导航到代码,然后在最后一行代码中打个断点。

现在选择一个简单的文件,然后点击 Upload。

正如你所看见的,在方法的开始和结束时,线程 ID 是不同的。输出的结果和之前的实验结果一样。

4. Lab 29 — 异常处理 — 呈现自定义错误页面

如果一个项目没有正确的异常处理,就不能算是一个完整的项目。

迄今为止,我们讨论过 ASP.NET MVC 中的两个过滤器,即 Action 过滤器和 Authentication 过滤器。现在是时候讨论第三个过滤器了,即 Exception 过滤器。

什么是 Exception 过滤器?

Exception 过滤器的使用方式同其它过滤器一样。我们将以属性的方式运用。

运用 Exception 过滤器的步骤。

  • 使它们可用

  • 将它们作为行为方法或者控制器的属性。我们也可以将它们应用到 Global 级别。

它们是用来做什么的?

一旦在行为方法内部发生异常时,Exception 过滤器就将会控制执行并开始自动执行其内部的代码。

是否存在自动的 Exception 过滤器?

ASP.NET MVC 提供给我们一个已经编写好的 Exception 过滤器,称作 HandleError。

正 如我们之前所说的,当行为方法中,一旦异常发生,过滤器就将被执行。这个过滤器将会在「~/Views/[current controller]」或者「~/Views/Shared」文件夹内发现一个名称为「Error」的视图,为这个视图创建一个 ViewResult,然后返回响应。

让我们看一个 Demo,用于更好地理解。在项目的实验最后,我们将会实现 BulkUpload 选项。现在存在着较高的输入文件的错误可能性。

第一步:创建一个简单的带有错误的 Upload 文件

创建一个简单的上传文件,就像之前一样。但是这次,文件中包含一些非法值。

正如你所看见的,Salary 是非法的。

第二步:执行并测试应用

按下 F5,执行应用。导航到 Bulk Upload 选项,选择上述的文件,然后点击 Upload。

第三步:使异常过滤器可用

自定义异常开启后,异常过滤器也被开启。为了开启自定义异常,打开 Web.config 文件,然后导航到 System.Web 区域,在该区域下增加自定义错误,如下所示。

  1. mode="On">

第四步:创建错误视图

在「~Views/Shared」文件夹下,可以看到一个文件,即「Error.cshtml」。这个文件作为 MVC 样本文件的一部分在开始的时候被创建。如果没有被创建,就手动创建。

  1. @{

  2. Layout=null;

  3. }


  4. DOCTYPE html>

  5. <meta name="viewport" content="width=device-width"/>

  6. </span><span class="typ">Error</span><span class="pun"></</span><span class="pln">title</span><span class="pun">></span></code></p></li> <li><p><code><span class="pun"></</span><span class="pln">head</span><span class="pun">></span></code></p></li> <li><p><code><span class="str"><body></span></code></p></li> <li><p><code><span class="str"><hgroup></span></code></p></li> <li><p><code><span class="str"><h1></span><span class="typ">Error</span><span class="pun">.</</span><span class="pln">h1</span><span class="pun">></span></code></p></li> <li><p><code><span class="str"><h2></span><span class="typ">An</span><span class="pln"> error occurred </span><span class="kwd">while</span><span class="pln"> processing your request</span><span class="pun">.</</span><span class="pln">h2</span><span class="pun">></span></code></p></li> <li><p><code><span class="pun"></</span><span class="pln">hgroup</span><span class="pun">></span></code></p></li> <li><p><code><span class="pun"></</span><span class="pln">body</span><span class="pun">></span></code></p></li> <li><p><code><span class="pun"></</span><span class="pln">html</span><span class="pun">></span></code></p></li> </ol> <p><strong>第五步:附上 Exception 过滤器</strong></p> <p>正如我们之前所讨论的,一旦我们使异常过滤器可用,我们将会把它绑定到一个行为方法或者控制器中。</p> <p>好的消息是我们无需手动附上过滤器。</p> <p>在 App_Start 文件夹下打开 FilterConfig.cs 文件。在 RegisterGlobalFilter 方法下,你可以看到 HandleError 过滤器已经被附上 Global 级别。</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="kwd">public</span><span class="kwd">static</span><span class="kwd">void</span><span class="typ">RegisterGlobalFilters</span><span class="pun">(</span><span class="typ">GlobalFilterCollection</span><span class="pln"> filters</span><span class="pun">)</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="pln"> filters</span><span class="pun">.</span><span class="typ">Add</span><span class="pun">(</span><span class="kwd">new</span><span class="typ">HandleErrorAttribute</span><span class="pun">());</span><span class="com">//ExceptionFilter</span></code></p></li> <li><p><code><span class="pln"> filters</span><span class="pun">.</span><span class="typ">Add</span><span class="pun">(</span><span class="kwd">new</span><span class="typ">AuthorizeAttribute</span><span class="pun">());</span></code></p></li> <li><p><code><span class="pun">}</span></code></p></li> </ol> <p>如果需要移除 Global 过滤器,将会被附上方法或者控制器级别。</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="pun">[</span><span class="typ">AdminFilter</span><span class="pun">]</span></code></p></li> <li><p><code><span class="pun">[</span><span class="typ">HandleError</span><span class="pun">]</span></code></p></li> <li><p><code><span class="kwd">public</span><span class="pln"> async </span><span class="typ">Task</span><span class="pun"><</span><span class="typ">ActionResult</span><span class="pun">></span><span class="typ">Upload</span><span class="pun">(</span><span class="typ">FileUploadViewModel</span><span class="pln"> model</span><span class="pun">)</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> </ol> <p>但是不建议这么做,最好还是应用 Global 级别。</p> <p><strong>第六步:执行并测试</strong></p> <p>像之前的方式一样,让我们来看一下应用的测试结果。</p> <p></p> <p><strong>第七步:在视图中展示错误信息</strong></p> <p>为了达到这个目的,我们需要将错误视图转换为 HandleErrorInfo 类的强类型视图,然后在视图中展示错误信息。</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="lit">@model</span><span class="typ">HandleErrorInfo</span></code></p></li> <li><p><code><span class="pun">@{</span></code></p></li> <li><p><code><span class="typ">Layout</span><span class="pun">=</span><span class="kwd">null</span><span class="pun">;</span></code></p></li> <li><p><code><span class="pun">}</span></code></p></li> <li><p><br></p></li> <li><p><code><span class="pun"><!</span><span class="pln">DOCTYPE html</span><span class="pun">></span></code></p></li> <li><p><code><span class="str"><html></span></code></p></li> <li><p><code><span class="str"><head></span></code></p></li> <li><p><code><span class="pun"><</span><span class="pln">meta name</span><span class="pun">=</span><span class="str">"viewport"</span><span class="pln"> content</span><span class="pun">=</span><span class="str">"width=device-width"</span><span class="pun">/></span></code></p></li> <li><p><code><span class="str"><title></span><span class="typ">Error</span><span class="pun"></</span><span class="pln">title</span><span class="pun">></span></code></p></li> <li><p><code><span class="pun"></</span><span class="pln">head</span><span class="pun">></span></code></p></li> <li><p><code><span class="str"><body></span></code></p></li> <li><p><code><span class="str"><hgroup></span></code></p></li> <li><p><code><span class="str"><h1></span><span class="typ">Error</span><span class="pun">.</</span><span class="pln">h1</span><span class="pun">></span></code></p></li> <li><p><code><span class="str"><h2></span><span class="typ">An</span><span class="pln"> error occurred </span><span class="kwd">while</span><span class="pln"> processing your request</span><span class="pun">.</</span><span class="pln">h2</span><span class="pun">></span></code></p></li> <li><p><code><span class="pun"></</span><span class="pln">hgroup</span><span class="pun">></span></code></p></li> <li><p><code><span class="typ">Error</span><span class="typ">Message</span><span class="pun">:</span><span class="lit">@Model</span><span class="pun">.</span><span class="typ">Exception</span><span class="pun">.</span><span class="typ">Message</span><span class="pun"><</span><span class="pln">br </span><span class="pun">/></span></code></p></li> <li><p><code><span class="typ">Controller</span><span class="pun">:</span><span class="lit">@Model</span><span class="pun">.</span><span class="typ">ControllerName</span><span class="pun"><</span><span class="pln">br </span><span class="pun">/></span></code></p></li> <li><p><code><span class="typ">Action</span><span class="pun">:</span><span class="lit">@Model</span><span class="pun">.</span><span class="typ">ActionName</span></code></p></li> <li><p><code><span class="pun"></</span><span class="pln">body</span><span class="pun">></span></code></p></li> <li><p><code><span class="pun"></</span><span class="pln">html</span><span class="pun">></span></code></p></li> </ol> <p><strong>第八步:执行并测试</strong></p> <p>这次测试结果,我们将会得到如下的错误视图。</p> <p></p> <p><strong>我们是否错失了什么?</strong></p> <p>Handle Error 属性确保了无论何时行为方法发生异常时,自定义视图都会被呈现。但是仅限于控制器和行为方法。它不会处理「Resource not found」错误。</p> <p>执行应用,输入一些古怪的 URL。</p> <p></p> <p><strong>第九步:创建 ErrorController</strong></p> <p>在 Controller 文件夹下创建一个名为 ErrorController 的控制器,然后创建一个行为方法,命名为 Index。</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="kwd">public</span><span class="kwd">class</span><span class="typ">ErrorController</span><span class="pun">:</span><span class="typ">Controller</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="com">// GET: Error</span></code></p></li> <li><p><code><span class="kwd">public</span><span class="typ">ActionResult</span><span class="typ">Index</span><span class="pun">()</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="typ">Exception</span><span class="pln"> e</span><span class="pun">=</span><span class="kwd">new</span><span class="typ">Exception</span><span class="pun">(</span><span class="str">"Invalid Controller or/and Action Name"</span><span class="pun">);</span></code></p></li> <li><p><code><span class="typ">HandleErrorInfo</span><span class="pln"> eInfo </span><span class="pun">=</span><span class="kwd">new</span><span class="typ">HandleErrorInfo</span><span class="pun">(</span><span class="pln">e</span><span class="pun">,</span><span class="str">"Unknown"</span><span class="pun">,</span><span class="str">"Unknown"</span><span class="pun">);</span></code></p></li> <li><p><code><span class="kwd">return</span><span class="typ">View</span><span class="pun">(</span><span class="str">"Error"</span><span class="pun">,</span><span class="pln"> eInfo</span><span class="pun">);</span></code></p></li> <li><p><code><span class="pun">}</span></code></p></li> <li><p><code><span class="pun">}</span></code></p></li> </ol> <p>HandleErrorInfo 控制器拥有三个参数,即异常对象,控制器名称和行为方法名称。</p> <p><strong>第十步:在非法的 URL 中呈现自定义错误视图</strong></p> <p>在 Web.config 中设定「Resource not found error」定义。</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="tag"><system.web></span></code></p></li> <li><p><code><span class="tag"><customErrors</span><span class="atn">mode</span><span class="pun">=</span><span class="atv">"On"</span><span class="tag">></span></code></p></li> <li><p><code><span class="tag"><error</span><span class="atn">statusCode</span><span class="pun">=</span><span class="atv">"404"</span><span class="atn">redirect</span><span class="pun">=</span><span class="atv">"~/Error/Index"</span><span class="tag">/></span></code></p></li> <li><p><code><span class="tag"></customErrors></span></code></p></li> </ol> <p><strong>第十一步:使所有人可访问 ErrorController</strong></p> <p>在 ErrorController 中应用 AllowAnonymous 属性,Index 方法不应该被绑定到一个有权限的用户。因为用户可能在登录前就输入了非法的 URL。</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="pun">[</span><span class="typ">AllowAnonymous</span><span class="pun">]</span></code></p></li> <li><p><code><span class="kwd">public</span><span class="kwd">class</span><span class="typ">ErrorController</span><span class="pun">:</span><span class="typ">Controller</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> </ol> <p><strong>第十二步:执行并测试</strong></p> <p>执行应用程序,然后在浏览器地址栏输入一些非法的 URL。</p> <p></p> <h3>Lab 29 的 Q&A</h3> <p><strong>可以改变视图的名称吗?</strong></p> <p>答案是肯定的,保持视图名称为「Error」不是总是必须的。</p> <p>在这种情形下,当附上 HandleError 过滤器时,我们需要指定视图的名称。</p> <pre>[HandleError(View="MyError")]</pre> <p>或者是</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="pln">filters</span><span class="pun">.</span><span class="typ">Add</span><span class="pun">(</span><span class="kwd">new</span><span class="typ">HandleErrorAttribute</span><span class="pun">()</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="typ">View</span><span class="pun">=</span><span class="str">"MyError"</span></code></p></li> <li><p><code><span class="pun">});</span></code></p></li> </ol> <p><strong>对于不同的异常,获取不同的错误视图,是否可行?</strong></p> <p>答案是肯定的,这是可行的。在这种情形下,我们需要应用 Handle Error 过滤器多次。</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="pun">[</span><span class="typ">HandleError</span><span class="pun">(</span><span class="typ">View</span><span class="pun">=</span><span class="str">"DivideError"</span><span class="pun">,</span><span class="typ">ExceptionType</span><span class="pun">=</span><span class="kwd">typeof</span><span class="pun">(</span><span class="typ">DivideByZeroException</span><span class="pun">))]</span></code></p></li> <li><p><code><span class="pun">[</span><span class="typ">HandleError</span><span class="pun">(</span><span class="typ">View</span><span class="pun">=</span><span class="str">"NotFiniteError"</span><span class="pun">,</span><span class="typ">ExceptionType</span><span class="pun">=</span><span class="kwd">typeof</span><span class="pun">(</span><span class="typ">NotFiniteNumberException</span><span class="pun">))]</span></code></p></li> <li><p><code><span class="pun">[</span><span class="typ">HandleError</span><span class="pun">]</span></code></p></li> </ol> <p>或者是</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="pln">filters</span><span class="pun">.</span><span class="typ">Add</span><span class="pun">(</span><span class="kwd">new</span><span class="typ">HandleErrorAttribute</span><span class="pun">()</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="typ">ExceptionType</span><span class="pun">=</span><span class="kwd">typeof</span><span class="pun">(</span><span class="typ">DivideByZeroException</span><span class="pun">),</span></code></p></li> <li><p><code><span class="typ">View</span><span class="pun">=</span><span class="str">"DivideError"</span></code></p></li> <li><p><code><span class="pun">});</span></code></p></li> <li><p><code><span class="pln">filters</span><span class="pun">.</span><span class="typ">Add</span><span class="pun">(</span><span class="kwd">new</span><span class="typ">HandleErrorAttribute</span><span class="pun">()</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="typ">ExceptionType</span><span class="pun">=</span><span class="kwd">typeof</span><span class="pun">(</span><span class="typ">NotFiniteNumberException</span><span class="pun">),</span></code></p></li> <li><p><code><span class="typ">View</span><span class="pun">=</span><span class="str">"NotFiniteError"</span></code></p></li> <li><p><code><span class="pun">});</span></code></p></li> <li><p><code><span class="pln">filters</span><span class="pun">.</span><span class="typ">Add</span><span class="pun">(</span><span class="kwd">new</span><span class="typ">HandleErrorAttribute</span><span class="pun">());</span></code></p></li> </ol> <p>在上述的例子中,我们增加了三个 Handle Error 过滤器。前两个为指定的异常,而后一个更加通用一些,它将会为所有其它异常展示错误视图。</p> <h2>5. 理解上述实验的局限</h2> <p>上述实验存在唯一的局限,便是我们没有将异常日志输出。</p> <h2>6. Lab 30 — 异常处理 — 异常日志</h2> <p><strong>第一步:创建 Logger 类</strong></p> <p>在项目的根目录下创建一个新的文件夹,称为 Logger。</p> <p>在 Logger 文件夹下创建一个类,命名为 FileLogger。</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="kwd">namespace</span><span class="typ">WebApplication1</span><span class="pun">.</span><span class="typ">Logger</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="kwd">public</span><span class="kwd">class</span><span class="typ">FileLogger</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="kwd">public</span><span class="kwd">void</span><span class="typ">LogException</span><span class="pun">(</span><span class="typ">Exception</span><span class="pln"> e</span><span class="pun">)</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="typ">File</span><span class="pun">.</span><span class="typ">WriteAllLines</span><span class="pun">(</span><span class="str">"C://Error//"</span><span class="pun">+</span><span class="typ">DateTime</span><span class="pun">.</span><span class="typ">Now</span><span class="pun">.</span><span class="typ">ToString</span><span class="pun">(</span><span class="str">"dd-MM-yyyy mm hh ss"</span><span class="pun">)+</span><span class="str">".txt"</span><span class="pun">,</span></code></p></li> <li><p><code><span class="kwd">new</span><span class="kwd">string</span><span class="pun">[]</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="str">"Message:"</span><span class="pun">+</span><span class="pln">e</span><span class="pun">.</span><span class="typ">Message</span><span class="pun">,</span></code></p></li> <li><p><code><span class="str">"Stacktrace:"</span><span class="pun">+</span><span class="pln">e</span><span class="pun">.</span><span class="typ">StackTrace</span></code></p></li> <li><p><code><span class="pun">});</span></code></p></li> <li><p><code><span class="pun">}</span></code></p></li> <li><p><code><span class="pun">}</span></code></p></li> <li><p><code><span class="pun">}</span></code></p></li> </ol> <p><strong>第二步:创建 EmployeeExceptionFilter 类</strong></p> <p>在 Filters 文件夹下创建一个新的类,命名为 EmployeeExceptionFilter。</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="kwd">namespace</span><span class="typ">WebApplication1</span><span class="pun">.</span><span class="typ">Filters</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="kwd">public</span><span class="kwd">class</span><span class="typ">EmployeeExceptionFilter</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="pun">}</span></code></p></li> <li><p><code><span class="pun">}</span></code></p></li> </ol> <p><strong>第三步:扩展 Handle Error 用于实现日志记录</strong></p> <p>让 EmployeeExceptionFilter 类继承 HandleErrorAttribute 类,然后重写 OnException 方法。</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="kwd">public</span><span class="kwd">class</span><span class="typ">EmployeeExceptionFilter</span><span class="pun">:</span><span class="typ">HandleErrorAttribute</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="kwd">public</span><span class="kwd">override</span><span class="kwd">void</span><span class="typ">OnException</span><span class="pun">(</span><span class="typ">ExceptionContext</span><span class="pln"> filterContext</span><span class="pun">)</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="kwd">base</span><span class="pun">.</span><span class="typ">OnException</span><span class="pun">(</span><span class="pln">filterContext</span><span class="pun">);</span></code></p></li> <li><p><code><span class="pun">}</span></code></p></li> <li><p><code><span class="pun">}</span></code></p></li> </ol> <p>注意:确保在 HandleErrorAttribute 类中的顶部引用了 System.Web.MVC。</p> <p><strong>第四步:定义 OnException 方法</strong></p> <p>在 OnException 方法中包含异常日志记录代码,如下所示。</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="kwd">public</span><span class="kwd">override</span><span class="kwd">void</span><span class="typ">OnException</span><span class="pun">(</span><span class="typ">ExceptionContext</span><span class="pln"> filterContext</span><span class="pun">)</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="typ">FileLogger</span><span class="pln"> logger </span><span class="pun">=</span><span class="kwd">new</span><span class="typ">FileLogger</span><span class="pun">();</span></code></p></li> <li><p><code><span class="pln"> logger</span><span class="pun">.</span><span class="typ">LogException</span><span class="pun">(</span><span class="pln">filterContext</span><span class="pun">.</span><span class="typ">Exception</span><span class="pun">);</span></code></p></li> <li><p><code><span class="kwd">base</span><span class="pun">.</span><span class="typ">OnException</span><span class="pun">(</span><span class="pln">filterContext</span><span class="pun">);</span></code></p></li> <li><p><code><span class="pun">}</span></code></p></li> </ol> <p><strong>第五步:改变默认的异常过滤器</strong></p> <p>打开 FilterConfig.cs 文件,移除 HandleErrorAttribute,然后附上我们上一步骤中所创建的。</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="kwd">public</span><span class="kwd">static</span><span class="kwd">void</span><span class="typ">RegisterGlobalFilters</span><span class="pun">(</span><span class="typ">GlobalFilterCollection</span><span class="pln"> filters</span><span class="pun">)</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="com">//filters.Add(new HandleErrorAttribute());//ExceptionFilter</span></code></p></li> <li><p><code><span class="pln"> filters</span><span class="pun">.</span><span class="typ">Add</span><span class="pun">(</span><span class="kwd">new</span><span class="typ">EmployeeExceptionFilter</span><span class="pun">());</span></code></p></li> <li><p><code><span class="pln"> filters</span><span class="pun">.</span><span class="typ">Add</span><span class="pun">(</span><span class="kwd">new</span><span class="typ">AuthorizeAttribute</span><span class="pun">());</span></code></p></li> <li><p><code><span class="pun">}</span></code></p></li> </ol> <p><strong>第六步:执行并测试</strong></p> <p>首先在 C 盘下创建一个文件夹,命名为「Error」。这个文件夹会存放错误的日志文件。</p> <p>注意:可以更改路径为你所期望的路径。</p> <p>按下 F5,然后执行应用。导航到 Bulk Upload 选项。选择文件,然后点击 Upload。</p> <p></p> <p>这次的输出将会有所不同,我们将会得到一些错误视图,就像之前一样。唯一的不同便是我们会在「C:\Errors」文件夹发现一些错误日志文件。</p> <p></p> <h3>Lab 30 的 Q&A</h3> <p><strong>异常发生时,错误视图是如何作为响应返回的?</strong></p> <p>在上述实验中,我们重写了 OnException 方法,然后实现了异常日志的功能。现在的问题是,默认的错误处理过滤器是如何继续工作的?答案是简单地,查看 OnException 方法的最后一行代码。</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="kwd">base</span><span class="pun">.</span><span class="typ">OnException</span><span class="pun">(</span><span class="pln">filterContext</span><span class="pun">);</span></code></p></li> </ol> <p>这意味着,基类 OnException 将会做剩余的工作,基类 OnException 将会返回错误视图的 ViewResult。</p> <p><strong>在 OnException 中,我们可以返回其它结果吗?</strong></p> <p>答案是肯定的,查看如下代码。</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="kwd">public</span><span class="kwd">override</span><span class="kwd">void</span><span class="typ">OnException</span><span class="pun">(</span><span class="typ">ExceptionContext</span><span class="pln"> filterContext</span><span class="pun">)</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="typ">FileLogger</span><span class="pln"> logger </span><span class="pun">=</span><span class="kwd">new</span><span class="typ">FileLogger</span><span class="pun">();</span></code></p></li> <li><p><code><span class="pln"> logger</span><span class="pun">.</span><span class="typ">LogException</span><span class="pun">(</span><span class="pln">filterContext</span><span class="pun">.</span><span class="typ">Exception</span><span class="pun">);</span></code></p></li> <li><p><code><span class="com">//base.OnException(filterContext);</span></code></p></li> <li><p><code><span class="pln"> filterContext</span><span class="pun">.</span><span class="typ">ExceptionHandled</span><span class="pun">=</span><span class="kwd">true</span><span class="pun">;</span></code></p></li> <li><p><code><span class="pln"> filterContext</span><span class="pun">.</span><span class="typ">Result</span><span class="pun">=</span><span class="kwd">new</span><span class="typ">ContentResult</span><span class="pun">()</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="typ">Content</span><span class="pun">=</span><span class="str">"Sorry for the Error"</span></code></p></li> <li><p><code><span class="pun">};</span></code></p></li> <li><p><code><span class="pun">}</span></code></p></li> </ol> <p>当我们想要返回自定义响应时,首先要做的事便是,通知 MVC 引擎,告知其我们已经手动处理异常了,所以不需要做默认的行为,即不需要呈现默认的错误屏幕。这一切可以通过如下代码来实现。</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="pln">filterContext</span><span class="pun">.</span><span class="typ">ExceptionHandled</span><span class="pun">=</span><span class="kwd">true</span></code></p></li> </ol> <h2>7. 路由</h2> <p>迄今为止我们讨论过许多概念,我们也回答了许多有关 MVC 的问题,但是除了一个基本和重要的概念。</p> <p>「当用户发出请求时,确切发生了什么」?</p> <p>一个很好的答案便是「行为方法的执行」。但是确切的答案是控制器和犯法是如何被一个特定的 URL 请求识别的?</p> <p>当我们开始「实现用户友好的 URLs」的实验时,我们首先需要回答上述的问题。你也许会奇怪为什么这个主题会放置到最后。我故意将其放置到最后,是因为我想让更多的人在理解内部之前,先了解 MVC。</p> <h3>理解 RouteTable</h3> <p>在 ASP.NET MVC 中,存在一个概念,称作 RouteTable。这里存储了应用的 URL 路由。用简单的话说,它承载了一个应用的 URL 模式的集合。</p> <p>默认情况下,一个路由将会作为项目模板的一部分被添加。可以通过 Global.asax 文件查看它。在 Application_Start 中,你将会发现如下的代码。</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="typ">RouteConfig</span><span class="pun">.</span><span class="typ">RegisterRoutes</span><span class="pun">(</span><span class="typ">RouteTable</span><span class="pun">.</span><span class="typ">Routes</span><span class="pun">);</span></code></p></li> </ol> <p>你将会在 App_Start 文件夹下发现 RouteConfig.cs 文件,它包含了如下代码。</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="kwd">namespace</span><span class="typ">WebApplication1</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="kwd">public</span><span class="kwd">class</span><span class="typ">RouteConfig</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="kwd">public</span><span class="kwd">static</span><span class="kwd">void</span><span class="typ">RegisterRoutes</span><span class="pun">(</span><span class="typ">RouteCollection</span><span class="pln"> routes</span><span class="pun">)</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="pln"> routes</span><span class="pun">.</span><span class="typ">IgnoreRoute</span><span class="pun">(</span><span class="str">"{resource}.axd/{*pathInfo}"</span><span class="pun">);</span></code></p></li> <li><p><br></p></li> <li><p><code><span class="pln"> routes</span><span class="pun">.</span><span class="typ">MapRoute</span><span class="pun">(</span></code></p></li> <li><p><code><span class="pln"> name</span><span class="pun">:</span><span class="str">"Default"</span><span class="pun">,</span></code></p></li> <li><p><code><span class="pln"> url</span><span class="pun">:</span><span class="str">"{controller}/{action}/{id}"</span><span class="pun">,</span></code></p></li> <li><p><code><span class="pln"> defaults</span><span class="pun">:</span><span class="kwd">new</span><span class="pun">{</span><span class="pln"> controller </span><span class="pun">=</span><span class="str">"Home"</span><span class="pun">,</span><span class="pln"> action </span><span class="pun">=</span><span class="str">"Index"</span><span class="pun">,</span><span class="pln"> id </span><span class="pun">=</span><span class="typ">UrlParameter</span><span class="pun">.</span><span class="typ">Optional</span><span class="pun">}</span></code></p></li> <li><p><code><span class="pun">);</span></code></p></li> <li><p><code><span class="pun">}</span></code></p></li> <li><p><code><span class="pun">}</span></code></p></li> <li><p><code><span class="pun">}</span></code></p></li> </ol> <p>正如你所看见的,RegisterRoutes 方法已经通过 Route.MapRoutes 方法定义了一个默认的路由。</p> <p>在 RegisterRoutes 方法中定义的路由将会在 ASP.NET MVC 请求周期中被用到,用于决定执行确切的控制器和方法。</p> <p>如果需要,我们可以通过使用 Route.MapRoutes 函数,创建多个路由。内部定义路由意味着创建 Route 对象。</p> <p>MapRoute 函数也可以把路由对象附上 RouteHandler,这样将会是 MVCRouteHandler。</p> <h3>理解 ASP.NET MVC 请求周期</h3> <p>在我们开始之前,你需要清楚,我们将要 100% 地解释请求周期。我们将要接触到之前未讲到的重要概念。</p> <p><strong>第一步:UrlRoutingModule</strong></p> <p>当终端用户发出请求后,首先会通过 UrlRoutingModule 对象。UrlRoutingModule 是一个 HTTP 模块。</p> <p><strong>第二步:路由</strong></p> <p>UrlRoutingModule 首先会从路由集合中匹配 Route 对象。对于匹配,请求的 URL 将会与路由中定义的 URL 模式相对比。</p> <p>下述的规则将会在匹配中被考虑到。</p> <ul class="list-paddingleft-2"> <li><p>请求 URL 中参数的数字以及在路由中定义的 URL 模式。例如:</p></li> </ul> <p></p> <ul class="list-paddingleft-2"> <li><p>URL 模式中定义的可选参数。例如:</p></li> </ul> <p></p> <ul class="list-paddingleft-2"> <li><p>在参数中定义的静态参数。</p></li> </ul> <p></p> <p><strong>第三步:创建 MVC Route Handler</strong></p> <p>一旦路由对象被选中,UrlRoutingModule 将会从路由对象中获得 MvcRouteHandler。</p> <p><strong>第四步:创建 RouteData 和 RequestContext</strong></p> <p>UrlRoutingModule 对象将会通过 Route 对象创建 RouteData,它将会用于创建 RequestContext。</p> <p>RouteData 封装了关于路由的信息,如控制器的名称,行为方法的名称,路由参数的值。</p> <p><strong>Controller 名称</strong></p> <p>为了从请求 URL 中获得控制器的名称,需要遵循如下的简单规则。即“在 URL 模式中{Controller} 是识别控制器名称的关键词”。</p> <p>例如:</p> <ul class="list-paddingleft-2"> <li><p>当URL 模式是 {Controller}/{Action}/{Id},而请求 URL 是「http://localhost:8870/BulkUpload/Upload/5」时,BulkUpload 是控制器的名称。</p></li> <li><p>当 URL 模式是 {Action}/{Controller}/{Id},而请求 URL 是 「http://localhost:8870/BulkUpload/Upload/5」时,Upload 是控制器的名称。</p></li> </ul> <p><strong>行为方法名称</strong></p> <p>为了获得请求 URL 中的行为方法,需要遵循如下的简单规则。即「在 URL 模式中 {Action} 是行为方法名称的关键词」。</p> <p>例如:</p> <ul class="list-paddingleft-2"> <li><p>当URL 模式是 {Controller}/{Action}/{Id},而请求 URL 是「http://localhost:8870/BulkUpload/Upload/5」时,Upload 是行为方法的名称。</p></li> <li><p>当 URL 模式是 {Action}/{Controller}/{Id},而请求 URL 是 「http://localhost:8870/BulkUpload/Upload/5」时,BulkUpload 是行为方法的名称。</p></li> </ul> <p><strong>路由参数</strong></p> <p>一个基本的 URL 模式包含如下四个要素。</p> <ol class="list-paddingleft-2"> <li><p>{Controller},用于识别控制器名称。</p></li> <li><p>{Action},识别行为方法名称。</p></li> <li><p>一些字符串,例如「MyCompany/{Controller}/{Action}」,在这个模式中,「MyCompany」是一个必须的字符串。</p></li> <li><p>{Something},例如「{Controller}/{Action}/{Id}」,在这个模式中「Id」是路由参数。在请求的 URL 中,路由参数可以被用于获取 URL 的值。</p></li> </ol> <p>我们来看一下如下示例。</p> <p>路由模式是 {Controller}/{Action}/{Id}。</p> <p>请求 URL 是「http://localhost:8870/BulkUpload/Upload/5」。</p> <p><strong>测试一:</strong></p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="kwd">public</span><span class="kwd">class</span><span class="typ">BulkUploadController</span><span class="pun">:</span><span class="typ">Controller</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="kwd">public</span><span class="typ">ActionResult</span><span class="typ">Upload</span><span class="pun">(</span><span class="kwd">string</span><span class="pln"> id</span><span class="pun">)</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="com">//value of id will be 5 -> string 5</span></code></p></li> <li><p><code><span class="pun">...</span></code></p></li> <li><p><code><span class="pun">}</span></code></p></li> <li><p><code><span class="pun">}</span></code></p></li> </ol> <p><strong>测试二:</strong></p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="kwd">public</span><span class="kwd">class</span><span class="typ">BulkUploadController</span><span class="pun">:</span><span class="typ">Controller</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="kwd">public</span><span class="typ">ActionResult</span><span class="typ">Upload</span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> id</span><span class="pun">)</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="com">//value of id will be 5 -> int 5</span></code></p></li> <li><p><code><span class="pun">...</span></code></p></li> <li><p><code><span class="pun">}</span></code></p></li> <li><p><code><span class="pun">}</span></code></p></li> </ol> <p><strong>测试三:</strong></p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="kwd">public</span><span class="kwd">class</span><span class="typ">BulkUploadController</span><span class="pun">:</span><span class="typ">Controller</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="kwd">public</span><span class="typ">ActionResult</span><span class="typ">Upload</span><span class="pun">(</span><span class="kwd">string</span><span class="typ">MyId</span><span class="pun">)</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="com">//value of MyId will be null</span></code></p></li> <li><p><code><span class="pun">...</span></code></p></li> <li><p><code><span class="pun">}</span></code></p></li> <li><p><code><span class="pun">}</span></code></p></li> </ol> <p><strong>第五步:创建 MVCHandler</strong></p> <p>MvcRouteHandler 将会创建 MVCHandler 的实例,传输 RequestContext 对象。</p> <p><strong>第六步:创建控制器实例</strong></p> <p>MVCHandler 将会通过 ControllerFactory(默认的是 DefaultControllerFactory) 创建控制器实例。</p> <p><strong>第七步:执行方法</strong></p> <p>MVCHandler 将会触发控制器的执行方法。执行方法在控制器基类中被定义。</p> <p><strong>第八步:触发行为方法</strong></p> <p>每一个控制器都与一个 ControllerActionInvoker 对象相关联。在执行方法中,ControllerActionInvoker 触发正确的行为方法。</p> <p><strong>第九步:执行结果</strong></p> <p>行为方法接收到用户的输入,然后准备合适的响应数据,并通过返回一个类型来执行结果。现在返回的结果可能是 ViewResult,可能是 RedirectToRoute 结果或者可能是其它。</p> <p>现在,我相信你已经对路由的概念有了很好的理解,所以让我们通过路由来使得项目的 URLs 更友好吧。</p> <h2>8. Lab 31 — 实现用户友好性的 URLs</h2> <p><strong>第一步:重新定义 RegisterRoutes 方法</strong></p> <p>在 RegisterRoutes 方法中包含额外的路由。</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="kwd">public</span><span class="kwd">static</span><span class="kwd">void</span><span class="typ">RegisterRoutes</span><span class="pun">(</span><span class="typ">RouteCollection</span><span class="pln"> routes</span><span class="pun">)</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="pln"> routes</span><span class="pun">.</span><span class="typ">IgnoreRoute</span><span class="pun">(</span><span class="str">"{resource}.axd/{*pathInfo}"</span><span class="pun">);</span></code></p></li> <li><p><br></p></li> <li><p><code><span class="pln"> routes</span><span class="pun">.</span><span class="typ">MapRoute</span><span class="pun">(</span></code></p></li> <li><p><code><span class="pln"> name</span><span class="pun">:</span><span class="str">"Upload"</span><span class="pun">,</span></code></p></li> <li><p><code><span class="pln"> url</span><span class="pun">:</span><span class="str">"Employee/BulkUpload"</span><span class="pun">,</span></code></p></li> <li><p><code><span class="pln"> defaults</span><span class="pun">:</span><span class="kwd">new</span><span class="pun">{</span><span class="pln"> controller </span><span class="pun">=</span><span class="str">"BulkUpload"</span><span class="pun">,</span><span class="pln"> action </span><span class="pun">=</span><span class="str">"Index"</span><span class="pun">}</span></code></p></li> <li><p><code><span class="pun">);</span></code></p></li> <li><p><br></p></li> <li><p><code><span class="pln"> routes</span><span class="pun">.</span><span class="typ">MapRoute</span><span class="pun">(</span></code></p></li> <li><p><code><span class="pln"> name</span><span class="pun">:</span><span class="str">"Default"</span><span class="pun">,</span></code></p></li> <li><p><code><span class="pln"> url</span><span class="pun">:</span><span class="str">"{controller}/{action}/{id}"</span><span class="pun">,</span></code></p></li> <li><p><code><span class="pln"> defaults</span><span class="pun">:</span><span class="kwd">new</span><span class="pun">{</span><span class="pln"> controller </span><span class="pun">=</span><span class="str">"Home"</span><span class="pun">,</span><span class="pln"> action </span><span class="pun">=</span><span class="str">"Index"</span><span class="pun">,</span><span class="pln"> id </span><span class="pun">=</span><span class="typ">UrlParameter</span><span class="pun">.</span><span class="typ">Optional</span><span class="pun">}</span></code></p></li> <li><p><code><span class="pun">);</span></code></p></li> <li><p><code><span class="pun">}</span></code></p></li> </ol> <p>正如你所看见的,我们现在已经不止定义一个路由了。</p> <p><strong>第二步:更改 URL 引用</strong></p> <p>从「~/Views/Employee」文件夹下打开 AddNewLink.cshtml 文件,然后更改 BulkUpload 链接如下。</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="pun">&</span><span class="pln">nbsp</span><span class="pun">;</span></code></p></li> <li><p><code><span class="pun"><</span><span class="pln">a href</span><span class="pun">=</span><span class="str">"/Employee/BulkUpload"</span><span class="pun">></span><span class="typ">BulkUpload</span><span class="pun"></</span><span class="pln">a</span><span class="pun">></span></code></p></li> </ol> <p><strong>第三步:执行并测试</strong></p> <p>执行应用,将会看到神奇的地方。</p> <p></p> <p>正如你所看见的,URL 不再是“Controller/Action”的形式。它看起来更加用户友好,但是输出是一样的。</p> <p>我建议你定义更多的路由,尝试更多的 URLs。</p> <h3>Lab 31 的 Q&A</h3> <p><strong>之前的 URL 还是否起作用?</strong></p> <p>答案是肯定的,之前的 URL 也会起作用。</p> <p>现在 BulkUploadController 中的 Index 方法可以通过两个 URLs 访问。</p> <ol class="list-paddingleft-2"> <li><p>http://localhost:8870/Employee/BulkUpload<br></p></li> <li><p>http://localhost:8870/BulkUpload/Index<br></p></li> </ol> <p><strong>默认路由中的「Id」是什么?</strong></p> <p>我们之前提到过它。它被称作路由参数。它可以通过 URL 来用于获取值。它是一个可被替换的查询字符串。</p> <p>路由参数和查询字符串的区别是什么?</p> <ul class="list-paddingleft-2"> <li><p>查询字符串有大小限制,然而我们可以定义路由参数的任意数字。</p></li> <li><p>我们不能向查询字符串值添加限制,但是我们可以向路由参数添加限制。</p></li> <li><p>可以设定路由参数的默认值,然而查询字符串的默认值不可设定。</p></li> <li><p>查询字符串使得 URL 凌乱,但是路由参数保持 URL 整洁。</p></li> </ul> <p><strong>如何向路由参数应用限制?</strong></p> <p>可以通过正则表达式来完成这件事。例如,查看如下路由。</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="pln">routes</span><span class="pun">.</span><span class="typ">MapRoute</span><span class="pun">(</span></code></p></li> <li><p><code><span class="str">"MyRoute"</span><span class="pun">,</span></code></p></li> <li><p><code><span class="str">"Employee/{EmpId}"</span><span class="pun">,</span></code></p></li> <li><p><code><span class="kwd">new</span><span class="pun">{</span><span class="pln">controller</span><span class="pun">=</span><span class="str">" Employee "</span><span class="pun">,</span><span class="pln"> action</span><span class="pun">=</span><span class="str">"GetEmployeeById"</span><span class="pun">},</span></code></p></li> <li><p><code><span class="kwd">new</span><span class="pun">{</span><span class="typ">EmpId</span><span class="pun">=</span><span class="pun">@</span><span class="str">"\d+"</span><span class="pun">}</span></code></p></li> <li><p><code><span class="pun">);</span></code></p></li> </ol> <p>行为方法将如下所示。</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="kwd">public</span><span class="typ">ActionResult</span><span class="typ">GetEmployeeById</span><span class="pun">(</span><span class="kwd">int</span><span class="typ">EmpId</span><span class="pun">)</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> <li><p><code><span class="pun">...</span></code></p></li> <li><p><code><span class="pun">}</span></code></p></li> </ol> <p>现在如果用户通过 URL「http://..../Employee/1」 或者 「http://..../Employee/111」来发出请求,行为方法将会得到执行,但是如果用户通过 URL「http://..../Employee/Sukesh」 ,他将会得到「Resource Not Found」的错误。</p> <p><strong>行为方法中的参数名称和路由参数名称需要保持一致吗?</strong></p> <p>从根本上说,路由模式也许包含多个 RouteParameters。为了单独地识别每一个路由参数,需要保持行为方法中的参数名称和路由参数名称一致。</p> <p><strong>定义自定义路由的次序重要吗?</strong></p> <p>答案是肯定的,次序是重要的。UrlRoutingModule 将会匹配第一个路由对象。</p> <p>在上述的实验中,我们已经定义了两个路由。一个是自定义路由,一个是默认路由。现在我们来讨论一种情况,默认路由被首先定义,自定义路由被第二个定义。</p> <p>在 这种情况下,终端用户发起一个请求 URL,即「http://…/Employee/BulkUpload」。在匹配阶段,UrlRoutingModules 将会发现请求的 URL 与默认的路由模式匹配,它将会认为「Employee」是控制器的名称,「BulkUpload」是行为方法的名称。</p> <p>因此次序在定义路由时是非常重要的。大多数通用的路由应该被放置到最后。</p> <p><strong>是否存在更简单的方式来定义行为方法的 URL 模式?</strong></p> <p>我们可以运用基于路由的属性来解决这个问题。让我们来试一下。</p> <p><strong>第一步:使基于路由的属性可用</strong></p> <p>在 RegisterRoutes 方法中的 IgnoreRoute 语句后添加如下代码。</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="pln">routes</span><span class="pun">.</span><span class="typ">IgnoreRoute</span><span class="pun">(</span><span class="str">"{resource}.axd/{*pathInfo}"</span><span class="pun">);</span></code></p></li> <li><p><code><span class="pln">routes</span><span class="pun">.</span><span class="typ">MapMvcAttributeRoutes</span><span class="pun">();</span></code></p></li> <li><p><code><span class="pln">routes</span><span class="pun">.</span><span class="typ">MapRoute</span><span class="pun">(</span></code></p></li> <li><p><code><span class="pun">...</span></code></p></li> </ol> <p><strong>第二步:为行为方法定义路由模式</strong></p> <p>在 EmployeeController 中的 Index 行为方法中附上 Route 属性。</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="pun">[</span><span class="typ">Route</span><span class="pun">(</span><span class="str">"Employee/List"</span><span class="pun">)]</span></code></p></li> <li><p><code><span class="kwd">public</span><span class="typ">ActionResult</span><span class="typ">Index</span><span class="pun">()</span></code></p></li> <li><p><code><span class="pun">{</span></code></p></li> </ol> <p><strong>第三步:执行并测试</strong></p> <p>执行应用程序,然后完成登录操作。</p> <p></p> <p>正如你所看见的,我们拥有相同的输出结果,但是不同的是拥有了更加用户友好性的 URL。</p> <p>我们可以通过基于路由的属性来定义路由参数吗?</p> <p>答案是肯定的,可以查看如下语法。</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="pun">[</span><span class="typ">Route</span><span class="pun">(</span><span class="str">"Employee/List/{id}"</span><span class="pun">)]</span></code></p></li> <li><p><code><span class="pln">publicActionResult </span><span class="typ">Index</span><span class="pun">(</span><span class="kwd">string</span><span class="pln"> id</span><span class="pun">)</span><span class="pun">{</span><span class="pun">...</span><span class="pun">}</span></code></p></li> </ol> <p><strong>在这种情况下的限制呢?</strong></p> <p>这将会变得更加容易。</p> <ol class="linenums list-paddingleft-2"> <li><p><code><span class="pun">[</span><span class="typ">Route</span><span class="pun">(</span><span class="str">"Employee/List/{id:int}"</span><span class="pun">)]</span></code></p></li> </ol> <p>我们可以拥有如下限制。</p> <ol class="list-paddingleft-2"> <li><p>{x:alpha} – 字符串认证</p></li> <li><p>{x:bool} – 布尔认证</p></li> <li><p>{x:datetime} – Date Time 认证</p></li> <li><p>{x:decimal} – Decimal 认证</p></li> <li><p>{x:double} – 64 位 Float 认证</p></li> <li><p>{x:float} – 32 位 Float 认证</p></li> <li><p>{x:guid} – GUID 认证</p></li> <li><p>{x:length(6)} – 长度认证</p></li> <li><p>{x:length(1,20)} – 最小和最大长度认证</p></li> <li><p>{x:long} – 64 位 Int 认证</p></li> <li><p>{x:max(10)} – 最大 Integer 长度认证</p></li> <li><p>{x:maxlength(10)} – 最大长度认证</p></li> <li><p>{x:min(10)} – 最小 Integer 长度认证</p></li> <li><p>{x:minlength(10)} – 最小长度认证</p></li> <li><p>{x:range(10,50)} – 整型 Range 认证</p></li> <li><p>{x:regex(SomeRegularExpression)} – 正则表达式认证</p></li> </ol> <p><strong>在 RegisterRoutes 方法中 IgnoreRoutes 是用于做什么的?</strong></p> <p>当我们不想运用路由做指定扩展时,我们可以运用 IgnoreRoutes。作为 MVC 模板的一部分,如下的代码已经写入 RegisterRoutes 方法中。</p> <pre>routes.IgnoreRoute("{resource}.axd/{*pathInfo}");</pre> <p>这意味着,当终端用户发出一个带有「.axd」扩展的请求时,将不会执行任何路由操作。请求将会直接定位到物理资源。我们也可以定义自己的 IgnoreRoute 语句。</p> <h2>9. 总结</h2> <p>在第 6 天的学习中,我们完成了简单的 MVC 项目。希望你能够享受完成系列学习的乐趣。</p> <p>稍等一下!第 7 天的学习呢?</p> <p>在第 7 天中,我们将会运用 MVC, JQuery 和 Ajax 来创建一个 Single Page 应用。这将会更加有趣,并富有挑战。</p> <p>保持学习的热情吧!</p> <p>原文地址:Learn MVC Project in 7 days<br></p> <p><strong>OneAPM for .NET 能够深入到所有 .NET 应用内部完成应用性能管理和监控,包括代码级别性能问题的可见性、性能瓶颈的快速识别与追溯、真实用户体验监控、服务器监控和端到端的应用性能管理。想阅读更多技术文章,请访问 OneAPM 官方博客。</strong></p> <p><br></p> <p><br></p> <p><br></p> <p><br></p> </div> </div> </div> </div> </div> <!--PC和WAP自适应版--> <div id="SOHUCS" sid="1289429168215367680"></div> <script type="text/javascript" src="/views/front/js/chanyan.js"></script> <!-- 文章页-底部 动态广告位 --> <div class="youdao-fixed-ad" id="detail_ad_bottom"></div> </div> <div class="col-md-3"> <div class="row" id="ad"> <!-- 文章页-右侧1 动态广告位 --> <div id="right-1" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_1"> </div> </div> <!-- 文章页-右侧2 动态广告位 --> <div id="right-2" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_2"></div> </div> <!-- 文章页-右侧3 动态广告位 --> <div id="right-3" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_3"></div> </div> </div> </div> </div> </div> </div> <div class="container"> <h4 class="pt20 mb15 mt0 border-top">你可能感兴趣的:(ASP.NET)</h4> <div id="paradigm-article-related"> <div class="recommend-post mb30"> <ul class="widget-links"> <li><a href="/article/1835288964056051712.htm" title="分享一个基于python的电子书数据采集与可视化分析 hadoop电子书数据分析与推荐系统 spark大数据毕设项目(源码、调试、LW、开题、PPT)" target="_blank">分享一个基于python的电子书数据采集与可视化分析 hadoop电子书数据分析与推荐系统 spark大数据毕设项目(源码、调试、LW、开题、PPT)</a> <span class="text-muted">计算机源码社</span> <a class="tag" taget="_blank" href="/search/Python%E9%A1%B9%E7%9B%AE/1.htm">Python项目</a><a class="tag" taget="_blank" href="/search/%E5%A4%A7%E6%95%B0%E6%8D%AE/1.htm">大数据</a><a class="tag" taget="_blank" href="/search/%E5%A4%A7%E6%95%B0%E6%8D%AE/1.htm">大数据</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/hadoop/1.htm">hadoop</a><a class="tag" taget="_blank" href="/search/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%AF%95%E4%B8%9A%E8%AE%BE%E8%AE%A1%E9%80%89%E9%A2%98/1.htm">计算机毕业设计选题</a><a class="tag" taget="_blank" href="/search/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%AF%95%E4%B8%9A%E8%AE%BE%E8%AE%A1%E6%BA%90%E7%A0%81/1.htm">计算机毕业设计源码</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/1.htm">数据分析</a><a class="tag" taget="_blank" href="/search/spark%E6%AF%95%E8%AE%BE/1.htm">spark毕设</a> <div>作者:计算机源码社个人简介:本人八年开发经验,擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等,大家有这一块的问题可以一起交流!学习资料、程序开发、技术解答、文档报告如需要源码,可以扫取文章下方二维码联系咨询Java项目微信小程序项目Android项目Python项目PHP项目ASP.NET项目Node.js项目选题推荐项目实战|p</div> </li> <li><a href="/article/1835117601345335296.htm" title="通过C# 裁剪PDF页面" target="_blank">通过C# 裁剪PDF页面</a> <span class="text-muted">Eiceblue</span> <a class="tag" taget="_blank" href="/search/C%23/1.htm">C#</a><a class="tag" taget="_blank" href="/search/.NET/1.htm">.NET</a><a class="tag" taget="_blank" href="/search/PDF/1.htm">PDF</a><a class="tag" taget="_blank" href="/search/c%23/1.htm">c#</a><a class="tag" taget="_blank" href="/search/pdf/1.htm">pdf</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/visual/1.htm">visual</a><a class="tag" taget="_blank" href="/search/studio/1.htm">studio</a> <div>在处理PDF文档时,有时需要精确地裁剪页面以适应特定需求,比如去除广告、背景信息或者仅仅是为了简化文档内容。本文将指导如何使用免费.NET控件通过C#实现裁剪PDF页面。免费库FreeSpire.PDFfor.NET支持在.NET(C#,VB.NET,ASP.NET,.NETCore)程序中实现创建、操作、转换和打印PDF文档等操作。可以从以下链接下载产品包后手动添加引用,或者直接通过NuGet安</div> </li> <li><a href="/article/1834725031565946880.htm" title="asp.net core的入门教学" target="_blank">asp.net core的入门教学</a> <span class="text-muted">21软件外包1班-庞兴南</span> <a class="tag" taget="_blank" href="/search/asp.net/1.htm">asp.net</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a> <div>什么是ASP.NETCoreasp.netcore是一个基于HTML和ASP的动态Web开发框架,主要用于web应用程序的开发。它是一个轻量级框架,使用HTML、ASP、CSS、JavaScript等技术。它易于使用和部署,可以快速构建web应用程序。asp.netcore提供了丰富的功能,包括模板引擎、文件解析、数据处理和用户管理等。本文将介绍asp.netcore的主要功能和特点,并提供使用方</div> </li> <li><a href="/article/1834723392780070912.htm" title="6.1 ASP.NET Core Web 入门" target="_blank">6.1 ASP.NET Core Web 入门</a> <span class="text-muted">步、步、为营</span> <a class="tag" taget="_blank" href="/search/.Net/1.htm">.Net</a><a class="tag" taget="_blank" href="/search/Core/1.htm">Core</a><a class="tag" taget="_blank" href="/search/asp.net/1.htm">asp.net</a><a class="tag" taget="_blank" href="/search/mvc/1.htm">mvc</a> <div>6.1ASP.NETCoreWeb入门ASP.NETCore中,严格来讲只有一个Asp.netCoreMVC一个框架,Asp.netCoreMVC既支持基于视图的MVC开发,也支持WebAPI和RazorPages开发。ASP.NETCoreMVC项目在VS2022中,一定选择ASP.NETCoreWeb应用(模型-视图-控制器)项目模板项目中wwwroot文件夹包含图片、JS、CSS等静态文件,</div> </li> <li><a href="/article/1834718975230046208.htm" title="asp.net core 8.0 使用 Autofac ioc 容器 具体实例" target="_blank">asp.net core 8.0 使用 Autofac ioc 容器 具体实例</a> <span class="text-muted">彭小彭~</span> <a class="tag" taget="_blank" href="/search/.net/1.htm">.net</a><a class="tag" taget="_blank" href="/search/core/1.htm">core</a><a class="tag" taget="_blank" href="/search/asp.net/1.htm">asp.net</a> <div>要在ASP.NETCore8.0项目中具体实现使用Autofac作为IOC容器,我们将遵循一个明确的示例,从创建新项目到配置Autofac,并演示如何注册和解析服务。步骤1:创建ASP.NETCore8.0项目首先,使用VisualStudio或命令行工具创建一个新的ASP.NETCoreWeb应用程序。如果使用命令行,可以运行以下命令:dotnetnewwebapp-nAutofacDemocd</div> </li> <li><a href="/article/1834713552166940672.htm" title="探索ASP.NET Core 8.0的奇妙世界" target="_blank">探索ASP.NET Core 8.0的奇妙世界</a> <span class="text-muted">郎凌队Lois</span> <div>探索ASP.NETCore8.0的奇妙世界practical-aspnetcore该项目提供了关于ASP.NETCore实际应用开发的一系列教程和示例,涵盖了从基础知识到高级主题,是一个实用的学习资源库。适合于想要掌握ASP.NETCore技术栈的开发者进行学习和参考。项目地址:https://gitcode.com/gh_mirrors/pr/practical-aspnetcore随着微软的A</div> </li> <li><a href="/article/1834713299648868352.htm" title="探索未来Web开发的精简之道:ASP.NET Core 8.0 Minimal API 示例项目" target="_blank">探索未来Web开发的精简之道:ASP.NET Core 8.0 Minimal API 示例项目</a> <span class="text-muted">尚舰舸Elsie</span> <div>探索未来Web开发的精简之道:ASP.NETCore8.0MinimalAPI示例项目随着微服务和云原生架构的兴起,轻量级API成为了开发社区的新宠。ASP.NETCore8.0MinimalAPIExample正是这样一个项目,它集成了最新技术栈,简化了API开发过程,让开发者能够以最少的代码实现强大的功能。本文将带你深入了解这一开源杰作,揭示其技术魅力,并探索其应用场景。项目介绍ASP.NET</div> </li> <li><a href="/article/1834705109032988672.htm" title="ASP.NET Core 入门教学二十八 linux打包部署" target="_blank">ASP.NET Core 入门教学二十八 linux打包部署</a> <span class="text-muted">充值内卷</span> <a class="tag" taget="_blank" href="/search/asp.net/1.htm">asp.net</a><a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a> <div>在Linux上打包和部署ASP.NETCore应用程序涉及几个步骤。以下是一个详细的指南,帮助你在Linux系统上完成这一过程。1.准备工作确保你的Linux系统已经安装了以下软件:.NETSDK(用于构建应用程序).NETRuntime(用于运行应用程序)Apache或Nginx(作为反向代理服务器)你可以使用以下命令安装.NETSDK和Runtime:sudoaptupdatesudoapti</div> </li> <li><a href="/article/1834617504568274944.htm" title="前后端分离,Asp.net core webapi 如何配置跨域" target="_blank">前后端分离,Asp.net core webapi 如何配置跨域</a> <span class="text-muted">代码掌控者</span> <a class="tag" taget="_blank" href="/search/C%23/1.htm">C#</a><a class="tag" taget="_blank" href="/search/asp.net/1.htm">asp.net</a><a class="tag" taget="_blank" href="/search/core/1.htm">core</a><a class="tag" taget="_blank" href="/search/.net/1.htm">.net</a><a class="tag" taget="_blank" href="/search/core/1.htm">core</a><a class="tag" taget="_blank" href="/search/%E7%BB%8F%E9%AA%8C%E5%88%86%E4%BA%AB/1.htm">经验分享</a><a class="tag" taget="_blank" href="/search/c%23/1.htm">c#</a> <div>前言可以说,前后端分离已经成为当今信息系统项目开发的主流软件架构模式,微服务的出现,让前后端分离发展更是迅速,大量优秀的前端框架如vue.js、react的出现,也让前后端分离趋势加快。所谓的前后端分离软件架构模式,就是指将前端和后端的开发完全分离,后端负责提供API接口和数据处理,而前端通过各种现代的JavaScript技术如AJAX或者Fetch等,来调用后端提供的API接口获取数据,从而构建</div> </li> <li><a href="/article/1834341208298713088.htm" title="探索现代Web API开发的典范:Asp.Net Core Web API N-Tier项目" target="_blank">探索现代Web API开发的典范:Asp.Net Core Web API N-Tier项目</a> <span class="text-muted">苏舰孝Noel</span> <div>探索现代WebAPI开发的典范:Asp.NetCoreWebAPIN-Tier项目aspnetcore.ntier.NETCoreN-TierarchitectureWebApisampleproject.项目地址:https://gitcode.com/gh_mirrors/as/aspnetcore.ntier在寻求高效、可扩展且遵循最佳实践的API开发框架时,Asp.NetCoreWebAP</div> </li> <li><a href="/article/1834341081551040512.htm" title="推荐:ASP.NET Core Web API 模板 —— 强大的启动项目!" target="_blank">推荐:ASP.NET Core Web API 模板 —— 强大的启动项目!</a> <span class="text-muted">戴洵珠Gerald</span> <div>推荐:ASP.NETCoreWebAPI模板——强大的启动项目!aspnetcore-webapi-templateThisprojectisanWebAPIOpen-SourceBoilerplateTemplatethatincludesASP.NETCore5,WebAPIstandards,cleann-tierarchitecture,GraphQLservice,Redis,Mssql</div> </li> <li><a href="/article/1834341082045968384.htm" title="ASP.NET Core N-Tier架构Web API示例项目教程" target="_blank">ASP.NET Core N-Tier架构Web API示例项目教程</a> <span class="text-muted">毛宝锋</span> <div>ASP.NETCoreN-Tier架构WebAPI示例项目教程aspnetcore.ntier.NETCoreN-TierarchitectureWebApisampleproject.项目地址:https://gitcode.com/gh_mirrors/as/aspnetcore.ntier本教程旨在指导您了解并使用从https://github.com/aghayeffemin/aspnet</div> </li> <li><a href="/article/1833864077202518016.htm" title="Whisper 模型在实时语音转录中有哪些具体的应用场景?" target="_blank">Whisper 模型在实时语音转录中有哪些具体的应用场景?</a> <span class="text-muted">借雨醉东风</span> <a class="tag" taget="_blank" href="/search/%E7%83%AD%E7%82%B9%E8%BF%BD%E8%B8%AA/1.htm">热点追踪</a><a class="tag" taget="_blank" href="/search/whisper/1.htm">whisper</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a> <div>关注我,持续分享逻辑思维&管理思维&面试题;可提供大厂面试辅导、及定制化求职/在职/管理/架构辅导;推荐专栏《10天学会使用asp.net编程AI大模型》,目前已完成所有内容。一顿烧烤不到的费用,让人能紧跟时代的浪潮。从普通网站,到公众号、小程序,再到AI大模型网站。干货满满。学成后可接项目赚外快,绝对划算。不仅学会如何编程,还将学会如何将AI技术应用到实际问题中,为您的职业生涯增添一笔宝贵的财富</div> </li> <li><a href="/article/1833671800639287296.htm" title="asp.net core 自定义过滤器 注入的几种方式和实现" target="_blank">asp.net core 自定义过滤器 注入的几种方式和实现</a> <span class="text-muted">彭小彭~</span> <a class="tag" taget="_blank" href="/search/.net/1.htm">.net</a><a class="tag" taget="_blank" href="/search/core/1.htm">core</a><a class="tag" taget="_blank" href="/search/.net/1.htm">.net</a><a class="tag" taget="_blank" href="/search/core/1.htm">core</a> <div>在ASP.NETCore中,过滤器(Filters)是一种在MVC应用程序中运行代码的方法,可以在操作(Actions)执行之前或之后运行。过滤器可以应用于控制器(Controllers)或特定的操作方法。过滤器可以用来实现跨切面的逻辑,比如异常处理、授权、缓存、日志等。有几种类型的过滤器:授权过滤器(Authorizationfilters)资源过滤器(Resourcefilters)操作过滤器</div> </li> <li><a href="/article/1833461897542856704.htm" title="【.NET全栈】ASP.NET开发Web应用——ADO.NET数据访问技术" target="_blank">【.NET全栈】ASP.NET开发Web应用——ADO.NET数据访问技术</a> <span class="text-muted">JosieBook</span> <a class="tag" taget="_blank" href="/search/%23/1.htm">#</a><a class="tag" taget="_blank" href="/search/.NET%E5%85%A8%E6%A0%88/1.htm">.NET全栈</a><a class="tag" taget="_blank" href="/search/.net/1.htm">.net</a><a class="tag" taget="_blank" href="/search/asp.net/1.htm">asp.net</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>文章目录前言一、ADO.NET基础1、ADO.NET架构2、ADO.NET数据提供者二、连接数据库1、SqlConnection数据库连接类2、使用SqlConnectionStringBuilder连接字符串3、关闭和释放连接4、在web.config配置文件中保存连接字符串5、连接池技术三、与数据库交互1、使用SqlCommand操作数据库2、为SqlCommand传递参数3、使用SqlCom</div> </li> <li><a href="/article/1833457728408875008.htm" title="ASP.NET中Response.Redirect的用法(详细)" target="_blank">ASP.NET中Response.Redirect的用法(详细)</a> <span class="text-muted">微微的猪食小窝</span> <a class="tag" taget="_blank" href="/search/asp.net/1.htm">asp.net</a><a class="tag" taget="_blank" href="/search/%E6%9C%8D%E5%8A%A1%E5%99%A8/1.htm">服务器</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>一、Response.Redirect是重定向到新的url。例如:if(!IsPostBack){if(Session["UserId"]==null||Session["UserId"].ToString()==""){Response.Redirect(Oper.GetSysUrl()+"/Default.aspx");//转到主页}******//其他实现代码}二、若想传递参数,只要在url</div> </li> <li><a href="/article/1833448767156744192.htm" title="【.NET全栈】ASP.NET开发Web应用——LINQ技术" target="_blank">【.NET全栈】ASP.NET开发Web应用——LINQ技术</a> <span class="text-muted">JosieBook</span> <a class="tag" taget="_blank" href="/search/%23/1.htm">#</a><a class="tag" taget="_blank" href="/search/.NET%E5%85%A8%E6%A0%88/1.htm">.NET全栈</a><a class="tag" taget="_blank" href="/search/.net/1.htm">.net</a><a class="tag" taget="_blank" href="/search/asp.net/1.htm">asp.net</a><a class="tag" taget="_blank" href="/search/linq/1.htm">linq</a> <div>文章目录一、LINQ基础1、LINQ简介2、延迟执行3、LINQ表达式简介1、基本查询语法2、投影新对象3、过滤和排序4、分组和聚合5、联合查询二、LINQtoDataSet操作内存表1、LINQtoDataSet简介2、类型化DataSet三、LINQtoSQL操作数据库1、数据实体类2、DataContext类介绍3、在ASP.NET中应用LINQtoSQL4、自动生成数据实体类5、生成存储过</div> </li> <li><a href="/article/1833436149876617216.htm" title="ASP.NET Core 开源项目详解与入门指南" target="_blank">ASP.NET Core 开源项目详解与入门指南</a> <span class="text-muted">沈菱嫱Marie</span> <div>ASP.NETCore开源项目详解与入门指南aspnetcoredotnet/aspnetcore:是一个ASP.NETCore应用程序开发框架的官方GitHub仓库,它包含了ASP.NETCore的核心源代码和技术文档。适合用于ASP.NETCore应用程序开发,特别是对于那些需要深入了解ASP.NETCore框架实现和技术的场景。特点是ASP.NETCore官方仓库、核心源代码、技术文档。项目</div> </li> <li><a href="/article/1833377419298435072.htm" title="ASP.NET Core 入门教学二十一 分布式追踪技术" target="_blank">ASP.NET Core 入门教学二十一 分布式追踪技术</a> <span class="text-muted">充值内卷</span> <a class="tag" taget="_blank" href="/search/asp.net/1.htm">asp.net</a><a class="tag" taget="_blank" href="/search/%E5%88%86%E5%B8%83%E5%BC%8F/1.htm">分布式</a> <div>分布式追踪技术在微服务架构中非常重要,它可以帮助开发者理解和监控应用程序在分布式环境中的行为。ASP.NETCore提供了对分布式追踪的原生支持,主要通过OpenTelemetry和ApplicationInsights实现。1.OpenTelemetryOpenTelemetry是一个开源的观测框架,用于生成、收集和导出遥测数据(如追踪、指标和日志)。ASP.NETCore可以通过集成OpenT</div> </li> <li><a href="/article/1833119579698720768.htm" title="Asp.Net 汉字转(拼音)" target="_blank">Asp.Net 汉字转(拼音)</a> <span class="text-muted">素年槿夏</span> <a class="tag" taget="_blank" href="/search/C%23/1.htm">C#</a> <div>1.ChinesConvertSpelling:汉字转拼音类(全拼)1usingSystem;2usingSystem.Data;3usingSystem.Configuration;4usingSystem.Text;56///7///SummarydescriptionforConvertHzToPz_Gb23128///9namespaceCommon10{11publicclassChin</div> </li> <li><a href="/article/1832770613786275840.htm" title="ASP.NET Core消息队列RabbitMQ基础入门实战演练" target="_blank">ASP.NET Core消息队列RabbitMQ基础入门实战演练</a> <span class="text-muted">阿笨NET</span> <a class="tag" taget="_blank" href="/search/%E8%B7%9F%E7%9D%80%E9%98%BF%E7%AC%A8%E4%B8%80%E8%B5%B7%E7%8E%A9NET/1.htm">跟着阿笨一起玩NET</a><a class="tag" taget="_blank" href="/search/ASP.NET/1.htm">ASP.NET</a><a class="tag" taget="_blank" href="/search/Core/1.htm">Core</a><a class="tag" taget="_blank" href="/search/ASP.NET/1.htm">ASP.NET</a><a class="tag" taget="_blank" href="/search/Core%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97/1.htm">Core消息队列</a><a class="tag" taget="_blank" href="/search/ASP.NET/1.htm">ASP.NET</a><a class="tag" taget="_blank" href="/search/Core/1.htm">Core</a><a class="tag" taget="_blank" href="/search/RabbitMQ/1.htm">RabbitMQ</a><a class="tag" taget="_blank" href="/search/.NET/1.htm">.NET</a><a class="tag" taget="_blank" href="/search/Core%E8%A7%86%E9%A2%91%E6%95%99%E7%A8%8B/1.htm">Core视频教程</a><a class="tag" taget="_blank" href="/search/ASP.NET/1.htm">ASP.NET</a><a class="tag" taget="_blank" href="/search/Core%E8%A7%86%E9%A2%91%E8%AF%BE%E7%A8%8B/1.htm">Core视频课程</a> <div>一、课程介绍人生苦短,我用.NETCore!消息队列RabbitMQ大家相比都不陌生,本次分享课程阿笨将给大家分享一下在一般项目中99%都会用到的消息队列MQ的一个实战业务运用场景。本次分享课程不是零基础教学,课程内容的侧重点是讲解的RabbitMQ的最实用、最简单的实战运用场景:Publish/Subscrib(发布/订阅)模式,发送端发送消息,单个接收端接收处理消息。学完本次"是猴子都看的懂的</div> </li> <li><a href="/article/1832768596288303104.htm" title="ASP.NET Core 入门教学十五 异步编程" target="_blank">ASP.NET Core 入门教学十五 异步编程</a> <span class="text-muted">充值内卷</span> <a class="tag" taget="_blank" href="/search/asp.net/1.htm">asp.net</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a> <div>在ASP.NETCore中,异步编程是一种非常重要的技术,它可以提高应用程序的性能和响应能力。本教程将介绍如何在ASP.NETCore中使用异步编程。1.异步编程基础异步编程允许程序在等待某些操作(如I/O操作)完成时继续执行其他任务,而不是阻塞整个线程。这可以显著提高应用程序的性能,特别是在处理大量并发请求时。2.使用async和await在C#中,async和await关键字用于实现异步编程。</div> </li> <li><a href="/article/1832768596707733504.htm" title="ASP.NET Core 入门教学十六 防止常见的Web攻击" target="_blank">ASP.NET Core 入门教学十六 防止常见的Web攻击</a> <span class="text-muted">充值内卷</span> <a class="tag" taget="_blank" href="/search/asp.net/1.htm">asp.net</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a> <div>在ASP.NETCore中,防止常见的Web攻击是非常重要的,以确保应用程序的安全性。以下是一些常见的Web攻击类型及其防范措施:1.跨站脚本攻击(XSS)跨站脚本攻击(XSS)是一种通过在网页中注入恶意脚本来攻击用户的浏览器的技术。为了防止XSS攻击,可以采取以下措施:输入验证:对用户输入进行严格的验证和清理。输出编码:在将用户输入的数据插入到HTML页面中时,进行适当的编码。ASP.NETCo</div> </li> <li><a href="/article/1832759017240358912.htm" title="ASP.NET Core 入门教学八 集成RocketMQ消息队列" target="_blank">ASP.NET Core 入门教学八 集成RocketMQ消息队列</a> <span class="text-muted">充值内卷</span> <a class="tag" taget="_blank" href="/search/asp.net/1.htm">asp.net</a><a class="tag" taget="_blank" href="/search/rocketmq/1.htm">rocketmq</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a> <div>在ASP.NETCore中集成RocketMQ消息队列,你需要遵循以下步骤:1.安装RocketMQ客户端库首先,你需要在你的ASP.NETCore项目中安装RocketMQ的.NET客户端库。你可以使用NuGet包管理器来完成这个任务。在VisualStudio中,右键点击你的项目,选择“管理NuGet程序包”,然后搜索并安装Apache.RocketMQ.Client包。2.配置RocketM</div> </li> <li><a href="/article/1832747422854508544.htm" title="分享一个基于微信小程序的智慧校园服务平台(源码、调试、LW、开题、PPT)" target="_blank">分享一个基于微信小程序的智慧校园服务平台(源码、调试、LW、开题、PPT)</a> <span class="text-muted">计算机源码社</span> <a class="tag" taget="_blank" href="/search/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F/1.htm">微信小程序</a><a class="tag" taget="_blank" href="/search/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F/1.htm">微信小程序</a><a class="tag" taget="_blank" href="/search/%E6%AF%95%E4%B8%9A%E8%AE%BE%E8%AE%A1%E9%A1%B9%E7%9B%AE/1.htm">毕业设计项目</a><a class="tag" taget="_blank" href="/search/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%AF%95%E8%AE%BE%E6%BA%90%E7%A0%81/1.htm">计算机毕设源码</a><a class="tag" taget="_blank" href="/search/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%AF%95%E8%AE%BE/1.htm">计算机毕设</a><a class="tag" taget="_blank" href="/search/%E6%AF%95%E8%AE%BE%E9%80%89%E9%A2%98/1.htm">毕设选题</a><a class="tag" taget="_blank" href="/search/%E8%AF%BE%E7%A8%8B%E8%AE%BE%E8%AE%A1%E6%BA%90%E7%A0%81/1.htm">课程设计源码</a><a class="tag" taget="_blank" href="/search/%E6%AF%95%E4%B8%9A%E8%AE%BE%E8%AE%A1%E7%AD%94%E8%BE%A9/1.htm">毕业设计答辩</a> <div>作者:计算机源码社个人简介:本人八年开发经验,擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等,大家有这一块的问题可以一起交流!学习资料、程序开发、技术解答、文档报告如需要源码,可以扫取文章下方二维码联系咨询Java项目微信小程序项目Android项目Python项目PHP项目ASP.NET项目Node.js项目选题推荐项目实战|基</div> </li> <li><a href="/article/1832527928919945216.htm" title="ASP.NET 整页缓存技术" target="_blank">ASP.NET 整页缓存技术</a> <span class="text-muted">lploveme</span> <a class="tag" taget="_blank" href="/search/asp.net/1.htm">asp.net</a><a class="tag" taget="_blank" href="/search/%E6%B5%8F%E8%A7%88%E5%99%A8/1.htm">浏览器</a><a class="tag" taget="_blank" href="/search/browser/1.htm">browser</a><a class="tag" taget="_blank" href="/search/%E5%BC%95%E6%93%8E/1.htm">引擎</a><a class="tag" taget="_blank" href="/search/vb.net/1.htm">vb.net</a><a class="tag" taget="_blank" href="/search/html/1.htm">html</a> <div>在网上找了好久的整页缓存技术今天终于可以解决我的问题我要求是这样的有AB两个客服机同时访问一个页面信息得到的应该都是缓存以后的信息而不是A得到的是缓存而B不是缓存信息今天找到了好的方式特意贴出来让我常常看整页输出缓存这是一篇很不错的文章来源是http://softbbs.pconline.com.cn/9740011.html要提升ASP.NET应用程序的性能,最简单、最有效的方式就是使用内建的缓</div> </li> <li><a href="/article/1832065026266066944.htm" title="ASP.NET Core 微服务初探[1]:服务发现之Consul" target="_blank">ASP.NET Core 微服务初探[1]:服务发现之Consul</a> <span class="text-muted">weixin_34015336</span> <a class="tag" taget="_blank" href="/search/%E8%BF%90%E7%BB%B4/1.htm">运维</a><a class="tag" taget="_blank" href="/search/ui/1.htm">ui</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/1.htm">数据结构与算法</a> <div>在传统单体架构中,由于应用动态性不强,不会频繁的更新和发布,也不会进行自动伸缩,我们通常将所有的服务地址都直接写在项目的配置文件中,发生变化时,手动改一下配置文件,也不会觉得有什么问题。但是在微服务模式下,服务会更细的拆分解耦,微服务会被频繁的更新和发布,根据负载情况进行动态伸缩,以及受资源调度影响而从一台服务器迁移到另一台服务器等等。总而言之,在微服务架构中,微服务实例的网络位置变化是一种常态,</div> </li> <li><a href="/article/1832062881831677952.htm" title="我眼中的ASP.NET Core之微服务" target="_blank">我眼中的ASP.NET Core之微服务</a> <span class="text-muted">dotNET跨平台</span> <div>前言前几天在博客园看到有园友在分享关于微软的一个微服务架构的示例程序,想必大家都已经知道了,那就是eShopOnContainers。我们先不看项目的后缀名称OnXXX,因为除了OnContainers还有OnAzure,OnWeb,OnKubernetes以及OnServiceFabric。我们就还是来先说说eShop这个项目吧,eShop是ASP.NETCore发布之后微软新开源出来的一个示例</div> </li> <li><a href="/article/1832047127124078592.htm" title="asp.net core 微服务架构搭建" target="_blank">asp.net core 微服务架构搭建</a> <span class="text-muted">战族狼魂</span> <a class="tag" taget="_blank" href="/search/%E5%BE%AE%E6%9C%8D%E5%8A%A1/1.htm">微服务</a><a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84/1.htm">架构</a><a class="tag" taget="_blank" href="/search/asp.net/1.htm">asp.net</a><a class="tag" taget="_blank" href="/search/%E5%BE%AE%E6%9C%8D%E5%8A%A1/1.htm">微服务</a> <div>在ASP.NETCore中实现微服务架构涉及多个步骤,包括服务划分、API网关、服务发现、通信方式、容器化等。以下是一个基本的微服务架构搭建指南。目录1.服务划分2.创建独立的ASP.NETCore服务3.设置API网关4.服务发现5.通信方式6.容器化7.总结1.服务划分首先,需要将你的应用程序划分成多个独立的服务,每个服务专注于单一职责。每个服务都应该是独立的,能够独立开发、部署和扩展。2.创</div> </li> <li><a href="/article/1830770155790102528.htm" title="2024年计算机毕业设计2000个热门选题推荐之NodeJS篇——全行业Java项目定制asp.net代做Python安卓NodeJS等" target="_blank">2024年计算机毕业设计2000个热门选题推荐之NodeJS篇——全行业Java项目定制asp.net代做Python安卓NodeJS等</a> <span class="text-muted">itszkt计算机项目源代码</span> <a class="tag" taget="_blank" href="/search/%E9%A1%B9%E7%9B%AE%E9%80%89%E9%A2%98/1.htm">项目选题</a><a class="tag" taget="_blank" href="/search/%E8%AF%BE%E7%A8%8B%E8%AE%BE%E8%AE%A1/1.htm">课程设计</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>✌精彩专栏推荐订阅以防找不到✌项目界面文字不会改?项目代码不懂?怕老师问?项目没有软件?不会运行?✌选题—项目修改教程—答疑—远程,为客户提供帮助和支持,努力解决问题和推动项目进展✌✌✌选题推荐——以防找不到我们,点击上方订阅专栏✌✌2024年计算机JavaPython安卓APP微信小程序asp.net项目PHP2000+热门选题推荐计算机毕业设计如何选题?计算机毕业设计开题报告如何书写论文的书写</div> </li> <li><a href="/article/14.htm" title="Spring4.1新特性——综述" target="_blank">Spring4.1新特性——综述</a> <span class="text-muted">jinnianshilongnian</span> <a class="tag" taget="_blank" href="/search/spring+4.1/1.htm">spring 4.1</a> <div>目录 Spring4.1新特性——综述 Spring4.1新特性——Spring核心部分及其他 Spring4.1新特性——Spring缓存框架增强 Spring4.1新特性——异步调用和事件机制的异常处理 Spring4.1新特性——数据库集成测试脚本初始化 Spring4.1新特性——Spring MVC增强 Spring4.1新特性——页面自动化测试框架Spring MVC T</div> </li> <li><a href="/article/141.htm" title="Schema与数据类型优化" target="_blank">Schema与数据类型优化</a> <span class="text-muted">annan211</span> <a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/1.htm">数据结构</a><a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a> <div> 目前商城的数据库设计真是一塌糊涂,表堆叠让人不忍直视,无脑的架构师,说了也不听。 在数据库设计之初,就应该仔细揣摩可能会有哪些查询,有没有更复杂的查询,而不是仅仅突出 很表面的业务需求,这样做会让你的数据库性能成倍提高,当然,丑陋的架构师是不会这样去考虑问题的。 选择优化的数据类型 1 更小的通常更好 更小的数据类型通常更快,因为他们占用更少的磁盘、内存和cpu缓存,</div> </li> <li><a href="/article/268.htm" title="第一节 HTML概要学习" target="_blank">第一节 HTML概要学习</a> <span class="text-muted">chenke</span> <a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/Web/1.htm">Web</a><a class="tag" taget="_blank" href="/search/css/1.htm">css</a> <div>第一节 HTML概要学习 1. 什么是HTML HTML是英文Hyper Text Mark-up Language(超文本标记语言)的缩写,它规定了自己的语法规则,用来表示比“文本”更丰富的意义,比如图片,表格,链接等。浏览器(IE,FireFox等)软件知道HTML语言的语法,可以用来查看HTML文档。目前互联网上的绝大部分网页都是使用HTML编写的。 打开记事本 输入一下内</div> </li> <li><a href="/article/395.htm" title="MyEclipse里部分习惯的更改" target="_blank">MyEclipse里部分习惯的更改</a> <span class="text-muted">Array_06</span> <a class="tag" taget="_blank" href="/search/eclipse/1.htm">eclipse</a> <div>继续补充中---------------------- 1.更改自己合适快捷键windows-->prefences-->java-->editor-->Content Assist-->      Activation triggers for java的右侧“.”就可以改变常用的快捷键 选中 Text </div> </li> <li><a href="/article/522.htm" title="近一个月的面试总结" target="_blank">近一个月的面试总结</a> <span class="text-muted">cugfy</span> <a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a> <div>本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/46753275 前言       打算换个工作,近一个月面试了不少的公司,下面将一些面试经验和思考分享给大家。另外校招也快要开始了,为在校的学生提供一些经验供参考,希望都能找到满意的工作。 </div> </li> <li><a href="/article/649.htm" title="HTML5一个小迷宫游戏" target="_blank">HTML5一个小迷宫游戏</a> <span class="text-muted">357029540</span> <a class="tag" taget="_blank" href="/search/html5/1.htm">html5</a> <div>     通过《HTML5游戏开发》摘抄了一个小迷宫游戏,感觉还不错,可以画画,写字,把摘抄的代码放上来分享下,喜欢的同学可以拿来玩玩! <html> <head> <title>创建运行迷宫</title> <script type="text/javascript"</div> </li> <li><a href="/article/776.htm" title="10步教你上传githib数据" target="_blank">10步教你上传githib数据</a> <span class="text-muted">张亚雄</span> <a class="tag" taget="_blank" href="/search/git/1.htm">git</a> <div>官方的教学还有其他博客里教的都是给懂的人说得,对已我们这样对我大菜鸟只能这么来锻炼,下面先不玩什么深奥的,先暂时用着10步干净利索。等玩顺溜了再用其他的方法。 操作过程(查看本目录下有哪些文件NO.1)ls (跳转到子目录NO.2)cd+空格+目录 (继续NO.3)ls (匹配到子目录NO.4)cd+ 目录首写字母+tab键+(首写字母“直到你所用文件根就不再按TAB键了”) (查看文件</div> </li> <li><a href="/article/903.htm" title="MongoDB常用操作命令大全" target="_blank">MongoDB常用操作命令大全</a> <span class="text-muted">adminjun</span> <a class="tag" taget="_blank" href="/search/mongodb/1.htm">mongodb</a><a class="tag" taget="_blank" href="/search/%E6%93%8D%E4%BD%9C%E5%91%BD%E4%BB%A4/1.htm">操作命令</a> <div>成功启动MongoDB后,再打开一个命令行窗口输入mongo,就可以进行数据库的一些操作。输入help可以看到基本操作命令,只是MongoDB没有创建数据库的命令,但有类似的命令 如:如果你想创建一个“myTest”的数据库,先运行use myTest命令,之后就做一些操作(如:db.createCollection('user')),这样就可以创建一个名叫“myTest”的数据库。 一</div> </li> <li><a href="/article/1030.htm" title="bat调用jar包并传入多个参数" target="_blank">bat调用jar包并传入多个参数</a> <span class="text-muted">aijuans</span> <div>下面的主程序是通过eclipse写的: 1.在Main函数接收bat文件传递的参数(String[] args)  如:   String ip =args[0];          String user=args[1];       &nbs</div> </li> <li><a href="/article/1157.htm" title="Java中对类的主动引用和被动引用" target="_blank">Java中对类的主动引用和被动引用</a> <span class="text-muted">ayaoxinchao</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E4%B8%BB%E5%8A%A8%E5%BC%95%E7%94%A8/1.htm">主动引用</a><a class="tag" taget="_blank" href="/search/%E5%AF%B9%E7%B1%BB%E7%9A%84%E5%BC%95%E7%94%A8/1.htm">对类的引用</a><a class="tag" taget="_blank" href="/search/%E8%A2%AB%E5%8A%A8%E5%BC%95%E7%94%A8/1.htm">被动引用</a><a class="tag" taget="_blank" href="/search/%E7%B1%BB%E5%88%9D%E5%A7%8B%E5%8C%96/1.htm">类初始化</a> <div>  在Java代码中,有些类看上去初始化了,但其实没有。例如定义一定长度某一类型的数组,看上去数组中所有的元素已经被初始化,实际上一个都没有。对于类的初始化,虚拟机规范严格规定了只有对该类进行主动引用时,才会触发。而除此之外的所有引用方式称之为对类的被动引用,不会触发类的初始化。虚拟机规范严格地规定了有且仅有四种情况是对类的主动引用,即必须立即对类进行初始化。四种情况如下:1.遇到ne</div> </li> <li><a href="/article/1284.htm" title="导出数据库 提示 outfile disabled" target="_blank">导出数据库 提示 outfile disabled</a> <span class="text-muted">BigBird2012</span> <a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a> <div>在windows控制台下,登陆mysql,备份数据库:   mysql>mysqldump -u root -p test test > D:\test.sql 使用命令 mysqldump 格式如下: mysqldump -u root -p *** DBNAME > E:\\test.sql。 注意:执行该命令的时候不要进入mysql的控制台再使用,这样会报</div> </li> <li><a href="/article/1411.htm" title="Javascript 中的 && 和 ||" target="_blank">Javascript 中的 && 和 ||</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/%26%26/1.htm">&&</a><a class="tag" taget="_blank" href="/search/%7C%7C/1.htm">||</a> <div>        准备两个对象用于下面的讨论 var alice = { name: "alice", toString: function () { return this.name; } } var smith = { name: "smith", </div> </li> <li><a href="/article/1538.htm" title="[Zookeeper学习笔记之四]Zookeeper Client Library会话重建" target="_blank">[Zookeeper学习笔记之四]Zookeeper Client Library会话重建</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/zookeeper/1.htm">zookeeper</a> <div>为了说明问题,先来看个简单的示例代码:   package com.tom.zookeeper.book; import com.tom.Host; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.Wat</div> </li> <li><a href="/article/1665.htm" title="【Scala十一】Scala核心五:case模式匹配" target="_blank">【Scala十一】Scala核心五:case模式匹配</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/scala/1.htm">scala</a> <div>package spark.examples.scala.grammars.caseclasses object CaseClass_Test00 { def simpleMatch(arg: Any) = arg match { case v: Int => "This is an Int" case v: (Int, String)</div> </li> <li><a href="/article/1792.htm" title="运维的一些面试题" target="_blank">运维的一些面试题</a> <span class="text-muted">yuxianhua</span> <a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a> <div>1、Linux挂载Winodws共享文件夹   mount -t cifs //1.1.1.254/ok /var/tmp/share/ -o username=administrator,password=yourpass 或 mount -t cifs -o username=xxx,password=xxxx //1.1.1.1/a /win    </div> </li> <li><a href="/article/1919.htm" title="Java lang包-Boolean" target="_blank">Java lang包-Boolean</a> <span class="text-muted">BrokenDreams</span> <a class="tag" taget="_blank" href="/search/boolean/1.htm">boolean</a> <div>         Boolean类是Java中基本类型boolean的包装类。这个类比较简单,直接看源代码吧。 public final class Boolean implements java.io.Serializable, </div> </li> <li><a href="/article/2046.htm" title="读《研磨设计模式》-代码笔记-命令模式-Command" target="_blank">读《研磨设计模式》-代码笔记-命令模式-Command</a> <span class="text-muted">bylijinnan</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">设计模式</a> <div>声明: 本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/ import java.util.ArrayList; import java.util.Collection; import java.util.List; /** * GOF 在《设计模式》一书中阐述命令模式的意图:“将一个请求封装</div> </li> <li><a href="/article/2173.htm" title="matlab下GPU编程笔记" target="_blank">matlab下GPU编程笔记</a> <span class="text-muted">cherishLC</span> <a class="tag" taget="_blank" href="/search/matlab/1.htm">matlab</a> <div>不多说,直接上代码 gpuDevice % 查看系统中的gpu,,其中的DeviceSupported会给出matlab支持的GPU个数。 g=gpuDevice(1); %会清空 GPU 1中的所有数据,,将GPU1 设为当前GPU reset(g) %也可以清空GPU中数据。 a=1; a=gpuArray(a); %将a从CPU移到GPU中 onGP</div> </li> <li><a href="/article/2300.htm" title="SVN安装过程" target="_blank">SVN安装过程</a> <span class="text-muted">crabdave</span> <a class="tag" taget="_blank" href="/search/SVN/1.htm">SVN</a> <div>SVN安装过程   subversion-1.6.12   ./configure --prefix=/usr/local/subversion --with-apxs=/usr/local/apache2/bin/apxs --with-apr=/usr/local/apr --with-apr-util=/usr/local/apr --with-openssl=/</div> </li> <li><a href="/article/2427.htm" title="sql 行列转换" target="_blank">sql 行列转换</a> <span class="text-muted">daizj</span> <a class="tag" taget="_blank" href="/search/sql/1.htm">sql</a><a class="tag" taget="_blank" href="/search/%E8%A1%8C%E5%88%97%E8%BD%AC%E6%8D%A2/1.htm">行列转换</a><a class="tag" taget="_blank" href="/search/%E8%A1%8C%E8%BD%AC%E5%88%97/1.htm">行转列</a><a class="tag" taget="_blank" href="/search/%E5%88%97%E8%BD%AC%E8%A1%8C/1.htm">列转行</a> <div>行转列的思想是通过case when 来实现 列转行的思想是通过union all 来实现 下面具体例子: 假设有张学生成绩表(tb)如下: Name Subject Result 张三 语文  74 张三 数学  83 张三 物理  93 李四 语文  74 李四 数学  84 李四 物理  94 */ /* 想变成 姓名   &</div> </li> <li><a href="/article/2554.htm" title="MySQL--主从配置" target="_blank">MySQL--主从配置</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a> <div> linux下的mysql主从配置: 说明:由于MySQL不同版本之间的(二进制日志)binlog格式可能会不一样,因此最好的搭配组合是Master的MySQL版本和Slave的版本相同或者更低, Master的版本肯定不能高于Slave版本。(版本向下兼容) mysql1  : 192.168.100.1    //master mysq</div> </li> <li><a href="/article/2681.htm" title="关于yii 数据库添加新字段之后model类的修改" target="_blank">关于yii 数据库添加新字段之后model类的修改</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/Model/1.htm">Model</a> <div>rules: array('新字段','safe','on'=>'search') 1、array('新字段', 'safe')//这个如果是要用户输入的话,要加一下, 2、array('新字段', 'numerical'),//如果是数字的话 3、array('新字段', 'length', 'max'=>100),//如果是文本 1、2、3适当的最少要加一条,新字段才会被</div> </li> <li><a href="/article/2808.htm" title="sublime text3 中文乱码解决" target="_blank">sublime text3 中文乱码解决</a> <span class="text-muted">dyy_gusi</span> <a class="tag" taget="_blank" href="/search/Sublime+Text/1.htm">Sublime Text</a> <div>sublime text3中文乱码解决 原因:缺少转换为UTF-8的插件 目的:安装ConvertToUTF8插件包 第一步:安装能自动安装插件的插件,百度“Codecs33”,然后按照步骤可以得到以下一段代码: import urllib.request,os,hashlib; h = 'eb2297e1a458f27d836c04bb0cbaf282' + 'd0e7a30980927</div> </li> <li><a href="/article/2935.htm" title="概念了解:CGI,FastCGI,PHP-CGI与PHP-FPM" target="_blank">概念了解:CGI,FastCGI,PHP-CGI与PHP-FPM</a> <span class="text-muted">geeksun</span> <a class="tag" taget="_blank" href="/search/PHP/1.htm">PHP</a> <div>CGI CGI全称是“公共网关接口”(Common Gateway Interface),HTTP服务器与你的或其它机器上的程序进行“交谈”的一种工具,其程序须运行在网络服务器上。 CGI可以用任何一种语言编写,只要这种语言具有标准输入、输出和环境变量。如php,perl,tcl等。 FastCGI FastCGI像是一个常驻(long-live)型的CGI,它可以一直执行着,只要激活后,不</div> </li> <li><a href="/article/3062.htm" title="Git push 报错 "error: failed to push some refs to " 解决" target="_blank">Git push 报错 "error: failed to push some refs to " 解决</a> <span class="text-muted">hongtoushizi</span> <a class="tag" taget="_blank" href="/search/git/1.htm">git</a> <div>Git push 报错 "error: failed to push some refs to " . 此问题出现的原因是:由于远程仓库中代码版本与本地不一致冲突导致的。 由于我在第一次git pull --rebase 代码后,准备push的时候,有别人往线上又提交了代码。所以出现此问题。 解决方案: 1: git pull    2:</div> </li> <li><a href="/article/3189.htm" title="第四章 Lua模块开发" target="_blank">第四章 Lua模块开发</a> <span class="text-muted">jinnianshilongnian</span> <a class="tag" taget="_blank" href="/search/nginx/1.htm">nginx</a><a class="tag" taget="_blank" href="/search/lua/1.htm">lua</a> <div>在实际开发中,不可能把所有代码写到一个大而全的lua文件中,需要进行分模块开发;而且模块化是高性能Lua应用的关键。使用require第一次导入模块后,所有Nginx 进程全局共享模块的数据和代码,每个Worker进程需要时会得到此模块的一个副本(Copy-On-Write),即模块可以认为是每Worker进程共享而不是每Nginx Server共享;另外注意之前我们使用init_by_lua中初</div> </li> <li><a href="/article/3316.htm" title="java.lang.reflect.Proxy" target="_blank">java.lang.reflect.Proxy</a> <span class="text-muted">liyonghui160com</span> <div>  1.简介   Proxy 提供用于创建动态代理类和实例的静态方法 (1)动态代理类的属性 代理类是公共的、最终的,而不是抽象的 未指定代理类的非限定名称。但是,以字符串 "$Proxy" 开头的类名空间应该为代理类保留 代理类扩展 java.lang.reflect.Proxy 代理类会按同一顺序准确地实现其创建时指定的接口</div> </li> <li><a href="/article/3443.htm" title="Java中getResourceAsStream的用法" target="_blank">Java中getResourceAsStream的用法</a> <span class="text-muted">pda158</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>1.Java中的getResourceAsStream有以下几种: 1. Class.getResourceAsStream(String path) : path 不以’/'开头时默认是从此类所在的包下取资源,以’/'开头则是从ClassPath根下获取。其只是通过path构造一个绝对路径,最终还是由ClassLoader获取资源。   2. Class.getClassLoader.get</div> </li> <li><a href="/article/3570.htm" title="spring 包官方下载地址(非maven)" target="_blank">spring 包官方下载地址(非maven)</a> <span class="text-muted">sinnk</span> <a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a> <div>SPRING官方网站改版后,建议都是通过 Maven和Gradle下载,对不使用Maven和Gradle开发项目的,下载就非常麻烦,下给出Spring Framework jar官方直接下载路径:   http://repo.springsource.org/libs-release-local/org/springframework/spring/   s</div> </li> <li><a href="/article/3697.htm" title="Oracle学习笔记(7) 开发PLSQL子程序和包" target="_blank">Oracle学习笔记(7) 开发PLSQL子程序和包</a> <span class="text-muted">vipbooks</span> <a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a><a class="tag" taget="_blank" href="/search/sql/1.htm">sql</a><a class="tag" taget="_blank" href="/search/%E7%BC%96%E7%A8%8B/1.htm">编程</a> <div>    哈哈,清明节放假回去了一下,真是太好了,回家的感觉真好啊!现在又开始出差之旅了,又好久没有来了,今天继续Oracle的学习!      这是第七章的学习笔记,学习完第六章的动态SQL之后,开始要学习子程序和包的使用了……,希望大家能多给俺一些支持啊!     编程时使用的工具是PLSQL</div> </li> </ul> </div> </div> </div> <div> <div class="container"> <div class="indexes"> <strong>按字母分类:</strong> <a href="/tags/A/1.htm" target="_blank">A</a><a href="/tags/B/1.htm" target="_blank">B</a><a href="/tags/C/1.htm" target="_blank">C</a><a href="/tags/D/1.htm" target="_blank">D</a><a href="/tags/E/1.htm" target="_blank">E</a><a href="/tags/F/1.htm" target="_blank">F</a><a href="/tags/G/1.htm" target="_blank">G</a><a href="/tags/H/1.htm" target="_blank">H</a><a href="/tags/I/1.htm" target="_blank">I</a><a href="/tags/J/1.htm" target="_blank">J</a><a href="/tags/K/1.htm" target="_blank">K</a><a href="/tags/L/1.htm" target="_blank">L</a><a href="/tags/M/1.htm" target="_blank">M</a><a href="/tags/N/1.htm" target="_blank">N</a><a href="/tags/O/1.htm" target="_blank">O</a><a href="/tags/P/1.htm" target="_blank">P</a><a href="/tags/Q/1.htm" target="_blank">Q</a><a href="/tags/R/1.htm" target="_blank">R</a><a href="/tags/S/1.htm" target="_blank">S</a><a href="/tags/T/1.htm" target="_blank">T</a><a href="/tags/U/1.htm" target="_blank">U</a><a href="/tags/V/1.htm" target="_blank">V</a><a href="/tags/W/1.htm" target="_blank">W</a><a href="/tags/X/1.htm" target="_blank">X</a><a href="/tags/Y/1.htm" target="_blank">Y</a><a href="/tags/Z/1.htm" target="_blank">Z</a><a href="/tags/0/1.htm" target="_blank">其他</a> </div> </div> </div> <footer id="footer" class="mb30 mt30"> <div class="container"> <div class="footBglm"> <a target="_blank" href="/">首页</a> - <a target="_blank" href="/custom/about.htm">关于我们</a> - <a target="_blank" href="/search/Java/1.htm">站内搜索</a> - <a target="_blank" href="/sitemap.txt">Sitemap</a> - <a target="_blank" href="/custom/delete.htm">侵权投诉</a> </div> <div class="copyright">版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved. <!-- <a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">京ICP备09083238号</a><br>--> </div> </div> </footer> <!-- 代码高亮 --> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shCore.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shLegacy.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shAutoloader.js"></script> <link type="text/css" rel="stylesheet" href="/static/syntaxhighlighter/styles/shCoreDefault.css"/> <script type="text/javascript" src="/static/syntaxhighlighter/src/my_start_1.js"></script> </body> </html>