| 摘要:无责任Windows Azure SDK .NET开发入门篇,将带来一系列基础文章:从Windows Azure开发前准备工作、使用Azure AD 管理用户信息、创建管理“云”服务、到使用Blob Storage服务等,帮助读者轻易上手使用这套开发工具。 
                          完成了身份授权和用户信息管理,我们终于可以真正使用Azure的服务了。Azure PaaS服务中比较出名的首推存储服务,存储服务中比较出名的首推Blob Storage服务,本章我们使用SDK 完成Blob Storage服务的应用。 Blob 存储一般用于存储文件数据。Blob 可以是任何类型的文本或二进制数据,如文档、媒体文件或应用程序安装程序。也就是说Blog非常适合用于存储提供下载的文件。在开封Blob服务前,你需要了解几个概念  
 
                          帐户。存储帐户是存储系统中的一个全局唯一标识的实体。帐户是 BLOB 服务的父级命名空间。所有容器都与一个帐户关联。
                          容器。容器是帐户内一组用户定义的 Blob。容器资源没有关联的内容,只有属性和元数据。容器名称必须是有效的 DNS 名称且符合以下命名规则
                          Blob。Blob 是表示一组内容的实体。Blob 资源包含内容、属性和元数据。Blob 名称可以包含任何字符组合,长度必须至少为 1 个字符,且不能超过 1,024 个字符。Blob 名称区分大小写,且组成 Blob 名称的路径段数目不能超过 254 个。大部分文件是块 blobs。单个块 blob 最大可以为 200 GB。
                          URL 格式: Blob 可使用以下 URL 格式寻址:http://<storage account>.blob.core.chinacloudapi.cn/<container>/<blob> 
                          你一定要记住:BLOB 服务基于平面存储方案而不是分层方案。但是,可以在 Blob 名称中指定字符或字符串分隔符来创建虚拟层次结构。 使用Blob Storage服务我们需要在配置文件写入存储资源的连接字符串,这个概念类似数据库的连接字符串。连接字符串在appSettings节点中 
                           
                            | <add key="Microsoft.ServiceBus.Namespace" value="Endpoint=sb://<你的存储链接url>/;SharedAccessKeyName=<你的共享密钥>" />
 <add key="Microsoft.WindowsAzure.Storage"
 value="BlobEndpoint=<你的存储资源链接>/;QueueEndpoint=<你的存储资源链接>;
 TableEndpoint=<你的存储资源链接>/;
 AccountName=<你的存储资源名称>;
 AccountKey=<你的存储资源访问密钥> " />
 |  
                          我们需要从NuGet获取WindowsAzure.Storage库,该库的项目地址是:https://www.nuget.org/packages/WindowsAzure.Storage,引用完成后,我们建立本章的控制器:StorageBlobController,该控制器有如下Action 
                          Index
                          Create
                          Delete
                          List
                          Upload 
                           
                            | [Authorize]public class StorageBlobController : Controller
 {
 CloudStorageAccount storageAccount = CloudStorageAccount.Parse
 (CloudConfigurationManager.GetSetting("Microsoft.WindowsAzure.Storage"));
 CloudBlobClient blobClient = null;
 
 public StorageBlobController()
 {
 blobClient = storageAccount.CreateCloudBlobClient();
 }
 }
 
 |  
                          这次我们将[Authorize]加载到Controller上,意味着本次控制器的所有操作都必须经过身份验证。 一、列出当前存储账号容器 代码简单到无法直视 
                           
                            | public ActionResult Index(){
 var containes = blobClient.ListContainers();
 return View(containes);
 }
 |  
                          对应的View 
                           
                            | @model IEnumerable<Microsoft.WindowsAzure.Storage.Blob.CloudBlobContainer>
                              @{
 ViewBag.Title = "Index";
 }
 
 <h2>Index</h2>
 
 <p>
 @Html.ActionLink("创建新的容器", "Create")
 </p>
 <table class="table">
 <tr>
 <th>Name</th>
 <th>StorageUri</th>
 <th>Uri</th>
 </tr>
 
 @foreach (var item in Model)
 {
 <tr>
 <td>
 @Html.ActionLink(@item.Name, "List", new { name = item.Name })
 </td>
 <td>@item.StorageUri</td>
 <td>@item.Uri</td>
 <td>
 @Html.ActionLink("上传文件", "Upload", new { name = item.Name }) |
 @Html.ActionLink("删除", "Delete", new { name = item.Name })
 </td>
 </tr>
 }
 </table>
 
 |  
                          运行结果如图 
 二、创建新的容器 创建新的容器之前我们必须判断有没有同名,然后设置容器访问权限 
                           
                            | [HttpPost]public ActionResult Create(string name)
 {
 CloudBlobContainer container = blobClient.GetContainerReference(name);
 container.CreateIfNotExists();
 container.SetPermissions(new BlobContainerPermissions
 {
 PublicAccess = BlobContainerPublicAccessType.Blob
 });
 return RedirectToAction("Index");
 }
 |  
                          对应View的代码 
                           
                            | @model Microsoft.WindowsAzure.Storage.Blob.CloudBlobClient
                              @{
 ViewBag.Title = "Create";
 }
 
 <h2>Create Cloud Blob</h2>
 
 @using (Html.BeginForm())
 {
 @Html.AntiForgeryToken()
 @Html.ValidationSummary(true, "", new { @class = "text-danger" })
 <div class="form-group">
 @Html.Label
 ("容器名称(容器名称只能包含小写字母、数字和连字符,并且必须以字母或数字开头。 名称不能包含两个连续的连字符)")
 @Html.TextBox("name", "", new { @class = "form-control" })
 </div>
 <div class="form-group">
 <input type="submit" value="Create" class="btn btn-default" />
 </div>
 }
 
 <div>
 @Html.ActionLink("Back to List", "Index")
 </div>
 
 |  
                          运行后你可以添加新的容器,关键就是:容器名称只能包含小写字母、数字和连字符,并且必须以字母或数字开头。 名称不能包含两个连续的连字符。并且SetPermissions必须在CreateIfNotExists成功执行之后运行。 
 创建成功后返回Index 
 三、删除容器 删除容器非常简单,获取到容器引用,然后删除 
                           
                            | public ActionResult Delete(string name){
 blobClient.GetContainerReference(name).Delete();
 return RedirectToAction("Index");
 }
 |  四、上传BLOB文件 现在是本章最后一节,也是最重要的一节,在本节中我们将了解到通过HTML的File将文件上传到容器中。控制器中将HttpPostedFileBase文件流上传到容器。 
                           
                            | [HttpPost]public ActionResult Upload(string name, HttpPostedFileBase[] files)
 {
 if (files == null)
 {
 return new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest);
 }
 CloudBlobContainer container = blobClient.GetContainerReference(name);
 
 foreach (HttpPostedFileBase item in files)
 {
 string filename = Guid.NewGuid().ToString() + "." + item.FileName.Split('.').Last();
 CloudBlockBlob blob = container.GetBlockBlobReference(filename);
 blob.UploadFromStream(item.InputStream);
 }
 
 return RedirectToAction("List", new { name = name });
 }
 
 |  
                          对应的View,注意Form需要声明enctype = "multipart/form-data" } 
                           
                            | @{ViewBag.Title = "Upload";
 }
 <h2>Upload</h2>
 
 @using (@Html.BeginForm("Upload", "StorageBlob", new
 { name = @ViewBag.Container }, FormMethod.Post, new { enctype = "multipart/form-data" }))
 {
 @Html.Label("选择文件")
 <input type="file" name="files"  multiple/>
 <input type="submit" value="上传" />
 }
 |  
 
 
                          你可以多上传几种文件,比如视频、音频、图片和其他文件。 五、列出容器中存储的数据 列出容器中存储的内容关键是需要将返回的对象转为CloudBlockBlob类型。在View建议你将不同类型的文件做更友好的显示,比如图片直接显示图片,音频文件直接使用HTML5的音频播发器 
                           
                            | public ActionResult List(string name){
 CloudBlobContainer container = blobClient.GetContainerReference(name);
 var result = container.ListBlobs(null, false).Where
 (x => x.GetType() == typeof(CloudBlockBlob)).Cast<CloudBlockBlob>();
 return View(result);
 }
 |  
                          对应的View对不同类型文件做了不同的呈现方案 
                           
                            | @model IEnumerable<Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob>
                              @{
 ViewBag.Title = "List";
 }
 
 <h2>List</h2>
 
 <p>
 @Html.ActionLink("上传文件", "Upload", new { name = @ViewBag.Container })
 </p>
 <table class="table">
 <tr>
 <th>Container</th>
 <th>Name</th>
 <th>Size</th>
 <th>Type</th>
 <th>Uri</th>
 <th>LastDate</th>
 </tr>
 
 @foreach (var item in Model)
 {
 <tr>
 <td>@item.Container.Name</td>
 <td>@item.Name</td>
 <td>@item.Properties.Length</td>
 <td>@item.BlobType</td>
 <td>
 @{
 var fileType = System.IO.Path.GetExtension(item.Name).ToLower();
 if (new string[] { ".jpg", ".png" }.Any(x => x == fileType))
 {
 <img src="@item.Uri" />
 }
 else if (new string[] { ".ogg", ".mp4" }.Any(x => x == fileType))
 {
 <video width="320" height="240" controls="controls">
 @if (fileType == "ogg")
 {
 <source src="@item.Uri" type="video/ogg">
 }
 else
 {
 <source src="@item.Uri" type="video/mp4">
 }
 
 Your browser does not support the video tag.
 </video>
 }
 else if (fileType == ".mp3")
 {
 <audio controls="controls">
 <source src="@item.Uri" type="audio/mpeg">
 Your browser does not support the audio tag.
 </audio>
 }
 else
 {
 <a href="@item.Uri">下载</a>
 }
 }
 </td>
 <td>@item.Properties.LastModified.Value.DateTime</td>
 </tr>
 }
 </table>
 
 |  
                          运行后如图 
 |