Azure Functions(二)集成 Azure Blob Storage 存儲文件

一,引言

  上一篇文章有介紹到什麼是 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     }

IBlobService.cs

 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     }

BlobService.cs

 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     }

UpLoadTrigger.cs

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     }

FileExtensions.cs

 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     }

FeatchPictureClient.cs

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 }

Startup.cs

3,測試!觸發 HttpTrigger,通過網路請求圖片URL,經過處理,將圖片存儲在Blob Storage

F5運行,可以看到控制中顯示 Function App 中的 UpLoadTrigger URL//localhost:7071/api/UpLoadTrigger

Postman 中輸入 HttpTrigger 的請求鏈接,輸入 FilePathFileName 兩個參數

回到控制台中,我們可以看到 Http 觸發器已經成功的處理了請求

同樣的,我們也可以在 Blob Container 中找到上傳到的網路圖片

Bingo!!!大功告成。使用 Vistual Studio 開發,測試Azure Function App 應用完結

三,結尾

  Azure Functions 用來處理很方便,直接將應用級別的項目縮小到方法級別上,在具體的的方法中處理業務,數據。並且 Azure Function 是按照使用付費定價模型:也就是僅僅為運行程式碼所用的時間而付費,這一點比某雲還是好一些。下一篇繼續講解/分享 Azure Function 實例程式碼。以上也是自己的學習的過程,謝謝各位指點。

參考資料:Azure Functions 簡介在 .NET Azure Functions 中使用依賴項注入

github://github.com/yunqian44/Azure.Functions.Upload.git

作者:Allen 

版權:轉載請在文章明顯位置註明作者及出處。如發現錯誤,歡迎批評指正。