使用Azure Cosmos DB和DocumentDB包进行快速ASP.NET核心开发

该的mvc控件工具箱的核心是建立专业水平的工具免费回收ASP.NETMVC的核心,它包括一个专业的MVC应用程序是由所有层的Web应用程序:数据和业务层的工具,控制工具和浏览工具。在这篇“如何”的文章中,我将演示如何使用MvcControlsToolkit.Business.DocumentDBNuget包快速构建一个基于CosmosDB的简单但完整的ASP.NETMVC核心应用程序。

什么是AzureCosmosDB?CosmosDB是Azure上可用的分布式数据库。数据可以在多个地理区域中复制,并且可以从通常由云服务提供的冗余和可伸缩性功能中受益。CosmosDB不是关系数据库。其数据元素称为“文档”,可以表示为JSON对象。这些文档没有预定义的结构:每个文档可能具有不同的属性,并且可能包含嵌套的JSON对象和数组。文档被分组为“集合”,通常是一组异构文档。

现在点击“AzureCosmosDB”。在显示的信息页面中,单击页面末尾的“创建”按钮。您应该看到与此类似的页面:

选择CosmosDB帐户的ID(与图像中显示的ID不同),然后选择SQLAPI。您可以创建新资源组,也可以使用现有资源组。然后选择您所在国家/地区旁边的位置,并选中“固定到信息中心”,以便您的Cosmos数据库显示在Azure信息中心中。避免选中“启用地理冗余”,因为这可能会迅速减少您的免费试用信用额度。您可以在以后添加地理冗余。最后点击“创建”。帐户创建需要几分钟。

部署后,单击新创建的资源,然后查找并单击“密钥”菜单项。

这将显示包含连接信息的页面。您需要CosmosDBURI和PRIMARYKEY。将它们存储在某处,或者只是将该页面保持打开状态。MvcControlsToolkit核心DocumentDB包MvcControlsToolkit.Business.DocumentDBNuget包是MvcControlsToolkitCore工具的一部分。

添加VisualStudio建议的所有using子句。JsonProperty属性指定如何序列化/反序列化每个属性以与CosmosDB进行通信。使用以下代码添加ToDoItem类:

“CollectionKey”属性应用于所有集合,它声明当两个元素表示同一实体时,集合元素的哪个属性用于验证。当更新应用于现有的CosmosDB文档时,还需要匹配集合元素。所有者使用权限系统对连接进行编码。在我们的简单应用程序中,它只是创建记录的用户的名称,也是唯一对其具有读/写权限的用户。

“您的URI”和“您的密钥”必须替换为您的CosmosDB帐户的URI和主键。静态类定义数据库名称和所有集合名称(在我们的示例中只是一个集合)。

GetConnection工厂方法基于类中包含的数据创建IDocumentDBConnection对象。“Initialize”方法首先确保已存在具有所需名称的数据库,然后确保创建所有必需的集合(在我们的示例中只有一个)。如果数据库不存在,则“CreateDocumentCollectionIfNotExistsAsync”将返回Created状态代码,因此必须创建它。

运行该项目。在azure门户中,您应该看到新创建的数据库,集合以及集合中包含的数据。编码业务/数据层由于我们的应用程序非常简单,我们不会定义单独的业务和数据层,而是一个独特的业务/数据层。在项目根目录中创建一个“Repository”文件夹,并将其添加为“ToDoItemsRepository”类:

我们的存储库继承自DocumentDBCRUDRepository通用存储库,并没有做太多,但以下内容:1.将作为第一个构造函数参数接收的连接对象传递给基础构造函数2.使用作为第二个参数接收的已记录用户的用户名来构建它传递给基础构造函数的两个过滤器子句。第一个过滤子句将自动应用于所有搜索操作,而第二个过滤器将应用于所有更新和删除操作;从而防止当前用户修改他/她不是所有者的文件。

连接对象作为单例添加,因为它不包含状态信息。相反,每次需要实例时都会创建存储库对象(因为它是有状态的)。在我们的示例应用程序中,存储库接收从HttpContext中提取的已记录用户名以处理权限。但是,在现实生活中,我们应该传递一个或多个从HttpContext中提取的声明?.User?.Claims枚举。

第一个参数是lambda表达式,指定每个“ToDoItem”必须转换为“ListItemDTO”,而第二个参数指定在“ListItemDTO”类中扮演键角色的属性。lambda表达式未指定如何使用“ToDoItem”类属性填充“ListItemDTO”属性。

我们对“AssignedTo”嵌套对象属性使用“Flattening”,并使用较短的类来表示子项。在这种情况下,投影稍微复杂一些,因为我们需要指定要包含的集合以及如何投影集合项:

在这里,嵌套在“AssignedTo”属性中的“Person”类属性的赋值是使用“Unflattening”约定来推断的,这些约定恰好与“Flattening”约定相反。必须始终在嵌套对象之前进行检查,以检查是否必须创建嵌套对象。在这种情况下,我们使用“AssignedToId”属性来验证嵌套人物对象的存在。省略对嵌套对象的检查可能会导致创建空对象或“空对象”异常。

然后我们重新定义已经存在的Index方法:

“GetPage”方法返回在方法的泛型参数中指定的DTO上投影的数据页面。第一个方法参数是过滤器表达式(在我们的例子中为null),而第二个参数是可选的排序(CosmosDB不支持“ThenBy”)。第三个参数是所需的页面:在我们的例子中是第一个数据页面:减号可以防止计算分布式数据库中的结果总数,这可能是一个非常昂贵的操作。

我们将使用它们来编辑和添加新项目。现在转到Views/Home/Index.cshtml视图,并使用以下代码替换其内容:

运行该项目。

如果您尚未登录,则应该看不到任何项目。一旦您使用frank@fake.com用户登录,您应该看到frank@fake.com拥有的两个项目;因为在“ToDoItemsRepository”的定义中,我们过滤了当前登录用户拥有的项目。在实际应用程序中,记录的所有权将添加到用户组而不是单个用户。

代码不言自明。我们使用“删除”存储库方法删除项目,使用“SaveChanges”方法提交删除操作。在实际应用中,需要更好的错误处理方法。例如,在出现网络错误的情况下,可能会在通知用户连接问题之前再次重试该操作。如果未找到要删除的项目,则可能会通知用户该项目不存在或已被删除。此外,值得指出的是,永远不应该使用Http“Get”来调用删除操作。

“创建”操作方法返回具有空ViewModel的页面,该页面具有空输入字段。而“编辑”操作方法从已经传递了id的“待办事项”返回填充了数据的页面。“GetById”存储库方法的两个泛型参数分别是DTO类型,以及传递给方法的主键“id”的类型。当用户提交此页面中包含的表单时,将调用“Edit”方法的“HttpPost”重载以执行所需的数据库修改:

在“Create”方法中,我们将创建一个新的主键,然后执行一个加法运算;而在“编辑”方法中,操作是更新。在这两种情况下,我们都调用“SaveChanges”来提交操作。

一个新的新主键也被添加到所有新添加的子项中,首先过滤它们然后修改它们。传递给所有存储库方法的“false”参数声明DTO不是“完整数据项”,即其属性不定义数据库数据项的所有属性。因此,在更新的情况下,必须将修改的项目与原始数据项合并而不是替换它。如果参数设置为“true”,则ViewModel中未指定的所有属性将重置为其默认值。

对于“DetailItemDTO”类,这是一个非常标准的基于Bootstrap的“编辑”视图。它不包含任何用于在编辑模式(添加,更新和删除)中呈现“子项”IEnumerable的代码。

您可以在“子项”标题和提交按钮表单组之间放置任何可编辑的网格。例如,如果您按照本教程中的说明配置项目以使用MvcControlsToolkit,则可以使用MvcControlsToolkit网格。您也可以使用基于Angular或Knockout.js的网格。

它是一个基于Bootstrap的表,其第一行是用于添加新行的行模板(这就是为什么它被设置为隐藏的原因)。表头包含一个用于添加新项的按钮,而每行的第一列包含一个用于删除该行的按钮。同一列包含“Subitems.Index”隐藏字段。

这是运行网格所需的JavaScript:

为简单起见,JavaScript是嵌入式插入的,但您可以在单独的JavaScript文件中按原样移动它。“addCount”变量用于为新添加的项生成唯一索引。程序启动时删除模板行。当用户单击“删除”按钮时,将删除包含该按钮的行。单击添加按钮时,将生成新索引,克隆模板行并将克隆附加到网格。新创建的索引将成为克隆行中“Subitems.Index”隐藏输入的值。

“表”方法的第一个参数是所需的页面大小。如果集合上定义了分区键,并且查询必须限制在特定分区,它还接受可选的分区键参数。最后,如果查询必须返回先前“ToSequence”查询的下一页,它会接受第三个“continuationtoken”字符串参数。

如果我们要列出当前登录用户拥有的所有“待办事项”的所有团队成员,该怎么办?首先,我们需要一个“PersonListDTO”DTO:在这种情况下,代码有点不同:

实际上,由于传递给“ToList”的“IQueryable”是IQueryable而不是IQueryable,因此我们必须使用包含第二个泛型参数的“ToList”的不同重载。此外,“ToDoItemsRepository”静态构造函数中的投影声明有点不同:

实际上,这次我们调用“DocumentreProjection”静态方法“DocumentDBCRUDRepository”而不是“DocumentDBCRUDRepository”。我们还需要两个“HomeController”动作方法:

and

可以在_Layout页面的主菜单中添加指向新添加页面的链接:

  • 发表于:
  • 原文链接:https://kuaibao.qq.com/s/20181019A1O94D00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券