一,引言
上一篇文章有介紹到什麼是 SeverLess ,ServerLess 都有哪些特點,以及多雲環境下 ServerLess 都有哪些解決方案。在這眾多解決方案中就包括 Function App(Azure 下的ServerLess),今天我們結合之前所講的 Azure Functions 以及 Azure Blob Storage 的相關知識,從實踐出發,再次回顧之前的知識點,以下是構想的基礎資源架構圖
--------------------Azure Functions 系列--------------------
1,使用 Visual Studio 開發、測試和部署 Azure Functions(一)開發
2,使用 Visual Studio 開發、測試和部署 Azure Functions(二)測試,部署
3,使用Azure Functions 在web 應用中啟用自動更新(一)分析基於輪詢的 Web 應用的限制
4,Azure Functions(一)什麼是 ServerLess
5,Azure Functions(二)整合 Azure Blob Storage 儲存檔案
二,正文
1,建立 Function App
Azure Portal,點選“Create a resource”,搜尋框中輸入 “Function App”。
點選 “Create”,建立 Function App
輸入相關引數:
Resource Group 選擇建立新的資源組:“Web_Test_Functions_RG”
Function App name:“cnbateblogweb”
Publicsh 釋出方式:Code(程式碼)
Runtime stack 選擇:“.NET”
Version:“3.1”
Region 選擇:“East Asia”
點選 “Next:Hosting” 設定承載
接下來 “Hosting” 相關引數
Storage:當我們在建立函式應用時,必須建立或連結到支援的Blob,Queue,Table Storage 的常規用途的 Azure 儲存賬號
Storage Account 選擇建立新的:cnbatestorageaccount
Operation system 選擇:“Windows”
Plan 選擇:Consumption(ServerLess) 消耗(無伺服器)
點選 “Next:Monitoring >” 設定監視資訊
接下來我們需要自身的需要 選擇是否開啟 Application Insights(用於在應用程式中提供詳細的可觀測性)
Enable Application Insights:“Yes”
Application Insights 選擇建立新的:“cnbateblogweb”
點選 “Review + create”,建立預覽。
預校驗完成後,點選 “Create” 進行建立。
稍等片刻,我們回到 “Web_Test_Functions_RG” 這個資源組可以檢視到我們建立好的資源
最後,我們需要建立用於儲存圖片的 Blob Container
選擇 “Blob service =》Container”,點選箭頭所指的 “+ Container”
輸入建立新的容器的相關引數:
Name:“picturecontainer”
Public access level 選擇預設:“Private(no anonymous access)”
點選 “Create”
建立完成後,就可以在當前頁面上看到 “picturecontainer” 的 Blob Container
2,Azure FunctionApp 新增對 Blob Storage 的使用方法
2.1,新增相關 Nuget 依賴包引用
使用程式包管理器控制檯進行安裝
Install-Package Azure.Storage.Blobs -Version 12.8.0 Install-Package Microsoft.AspNetCore.StaticFiles -Version 2.2.0 Install-Package Microsoft.Azure.Functions.Extensions -Version 1.1.0 Install-Package Microsoft.Extensions.DependencyInjection -Version 5.0.1 Install-Package Microsoft.NET.Sdk.Functions -Version 3.0.11
這裡要注意的是 "Microsoft.Extensions.DependencyInjection"、"Microsoft.NET.Sdk.Functions"、"Microsoft.Azure.Functions.Extensions" ,主要是想在 Azure Functions 中使用一倆注入(DI)
大家可以自行參考 Use dependency injection in .NET Azure Functions
2.2,IBlobService 介面方法定義,BlobService 具體實現和 Http觸發器
1 public interface IBlobService 2 { 3 Task UploadImagesBlobAsync(string filePath, string filename); 4 5 Task UploadFileBlobAsync(string filePath, string filename); 6 7 Task UploadContentBlobAsync(string content, string filename); 8 }
1 public class BlobService : IBlobService 2 { 3 private readonly BlobServiceClient _blobServiceClient; 4 5 public BlobService(BlobServiceClient blobServiceClient) 6 { 7 this._blobServiceClient = blobServiceClient; 8 } 9 10 #region 02,抓取網路圖片,根據圖片URL和圖片名稱+async Task UploadFileBlobAsync(string filePath, string filename) 11 /// <summary> 12 /// 上傳圖片流,根據圖片URL和圖片名稱 13 /// </summary> 14 /// <param name="filePath">圖片URL</param> 15 /// <param name="filename">圖片名稱</param> 16 /// <returns></returns> 17 public async Task UploadImagesBlobAsync(string filePath, string filename) 18 { 19 var containerClient = _blobServiceClient.GetBlobContainerClient("picturecontainer"); 20 var blobClient = containerClient.GetBlobClient(filename); 21 22 #region 獲取圖片流 23 var response = FeatchPictureClient.GetWebResponse(filePath); 24 var bytes = FeatchPictureClient.GetResponseStream(response); 25 await using var memoryStream = new MemoryStream(bytes); 26 27 //上傳圖片流 28 await blobClient.UploadAsync(memoryStream, new BlobHttpHeaders() { ContentType = filename.GetContentType() }); 29 #endregion 30 } 31 #endregion 32 33 #region 03,上傳圖片,根據檔案路徑和檔名稱+async Task UploadFileBlobAsync(string filePath, string filename) 34 /// <summary> 35 /// 上傳圖片流,根據檔案路徑和檔名稱 36 /// </summary> 37 /// <param name="filePath">檔案路徑</param> 38 /// <param name="filename">檔名稱</param> 39 /// <returns></returns> 40 public async Task UploadFileBlobAsync(string filePath, string filename) 41 { 42 var containerClient = _blobServiceClient.GetBlobContainerClient("picturecontainer"); 43 var blobClient = containerClient.GetBlobClient(filename); 44 await blobClient.UploadAsync(filePath, new BlobHttpHeaders { ContentType = filePath.GetContentType() }); 45 } 46 #endregion 47 48 #region 04,上傳檔案內容,根據檔案內容和檔名稱+async Task UploadContentBlobAsync(string content, string filename) 49 /// <summary> 50 /// 上傳檔案流,根據檔案內容和檔名稱 51 /// </summary> 52 /// <param name="content">檔案內容</param> 53 /// <param name="filename">檔名稱</param> 54 /// <returns></returns> 55 public async Task UploadContentBlobAsync(string content, string filename) 56 { 57 var containerClient = _blobServiceClient.GetBlobContainerClient("picturecontainer"); 58 var blobClient = containerClient.GetBlobClient(filename); 59 var bytes = Encoding.UTF8.GetBytes(content); 60 await using var memoryStream = new MemoryStream(bytes); 61 await blobClient.UploadAsync(memoryStream, new BlobHttpHeaders() { ContentType = filename.GetContentType() }); 62 } 63 #endregion 64 65 }
1 public class UpLoadTrigger 2 { 3 private readonly IBlobService _blobSergvice; 4 5 public UpLoadTrigger(IBlobService blobSergvice) 6 { 7 _blobSergvice = blobSergvice; 8 } 9 10 [FunctionName("UpLoadTrigger")] 11 public async Task<IActionResult> Run( 12 [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] BlobViewModel req, 13 ILogger log) 14 { 15 log.LogInformation("C# HTTP trigger function processed a request."); 16 17 await _blobSergvice.UploadImagesBlobAsync(req.FilePath, req.FileName); 18 return new OkObjectResult("ok"); 19 } 20 }
2.3,FileExtensions 方法和 FeatchpictureClient 網路請求方法
1 public static class FileExtensions 2 { 3 private static readonly FileExtensionContentTypeProvider provider = new FileExtensionContentTypeProvider(); 4 5 public static string GetContentType(this string fileName) 6 { 7 if (!provider.TryGetContentType(fileName, out var contentType)) 8 { 9 contentType = "application/octet-stream"; 10 } 11 return contentType; 12 } 13 }
1 public class FeatchPictureClient 2 { 3 /// <summary> 4 /// 獲取URL響應物件 5 /// </summary> 6 /// <param name="url"></param> 7 /// <returns></returns> 8 public static WebResponse GetWebResponse(string url) 9 { 10 System.Net.HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url); 11 request.CookieContainer = new CookieContainer(); 12 request.KeepAlive = true; 13 WebResponse res = request.GetResponse(); 14 return res; 15 } 16 17 public static byte[] GetResponseStream(WebResponse response) 18 { 19 Stream smRes = response.GetResponseStream(); 20 byte[] resBuf = new byte[10240]; 21 int nReaded = 0; 22 MemoryStream memSm = new MemoryStream(); 23 while ((nReaded = smRes.Read(resBuf, 0, 10240)) != 0) 24 { 25 memSm.Write(resBuf, 0, nReaded); 26 } 27 byte[] byResults = memSm.ToArray(); 28 memSm.Close(); 29 return byResults; 30 } 31 }
2.4,新增對 BlobService 以及BlobServiceClient 的依賴注入
大家需要注意,我們需要配置Blob Storage 的訪問金鑰
找到建立 Function App 時一起建立出來的 Storage Account "cnbatestorageaccount "
選擇 “Settings =》Access keys”,複製圖中圈中的 “Connection string” 貼上到對應的程式碼中。
1 using Azure.Storage.Blobs; 2 using Microsoft.Azure.Functions.Extensions.DependencyInjection; 3 using Microsoft.Extensions.Configuration; 4 using Microsoft.Extensions.DependencyInjection; 5 using System; 6 using System.Collections.Generic; 7 using System.Text; 8 using UploadImages; 9 using UploadImages.Service; 10 11 [assembly: FunctionsStartup(typeof(Startup))] 12 13 namespace UploadImages 14 { 15 public class Startup : FunctionsStartup 16 { 17 //public Startup(IConfiguration configuration) 18 //{ 19 // Configuration = configuration; 20 //} 21 22 //public IConfiguration Configuration { get; } 23 24 public override void Configure(IFunctionsHostBuilder builder) 25 { 26 //builder.Services.AddSingleton(x => new BlobServiceClient("storageaccount_connection")); 27 builder.Services.AddSingleton(x => new BlobServiceClient("DefaultEndpointsProtocol=https;AccountName=cnbateblogaccount;AccountKey=f9n+Cm3brR+39SVhNMzzMPj54f6KD7rINi9G2OlxVkk2oUfi3o7ZGdDS8SHkF8H8G5pSmedOOMmOhc95uRNZxA==;EndpointSuffix=core.windows.net")); 28 builder.Services.AddTransient<IBlobService, BlobService>(); 29 } 30 } 31 }
3,測試!觸發 HttpTrigger,通過網路請求圖片URL,經過處理,將圖片儲存在Blob Storage
F5執行,可以看到控制中顯示 Function App 中的 UpLoadTrigger URL:http://localhost:7071/api/UpLoadTrigger
Postman 中輸入 HttpTrigger 的請求連結,輸入 FilePath,FileName 兩個引數
回到控制檯中,我們可以看到 Http 觸發器已經成功的處理了請求
同樣的,我們也可以在 Blob Container 中找到上傳到的網路圖片
Bingo!!!大功告成。使用 Vistual Studio 開發,測試Azure Function App 應用完結
三,結尾
Azure Functions 用來處理很方便,直接將應用級別的專案縮小到方法級別上,在具體的的方法中處理業務,資料。並且 Azure Function 是按照使用付費定價模型:也就是僅僅為執行程式碼所用的時間而付費,這一點比某雲還是好一些。下一篇繼續講解/分享 Azure Function 例項程式碼。以上也是自己的學習的過程,謝謝各位指點。
參考資料:Azure Functions 簡介,在 .NET Azure Functions 中使用依賴項注入
github:https://github.com/yunqian44/Azure.Functions.Upload.git
作者:Allen
版權:轉載請在文章明顯位置註明作者及出處。如發現錯誤,歡迎批評指正。