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

该的mvc控件工具箱的核心是建立专业水平的工具免费回收asp.net mvc的核心,它包括一个专业的mvc应用程序是由所有层的web应用程序:数据和业务层的工具,控制工具和浏览工具。
在这篇“如何”的文章中,我将演示如何使用mvccontrolstoolkit.business.documentdb nuget包快速构建一个基于cosmosdb的简单但完整的asp.net mvc核心应用程序。
什么是azure cosmos db?
cosmos db是azure上可用的分布式数据库。数据可以在多个地理区域中复制,并且可以从通常由云服务提供的冗余和可伸缩性功能中受益。
cosmos db不是关系数据库。其数据元素称为“文档”,可以表示为json对象。这些文档没有预定义的结构:每个文档可能具有不同的属性,并且可能包含嵌套的json对象和数组。
文档被分组为“集合”,通常是一组异构文档。最后,集合被分组到数据库中。所有文档属性都会自动编入索引,但可以对构建索引的方式以及如何索引属性执行一些调整。
cosmos db不仅提供不同的数据模型,而且比sql azure数据库便宜,这是一个分布式关系数据库,
事实上,cosmos db提供了一些不同的数据模型,即:
1.我们刚刚讨论过的严格的json文档/集合数据模型
2. 图形数据模型,其中文档可以是整个图形的顶点或标签。此模型可用于表示连接现实生活实体的语义关系,类似于社交应用程序中的关系。可以使用gremlin语言查询此模型。
3.基于两种不同的表/行/列数据模型,即老azure的表和卡桑德拉这是基于apache的卡桑德拉阿比。
在本文中,我将重点介绍严格的json文档/集合数据模型,该模型可以使用旧的documentdb azure服务的相同api或mongodb数据库的相同api进行查询。
我们将重点关注基于sql子集的documentdb接口,也可以使用linq查询。为了使用linq,json对象在json.net的帮助下映射到.net类,我们将在本文后面看到。
cosmos db documentdb接口限制
cosmos db documentdb接口具有一些在大多数实际应用中非常相关的限制。
首先,文档不能部分更新,但只能完全替换。
因此,例如,假设我们想要更改person复杂对象的“name”属性,该对象也可能具有其他属性,如“surname”,“spouse”。这些属性可能还包含嵌套的person对象,以及可能包含person对象的嵌套枚举的“children”。
正如您所看到的,我们被迫读取修改它的整个对象,并最终用完全修改的对象替换以前的版本。这种限制来自避免文档“锁定”以提高性能的设计选择。
另一个限制是能够对嵌套枚举执行“选择”操作。
因此,如果我们在linq查询中再次考虑前一个person文档示例,我们可能会在包含一些person属性的dto类中投影根person对象,但是我们不得不采用包含在其中的整个person对象。它的儿童财产。
这种限制非常“令人不安”,因为我们要么将整个person对象从数据层导出到表示层,从而打破了两层之间的分离; 或者我们被迫定义一组中间对象并执行一系列复制操作以获得不包含数据层对象的对象树。
性能限制的另一个缺点是缺乏对有效分页查询结果所需的linq“跳过”操作的支持。
一个次要但相关的限制是在排序中仅支持一个属性。因此,例如,不可能首先按姓氏对姓氏文件进行排序,然后按姓名排序,但必须在姓氏或姓名之间进行选择。
创建azure cosmos db帐户
如果您已拥有azure帐户,请登录您的帐户。或者,按照此页面上的说明创建免费试用帐户。登录后,转到门户(通过单击页面顶部的门户链接)。然后单击“创建资源按钮”(页面顶部的“+新建”)并搜索“数据库”。
现在点击“azure cosmos db”。在显示的信息页面中,单击页面末尾的“创建”按钮。您应该看到与此类似的页面:
选择cosmos db帐户的id(与图像中显示的id不同),然后选择sql api。您可以创建新资源组,也可以使用现有资源组。
然后选择您所在国家/地区旁边的位置,并选中“固定到信息中心”,以便您的cosmos数据库显示在azure信息中心中。避免选中“启用地理冗余”,因为这可能会迅速减少您的免费试用信用额度。您可以在以后添加地理冗余。最后点击“创建”。
帐户创建需要几分钟。在帐户创建期间,门户网站在右侧显示“部署azure cosmos数据库磁贴”,您可能需要在仪表板上向右滚动才能看到磁贴。屏幕顶部附近还显示一个进度条。您可以观看跟踪进度。
部署后,单击新创建的资源,然后查找并单击“密钥”菜单项。
这将显示包含连接信息的页面。您需要cosmos db uri和primary key。将它们存储在某处,或者只是将该页面保持打开状态。
mvc controls toolkit核心documentdb包
mvccontrolstoolkit.business.documentdb nuget包是mvc controls toolkit core工具的一部分。虽然本文不需要mvc controls toolkit的先验知识,但可以在dotnetcurry/aspnet-mvc/1376/full-stack-development-using-aspnet-mvc上找到mvc controls toolkit的完整介绍。 -core-toolkit。
所有documentdb特定的详细信息都由icrudrepository接口的documentdb特定实现的update,add,delete,updatelist,getbyid和getpage方法处理。
所有存储库方法都在dto / viewmodel上运行,并负责将dto / viewmodel映射到实际的数据库对象。
映射是递归的,并且涉及dto / viewmodel中递归包含的对象和集合。映射基于通过linq表达式提供的命名约定和规范。
命名约定自动处理对象展平和去展平,因此linq表达式通常非常简单,因为它们不需要指定每个属性的映射方式,而只是:1)名称约定的例外,以及2)部分必须映射对象树。简而言之,getbyid和getpage仅指定应用程序进入dto / viewmodel所需的每个documentdb条目的子树。
mvccontrolstoolkit.business.documentdb nuget包的“documentdbcrudrepository”类实现了“icrudrepository”接口,该接口在mvc controls toolkit中定义了用于将控制器与db层连接的可扩展标准。它包含一些直接用dto / viewmodel表示的常见更新和查询操作,因此数据对象对表示层隐藏。
“icrudrepository”的所有更新/添加/删除和查询方法将在本文后面进行演示。
堆叠所有“documentdbcrudrepository”更新,直到调用“async savechanges”“icrudrepository”方法,然后并行执行所有操作以最大化性能。所有失败的操作都由“documentsupdateexception ”聚合异常报告,可以通过将此异常传递给“retrychanges”方法来重试。
克服documentdb的局限性
“documentdbcrudrepository”还包含一些实用方法,用于构建复杂的linq查询,克服我们讨论的一些documentdb限制,即:
1.它允许文档的部分更新,这是documentdb接口本身不允许的(只允许完整的文档替换)。部分更新是通过自动检索完整文档并复制dto / viewmodels树中包含的所有更改来实现的。我们的模拟部分更新支持乐观并发。并发性在专门的章节中讨论。
2.它允许将嵌套集合投影到dto / viewmodels集合中。由于documentdb sql接口不允许对嵌套集合执行select操作,因此documentdbcrudrepository首先计算要从数据库中检索的所有属性,以便构建有效的查询,然后使用高效的内存在dto / viewmodel上投影结果预测。通过在程序开始时编译所有投影操作来实现性能。
3.它允许通过模拟documentdb sql接口不允许的跳过操作来进行经典的结果分页。更具体地说,它检索直到当前页面的所有文档密钥,仅获取所需的密钥,然后执行查询以检索与这些密钥相关联的所有文档。
在本文的其余部分,我将演示以下内容:
如何创建cosmosdb数据库,如何配置asp.net core项目以使用mvccontrolstoolkit.business.documentdb,如何定义/到dto类的投影,如何使用documentdbcrudrepository的icrudrepository方法,最后如何使用documentdbcrudrepository linq帮助器方法构建一些基于select many的查询。
设置项目
打开visual studio 2017并选择“文件”>“新建”>“项目”。然后选择asp.net core web application。将项目命名为“cosmosdbutilitiesexample”。在出现的弹出窗口中,选择“.net core”作为框架,选择“asp.net core 2.0”作为asp.net版本。最后,选择mvc应用程序,并将“个人帐户”作为身份验证(因为我们需要用户根据记录的用户过滤文档)。
现在运行项目并使用电子邮件注册用户:frank@fake(没有电子邮件验证),我们需要此用户名来过滤我们的数据。点击“注册”按钮时,系统将要求您应用所有挂起的数据库迁移。这样做,并刷新页面。
我们准备安装我们的实用程序包。右键单击解决方案资源管理器中的dependencies节点,然后打开nuget软件包安装程序。查找并安装最新版本的mvccontrolstoolkit.business.documentdb。
设置业务层
作为第一步,我们必须准备构建我们的cosmos db数据库的代码,以及我们的cosmos db集合(我们使用单个集合)。
在“models”文件夹下,为我们的cosmosdb数据模型添加一个名为“cosmosdb”的新文件夹。然后,在这个新文件夹下,添加一个名为“person”的新类,其代码如下:
添加visual studio建议的所有using子句。jsonproperty属性指定如何序列化/反序列化每个属性以与cosmos db进行通信。
使用以下代码添加todoitem类:
“collectionkey”属性应用于所有集合,它声明当两个元素表示同一实体时,集合元素的哪个属性用于验证。当更新应用于现有的cosmosdb文档时,还需要匹配集合元素。
所有者使用权限系统对连接进行编码。在我们的简单应用程序中,它只是创建记录的用户的名称,也是唯一对其具有读/写权限的用户。
更现实的应用程序可能包含用户对文档具有读取权限的组的名称,以及用户对文档具有更新权限的组的名称,或者有关已记录用户的更复杂声明。
现在我们准备编写一些代码来初始化和填充cosmos db数据库。
在项目“data”文件夹下,添加一个新的“cosmosdbdefinitions”类,其中包含以下代码:
“您的uri”和“您的密钥”必须替换为您的cosmosdb帐户的uri和主键。静态类定义数据库名称和所有集合名称(在我们的示例中只是一个集合)。
getconnection工厂方法基于类中包含的数据创建idocumentdbconnection对象。
“initialize”方法首先确保已存在具有所需名称的数据库,然后确保创建所有必需的集合(在我们的示例中只有一个)。
如果数据库不存在,则“createdocumentcollectionifnotexistsasync”将返回created状态代码,因此必须创建它。在这种情况下,调用“initdata”方法以使用测试数据填充集合。
在数据库和集合创建期间,可以指定几个选项来配置它们。有关更多详细信息,请参阅官方文档(这足以google方法的名称)。我只更改了字符串集合的索引策略以允许对字符串字段进行排序,因为只能使用使用基于树的索引而不是基于散列的索引的非默认“范围”策略进行排序。
必须在程序启动时调用“initialize”方法。这可以通过在“usemvc”调用之后立即将其调用放在startup.cs的“configure”方法中来实现,如下所示:
运行该项目。在azure门户中,您应该看到新创建的数据库,集合以及集合中包含的数据。
编码业务/数据层
由于我们的应用程序非常简单,我们不会定义单独的业务和数据层,而是一个独特的业务/数据层。
在项目根目录中创建一个“repository”文件夹,并将其添加为“todoitemsrepository”类:
我们的存储库继承自documentdbcrudrepository通用存储库,并没有做太多,但以下内容:
1.将作为第一个构造函数参数接收的连接对象传递给基础构造函数
2.使用作为第二个参数接收的已记录用户的用户名来构建它传递给基础构造函数的两个过滤器子句。第一个过滤子句将自动应用于所有搜索操作,而第二个过滤器将应用于所有更新和删除操作; 从而防止当前用户修改他/她不是所有者的文件。
在实际应用程序中,我们会传递从已记录用户提取的声明,例如“公司名称”,而不是简单的用户名。
我还添加了一个空的静态构造函数。稍后,在本文中,我们将添加声明,指定如何将todoitem数据类与dto类进行投影。
为了使我们的存储库可供所有需要它的控制器使用,我们必须将它添加到启动类的“configureservices”方法中:
连接对象作为单例添加,因为它不包含状态信息。
相反,每次需要实例时都会创建存储库对象(因为它是有状态的)。
在我们的示例应用程序中,存储库接收从httpcontext中提取的已记录用户名以处理权限。但是,在现实生活中,我们应该传递一个或多个从httpcontext中提取的声明?.user?.claims枚举。可以在使用usermanager.addclaimasync方法注册新用户时或稍后添加声明。
编写表示层
表示层实现的第一步是定义所需的dto类。
让我们将“dtos”文件夹添加到项目根目录。我们基本上需要两个dto - 一个用于列出搜索结果的短dto,另一个用于编辑/细节/添加目的。短dto可能只包含项目名称和“待办事项”分配给的姓名:
将列表页面与详细信息页面连接需要项目id。我们把属于“做项目”的人的“姓”分配给了一个财产。属性名称是“todoitem”数据模型的“assignedto”属性名称和person数据模型的surname属性名称的串联。将名称分配给dto属性的这种约定称为“展平”。
为了指定如何将数据模型投影到“listitemdto”对象�...