學好Windows Azure必看的一本書
圖片來源:http://books.gotop.com.tw/v_ACL036700
首先,如果各位對Windows Azure不是很熟悉的話,我推薦小朱的《Windows Azure Platform應用程式開發教戰手札(第二版)》。
ASP.NET Web API介接服務
「介接服務」的意思是,在Web API裡,我們可以拿別人的服務來成為我的服務,Client只是使用者,他不需要知道細節。以「上傳檔案」而言,當Client上傳一個檔案,你可以儲存在本機,也就是進行File I/O的動作,你可以儲存在Database裡,也就是進行Database I/O動作。
在以下範例中,我們要在Web API裡去儲存檔案至Windows Azure的Blob儲存體中,也就是說,我們拿Windows Azure Storage服務來當成我們服務內容之一。
這裡的概念很重要,例如,我們公司有申請HiCloud服務,在HiCloud的服務內容中有一項HiCloud S3服務,它是一項和Amazon S3一模一樣服務。S3是Simple Storage Service的縮寫,基本上,它也是一項RESTful Service,透過RESTful Service提供“檔案存取”的功能。
也就是說,我們不一定只能選擇Windows Azure Storage,只要對方有提供API給我們存取,我們都可以拿來當成Web API服務的一部分,而Client並不需要知道這些細節。
使用Windows Azure Storage Emulator測試
那天在twMVC#8課程現場並無網路,而我有辦法進行此一範例的Demo要拜謝Windows Azure Storage Emulator,如果各位有安裝Web Tools 2012.2,預設就會安裝Windows Azure SDK,不然就必須到Windows Azure官網去下載安裝(VS 2012 SDK | VS 2010 SDK)。Windows Azure SDK會在本機安裝模擬器(Emulator),讓我們就算在沒有網路的環境,也能進行Windows Azure相關程式碼的測試。
在使用要切換本機與Windows Azure正式環境也非常容易,只需要透過web.config裡的<appSettings>段落去進行組態切換即可。
<!-- 重點一:連線Blob資訊 -->
<add key="CloudStorageConnectionString" value="UseDevelopmentStorage=true" />
<!--
<add key="CloudStorageConnectionString" value="DefaultEndpointsProtocol=http;AccountName=NAME;AccountKey=KEY"/>
-->
Key名稱可自訂,value是才是重點,使用本機的儲存體模擬器必須指定“UseDevelopmentStorage=true”,當完成開發後,只需要切換組態至Windows Azure的設定,會立即馬上改為Windows Azure Storage服務。
上傳檔案至Blob
一、首先在Models目錄新增一個Files類別,用來儲存檔案資訊:
''' <summary>
''' 儲存上傳檔案資訊
''' </summary>
Public Class FileDetails
Property Name As String
Property Size As Long
Property ContentType As String
Property Location As String
End Class
二、新增一個Helpers目錄,新增BlobHelper輔助類別,用以幫忙我們快速取得容器資訊。這裡注意的是,必須先將「Microsoft.WindowsAzure.Configuration」與「Microsoft.WindowsAzure.StorageClient」加入參考。
Imports Microsoft.WindowsAzure
Imports Microsoft.WindowsAzure.StorageClient
''' <summary>
''' Windows Azure Blob輔助方法
''' </summary>
''' <remarks></remarks>
Public Class BlobHelper
''' <summary>
''' 取得與設定Azure Blob容器
''' </summary>
Public Shared Function GetWebApiContainer() As CloudBlobContainer
' 從appSettings裡的連線字串取得Storage的AccountName
Dim storageAccount As CloudStorageAccount = CloudStorageAccount.Parse(
CloudConfigurationManager.GetSetting("CloudStorageConnectionString"))
' 建立Blob client
Dim blobClient As CloudBlobClient = storageAccount.CreateCloudBlobClient()
' 取得容器(container)的參考
' 容器名稱必須小寫,請參考:http://msdn.microsoft.com/en-us/library/windowsazure/dd135715.aspx
Dim container As CloudBlobContainer = blobClient.GetContainerReference("webapicontainer")
' 確認容器是否存在,不存在就建立一個新容器
container.CreateIfNotExist()
' 啟用公開存取Blob
Dim permissions As BlobContainerPermissions = container.GetPermissions()
If permissions.PublicAccess = BlobContainerPublicAccessType.Off Then
permissions.PublicAccess = BlobContainerPublicAccessType.Blob
container.SetPermissions(permissions)
End If
Return container
End Function
End Class
三、新增一個Providers目錄,新增一個AzureBlobStorageMultipartProvider類別。
Imports System.Collections.Generic
Imports System.IO
Imports System.Net.Http
Imports System.Threading.Tasks
Imports Microsoft.WindowsAzure.StorageClient
''' <summary>
''' 繼承MultipartFileStreamProvider,實作ExecutePostProcessingAsync方法。
''' </summary>
''' <remarks>http://msdn.microsoft.com/zh-tw/library/system.net.http.multipartfilestreamprovider(v=vs.108).aspx</remarks>
Public Class AzureBlobStorageMultipartProvider
Inherits MultipartFileStreamProvider
Private _container As CloudBlobContainer
Public Property Files As List(Of FileDetails)
Sub New(container As CloudBlobContainer)
' Path.GetTempPath():回目前使用者的暫存資料夾的路徑。
MyBase.New(Path.GetTempPath())
_container = container
Files = New List(Of FileDetails)()
End Sub
Public Overrides Function ExecutePostProcessingAsync() As Task
' 上傳檔案到Azure Blob儲存體,然後從本機移除它們
' FileData:http://msdn.microsoft.com/zh-tw/library/system.net.http.multipartfiledata(v=vs.108).aspx
For Each Data As MultipartFileData In FileData
Dim fileName As String = Path.GetFileName(Data.Headers.ContentDisposition.FileName.Trim(""""))
' 取得加入Blob
Dim blob As CloudBlob = _container.GetBlobReference(fileName)
' 指定上傳MediaType
blob.Properties.ContentType = Data.Headers.ContentType.MediaType
' 上傳
blob.UploadFile(Data.LocalFileName)
' 刪除本機檔案
File.Delete(Data.LocalFileName)
' 加入Files集合
Files.Add(New FileDetails With {
.ContentType = blob.Properties.ContentType,
.Location = blob.Uri.AbsoluteUri,
.Name = blob.Name,
.Size = blob.Properties.Length})
Next
Return MyBase.ExecutePostProcessingAsync()
End Function
End Class
這裡我們繼承MultipartFileStreamProvider類別並覆寫ExecutePostProcessingAsync方法。MultipartFileStreamProvider類別在《ASP.NET MVC 4網站開發美學》第7-124頁 上傳檔案一節我們有進行討論,讀者可以配合著看以加強瞭解。
這裡基本上是使用Windows Azure SDK裡的方法,將上傳的檔案寫入Blob儲存體之中。
四、新增FilesController類別,新增Post方法與Get方法。
Imports System.Collections.Generic
Imports System.Net
Imports System.Net.Http
Imports System.Threading.Tasks
Imports System.Web.Http
Imports Microsoft.WindowsAzure.StorageClient
Public Class FilesController
Inherits ApiController
''' <summary>
''' 上傳檔案至Windows Azure Blob儲存體
''' </summary>
Function PostFile() As Task(Of List(Of FileDetails))
' 確認MIME為form-data(上傳檔案)
If Not Request.Content.IsMimeMultipartContent("form-data") Then
' 回傳HTTP 415 狀態碼
Throw New HttpResponseException(HttpStatusCode.UnsupportedMediaType)
End If
Dim streamProvider = New AzureBlobStorageMultipartProvider(BlobHelper.GetWebApiContainer())
' ReadAsMultipartAsync:http://msdn.microsoft.com/zh-tw/library/system.net.http.httpcontentmultipartextensions(v=vs.108).aspx
' 讀取 MIME 多組件訊息的所有主體組件,並產生一組 HttpContent 執行個體,使用 streamProvider 執行個體判斷寫入每一個主體組件的內容。
Return Request.Content.ReadAsMultipartAsync(Of AzureBlobStorageMultipartProvider)(streamProvider) _
.ContinueWith(Of List(Of FileDetails))(
Function(f)
' 如果Task發生例外就中斷
If f.IsFaulted Then
Throw f.Exception
End If
Dim provider As AzureBlobStorageMultipartProvider = f.Result
Return provider.Files
End Function)
End Function
''' <summary>
''' 由Blob容器取得已上傳的檔案清單
''' </summary>
Iterator Function GetFiles() As IEnumerable(Of FileDetails)
Dim container As CloudBlobContainer = BlobHelper.GetWebApiContainer()
For Each blob As CloudBlockBlob In container.ListBlobs()
Yield New FileDetails With {
.ContentType = blob.Properties.ContentType,
.Location = blob.Uri.AbsoluteUri,
.Name = blob.Name,
.Size = blob.Properties.Length}
Next
End Function
End Class
HTTP POST會對應至PostFile方法,HTTP GET會對應至GetFile方法。PostFile方法讀取上傳的檔案並寫入Blob儲存體之中。GetFile方法會讀取容器內的資訊,產出一分清單。
接下來看是要用Postman或Fiddler進行上傳檔案測試即可。
上傳大檔案的額外設定
ASP.NET預設上傳的檔案大小是 4 MB,如果有上傳大檔案的需求,可以在web.config進行組態設置。
<httpRuntime targetFramework="4.5" maxRequestLength ="1048576"/>
重點在maxRequestLength的設置,例如,上面設置允許上傳 1 GB 大小的檔案。
另外,如果是在IIS,可以設置maxAllowedContentLength,例如,下面在IIS端設置允許 2GB 大小的檔案。
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="2147483648" />
</requestFiltering>
</security>
</system.webServer>
這邊注意一下,maxRequestLength的計算單位是kilobytes,maxAllowedContentLength的計算單位是bytes。



沒有留言:
張貼留言
感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。