1. 程式人生 > 實用技巧 >學習MVC專案在7天-第6天

學習MVC專案在7天-第6天

介紹 歡迎來到第6天“學習MVC專案7天”系列。希望你們在第一天到第五天讀得愉快。前幾天必須在第6天之前完成。 完整的系列 第1天第2天第3天第4天第5天第6天7天獎金第1天獎金第2天 我們很高興地宣佈,這篇文章現在可以從www.amazon.com和www.flipkart.com獲得同樣的紙質書 議程 實驗室27 -新增批量上傳選項講實驗室27個問題在上面的解決方案解決方案實驗室28 - 29 -異常處理解決執行緒飢餓問題實驗室顯示自定義錯誤頁面談論實驗室29以上理解限制在實驗室實驗室30 -異常處理日誌異常實驗室30路由瞭解routetable瞭解ASP。NET MVC請求週期實驗室31 -實現使用者友好的url討論實驗室31結論 實驗27 -新增批量上傳選項 在這個實驗室中,我們將建立一個選項,用於從CSV檔案中上傳多個員工。 我們將在這裡學到兩件新事情。 如何使用檔案上傳控制非同步控制器。 步驟1 -建立FileUploadViewModel 在ViewModels資料夾中建立一個名為FileUploadViewModel的新類,如下所示。 隱藏,複製Code

public class FileUploadViewModel: BaseViewModel
{
  public HttpPostedFileBase fileUpload {get; set ;}
}

HttpPostedFileBase將提供客戶機對上傳檔案的訪問。 步驟2 -建立BulkUploadController和索引操作 建立一個名為BulkUploadController的新控制器和一個名為Index action的操作方法,如下所示。 隱藏,複製Code

public class BulkUploadController : Controller
{
    [HeaderFooterFilter]
    [AdminFilter]
    public ActionResult Index()
    {
      return View(new FileUploadViewModel());
    }
}

如您所見,索引操作附加了HeaderFooterFilter和AdminFilter屬性。HeaderFooterFilter確保將正確的頁首和頁尾資料傳遞給ViewModel,而AdminFilter則限制非admin使用者對操作方法的訪問。 步驟3 -建立上傳檢視 為上面的操作方法建立一個檢視。 請注意,檢視名稱應該是index。cshtml,應該放在" ~/Views/BulkUpload "資料夾中。 步驟4 -設計上傳檢視 在檢視中放置以下內容。 隱藏,複製Code

@using WebApplication1.ViewModels
@model FileUploadViewModel
@{
    Layout = "~/Views/Shared/MyLayout.cshtml";
}

@section TitleSection{
    Bulk Upload
}
@section ContentBody{
    <
div> <ahref="/Employee/Index">Back</a> <formaction="/BulkUpload/Upload"method="post"enctype="multipart/form-data"> Select File : <inputtype="file"name="fileUpload"value=""/> <inputtype="submit"name="name"value="Upload"/> </form> </div> }

正如您在FileUploadViewModel中看到的,屬性的名稱和輸入的名稱[type="file"]是相同的。這是“類”。我們在模型繫結實驗室中談到了名稱屬性的重要性。注意:在標籤的形式中指定了一個附加屬性,即enctype。我們會在實驗的最後討論這個問題。 步驟5 -建立業務層上傳方法 在employeebusinesslayer中建立一個名為duploademployees的新方法,如下所示。 隱藏,複製Code

public void UploadEmployees(List<Employee> employees)
{
  SalesERPDAL salesDal = new SalesERPDAL();
  salesDal.Employees.AddRange(employees);
  salesDal.SaveChanges();
}<employee>
</employee>

步驟6 -建立上傳動作方法 在BulkUploadController中建立一個名為Upload的新操作方法,如下所示。 隱藏,複製Code

[AdminFilter]
public ActionResult Upload(FileUploadViewModel model)
{
    List<Employee> employees = GetEmployees(model);
    EmployeeBusinessLayer bal = new EmployeeBusinessLayer();
    bal.UploadEmployees(employees);
    return RedirectToAction("Index","Employee");
}

private List<Employee> GetEmployees(FileUploadViewModel model)
{
    List<Employee> employees = new List<Employee>();
    StreamReader csvreader = new StreamReader(model.fileUpload.InputStream);
    csvreader.ReadLine(); // Assuming first line is header
    while (!csvreader.EndOfStream)
    {
        var line = csvreader.ReadLine();
        var values = line.Split(',');//Values are comma separated
        Employee e = new Employee();
        e.FirstName = values[0];
        e.LastName = values[1];
        e.Salary = int.Parse(values[2]);
        employees.Add(e);
    }
    return employees;
}

附加到上傳操作的AdminFilter限制非管理員使用者的訪問。 步驟7 -為BulkUpload建立一個連結 AddNewLink開放。從“Views/Employee”資料夾中下載cshtml,並將下面的BulkUpload連結。 隱藏,複製Code

<ahref="/Employee/AddNew">Add New</a>
&nbsp;
&nbsp;
<ahref="/BulkUpload/Index">BulkUpload</a>

步驟8 -執行和測試 步驟8.1 -建立用於測試的樣例檔案 建立一個示例檔案,如下所示,並將其儲存在計算機中的某個地方。 步驟8.2 -執行和測試 按F5並執行應用程式。完成登入過程並通過單擊連結導航到BulkUpload選項。 選擇檔案並點選上傳。 注意: 在上面的示例中,我們沒有在檢視中應用任何客戶端或伺服器端驗證。這可能會導致以下錯誤。 "一個或多個實體驗證失敗。有關更多細節,請參見“EntityValidationErrors”屬性。 要查詢錯誤的確切原因,只需在異常發生時新增一個帶有以下手錶表示式的手錶。 ((System.Data.Entity.Validation.DbEntityValidationException)例外)美元.EntityValidationErrors 監視表示式' $exception '顯示當前上下文中丟擲的任何異常,即使它沒有被捕獲並分配給變數。 在27實驗室演講 為什麼這裡沒有驗證呢? 向此選項新增客戶端和伺服器端驗證將是讀者的一個分配。我給你們一個提示。 對於伺服器端驗證,使用資料註釋。對於客戶端,您可以利用資料註釋和實現jQuery不顯眼的驗證。顯然,這次您必須手動設定自定義資料屬性,因為我們還沒有readymade Htmlhelper方法用於檔案輸入。 注意:如果您還沒有理解這一點,我建議您再次完成“在登入檢視中植入客戶端驗證”。對於客戶端驗證,您可以編寫自定義JavaScript並在單擊按鈕時呼叫它。這並不困難,因為檔案輸入說到底是一個輸入控制元件,它的值可以在JavaScript中檢索並驗證。 HttpPostedFileBase是什麼? HttpPostedFileBase將提供對客戶機上傳的檔案的訪問。模型繫結器將在釋出請求期間更新所有屬性FileUploadViewModel類的值。現在我們在FileUploadViewModel中只有一個屬性,模型繫結器會將其設定為客戶端上傳的檔案。 有可能提供嗎e多檔案輸入控制? 是的,我們可以通過兩種方式實現。 建立多個檔案輸入控制元件。每個控制元件必須有唯一的名稱。現在在FileUploadViewModel類中為每個控制元件建立型別為HttpPostedFileBase的屬性。每個屬性名稱應該與一個控制元件的名稱匹配。剩下的魔術將由ModelBinder完成。☺create多個檔案輸入控制元件。每個控制元件必須具有相同的名稱。現在不是建立HttpPostedFileBase型別的多個屬性,而是建立一個List< httppostedfilebase>型別的屬性。 注:以上情況適用於所有控制元件。如果屬性是一個簡單引數,那麼當您擁有多個同名控制元件時,ModelBinder將使用第一個控制元件的值更新屬性。如果屬性是列表屬性,ModelBinder將把每個控制元件的值放在列表中。 enctype="multipart/form-data"將做什麼? 這不是一個很重要的事情,但是知道這個肯定很好。 此屬性指定在釋出資料時使用的編碼型別。 這個屬性的預設值是“application/x-www-form-urlencoded” 示例-我們的登入表單將傳送以下post請求到伺服器 隱藏,複製Code

POST /Authentication/DoLogin HTTP/1.1
Host: localhost:8870
Connection: keep-alive
Content-Length: 44
Content-Type: application/x-www-form-urlencoded
...
...
UserName=Admin&Passsword=Admin&BtnSubmi=Login

所有輸入值都以“&”連線的鍵/值對的形式作為一部分發送。 當將enctype="multipart/form-data"屬性新增到表單標籤時,後續的post請求將傳送到伺服器。 隱藏,複製Code

POST /Authentication/DoLogin HTTP/1.1
Host: localhost:8870
Connection: keep-alive
Content-Length: 452
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarywHxplIF8cR8KNjeJ
...
...
------WebKitFormBoundary7hciuLuSNglCR8WC
Content-Disposition: form-data; name="UserName"

Admin
------WebKitFormBoundary7hciuLuSNglCR8WC
Content-Disposition: form-data; name="Password"

Admin
------WebKitFormBoundary7hciuLuSNglCR8WC
Content-Disposition: form-data; name="BtnSubmi"

Login
------WebKitFormBoundary7hciuLuSNglCR8WC--

如你所見,表單是在多個部分張貼。每個部分由Content-Type定義的邊界分隔,每個部分包含一個值。 如果表單標籤包含檔案輸入控制元件,則必須將encType設定為“multipart/form-data”。 注意:邊界將在每次請求時隨機生成。你可能會看到一些不同的邊界。 為什麼我們不總是設定encType為“multipart/form-data”? 當encType被設定為“multipart/form-data”時,它會同時做兩件事——釋出資料和上傳檔案。那麼為什麼我們不總是將其設定為“multipart/form-data”呢? 答案是,它還會增加請求的總體大小。請求的大小越大,效能就越差。因此,作為最佳實踐,我們應該將其設定為預設值,即“application/x-www-form-urlencoded”。 為什麼我們在這裡建立ViewModel ? 我們的檢視中只有一個控制元件。我們可以通過直接在Upload操作方法中新增一個名為fileUpload的型別為HttpPostedFileBase的引數來實現相同的結果,而不是建立一個單獨的ViewModel。請看下面的程式碼。 隱藏,複製Code

public ActionResult Upload(HttpPostedFileBase fileUpload)
{
}

那麼為什麼我們要建立一個單獨的類呢? 建立ViewModel是最佳實踐。控制器應該總是以ViewModel的形式向檢視傳送資料,從檢視傳送的資料應該以ViewModel的形式傳送給控制器。 問題在上面解決 您是否曾經想過在傳送請求時如何獲得響應? 現在不要說,動作方法接收請求等等!!☺ 雖然這是正確的答案,但我希望會有一些不同的答案。 我的問題是一開始會發生什麼。 一個簡單的程式設計規則——程式中的一切都是由執行緒執行的,甚至是一個請求。 在Asp.net的情況下,。net framework維護了一個執行緒池。 每當一個請求被髮送到web伺服器時,就會從池中分配一個空閒執行緒來處理該請求。這個執行緒將被稱為工作執行緒。 工作執行緒將被阻塞時,請求正在處理,不能服務於另一個請求。 現在讓我們假設一個應用程式接收了太多的請求,並且每個請求將花費很長時間來完全處理。在這種情況下,我們可能會在新請求進入沒有工作執行緒可用來服務該請求的狀態時結束。這被稱為執行緒短缺。 在我們的例子中,示例檔案有2條員工記錄,但在實時情況下,它可能包含數千條或缺少記錄。這意味著請求將花費大量的時間來完成處理。它可能會導致執行緒飢餓。 解決方案 現在,我們到目前為止討論的請求的型別是synchronous request。 而不是同步,如果客戶端做一個非同步請求,執行緒短缺的問題得到解決。 在非同步請求的情況下,通常從執行緒池中分配工作執行緒來服務請求。工作執行緒啟動非同步操作並返回執行緒池服務另一個請求。非同步操作現在將由CLR執行緒繼續。現在的問題是,CLR執行緒不能返回響應,所以一旦它完成非同步操作,它會通知ASP.NET。Webserver再次從執行緒池中獲取工作執行緒,處理剩餘的請求並呈現響應。 在整個場景中,從執行緒池中檢索工作執行緒兩次。它們可能是同一條線,也可能不是。 在我們的示例中,讀取檔案是一個I/O繫結操作,它不需要由工作執行緒處理。所以這是變換s的最佳位置同步請求到非同步請求。 非同步請求是否提高了響應時間? 不,響應時間將保持不變。在這裡,執行緒將被釋放以處理其他請求。 實驗室28 -解決執行緒飢餓問題 在ASP。我們可以通過將同步動作方法轉換為非同步動作方法來將同步請求轉換為非同步請求。 步驟1 -建立非同步控制器 將UploadController的基類從Controller更改為AsynController。 隱藏,複製Code

{
  public class BulkUploadController : AsyncController
  {

步驟2 -將同步操作方法轉換為非同步操作方法 在兩個關鍵字的幫助下,可以很容易地完成非同步和等待。 隱藏,複製Code

[AdminFilter]
public async Task<ActionResult> Upload(FileUploadViewModel model)
{
  int t1 = Thread.CurrentThread.ManagedThreadId;
  List<Employee> employees = await Task.Factory.StartNew<List<Employee>>
    (() => GetEmployees(model));
  int t2 = Thread.CurrentThread.ManagedThreadId;
  EmployeeBusinessLayer bal = new EmployeeBusinessLayer();
  bal.UploadEmployees(employees);
  return RedirectToAction("Index", "Employee");
}<actionresult><employee><list<employee>
</list<employee></employee></actionresult>

正如您所看到的,我們在操作方法的開頭和結尾將執行緒id儲存在一個變數中。 讓我們來理解一下程式碼。 當客戶端單擊upload按鈕時,新的請求將傳送到伺服器。Webserver將從執行緒池中獲取一個工作執行緒,並分配它來服務於請求。工作執行緒使動作方法執行。Worker方法在Task.Factory的幫助下啟動一個非同步操作。StartNew方法。可以看到,在async關鍵字的幫助下,動作方法被標記為非同步。它將確保工作執行緒在非同步操作開始時就被釋放。從邏輯上講,非同步操作將通過單獨的CLR執行緒在後臺繼續執行。現在非同步操作呼叫被標記為await關鍵字。它將確保除非非同步操作完成,否則下一行不會執行。一旦非同步操作完成,動作方法中的下一個語句就應該執行,為此,同樣需要一個工作執行緒。因此,webserver將從執行緒池中獲取一個新的空閒工作執行緒,並分配它來服務剩餘的請求和呈現響應。 步驟3 -執行和測試 執行應用程式。導航到BulkUpload選項。 現在,在對輸出執行更多操作之前,導航到程式碼並在最後一行放置斷點。 現在選擇示例檔案並單擊Upload。 正如您所看到的,開頭和結尾的執行緒id不同。輸出和之前的實驗一樣。 實驗29 -異常處理-顯示自定義錯誤頁面 一個專案如果沒有適當的異常處理,就不會被認為是一個完整的專案。 到目前為止,我們已經討論了Asp中的兩個過濾器。操作過濾器和授權過濾器。現在是第三個例外過濾器的時候了。 什麼是異常過濾器? 使用異常過濾器的方式與使用其他過濾器的方式相同。我們將使用它們作為屬性。 使用異常篩選器的步驟 使他們。將它們作為屬性應用於操作方法或控制器。我們還可以在全域性級別應用異常過濾器。 他們會怎麼做? 異常過濾器將控制執行,並在操作方法中一旦發生異常,就自動開始執行在其內部編寫的程式碼。 有自動化嗎? ASP。NET MVC提供了一個現成的異常過濾器稱為HandeError。 如前所述,當操作方法中出現異常時,它將執行。這個過濾器會在“~/Views/[當前控制器]”或“~/Views/Shared”資料夾中找到一個名為“Error”的檢視,建立該檢視的ViewResult並作為響應返回。 讓我們看一個演示,更好地理解它。 在我們專案的最後一個實驗室中,我們實現了BulkUpload選項。現在輸入檔案出錯的可能性很大。 步驟1 -建立一個帶有錯誤的示例上傳檔案 像前面一樣建立一個示例上傳檔案,但是這次放了一些無效的值。 如你所見,工資是無效的。 步驟2 -執行並測試異常 按F5並執行應用程式。導航到批量上傳選項。選擇上面的檔案並點選上傳。 步驟3 -啟用異常過濾器 在啟用自定義異常時啟用異常過濾器。要啟用自定義異常,請開啟web。配置檔案,並導航到系統。網路部分。為自定義錯誤新增一個新的部分,如下所示。 隱藏,複製Code

<system.web>
   <customErrorsmode="On"></customErrors>

步驟4 -建立錯誤檢視 在“~/Views/Shared”資料夾中,你會發現一個名為“Error.cshtml”的檢視。這個檔案只是在開始時作為mvc模板的一部分建立的。如果沒有建立,請手動建立。 隱藏,複製Code

@{
    Layout = null;
}

<!DOCTYPEhtml>
<html>
<head>
    <metaname="viewport"content="width=device-width"/>
    <title>Error</title>
</head>
<body>
    <hgroup>
        <h1>Error.</h1>
        <h2>An error occurred while processing your request.</h2>
    </hgroup>
</body>
</html>

& lt; hgroup> 步驟5 -附加異常過濾器 如前所述,啟用異常過濾器後,我們將它們附加到操作方法或控制器。 好訊息。不需要手動連線它。 從App_Start資料夾中開啟FilterConfig.cs檔案。在RegisterGlobalFilters方法中,您將看到HandleError過濾器已經在全域性級別上附加。 隱藏,複製Code

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
  filters.Add(new HandleErrorAttribute());//ExceptionFilter
  filters.Add(new AuthorizeAttribute());
}

如果需要,刪除全域性過濾器並將其附加在操作或控制器級別,如下所示。 隱藏,複製Code

[AdminFilter]
[HandleError]
public async Task<ActionResult> Upload(FileUploadViewModel model)
{<actionresult>
</actionresult>

不建議這樣做。最好是在全球層面上應用。 步驟6 -執行和測試 讓我們用與前面相同的方法測試這個應用程式。 步驟7 -在檢視中顯示錯誤資訊 為了實現這個轉換錯誤檢視為型別HandleErrorInfo類的強型別檢視,然後在檢視中顯示錯誤訊息。 隱藏,複製Code

@model HandleErrorInfo
@{
    Layout = null;
}

<!DOCTYPEhtml>
<html>
<head>
    <metaname="viewport"content="width=device-width"/>
    <title>Error</title>
</head>
<body>
    <hgroup>
        <h1>Error.</h1>
        <h2>An error occurred while processing your request.</h2>
    </hgroup>
        Error Message :@Model.Exception.Message<br/>
        Controller: @Model.ControllerName<br/>
        Action: @Model.ActionName
</body>
</html>

步驟8 -執行和測試 執行相同的測試,但這一次我們將得到以下錯誤檢視。 我們是不是漏掉了什麼? 處理錯誤屬性確保在操作方法中發生異常時顯示自定義檢視。但是它的功能僅限於控制器和動作方法。它不會處理“資源未找到”錯誤。 執行應用程式並在URL中新增一些奇怪的內容 步驟9 -建立ErrorController,如下所示 在控制器資料夾中建立一個名為ErrorController的新控制器,並建立一個名為Index的操作方法,如下所示。 隱藏,複製Code

public class ErrorController : Controller
{
  // GET: Error
  public ActionResult Index()
  {
    Exception e=new Exception("Invalid Controller or/and Action Name");
    HandleErrorInfo eInfo = new HandleErrorInfo(e, "Unknown", "Unknown");
    return View("Error", eInfo);
  }
}

HandleErrorInfo建構函式有3個引數——異常物件、控制器名稱和操作方法名稱。 在無效的URL上顯示自定義錯誤檢視 在網路上。配置定義“資源未找到錯誤”的設定如下。 隱藏,複製Code

<system.web>
    <customErrorsmode="On">
      <errorstatusCode="404"redirect="~/Error/Index"/>
    </customErrors>

步驟11 -讓每個人都可以訪問ErrorController 將AllowAnonymous屬性應用到ErrorController,因為錯誤控制器和索引操作不應該繫結到經過身份驗證的使用者。使用者可能在登入前輸入了無效的URL。 隱藏,複製Code

[AllowAnonymous]
public class ErrorController : Controller
{

步驟12 -執行和測試 執行應用程式並在位址列中放置一些無效的URL。 在29實驗室演講 是否可以更改檢視名稱? 是的,不需要將檢視名稱始終保持為“錯誤”。 在這種情況下,我們必須在附加HandlError過濾器時指定檢視名。 隱藏,複製Code

[HandleError(View="MyError")]
Or
filters.Add(new HandleErrorAttribute()
 {
 View="MyError"
 });

有可能為不同的異常獲得不同的錯誤檢視嗎? 是的,這是可能的。在這種情況下,我們必須多次應用處理錯誤過濾器。 隱藏,複製Code

[HandleError(View="DivideError",ExceptionType=typeof(DivideByZeroException))]
[HandleError(View = "NotFiniteError", ExceptionType = typeof(NotFiniteNumberException))]
[HandleError]

OR

filters.Add(new HandleErrorAttribute()
    {
        ExceptionType = typeof(DivideByZeroException),
        View = "DivideError"
    });
filters.Add(new HandleErrorAttribute()
{
    ExceptionType = typeof(NotFiniteNumberException),
    View = "NotFiniteError"
});
filters.Add(new HandleErrorAttribute());

在上面的例子中,我們添加了三次處理錯誤過濾器。前兩個是特定於異常的,而最後一個是更一般的,它將顯示所有其他異常的錯誤檢視。 瞭解上述實驗室的侷限性 唯一的限制與上述實驗室是我們不記錄我們的異常任何地方。 實驗30 -異常處理-日誌異常 步驟1 -建立記錄器類 在專案的根位置建立一個名為Logger的新資料夾。 在Logger資料夾中建立一個名為FileLogger的新類,如下所示。 隱藏,複製Code

namespace WebApplication1.Logger
{
  public class FileLogger
  {
    public void LogException(Exception e)
    {
      File.WriteAllLines("C://Error//" + DateTime.Now.ToString("dd-MM-yyyy mm hh ss")+".txt",
        new string[]
        {
          "Message:"+e.Message,
          "Stacktrace:"+e.StackTrace
        });
    }
  }
}

步驟2 -建立EmployeeExceptionFilter類 在過濾器資料夾中建立一個名為EmployeeExceptionFilter的新類,如下所示。 隱藏,複製Code

namespace WebApplication1.Filters
{
  public class EmployeeExceptionFilter
  {
  }
}

步驟3 -擴充套件控制代碼錯誤以實現日誌記錄 從HandleErrorAttribute類繼承EmployeeExceptionFilter並覆蓋OnException方法,如下所示。 隱藏,複製Code

public class EmployeeExceptionFilter:HandleErrorAttribute
{
  public override void OnException(ExceptionContext filterContext)
  {
    base.OnException(filterContext);
  }
}

注意:請務必使用System.Web。MVC在頂部。HandleErrorAttribute類存在於此名稱空間中。 步驟4 -定義OnException方法 在OnException方法中包含異常日誌程式碼,如下所示。 隱藏,複製Code

public override void OnException(ExceptionContext filterContext)
{
  FileLogger logger = new FileLogger();
  logger.LogException(filterContext.Exception);
  base.OnException(filterContext);
}

步驟5 -更改預設異常過濾器 開啟FilterConfig.cs檔案,刪除HandErrorAtrribute並附加我們在最後一步中建立的檔案,如下所示。 隱藏,複製Code

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
  //filters.Add(new HandleErrorAttribute());//ExceptionFilter
  filters.Add(new EmployeeExceptionFilter());
  filters.Add(new AuthorizeAttribute());
}

步驟6 -執行和測試 首先,在C驅動器中建立一個名為“Error”的資料夾,因為這是錯誤檔案將要放置的地方。 注意:如果需要,將路徑更改為您想要的路徑。 按F5並執行應用程式。導航到批量上傳選項。選擇上面的檔案並點選上傳。 這次的輸出也不會有什麼不同。我們會得到和之前一樣的錯誤檢視。唯一的區別是,這次我們還會找到一個在“C:\\Errors”資料夾中建立的錯誤檔案。 關於30號實驗室的演講 當異常發生時,如何返回錯誤檢視作為響應? 在上面的實驗室中,我們覆蓋了OnException方法並實現了異常日誌記錄功能。現在的問題是,為什麼預設的處理錯誤過濾器還在工作?這很簡單。檢查OnException方法的最後一行。 隱藏,複製Code

base.OnException(filterContext);

這意味著,讓基類OnException來做重新命名工作,基類OnException將返回錯誤檢視的ViewResult。 我們可以在OnException中返回其他結果嗎? 是的。請看下面的程式碼。 隱藏,複製Code

public override void OnException(ExceptionContext filterContext)
{
  FileLogger logger = new FileLogger();
  logger.LogException(filterContext.Exception);
  //base.OnException(filterContext);
  filterContext.ExceptionHandled = true;
  filterContext.Result = new ContentResult()
  {
    Content="Sorry for the Error"
  };
}

當我們想返回自定義響應,我們應該做的第一件事是,通知MVC引擎,我們已經手動處理異常,所以不要執行預設行為,即不顯示預設的錯誤螢幕。這將通過以下語句完成。 隱藏,複製Code

filterContext.ExceptionHandled = true

你可以閱讀更多關於ASP中的異常處理。淨MVC這裡 路由 到目前為止,我們已經討論了很多概念,我們回答了很多關於MVC的問題,除了一個基本的和重要的問題。 “當終端使用者發出請求時,到底會發生什麼?” 答案肯定是“行動方法”執行”。但我的確切問題是,如何為特定的URL請求標識控制器和動作方法。 在我們開始我們的實驗室“實現使用者友好的url”之前,首先讓我們找出上面問題的答案。你可能想知道為什麼這個話題會出現在結尾。我故意把這個主題放在接近尾聲的地方,因為我想讓人們在理解內部內容之前就充分了解MVC。 理解RouteTable 在Asp。有一個概念叫做RouteTable,它將為應用程式儲存URL路由。簡單地說,它包含一個定義應用程式可能的URL模式的集合。 預設情況下,一個路由將作為專案模板的一部分新增到其中。檢查它開啟全域性。asax檔案。在Application_Start中,您將發現如下語句。 隱藏,複製Code

RouteConfig.RegisterRoutes(RouteTable.Routes);

您將在App_Start資料夾中找到RouteConfig.cs檔案,該檔案包含以下程式碼塊。 隱藏,複製Code

namespace WebApplication1
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}

正如您在RegisterRoutes方法中看到的,已經在route的幫助下定義了一個預設路由。MapRoute方法。 在RegisterRoutes方法中定義的路由將在稍後的asp.net中使用。Net MVC請求週期確定要執行的控制器和動作方法。 如果需要的話,我們可以使用route建立多個路由。MapRoute函式。在內部定義route意味著建立route物件。 MapRoute函式還將RouteHandler附加到route物件上,該物件在ASP中為MVCRouteHandler。NET MVC預設。 瞭解ASP。NET MVC請求週期 在你開始之前,讓我讓你清楚,我們不打算解釋100%的請求週期在這裡。我們只會接觸重要的人。 步驟1 - urlrouting模組 當終端使用者發出請求時,它首先通過UrlRoutingModule物件傳遞。UrlRoutingModule是一個HTTP模組。 步驟2 -路由 UrlRoutingModule將從路由表集合中獲取第一個匹配的路由物件。現在進行匹配,請求URL將與路由中定義的URL模式進行比較。 匹配時將考慮以下規則。 請求URL(不包括域名)和路由中定義的URL模式中的引數數量 例子: URL模式中定義的可選引數 例子: 在引數中定義的靜態引數 步驟3 -建立MVC路由處理程式 選擇Route物件後,UrlRoutingModule將從Route物件獲得MvcRouteHandler物件。 步驟4 -建立RouteData和RequestContext UrlRoutingModule物件將使用Route物件建立RouteData,然後使用該物件建立RequestContext。 RouteData封裝了關於路由的資訊,如控制器的名稱、操作的名稱和路由引數的值。 控制器名稱 為了從請求URL獲得控制器名稱,遵循以下簡單規則。"在URL模式中,{controller}是識別控制器名稱的關鍵字"。 例子: 當URL模式為{controller}/{action}/{id},請求URL為“http://localhost:8870/bulkupload / upload/5”時,BulkUpload將是控制器的名稱。當URL模式為{action}/{controller}/{id},請求URL為“http://localhost:8870/bulkupload / upload/5”時,Upload將是控制器的名稱。 動作方法的名字 為了從請求URL獲得動作方法名稱,遵循以下簡單規則。"在URL模式中,{action}是識別動作方法名稱的關鍵字"。 例子: 當URL模式為{controller}/{action}/{id},請求URL為“http://localhost:8870/bulkupload / upload/5”時,Upload將是動作方法的名稱。當URL模式是{action}/{controller}/{id}並且請求URL是“http://localhost:8870/bulkupload / upload/5”時,BulkUpload將是動作方法的名稱。 線路引數 基本上,URL模式可以包含以下四點 {控制器}→標識控制器名稱{action} ->標識actionmethod名字。SomeString→示例-“MyCompany/{controller}/{action}”->在此模式中,“MyCompany”成為強制字串。{一}→示例-“{controller}/{action}/{id}”->在這個模式中,“id”是路由引數。Route引數可用於在請求時獲取URL本身的值。 請看下面的示例。 路線模式- >“{控制器}/{行動}/ {id}” 請求URL→http://localhost: 8870 / BulkUpload /上傳/ 5 測試1 隱藏,複製Code

public class BulkUploadController : Controller
{
  public ActionResult Upload (string id)
  {
   //value of id will be 5 -> string 5
   ...
  }
}

測試2 隱藏,複製Code

public class BulkUploadController : Controller
{
  public ActionResult Upload (int id)
  {
   //value of id will be 5 -> int 5
   ...
  }
}

測試3 隱藏,複製Code

public class BulkUploadController : Controller
{
  public ActionResult Upload (string MyId)
  {
   //value of MyId will be null
   ...
  }
}

步驟5 -建立MVCHandler MvcRouteHandler將建立傳遞RequestContext物件的MVCHandler的例項。 步驟6 -建立控制器例項 MVCHandler將在ControllerFactory的幫助下建立控制器例項(預設情況下為DefaultControllerFactory)。 第7步-執行方法 MVCHandler將呼叫控制器的執行方法。執行方法是在控制器基類內部定義的。 步驟8 -呼叫動作方法 每個控制器都與一個Cont相關聯rollerActionInvoker物件。在執行方法ControllerActionInvoker物件內部呼叫正確的操作方法。 步驟9 -執行結果。 Action方法接收使用者輸入並準備適當的響應資料,然後通過返回一個返回型別來執行結果。返回型別可以是ViewResult,也可以是RedirectToRoute Result,也可以是其他型別。 現在我相信您已經很好地理解了路由的概念,所以讓我們的專案url在路由的幫助下更加使用者友好。 實驗室31 -實現使用者友好的url 步驟1 -重新定義RegisterRoutes方法 如下所示,在RegisterRoutes方法中包含其他路由。 隱藏,複製Code

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
    name: "Upload",
    url: "Employee/BulkUpload",
    defaults: new { controller = "BulkUpload", action = "Index" }
    );

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}

正如您現在看到的,我們定義了不止一個路由。 (預設路徑保持不變。) 步驟2 -更改URL引用 AddNewLink開放。從“~/Views/Employee”資料夾中的cshtml更改BulkUpload連結,如下所示。 隱藏,複製Code

&nbsp;
<ahref="/Employee/BulkUpload">BulkUpload</a>

步驟3 -執行和測試 執行該應用程式並看到奇蹟。 正如你所看到的,URL不再是“控制器/動作”的形式。相反,它更便於使用者使用,但輸出是相同的。 我建議您定義更多的路由並嘗試更多的url。 關於31實驗室的演講 以前的URL現在工作嗎? 是的,以前的URL也可以。 現在可以從兩個url訪問BulkUploadController中的索引操作 “http://localhost: 8870 /員工/ BulkUpload”“http://localhost: 8870 / BulkUpload指數” 預設路由中的“id”是什麼? 我們已經說過了。它被稱為路由引數。它可用於通過URL獲取值。它是查詢字串的替代品。 路由引數和查詢字串之間的區別是什麼? 查詢字串有大小限制,而我們可以定義任意數量的路由引數。我們不能向查詢字串值新增約束,但可以向路由引數新增約束。路由引數的預設值是可能的,而查詢字串的預設值是不可能的。查詢字串使URL混亂,而路由引數保持乾淨。 如何將約束應用到路由引數? 這可以在正則表示式的幫助下完成。 例子:看看下面的路線。 隱藏,複製Code

routes.MapRoute(
  "MyRoute",
  "Employee/{EmpId}",
  new {controller=" Employee ", action="GetEmployeeById"},
  new { EmpId = @"\d+" }
);

操作方法如下所示。 隱藏,複製Code

public ActionResult GetEmployeeById(int EmpId)
{
 ...
}

現在,當有人用URL“http://..”發出請求時。/員工/ 1”或“http://..。/ employee/111 "時,action方法將被執行,但當有人發出URL為" http://..他/她將得到“資源未找到”的錯誤。 操作方法中的引數名是否需要與路由引數名相同? 基本上,單個路由模式可以包含一個或多個涉及的路由引數。為了獨立地識別每個路由引數,必須將操作方法中的引數名稱與路由引數名稱保持一致。 序列在定義自定義路由時重要嗎? 是的,這很重要。如果你還記得UrlRoutingModule會先取匹配的route物件。 在上面的實驗室中,我們定義了兩條路線。一個自定義路由和一個預設路由。現在,假設對於一個例項,首先定義預設路由,然後定義自定義路由。 在本例中,當終端使用者使用URL“http://..”發出請求時。在比較階段,UrlRoutingModule會發現所請求的URL與預設路由模式匹配,並將“Employee”作為控制器名,“BulkUpload”作為操作方法名。 因此,序列在定義路由時非常重要。大多數通用路由應該保留在最後。 有沒有一種更簡單的方法來定義動作方法的URL模式? 我們可以使用基於屬性的路由。 讓我們試一試。 步驟1 -啟用基於屬性的路由。 在RegisterRoutes方法中,保持跟隨IgnoreRoute語句之後的行。 隱藏,複製Code

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

routes.MapMvcAttributeRoutes();

routes.MapRoute(
...

步驟2 -定義一個動作方法的路由模式 簡單地將路由屬性附加到動作方法到EmployeeController的索引動作,如下所示。 隱藏,複製Code

[Route("Employee/List")]
public ActionResult Index()
{

步驟3 -執行和測試 執行應用程式並完成登入過程。 正如您所看到的,我們有相同的輸出,但使用了不同的更使用者友好的URL。 我們可以用基於屬性的路由定義路由引數嗎? 是的,看看下面的語法。 隱藏,複製Code

[Route("Employee/List/{id}")]
publicActionResult Index (string id) { ... }

這種情況下的約束條件是什麼? 這樣就容易多了。 隱藏,複製Code

[Route("Employee/List/{id:int}")]

我們可以有以下約束條件 {x:α}- {x: bool}字串驗證邏輯驗證{x: datetime} -日期時間驗證{x:小數}-十進位制驗證{x:雙}- 64位浮點值驗證{x:浮動}- 32位浮點值驗證{x: guid} - guid驗證{x:長度(6)}長度驗證{x:長度(20)}- Min和Max長度驗證{x:長}- 64 int驗證{x: Max (10)} - Max整數驗證{x:最大長度(10)}- Max長度驗證{x: Min(10)} -最小整數驗證{x:minlength(10)} -最小長度驗證{x:range(10,50)} -整數範圍validation {x:regex(SomeRegularExpression)} -正則表示式驗證 在RegisterRoutes方法中IgnoreRoutes做什麼? 當我們不想為特定的擴充套件使用路由時,將使用IgnoreRoutes。作為MVC模板的一部分,下面的語句已經在RegisterRoutes方法中寫好了。 隱藏,複製Code

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

它的意思是如果終端使用者提出一個請求與延期。這樣就不會有任何路由操作。請求將直接到達物理資源。 我們也可以定義自己的IgnoreRoute語句。 結論 到第六天,我們已經完成了示例MVC專案。希望您喜歡完整的系列。 等待! !第七天在哪裡? 我的朋友們,第七天就到了。在第7天,我們將使用MVC、jQuery和Ajax建立一個單一頁面應用程式。這樣會更有趣,也更有挑戰。請繼續關注☺ 你的評論,郵件總是激勵我們做更多。把你的想法和評論寫在下面,或者傳送郵件到[email protected] 在Facebook, LinkedIn或twitter上聯絡我們,以保持最新的版本。 如果你想開始與MVC 5開始與下面的視訊學習MVC 5在2天。 本文轉載於:http://www.diyabc.com/frontweb/news1740.html