10個小技巧助您寫出高性能的ASP.NET Core代碼

原文: 10個小技巧助您寫出高性能的ASP.NET Core代碼

今天這篇文章咱們來聊一聊如何提高並優化ASP.NET Core應用程序的性能,本文的大部份內容來自翻譯,固然中間穿插着本身的理解,但願對你們有所幫助!話很少說開始今天的主題吧!
咱們都知道性能是公共網站取得成功的關鍵因素之一。若是一個網站的響應時間超過3秒,那麼用戶一般不會再此光顧(此網站)。谷歌,Bing,百度以及其餘搜索引擎也更傾向於推薦優化後的,移動友好的以及響應速度更快的網站。css

做者:依樂祝html

原文地址:https://www.cnblogs.com/yilezhu/p/10507984.html算法

大部份內容翻譯自:https://www.c-sharpcorner.com/article/10-tips-to-improve-performance-of-asp-net-core-application/數據庫

這裏咱們舉一個例子:咱們有多個搜索引擎,如Google、Bing、百度、搜狗等等;然而,咱們更喜歡Google或Bing,由於這些搜索引擎速度很是快,能夠在3-4秒內得到結果。若是這些搜索引擎的響應速度超過10秒,你還會使用它們嗎?我認爲大夥應該不會用了吧。現在的用戶最不能容忍的想必就是等待了吧。編程

今天,咱們將學習一些有助於提升ASP.NET Core網站性能的一些小技巧。但願你們可以有所收穫。c#

咱們都知道ASP.NET Core是微軟提供的一個免費的、開源的、跨平臺的Web開發框架。它不是ASP.NET的升級版本,但它是一個從頭開始徹底重寫的框架,它附帶了ASP.NET MVC和ASP.NET Web API的單一編程模型。緩存

在這裏,我不打算討論ASP.NET Core及其特性。若是您是ASP.NET Core的新手,您能夠閱讀個人ASP.NET Core實戰教程《.NET Core實戰項目之CMS 第一章 入門篇-開篇及整體規劃服務器

下面咱們就開始今天的主題,如何提高ASP.NET Core應用程序的性能的技巧開始吧。微信

始終使用ASP.NET Core的最新版本

ASP.NET Core的第一個版本是在2016年與VisualStudio 2015一塊兒發佈的,如今咱們有了ASP.NET Core3.0,每個新版本都愈來愈好。最新的ASP.NET Core 3.0的主要更新以下:網絡

  • Razor組件的改進。如今2個項目合併成單個項目模板,Razor組件支持端點路由和預渲染,Razor組件能夠託管在Razor類庫中。還改進了事件處理和表單和驗證支持。
  • 運行時編譯。它在ASP.NET Core 3.0模板中被禁用,但如今能夠經過向項目添加特殊的NuGet包來打開它。
  • Worker Service 模板。須要編寫Windows服務仍是Linux守護進程?如今咱們有了Worker Service 模板。
  • gRPC模板。與谷歌一塊兒構建的gRPC是一種流行的遠程過程調用(RPC)框架。此版本的ASP.NET Core在ASP.NET Core上引入了第一等的gRPC支持。
  • Angular模板使用Angular 7. Angular SPA模板如今使用Angular 7,在第一次穩定釋放以前,它將被Angular 8替換。
  • SPA-s的身份驗證。Microsoft經過此預覽爲單頁應用程序添加了現成的身份驗證支持。
  • SignalR與端點路由集成。小變化 - 如今使用端點路由定義SingalR路由。
  • SignalR Java客戶端支持長輪詢。即便在不支持或不容許WebSocket的環境中,SignalR Java客戶端如今也可使用。

友情提示:在構建新的ASP.NET Core項目時,不要忘記選擇最新版本。VisualStudio 2019預覽版如今已經支持ASP.NET Core 3.0了。

避免任何層的同步調用

在開發ASP.NET Core應用程序時,儘可能避免建立阻塞的調用。阻塞調用是指當前請求未完成以前會一直阻止下一個執行的調用。阻塞調用或同步調用能夠是任何東西,能夠是從API中獲取數據,也能夠是執行一些內部操做。您應該始終以異步方式執行調用。

始終使用異步編程(ASYNC-AWAIT)

異步編程模型是在C#5.0中引入的,並變得很是流行。ASP.NET Core使用相同的異步編程範例來使應用程序更可靠、更快和更穩定。

您應該在代碼中使用端到端異步編程。

讓咱們舉一個例子;咱們有一個ASP.NET CoreMVC應用程序,中間有一些數據庫的操做。正如咱們所知道的,它可能有不少分層結構,這都取決於用戶的項目架構,可是讓咱們舉一個簡單的例子,其中咱們有Controller》Repository 層等等。讓咱們看看如何在控制器層編寫示例代碼。

[HttpGet]
[Route("GetPosts")]  
public async Task GetPosts()
{  
    try  
    {  
var posts = await postRepository.GetPosts();
        if (posts == null)  
        {  
            return NotFound();
        }  
  
        return Ok(posts);
    }  
    catch (Exception)
    {  
        return BadRequest();
  
    }  
}

接下來的代碼然是了咱們如何在repository  層實現異步編程。

public async Task<List<PostViewModel>> GetPosts()
{  
    if (db != null)  
       {  
         return await (from p in db.Post
from c in db.Category
where p.CategoryId == c.Id
select new PostViewModel
                       {  
PostId = p.PostId,
Title = p.Title,
Description = p.Description,
CategoryId = p.CategoryId,
CategoryName = c.Name,
CreatedDate = p.CreatedDate
}).ToListAsync();
      }  
    
      return null;  
}

使用異步編程避免TASK.WAIT或TAST.RESULT

在使用異步編程時,我建議您避免使用Task.Wait和Task.Result並嘗試使用WAIT,緣由以下:

  1. 它們阻塞線程直到任務完成,並等待任務完成。等待同步阻塞線程,直到任務完成。
  2. Wait 和 Task.Result 在AggregateException中包含全部類型的異常,並在在執行異常處理時增長複雜性。若是您使用的是等待await 而不是 Task.Wait和Task.Result的話,那麼您就沒必要擔憂異常的處理了。
  3. 有時,它們都會阻塞當前線程並建立死鎖。
  4. 只有在並行任務執行正在進行時才能使用Wait 和Task.Result 。咱們建議您不要在異步編程中使用它。

下面讓咱們分別演示下正確使用以及不建議使用Task.Wait 的例子,來加深理解吧!

// 正確的例子 
Task task = DoWork();
await task;
  
// 不建議使用的例子 
Task task = DoWork();
task.Wait();

下面讓咱們分別演示下正確使用以及不規範使用Task.Result 的例子,來加深理解吧!

// Good Performance on UI  
Task<string> task = GetEmployeeName();
txtEmployeeName.Text = await task;
  
// Bad Performance on UI  
Task<string> task = GetEmployeeName();
txtEmployeeName.Text = task.Result;

瞭解更多關於異步編程的最佳實踐.

異步執行I/O操做

在執行I/O操做時,您應該異步執行它們,這樣就不會影響其餘進程。I/O操做意味着對文件執行一些操做,好比上傳或檢索文件。它能夠是任何操做如:圖像上傳,文件上傳或其餘任何操做。若是您試圖以同步的方式完成它,那麼它會阻塞主線程並中止其餘後臺執行,直到I/O完成爲止。所以,從提高性能上來講,您在對I/O進行操做時應該始終進行異步執行。

咱們有不少異步方法可用於I/O操做,如ReadAsync、WriteAsync、FlushAysnc等。下面是一個簡單的例子,說明咱們如何異步建立一個文件的副本。

public async void CreateCopyOfFile()
{  
    string dir = @"c:\Mukesh\files\";  
  
    using (StreamReader objStreamReader= File.OpenText(dir + "test.txt"))  
    {  
        using (StreamWriter objStreamWriter= File.CreateText(dir+ "copy_test.txt"))  
        {  
await CopyFileToTarget(objStreamReader, objStreamWriter);
        }  
    }  
}  
  
public async Task CopyFileToTarget(StreamReader objStreamReader, StreamWriter objStreamWriter)
{   
    int num;
    char[] buffer = new char[0x1000];
  
    while ((num= await objStreamReader.ReadAsync(buffer, 0, buffer.Length)) != 0)
    {  
await objStreamWriter.WriteAsync(buffer, 0, num);
    }   
}

老是使用緩存

若是咱們能在每次執行的時候減小減小對服務器的請求次數,那麼咱們就能夠提升應用程序的性能。這並不意味着您執行的時候不會請求服務器,而是意味着您不會每次執行都請求服務器。第一次,您將請求服務器並得到響應,此響應將在某個地方存儲一段時間(將有一些到期),下一次當您對相同的響應進行調用時,您將首先檢查您是否已經在第一個請求中得到了數據並存儲在某個地方,若是是的話,您將檢查是否已經得到了數據。使用存儲的數據,而不是調用服務器。

將數據保存在某個位置並讓下次請求從這個地方獲取數據而不是從服務器獲取是一種很好的作法。在這裏,咱們可使用緩存。緩存內容有助於咱們再次減小服務器調用,並幫助咱們提升應用程序的性能。咱們能夠在客戶端緩存、服務器端緩存或客戶機/服務器端緩存等位置的任意點執行緩存。

咱們能夠在ASP.NET Core中使用不一樣類型的緩存,好比咱們能夠在內存中進行緩存,也可使用響應緩存,也可使用分佈式緩存。更多關於ASP.NET Core 中的緩存

public async Task GetCacheData()
{  
var cacheEntry = await
_cache.GetOrCreateAsync(CacheKeys.Entry, entry =>
    {  
entry.SlidingExpiration = TimeSpan.FromSeconds(120);
        return Task.FromResult(DateTime.Now);
    });  
  
    return View("Cache", cacheEntry);
}

優化數據訪問

咱們還能夠經過優化數據訪問邏輯、數據庫表和查詢來提升應用程序的性能。衆所周知,大多數應用程序都使用某種數據庫,每次從數據庫獲取數據時,都會影響應用程序的性能。若是數據庫加載緩慢,則整個應用程序將緩慢運行。這裏咱們有一些建議:

  1. 減小HTTP請求的次數,意味着您應該始終嘗試減小網絡往返次數。
  2. 試着一次獲得全部的數據。這意味着不對服務器進行屢次調用,只需進行一兩次調用就能夠帶來全部所需的數據。
  3. 常常對不常常變化的數據設置緩存。
  4. 不要試圖提早獲取不須要的數據,這會增長響應的負載,並致使應用程序的加載速度變慢。

優化自定義代碼

除了業務邏輯和數據訪問代碼以外,應用程序中可能還有一些自定義代碼。確保此代碼也是優化的。這裏有一些建議:

  1. 應該優化對每一個請求執行的自定義日誌記錄、身份驗證或某些自定義處理程序的代碼。
  2. 不要在業務邏輯層或中間件中執行長時間運行的代碼,它會阻塞到服務器的請求,從而致使應用程序須要很長時間才能得到數據。您應該在客戶端或數據庫端爲此進行優化代碼。
  3. 始終檢查長期運行的任務是否應該異步執行,而不影響其餘進程。
  4. 您可使用實時客戶端-服務器通訊框架,如:SignalR,來進行異步工做。

Entity Framework Core 的查詢優化

衆所周知,EF Core是一個面向.NET開發人員的ORM,它幫助咱們處理數據庫對象,而不像往常那樣編寫大量代碼。它幫助咱們使用模型的數據庫。數據訪問邏輯代碼在性能上起着相當重要的做用。若是您的代碼沒有優化,那麼應用程序的性能一般就不會很好。

可是,若是您在EFCore中以優化的方式編寫數據訪問邏輯,那麼確定會提升應用程序的性能。在這裏,咱們有一些技巧來提升性能。

  1. 在獲取只是用來只讀顯示的數據時不使用跟蹤。它提升了性能。

  2. 嘗試在數據庫端過濾數據,不要使用查詢獲取整個數據,而後在您的末尾進行篩選。您可使用EF Core中的一些可用功能,能夠幫助您在數據庫端篩選數據的操做,如:WHERE,Select等。

  3. 使用Take和Skip來獲取咱們所必需要顯示的數量的記錄。這裏能夠舉一個分頁的例子,在這個例子中,您能夠在單擊頁碼的同時使用Take和Skip來獲取當前頁面的數據。

讓咱們以一個例子爲例,瞭解如何使用Select和AsNoTracking優化EF Core的查詢。

public async Task<PaginatedList> GetPagedPendingPosts(int pageIndex, int pageSize, List allowedCategories)
{  
var allowedCatIds = allowedCategories.Select(x => x.Id);
var query = _context.Post
.Include(x => x.Topic.Category)
.Include(x => x.User)
.Where(x => x.Pending == true && allowedCatIds.Contains(x.Topic.Category.Id))
.OrderBy(x => x.DateCreated);
  
    return await PaginatedList.CreateAsync(query.AsNoTracking(), pageIndex, pageSize);
}

其餘一些提示

這裏咱們還有一些其餘性能改進的東西能夠在ASP.NET Core應用程序中進行實現。

  1. 編寫優化和測試代碼。您還可使用來自專業高級開發者的代碼示例,包括產品文檔。產品團隊編寫的代碼(如C#團隊)一般是優化的、現代化的,而且遵循最佳實踐。

  2. 使用通過優化和良好測試的API和庫。例如,在某些狀況下,ADO.NET多是比 Entity Framework 或其餘ORM庫更好的選擇。

  3. 若是您須要下載一個很大的文件的話,您可能須要考慮使用壓縮算法。這裏有幾個內置的壓縮庫,如Gzip和Brotli。

public void ConfigureServices(IServiceCollection services)
{  
services.AddResponseCompression();
  
services.Configure(options =>
    {  
options.Level = CompressionLevel.Fastest;
    });  
}

附加的建議(面向Client)

我想分享一些面向客戶端的提高性能的技巧。若是您正在使用ASP.NET Core MVC建立網站,下面是一些提示:

  • 捆綁和小型化

    使用捆綁和小型化能夠減小服務器請求次數。嘗試一次加載全部客戶端資源,如樣式、js/css。您能夠首先使用小型化縮小文件,而後將這些文件打包到一個文件中,這將加快加載速度並減小HTTP請求的數量。

  • 最後加載 JavaScript

    您應該始終嘗試在頁面尾部加載JavaScript文件,除非在此以前須要使用它們。若是您這樣作,您的網站將顯示的更快,而且用戶也不須要等待並看到這些內容。

  • 壓縮圖像

    確保使用壓縮技術縮小圖像的大小。

  • 使用 CDN

    若是您只有幾個樣式和JS文件,那麼能夠從您的服務器加載。對於較大的靜態文件,請嘗試使用CDN。CDN一般能夠在多個位置上使用,而且文件是從本地服務器提供的。從本地服務器加載文件能夠提升網站性能。

最後

今天,咱們學習瞭如何提高ASP.NET Core 應用程序的性能。很是但願這篇文章對你有所幫助,若是您有任何問題或建議,能夠在博客下面進行留言或者點贊!最後感謝大夥的閱讀,若是你有興趣的話能夠加入ASP.NET Core實戰項目交流羣跟大夥進行交流,或者加我微信:jkingzhu,備註:合肥,我拉你進入合肥.NET技術社區進行交流!

相關文章
相關標籤/搜索