在这篇博客文章中,我们将通过在Azure BLOB存储中保存ASP.NET标识2.0用户的图像,将ASP.NET MVC与Azure BLOB存储集成。我们将在这篇文章中涵盖很多内容,包括:
- 使用ASP.NET标识2.0用户作为其他表中的引用。
- 创建一对多关系与ASP.NET标识2.0用户表
- 将ASP.NET MVC应用程序连接到Azure存储
- 创建或上载BLOB
- 删除BLOB
- 下载BLOB
- 上传文件从MVC窗体到Azure BLOB
我们计划在这篇文章中创建的博客文章的最终输出将看起来或多或少像下面的图片。如您所见,用户可以将照片上传到她的相册,删除照片,当然也可以查看照片。
架构的应用程序
可以绘制应用程序的高级体系结构,如下图所示:
创建表以保存图像
当我们在Visual Studio中使用给定的MVC模板创建ASP.NET MVC应用程序时,默认情况下,使用ASP.NET标识2.0创建基本身份验证。在默认的MVC项目中,用于身份验证和授权目的的模板ASP.NET Identity 2.0创建表,如下图所示:
用户的信息存储在AspNetUsers表中。让我们看看这个表在这里:
对于AspNetUsers,表Id是主键。我们的目标是保存用户的各种照片。为了维护用户照片,让我们创建一个表。如果您不知道,ASP.NET标识2.0使用实体框架代码优先方法创建表。因此,我们将遵循相同的方法来创建一个表,该表将保存有关用户照片的信息。
要创建表,请右键单击模型文件夹,然后添加一个类。将名称UserImage提供给创建的类。
UserImage.cs
UserImage公共类{ 公共字符串Id {get; set; } 公共字符串ImageUrl {get; set; } 公共字符串UserId {get; set; } 公共虚拟ApplicationUser ApplicationUser {get; set; }}
在我们继续之前,让我们了解AspNetUsers表和UserImages表之间的关系,可以定义如下:
- 一个用户可以拥有多张照片
- 没有任何用户关联
- AspNetUsers表和UserImages表是一对多的关系。
- AspNetUsers表是主表,UserImages表是辅助表。
- 用户id是UserImages表中的外键。
就没有照片
正如我们所知,ASP.NET身份2.0使用实体框架代码优先的方法,因此我们使用代码优先的方法创建实体之间的关系。正如您在上面的代码片段中注意到的,对于导航属性,我们正在UserImage类中创建ApplicationUser类的虚拟属性。请记住,ApplicationUser类是AspNetUsers表的模型类。我们已经在UserImage类中创建了关系。接下来,我们需要在ApplicationUser类中创建一个关系。您可以在Model/IndetityModel.cs中找到ApplicationUser类
不要删除ApplicationUser类中的任何现有代码,并添加以下代码。下面的代码是创建ApplicationUser和UserImage之间的一对多关系:
public ApplicationUser (){UserImages = new HashSet(); } public ICollection UserImages {get; set; }
最后但并非最不重要的是要创建UserImages表,请在ApplicationDbContext类中添加以下代码行。你会发现ApplicationDbContext类在相同的模型/inditymodel.cs
公共DbSet UserImages {get; set; }
剩下的最后一步是使用新表UserImages更新数据库,并在AspNetUsers表中创建关系。由于我们遵循的是代码优先的方法,迁移应该是小菜一碟!从菜单中选择 “ 查看”-> “其他窗口”-> “管理”-> “包管理器控制台”
在Package Manger控制台上,运行以下命令。
启用迁移 > PM
添加迁移v1 > PM
更新-数据库 > PM
成功执行这些命令后,数据库将使用新表进行更新。新的表结构将如下图所示。如您所见,UserId是UserImages表中的外键。
由于我们没有更改连接字符串,因此将在默认的本地数据库服务器中创建数据库。但是,您可以更改指向任何数据库服务器的连接字符串,并更新ApplicationDbContext类中的连接字符串。
创建帮助程序类上传图像在Azure BLOB
我们将使用Azure团队创建的Azure存储库从MVC应用程序对Azure blob执行操作。为此,我们需要在项目中添加WindowsAzure.Storage NuGet包。右键单击项目,然后单击管理NuGet包。在包管理器中,搜索WinowsAzure.Storage并将其安装在项目中。
我们将创建一个实用工具类来在Azure BLOB存储中执行以下任务。
- 上传图像到BLOB
- 下载映像
- 删除图像和BLOB
在这个例子中,我将对容器名称进行硬编码。如果您是Azure BLOB存储的新手,请将图像作为容器内的BLOB上传。我们不打算创建容器,但将使用门户中已创建的容器。
在我们继续前进之前,让我们执行以下任务
- 登录到Azure门户
- 点击新建-> 数据存储-> 存储帐户创建一个新的存储帐户
- 创建存储帐户后,从所有资源中选择该帐户。
- 单击BLOB服务,然后单击容器。从顶部单击以创建容器。
我将使用已经创建的名为jsr的容器。您可以找到存储服务的容器列表,如下图所示:
从与Azure存储连接。NET代码,我们需要一个连接字符串或密钥到Azure存储。通过单击Azure存储服务中的设置-> 键,可以在门户中找到连接字符串和键,如下图所示:
我们需要在代码中使用主连接字符串来连接Azure存储。
太好了,现在让我们继续创建一个类。我将类命名为BlobUtility,并将其放入名为Utilities的文件夹中。
在BlobUtility类的构造函数中,我们正在创建一个连接字符串来连接Azure存储。要创建连接字符串,我们需要传递两个参数:
- 存储帐户名称
- 存储帐户密钥
我们已经从门户记录了帐户名称和帐户密钥。我们将在控制器类中创建BlobUtility类的实例,并从那里传递存储帐户名称和密钥。
下面的清单显示了如何为Azure存储创建连接字符串:
公共类的blobuility{ 公共CloudStorageAccount storageAccount; 公共BlobUtility (string AccountName、string AccountKey){ string UserConnectionString = string .Format( "DefaultEndpointsProtocol = https;AccountName ={0};AccountKey ={1}", AccountName, AccountKey);storageAccount = CloudStorageAccount.Parse(UserConnectionString);}}
现在我们需要函数来:
- 上传图像在BLOB
- 删除图像或BLOB
- 下载映像
要在BLOB中上传图像,我们将传递BLOB或图像的名称、容器名称 (在本例中为JSR) 和图像流。我们将图像作为块上传。创建BLOB的方法有两种:
- 页面BLOB
- 块BLOB
我们将创建一个块BLOB。还要记住,容器是一个公共容器,对它没有限制。下面是将图像上传到BLOB的最简单的方法。
公共CloudBlockBlob UploadBlob (字符串BlobName, 字符串ContainerName,Stream stream){ CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();CloudBlobContainer容器 = blobClient.GetContainerReference(ContainerName.ToLower ());CloudBlockBlob blockBlob = 容器.GetBlockBlobReference(BlobName); // blockBlob.UploadFromByteArray() 尝试{blockBlob.UploadFromStream (流); 返回blockBlob;} catch (异常e){ var r = e.消息; 返回null;}}
在上面的清单中,我们执行以下任务:
- 在CloudBlobClient中创建对象
- 获取引用的容器
- 创建一个对象块BLOB
- 上传图像流在块BLOB
UploadBlob函数将图像作为块BLOB上传,并将返回新创建的CloudBlobBlock。
可以通过对CloudBlobBlock的对象调用Delete方法来删除BLOB。下面列出的代码将基于给定Azure容器中的BlobName删除。
DeleteBlob (字符串BlobName, 字符串ContainerName)
public void{CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();CloudBlobContainer容器 = blobClient.GetContainerReference(ContainerName);CloudBlockBlob blockBlob = 容器.GetBlockBlobReference(BlobName);blockBlob.Delete();}
可以使用下面详述的函数下载BLOB:
公共CloudBlockBlob DownloadBlob (string BlobName, string ContainerName){CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();CloudBlobContainer容器 = blobClient.GetContainerReference(ContainerName);CloudBlockBlob blockBlob = 容器.GetBlockBlobReference(BlobName); // blockBlob.DownloadToStream(Response.OutputStream); 返回blockBlob;}
请记住,公共BLOB的可以直接通过点击BLOB URL下载。因此,我们可能不使用此功能,而是直接点击URL在浏览器中下载BLOB。当我们把所有的东西放在一起时,BlobUtility类将有以下代码:
使用Microsoft.WindowsAzure.Storage的
;Microsoft.WindowsAzure.Storage.Blob使用;使用系统;System.IO使用;UserImageUploadAzure.Utilities命名空间{ BlobUtility公共类{ 公共CloudStorageAccount storageAccount; 公共BlobUtility (string AccountName、string AccountKey){ string UserConnectionString = string .Format( "DefaultEndpointsProtocol = https;AccountName ={0};AccountKey ={1}", AccountName, AccountKey);storageAccount = CloudStorageAccount.Parse(UserConnectionString);} 公共CloudBlockBlob UploadBlob (字符串BlobName, 字符串ContainerName,Stream stream){ CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();CloudBlobContainer容器 = blobClient.GetContainerReference(ContainerName.ToLower ());CloudBlockBlob blockBlob = 容器.GetBlockBlobReference(BlobName); // blockBlob.UploadFromByteArray() 尝试{blockBlob.UploadFromStream (流); 返回blockBlob;} catch (异常e){ var r = e.消息; 返回null;}} DeleteBlob (字符串BlobName, 字符串ContainerName) public void{CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();CloudBlobContainer容器 = blobClient.GetContainerReference(ContainerName);CloudBlockBlob blockBlob = 容器.GetBlockBlobReference(BlobName);blockBlob.Delete();} 公共CloudBlockBlob DownloadBlob (string BlobName, string ContainerName){CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();CloudBlobContainer容器 = blobClient.GetContainerReference(ContainerName);CloudBlockBlob blockBlob = 容器.GetBlockBlobReference(BlobName); // blockBlob.DownloadToStream(Response.OutputStream); 返回blockBlob;}}}
我们编写了实用程序类,它将执行以下操作:
- 上传图片到BLOB
- 删除BLOB
- 下载BLOB
创建控制器和视图
到目前为止,我们已经创建了一个表和实用程序类。现在让我们在控制器中使用它来执行操作。首先在HomeController中创建BlobUtility类和ApplicationDbContext的对象。我们在HomeController的构造函数中声明全局变量并创建对象,如下所示:
公共类HomeController: 控制器{膨胀效用;ApplicationDbContext db; string accountName = "yourazurestorageaccountname"; string accountKey = "yourazurestorageaccountkey"; 公共主页 (){utility = 新的BlobUtility(accountName,accountKey);db = 新ApplicationDbContext();}
在HomeController的索引操作中,我们希望显示登录用户的所有照片。我们可以通过以下步骤做到这一点:
- 获取当前登录用户
- 从UserImages表中,获取已登录用户的所有映像。我们正在获取基于用户id的所有图像。
- 在ViewBag中,传递总计数的照片
- 传递一个列表的用户图像的视图
的Id
将上述所有内容放在一起,索引操作将具有如下所示的代码:
公共ActionResult索引 (){ 字符串loggedInUserId = User.Identity.GetUserId();List<UserImage> userImages = (从db.UserImages中的r. 其中r.UserId = = loggedInUserId选择r).ToList();ViewBag.PhotoCount = userImages.Count; 返回视图 (userImages);}
我们已经创建了获取已登录用户的所有图像的操作。让我们继续,下一步创建一个视图来显示照片。视图将非常简单。在视图中,我们正在迭代图像列表并在引导列中显示。此外,我们还为每个图像添加了一个删除按钮。当用户单击 “删除” 按钮时,该特定图像将从UserImages表和Azure BLOB中删除。
本质上,我们在视图中执行以下任务:
- 迭代所有照片并显示在-image元素
- 显示照片的页眉
- 添加删除按钮以删除所有照片。
中
可以创建如下所示的视图:
@ model IEnumerable <UserImageUploadAzure。模特。UserImage > <div class = "row" > <div class = "col-lg-12" > <div class = "alert-warning" 您有 @ ViewBag.PhotoCount照片 </div> </div> </div>@ foreach (模型中的var项){ “col-lg-3 col-md-4 col-xs-6拇指” <div class = > <a class = "thumbnail" href = "@ item.ImageUrl" > <img 类 ="img-响应" src ="@ item.ImageUrl" 样式 ="高度: 300px; 宽度: 100%;" alt =""> </a> <a href ="@ Url.Action("DeleteImage", "首页",新建 { id = item.Id })" 类 ="btn btn-默认btn-块"> <span class = "glyphicon glyphicon-remove" aria-hidden = "true" ></span> </a> </div> } </div>
正如您可以清楚地看到的,我们使用了许多bootstrap类来使视图更加身临其境。给定用户的图像将显示在视图上,如下图所示:
好极了!到目前为止,我们已经列出了登录用户的所有照片。现在让我们执行删除操作。正如您在视图中可能已经注意到的那样,在删除按钮上,我们正在调用Home controller的DeleteImage操作。我们还传递了要删除的id。
DeleteImage操作执行两个任务:
- 删除一行从UserImages表中的给定id;
- 删除图像从Azure BLOB
这两种操作都非常简单。首先,我们从表中获取要删除的行,并删除它。之后,我们从URL中提取BLOB名称,并从Azure BLOB存储中删除BLOB。可以创建DeleteImage操作,如下面的清单所示:
公共ActionResult DeleteImage (字符串id){UserImage userImage = db.UserImages.Find(id);db.UserImages.Remove(userImage);db.SaveChanges(); 字符串BlobNameToDelete = userImage.ImageUrl.Split( '/' ).Last();utility.DeleteBlob(BlobNameToDelete, "jsr" ); 返回 “Index” (RedirectToAction );}
到目前为止,我们已经执行了列出所有图像和删除图像的任务。现在让我们编写一个动作来上传图像。在UploadImage操作中,
- 上传图像到Azure BLOB
- 正在向UserImages表插入新行。
[HttpPost] 公共ActionResult UploadImage (HttpPostedFileBase文件){ if (file != null){ string ContainerName = "jsr"; // 硬编码的容器名称.文件 = 文件??Request.Files (“文件” ); 字符串文件名 = Path.GetFileName(file.fileName);流imageStream = file.InputStream; var结果 = utility.UploadBlob(fileName,ContainerName,imageStream); if (result != null){ 字符串loggedInUserId = User.Identity.GetUserId();UserImage userimage = new UserImage();userimage.Id = 新的随机 ().Next().ToString();userimage.UserId = loggedInUserId;userimage.ImageUrl = result.Uri.ToString();db.UserImages.Add(userimage);db.SaveChanges(); 返回 “Index” (RedirectToAction );} 其他{ 返回 “Index” (RedirectToAction );}} 其他{ 返回 “Index” (RedirectToAction );} }
在UploadImage操作中,我们将HttpPostedFileBase作为输入参数传递,并将图像作为流上传。在视图中,我们使用HTML文件类型和上传作为multipart/formdata。此外,文件上传在表单内,并调用家庭控制器的UploadImage动作。可以创建上传图像的视图,如下面的清单所示:
<div class = "row" >@ using (Html.BeginForm("UploadImage", "Home", FormMethod.Post, new { enctype = "multipart/form-data" })){ <div class = "panel panel-warning" > <div class = "panel-heading" > <h3: class = "panel-title" > 将照片保存到相册中 </h3> </div> <div class = "panel-body" > <div class = "row" > <div class = "col-md-4 col-md-offset-4" > <input type = "file" name = "file" /> <br /> <input type = "submit" class = "btn btn-warning form-control" value = "Save Photo" /> </div> </div> </div> </div>} </div>
通过将所有部分放在一起,查看,上传,删除和列出照片将具有如下所示的代码:
@ model IEnumerable <UserImageUploadAzure。模特。UserImage ><div class = "container" > <div class = "page-header" > <h1> 用户相册MVC <small> 使用ASP.NET标识2.0用户和Azure BLOB存储 </small></h1> </div> <div class = "row" >@ using (Html.BeginForm("UploadImage", "Home", FormMethod.Post, new { enctype = "multipart/form-data" })){ <div class = "panel panel-warning" > <div class = "panel-heading" > <h3: "panel-title" class = "> 将照片保存到相册中 </h3> </div> <div class = "panel-body" > <div class = "row" > <div class = "col-md-4 col-md-offset-4" > <input type = "file" name = "file" /> <br /> <input type = "submit" class = "btn btn-warning form-control" value = "Save Photo" /> </div> </div> </div> </div>} </div> <br /> <div class = "row" > <div class = "col-lg-12" > <div class = "alert-warning" 您有 @ ViewBag.PhotoCount照片 </div> </div> </div>@ foreach (模型中的var项){ “col-lg-3 col-md-4 col-xs-6拇指” <div class = > <a class = "thumbnail" href = "@ item.ImageUrl" > <img 类 ="img-响应" src ="@ item.ImageUrl" 样式 ="高度: 300px; 宽度: 100%;" alt =""> </a> <a href ="@ Url.Action("DeleteImage", "首页",新建 { id = item.Id })" 类 ="btn btn-默认btn-块"> <span class = "glyphicon glyphicon-remove" aria-hidden = "true" ></span> </a> </div> } </div></div>
结论
给你!这就是为使用Azure BLOB存储的ASP.NET用户创建相册所需的全部内容。在这篇文章中,我们讨论了以下主题:
- 使用ASP.NET标识2.0用户作为其他表中的引用。
- 创建一对多关系与ASP.NET标识2.0用户表
- 将ASP.NET MVC应用程序连接到Azure存储
- 创建或上载BLOB
- 删除BLOB
- 下载BLOB
- 上传文件从MVC窗体到Azure BLOB
我希望你发现这篇文章有用-感谢阅读!</p