九、创建 Azure 应用服务
Azure 应用服务是一种平台即服务(PaaS),面向移动和应用开发人员,可以托管多种不同的应用模型和服务。 虽然开发人员可以在几分钟内创建一个简单的移动应用服务来充当数据存储访问层,而无需编写一行代码,但复杂而健壮的。net Core 应用也可以通过与其他 Azure 服务的内在集成来实现。
在本章中,我们将学习 Azure App Service 的基础知识,并使用 ASP 为我们的应用创建一个简单的面向数据的后端.NET 5,认证由Azure Active Directory(Azure AD)提供。 我们也将提高我们的 web API 端点 Redis 缓存的性能。 以下部分将指导您创建我们的服务后端:
- 选择正确的应用模式
- 创建我们的第一个微服务
- 集成 Redis 缓存
- 托管服务
- 确保应用
到本章结束时,您将完全有能力从头开始设计和创建 web 服务,并将它们集成到云基础设施中,同时还具有额外的性能和身份验证方面的非功能性需求。
技术要求
你可以通过以下 GitHub 链接找到本章使用的代码:https://github.com/PacktPublishing/Mobile-Development-with-.NET-Second-Edition/tree/master/chapter09。
选择正确的应用模式
Azure 堆栈提供了多个主机 web 应用的方法,不同的从简单的基础设施即服务(IaaS)产品,如虚拟机(【显示】vm)完全托管 PaaS 托管服务等应用服务。 因为。net Core 和 ASP 的平台无关性.NET Core、甚至 Linux 容器和容器编排服务(如 Kubernetes)都是可用的选项。****
**Azure 计算服务可以根据职责的划分分为三个主要类别,即 IaaS、PaaS 和容器即服务(CaaS**),如下图所示:
【t】【t】
图 9.1 -托管主机模型
除了 IaaS 和 PaaS 之外,还有各种托管选项,每种都有自己的优点和用例。 现在我们将仔细研究这些产品。
下面几节将带领您了解 Azure 生态系统中的不同应用托管模型。
Azure 虚拟机
虚拟机(虚拟机)是微软 Azure Cloud 上最古老的 IaaS 产品之一。 简单地说,这个产品提供了一个在云上具有完全控制的托管服务器。 Azure 自动化服务为您提供很需要的工具来管理这些服务器与基础设施代码(【显示】IaC)原则使用 PowerShell期望状态配置【病人】(DSC)和计划运行手册。 您可以根据您的应用需求轻松地伸缩和监视它们。
有了 Windows 和 Linux 变体,Azure vm 可以成为现有应用的简单、浅层云迁移路径。
VM 的扩展是通过在 VM 级别上调整系统配置(例如,CPU、虚拟磁盘、RAM 等)或在基础架构中引入额外的 VM 来实现的。
虚拟机托管发生在托管模型频谱的最左边; 换句话说,它提供了一个几乎完全自管理的主机模型。 在管理区域,我们有集装箱服务。
Azure 中的容器
如果虚拟机是硬件的虚拟化,则容器将操作系统虚拟化。 容器为共享相同操作系统内核的应用创建隔离的沙箱。 这样,由应用及其依赖项组成的应用容器可以轻松地托管在任何满足容器需求的环境中。 容器映像可以作为多个应用容器执行,这些容器实例可以使用 Docker Swarm、Kubernetes 和 Service Fabric 等编制工具进行编排。
Azure 目前有两个托管容器编排产品:Azure Kubernetes Service(AKS)和 Service Fabric Mesh。
Azure 集装箱服务与 Kubernetes
Azure 容器服务(ACS)是一个托管容器调度环境,在这里开发人员可以轻松地部署容器,并享受自动恢复和缩放体验。
Kubernetes 是一个开放源码的容器编排系统,最初是由谷歌设计和开发的。 Azure Kubernetes 是该服务的托管实现,其中大部分配置和管理职责都委托给了平台本身。 在这种设置中,作为这个 PaaS 产品的消费者,您只负责管理和维护代理节点。
AKS 支持 Linux 容器和 Windows 操作系统虚拟容器。 Windows 容器支持目前处于私有预览状态。
服务结构网格
Azure Service FabricMesh 是一个完全受管理的容器编排平台,在这个平台中,使用者无需与底层集群的配置或维护进行任何直接交互。 所谓的多语言服务(即任何语言和任何操作系统)是在容器中运行的。 在这种设置中,开发人员只负责指定应用所需的资源,例如容器的数量及其大小、网络需求和自动伸缩规则。
一旦部署了应用容器,Service Fabric Mesh 将容器托管在一个由数千台机器组成的集群中,而集群操作对开发人员是完全隐藏的。 通过软件定义网络(SDN)的智能消息路由实现了微服务之间的业务发现和路由。
尽管服务结构网格共享相同的底层平台,但它与 Azure 服务结构有很大的不同。 虽然 Service Fabric Mesh 是一个托管解决方案,但 Azure Service Fabric 是一个完整的微服务平台,允许开发人员创建容器化或本地云应用。
Azure 服务结构的微服务
Azure Service Fabric 是一个托管和开发平台,允许开发人员创建由微服务组成的企业级应用。 Service Fabric 提供了全面的运行时和生命周期管理功能,以及使用可变状态容器(如可靠的字典和队列)的持久编程模型。
服务 Fabric 应用可以由三种不同的托管服务模型组成:容器、服务/参与者和来宾可执行文件。
与它的托管版本(即 Service Fabric Mesh)和 Azure Kubernetes 类似,Service Fabric 能够运行针对 Linux 和 Windows 容器的容器化应用。 可以很容易地将容器包含在一个 Service Fabric 应用中,该应用与其他组件捆绑在一起,并通过高密度共享计算池(称为集群)和预定义的节点进行伸缩。
可靠的服务和可靠的参与者是真正的云本地服务,它们利用了服务结构编程模型。 在本地开发集群和。net Core 以及 Java 可用的 sdk 上进行开发的方便性,允许开发人员以平台无关的方式创建有状态和无状态的微服务。
重要提示
开发环境可用于 Windows、Linux 和 Mac OS X, Linux 和 OS X 开发设置依赖于在容器中运行 Service Fabric 本身,. net Core 是创建针对这些平台的应用的首选语言。 可用的 Visual Studio Code 扩展使得在每个操作系统上开发。NET Core 服务结构应用变得很容易。
最后,客户可执行文件可以是在各种语言/框架(如 Node.js、Java 或 c++)上开发的应用。 客户可执行文件作为无状态服务进行管理和处理,可以与其他服务 Fabric 服务并排放置在集群节点上。
Azure 基于容器的资源可以为开发高度复杂的微服务生态系统提供灵活性; 但是,您为容器和容器托管选择的任何模型都需要配置和基础设施管理,并且通常需要一个陡峭的学习曲线。 如果你正在寻找一个在配置和基础设施管理方面负担更轻的替代方案,我们可以继续我们的托管模型,选择 Azure App Service 作为我们的托管模型。
Azure 应用服务
Azure 应用服务是一个完全管理的 web 应用托管服务。 App Service 可以用于托管应用,而不考虑开发平台或操作系统。 App Service 为 ASP 提供了一流的支持.NET (Core)、Java、Ruby、Node.js、PHP 和 Python。 它可以与 Azure DevOps、GitHub 和 BitBucket 等 DevOps 平台进行即时集成和部署。 通常托管环境的大多数管理功能都集成到 App Service 刀片上的 Azure 门户中,例如伸缩、CORS、应用设置、SSL 等等。 此外,WebJobs 可以用来创建后台进程,这些进程可以作为应用包的一部分定期执行。
容器 Web 应用是 Azure 应用服务的另一个特性,它允许将容器化应用部署为应用服务,并与 Kubernetes 进行协调。
移动应用服务(Mobile App Service)是一种为简单的移动应用集成所有必要功能的简单方法,如身份验证、推送通知和离线同步。 然而,移动应用服务目前正在过渡到应用中心,不支持 ASP。 净的核心。
最后,Azure Functions 提供了一个平台来创建代码片段或无状态按需函数,并托管它们,而无需显式地提供或管理基础设施。
在本节中,我们了解了不同的托管模型及其优缺点。我们从 Azure vm 开始研究,对容器做了简短的介绍,最后讨论了 Azure 应用服务和功能的 PaaS 模型。 现在我们已经讨论了关于选择模型的基础知识,接下来我们将看看如何创建我们的第一个微服务。
打造首个微服务
对于我们的移动应用,在第八章,用 Cosmos DB 创建一个数据存储中,我们创建了一个简单的数据访问代理,从 Cosmos DB 中检索数据。 在这个练习中,我们将创建小型 web API 组件,这些组件将在集合上公开用于 CRUD 操作的各种方法。
初始设置
让我们开始我们的实现:
-
First, create an ASP.NET Core project:
图 9.2 -创建 ASP。 网项目
-
创建项目后,进行快速测试,检查
dotnet
核心组件是否正确设置。 - 打开一个控制台窗口并导航到项目文件夹。 以下命令将恢复引用的包并编译应用:
-
Once the application is built, we can use the
run
command and execute aGET
call to theapi/values
endpoint:图 9.3 -第一次运行 ASP.NET Core 应用
这将导致
WeatherForecastController
控制器的GET
方法的值输出。重要提示
在前面的示例中,我们使用
curl
来执行一个快速 HTTP 请求。 客户端 URL(curl)是一个实用程序,可在基于 unix 的系统、macOS 和 Windows 10 上使用。 -
Next, we will set up the Swagger endpoint so that we have a metadata endpoint, as well as a UI to execute test requests. For this purpose, we will be using the Swashbuckle NuGet packages to generate the API endpoint metadata. A basic setup of Swashbuckle requires three packages, and we can reference them together by adding the
Swashbuckle.AspNetCore
meta-package:图 9.4 - Swashbuckle NuGet
-
在添加了元包和依赖项之后,修改
Startup
类来声明服务: - 现在,运行应用并导航到
{dev host}/swagger
端点。 我们将看到生成的 Swagger UI 和方法声明:
图 9.5 - Swagger UI
现在我们已经准备好了样板 API 项目,这意味着我们可以继续实现我们的服务了。
实现检索操作
考虑到拍卖数据集,由于我们已经创建了 MVC 应用,我们应该在控制器中包含两个GET
方法:一个用于检索拍卖的完整集合,另一个用于检索特定的拍卖。
让我们看看如何做到这一点:
- 在开始实现之前,让我们将
WeatherForecastController
重命名为AuctionsController
。 -
We can simply initialize our repository and return the results for the first
GET
method:[HttpGet] public async Task<IEnumerable<Auction>> Get() { var result = Enumerable.Empty<Auction>(); try { result = await _cosmosCollection.GetItemsAsync(item => true); } catch (Exception ex) { // Log the error or throw depending on the requirements } return result; }
注意,这里使用的谓词针对的是完整的拍卖集。 我们可以使用查询参数来扩展这个实现,这些查询参数使用附加的谓词来过滤集合。
-
The
GET
method for retrieving a specific item would not be much different:``` [HttpGet("{id}")] public async Task Get(string id) { User result = null; try { result = await _cosmosCollection.GetItemAsync(id); } catch (Exception ex) { // Log or throw error depending on the requirements }
return result;
} ```
这样就可以满足需求,但是为了改进移动应用和 Cosmos 集合之间的交互,我们还可以启用OData查询,并创建一个到数据存储的透明查询管道。 为此,我们可以使用可用的。net Core 包实现 OData 控制器,或者在当前 MVC 控制器上启用查询。
重要提示
需要注意的是,我们用来生成 Swagger UI 的 Swashbuckle 包目前不支持 OData 控制器,因此这些 api 在 Swagger 接口上不可用。
-
对于 OData 的实现,我们首先在启动类中设置基础设施:
public void ConfigureServices(IServiceCollection services) { services.AddOData(); services.AddODataQueryFilter(); // ... Removed }
-
现在,为 MVC 控制器设置路由:
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseMvc(builder => { builder.Count().Filter().OrderBy().Expand().Select().MaxTop(null); builder.EnableDependencyInjection(); }); // ... Removed }
-
在 Cosmos 存储库客户端上创建一个新的方法,该方法将返回一个可查询集而不是一个结果集:
public IQueryable<T> GetItemsAsync() { var feedOptions = new FeedOptions { MaxItemCount = -1, PopulateQueryMetrics = true, EnableCrossPartitionQuery = true }; IOrderedQueryable<T> query = _client.CreateDocumentQuery<T>( UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId), feedOptions); return query; }
-
Finally, we need to implement our query action:
[HttpGet] [EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)] public ActionResult<IQueryable<Auction>> Get(ODataQueryOptions<Auction> queryOptions) { var items = _cosmosCollection.GetItemsAsync(); return Ok(queryOptions.ApplyTo(items.AsQueryable())); }
现在,可以在集合上执行简单的 OData 查询(例如,第一层 OData 过滤器查询)。 例如,如果我们在
Users
端点上执行一个查询,一个简单的过滤器查询以检索一个或多个拍卖的用户将如下所示:http://localhost:20337/api/users?$filter=NumberOfAuctions ge 1
为了能够扩大查询选项,执行查询相关的实体,我们需要创建一个实体数据模型(EDM)和注册各自 OData 控制器。****
**重要提示
支持高级搜索的另一个更合适的选项是创建一个 Azure 搜索索引,并在该索引之上公开 Azure 搜索功能。
对于内存中的 EDM 和数据上下文,我们将使用Microsoft.EntityFrameworkCore
的特性和功能。 让我们从实现开始:
-
创建一个
DbContext
,它将定义我们的主数据模型和实体之间的关系:``` public class AuctionsStoreContext : DbContext { public AuctionsStoreContext(DbContextOptions options) : base(options) { }
public DbSet Auctions { get; set; } public DbSet Users { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity().OwnsOne(c => c.Address); modelBuilder.Entity().HasMany(c => c.Auctions); } } ```
-
现在,让我们用在
ConfigureServices
方法中注册这个上下文:public void ConfigureServices(IServiceCollection services) { servics.AddDbContext<AuctionsStoreContext>(option => option.UseInMemoryData("AuctionsContext")); services.AddOData(); services.AddODataQueryFilter(); // ... Removed }
-
现在,创建一个返回 EDM 的方法:
private static IEdmModel GetEdmModel() { ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); var auctionsSet = builder.EntitySet<Auction>("Auctions"); var usersSet = builder.EntitySet<User>("Users"); builder.ComplexType<Vehicle>(); builder.ComplexType<Engine>(); return builder.GetEdmModel(); }
-
最后注册一条 OData 路由,实体控制器可以通过这条路由服务:
app.UseMvc(builder => { builder.Count().Filter().OrderBy().Expand().Select().MaxTop(null); builder.EnableDependencyInjection(); builder.MapODataServiceRoute("odata", "odata", GetEdmModel()); });
-
Now that the infrastructure is ready, you can navigate to the
$metadata
endpoint to take a look at the EDM that was generated:Figure 9.6 – OData EDM
-
现在,通过实现快速
ODataController
,我们可以向 OData 查询公开整个集合:public class AuctionsController : ODataController { private readonly CosmosCollection<Auction> _cosmosCollection; public AuctionsController() { _cosmosCollection = new CosmosCollection<Auction>("AuctionsCollection"); } // GET: api/Users [EnableQuery] public IActionResult Get() { var items = _cosmosCollection.GetItemsAsync(); return Ok(items.AsQueryable()); } [EnableQuery] public async Task<IActionResult> Get(string key) { var auction = await _cosmosCollection.GetItemsAsync(item => item.Id == key); return Ok(auction.FirstOrDefault()); } }
有了给定的ODataController
和用户集合的附加实现,就可以执行各种实体过滤器表达式,如以下所示:
http://localhost:20337/odata/auctions?$filter=Vehicle/Engine/Power%20gt%20120
http://localhost:20337/odata/users?$filter=Address/City%20eq%20'London'
http://localhost:20337/odata/users?$filter=startswith(FirstName,%20'J')
http://localhost:20337/odata/auctions('7ad0d2d4-e19c-4715-921b-950387abbe50')
至此,我们已经成功地使用 ASP 为 Cosmos Document DB 公开了一个 OData 端点.NET Core 和实体框架核心。 现在我们已经有了检索方法,我们需要实现处理数据创建和操作的方法。
实现更新方法
当我们处理不支持部分更新的 NoSQL 数据存储时,至少可以说,实现更新端点实际上是不同的。 根据应用需求,我们可以选择两个不同的模式。
在经典的并发模型中,我们将接收一个带有完整对象主体的PUT
请求,并检查更新是否正在对象的最新版本上执行。 可以在_ts
属性集合项上执行此并发检查。 时间戳属性也被 Cosmos DB 容器本身用于处理并发性问题。 让我们开始吧。
在这个模型中,传入的对象体将被验证,以检查它是否携带最新的时间戳,如果不携带,表示冲突的409
响应将作为响应发送回。 如果时间戳与存储库中的时间戳相匹配,那么我们可以自由地修改实体:
[EnableQuery]
[HttpPut]
public async Task<IActionResult> Put([FromODataUri]string key, [FromBody] Auction auctionUpdate)
{
var cosmosCollection = new CosmosCollection<Auction>("AuctionsCollection");
var auction = (await cosmosCollection.GetItemsAsync(item => item.Id == key)).FirstOrDefault();
if (auction == null)
{
return NotFound();
}
if (auction.TimeStamp != auctionUpdate.TimeStamp)
{
return Conflict();
}
await cosmosCollection.UpdateItemAsync(key, auctionUpdate);
return Accepted(auction);
}
然而,使用这种方法,随着对象树的大小增长,以及容器项的复杂性增加,更新的请求将变得更大,更难以执行(例如,更有可能发生冲突、无意识地删除属性等等)。 下面的截图显示了一个只更新拍卖文档的描述字段的请求:
图 9.7 - ASP。 网络更新请求/响应
为了减少更新调用的影响,至少对于客户端,我们可以使用PATCH
方法。 在PATCH
方法中,只有对象树的一部分作为增量传递,或者只有部分更新操作作为补丁操作传递。
让我们为相同的拍卖服务实现一个PATCH
操作,并检查请求:
[EnableQuery]
[HttpPatch]
public async Task<IActionResult> Patch(
string key,
[FromBody] JsonPatchDocument<Auction> auctionPatch)
{
var cosmosCollection = new CosmosCollection<Auction>("AuctionsCollection");
var auction = (await cosmosCollection.GetItemsAsync(item => item.Id == key)).FirstOrDefault();
if (auction == null)
{
return NotFound();
}
auctionPatch.ApplyTo(auction);
await cosmosCollection.UpdateItemAsync(key, auction);
return Accepted(auction);
}
对给定端点的请求如下所示:
PATCH /odata/auctions('3634031a-1f45-4aa0-9385-5e2c86795c49')
[
{"op" : "replace", "path" : "description", "value" : "Updated Description"}
]
我们用时间戳值实现的乐观并发控制机制也可以用Test
操作实现:
PATCH /odata/auctions('3634031a-1f45-4aa0-9385-5e2c86795c49')
[
{ "op": "test", "path": "_ts", "value": 1552741629 },
{ "op" : "replace", "path" : "vehicle/year", "value" : 2017},
{ "op" : "replace", "path" : "vehicle/engine/displacement", "value" : "2.4"}
]
在本例中,如果时间戳值与请求中的值不匹配,后续的更新操作将不会执行。
我们已经完成了UPDATE
和PATCH
方法,现在让我们继续DELETE
动作。
软删除
如果您计划将存储级操作与触发器和/或更改提要集成在一起,那么可以使用软删除实现而不是实现对象的完全删除。 在软删除方法中,我们可以使用一个特定的属性(例如isDeleted
)来扩展实体模型,该属性将定义文档被消费应用删除。
在此设置中,消费应用可以使用已实现的PATCH
方法或显式的DELETE
方法,可以为我们的实体服务实现该方法。
让我们来看看下面的PATCH
请求:
PATCH /odata/auctions('3634031a-1f45-4aa0-9385-5e2c86795c49')
[
{ "op": "test", "path": "_ts", "value": 1552741629 },
{ "op" : "replace", "path" : "isDeleted", "value" : true},
{ "op" : "replace", "path" : "ttl", "value" : "30"}
]
通过此请求,我们表示应该将具有给定 ID 的拍卖实体标记为删除。 此外,通过设置Time To Live(TTL)属性,我们将触发给定实体的过期时间。 通过这种方式,触发器和更改提要都将收到关于此更新的通知,并且在给定的 TTL 内,实体将从数据存储中删除。
重要提示
TTL 是 Cosmos DB 的固有特性。 TTL 可以在容器级别设置,也可以在项目级别设置。 如果在容器级别没有设置值,那么平台将忽略项目的值集。 但是,容器的默认过期时间可以为-1,并且我们希望在某段时间后过期的项目可以声明一个大于 0 的值。 TTL 不消耗资源,不作为消耗的 RUs 的一部分计算。
通过删除实现,我们拥有一组完整的函数,可以根据 Cosmos 集合为微服务创建基本的 CRUD 结构。 我们用一个简单的。net core 风格的请求管道开始实现,我们创建了UPDATE
和PATCH
方法,最后,我们用软删除实现完成了实现。 现在我们可以开始处理 API 的润饰了。 我们将从使用 Redis 的性能改进开始。
集成 Redis 缓存
在具有细粒度微服务架构的分布式云应用中,分布式缓存可以提供非常需要的数据一致性以及性能改进。 一般来说,基础设施的分布、数据模型和成本是决定是否使用分布式缓存实现的因素。
ASP.NET Core 提供了各种缓存选项,其中之一是分布式缓存。 可选择的分布式缓存选项如下:
- 分布式内存缓存
- 分布式 SQL 服务器缓存
- 分布式缓存复述,
虽然内存缓存并不是一个生产准备策略,但 SQL 和 Redis 对于使用。net Core 开发的云应用来说是可行的选择。 然而,对于 NoSQL 数据库和半结构化数据,Redis 将是一个理想的选择。 让我们来看看如何引入分布式缓存并使其准备好使用:
-
In order to introduce a distributed cache that can be used across controllers, we would need to use the available extensions so that we can inject an appropriate implementation of the
IDistributedCache
interface.IDistributedCache
would be our main tool for implementing the cache, aside from the pattern we mentioned previously:public interface IDistributedCache { byte[] Get(string key); Task<byte[]> GetAsync(string key, CancellationToken token = default(CancellationToken)); void Set(string key, byte[] value, DistributedCacheEntryOptions options); Task SetAsync(string key, byte[] value, DistributedCacheEntryOptions options, CancellationToken token = default(CancellationToken)); void Refresh(string key); Task RefreshAsync(string key, CancellationToken token = default(CancellationToken)); void Remove(string key); Task RemoveAsync(string key, CancellationToken token = default(CancellationToken)); }
如您所见,使用注入的实例,我们将能够以字节数组的形式设置和获取数据结构。 应用将首先访问分布式缓存以检索数据。 如果我们需要的数据不存在,我们将从实际的数据存储(或服务)中检索它,并将结果存储在我们的缓存中。
-
在我们可以在我们的应用中实现 Redis 缓存之前,我们可以前往 Azure 门户,在我们一直使用的资源组中创建一个 Microsoft Azure Redis 缓存资源。
- 一旦 Redis 缓存实例被创建,记录一个可用的连接字符串。 连接字符串可以在管理键刀片下找到,可以使用概述屏幕上的显示访问键选项访问该刀片。 现在我们可以继续我们的实现。
-
Start the implementation by installing the required Redis extension:
图 9.8 - Redis 扩展
-
在安装了扩展及其依赖项之后,使用扩展方法
services.AddDistributedRedisCache( option => { option.Configuration = Configuration.GetConnectionString("AzureRedisConnection"); option.InstanceName = "master"; });
配置我们的分布式缓存服务 6. 现在,在
appsettings.json
文件中插入我们从 Azure 门户检索到的连接字符串,然后转到我们的控制器,为IDistributedCache
实例设置构造函数注入:private readonly IDistributedCache _distributedCache; public UsersController(IDistributedCache distributedCacheInstance) { _distributedCache = distributedCacheInstance; }
就这些了——分布式缓存已经可以使用了。 现在,我们可以将序列化的数据项作为键/值(其中值是序列化的字节数组)插入到缓存中,而无需与实际数据源通信。
与前端模式的后端结合,Redis 缓存可以将缓存的数据交付到应用网关服务,而无需联系多个微服务,提供了一个简单的成本削减解决方案,以及承诺的性能增强。
托管服务
由于我们的 web 实现使用了 ASP.NET Core,我们有多种部署和托管选项,可以跨越 Windows 和 Linux 平台。 我们将考虑的第一个选项是 Azure Web App 设置,它可以设置在 Windows 或 Linux 服务计划中。 然后我们将移动我们的 ASP。 它可以托管在我们之前提到的任何容器编排平台上,也可以简单地托管在一个运行在 Linux 服务器群上的 Azure web 应用中。
Azure Web App for App Service
此时,不需要任何额外的实现或配置,我们的微服务就可以部署了,它们已经可以作为一个完全托管的应用服务托管在 Azure 云上了。 为了将服务部署为应用服务,您可以使用 Visual Studio Azure 扩展,它允许您创建发布配置文件以及目标托管环境。
让我们看看如何做到这一点:
-
Right-click on the project to be deployed. You will see the Pick a publish target selection window:
图 9.9 -发布目标
对于完整的托管选项,我们可以选择App Service或App Service Linux选项,并继续创建新的应用服务。
-
If we were to choose the App Service option, the application would be hosted on the Windows platform with a full .NET Framework profile, whereas the Linux option would use Linux operating systems with the .NET Core runtime. Selecting the Create New option allows us to select/create the resource group we want the App Service instance to be added to:
图 9.10 - Azure App Service
-
一旦发布,从站点 URL 字段复制 URL 并使用
curl
:Microsoft Windows [Version 10.0.17134.590] (c) 2018 Microsoft Corporation. All rights reserved. C:\Users\can.bilgin>curl https://netcoreuserapi-dev.azurewebsites.net/odata/users?$filter=FirstName%20eq%20%27Jane%27 {"@odata.context":"https://netcoreuserapi-dev.azurewebsites .net/odata/$metadata#Users","value":[{"Id":"7aa0c870- cb90-4f02-bf7e-867914383190","FirstName":"Jane","LastName": "Doe","NumberOfAuctions":1,"Auctions":[],"Address": {"AddressTypeId":4000,"City":"Seattle","Street1":"23 Pike St.","CountryCode":"USA"}}]} C:\Users\can.bilgin>
执行查询
集装箱服务
托管的另一种选择是将我们的应用容器化,这将带来作为代码原则配置的额外好处。 在容器设置中,每个服务都将被隔离在自己的沙箱中,并以高度的灵活性和性能轻松地从一个环境迁移到下一个环境。 如果将容器部署到前面提到的容器注册中心和平台(如 ACS、AKS、Service Fabric 和 Service Fabric Mesh),那么与 web 应用相比,容器还可以节省成本。
重要提示
容器是隔离的、受管理的、可移植的操作环境。 它们提供了一个位置,在这个位置上,应用可以在不影响系统其他部分的情况下运行,系统也不会影响应用。 与 vm 相比,它们提供了更高的服务器密度,因为它们不共享硬件,而是共享操作系统内核。
Docker 是一种容器技术,近年来已经几乎成为容器本身的同义词。 Docker 容器托管环境可以使用提供的免费软件在 Windows 和 macOS 上创建。 让我们开始:
- 为了准备一台用于 Docker 容器化的 Windows 开发机器,我们需要确保已经安装了以下设备:
- Docker for Windows(用于承载 Windows 和 Linux 容器)
- 用于 Visual Studio 的 Docker 工具(可选择安装 Visual Studio 2017 v15.8+)
-
Now that we have the prerequisites, we can add a Docker container image definition to each microservice project using the Add | Docker Support menu item:
图 9.11 - Docker 支持
-
这将创建一个多级 Docker 文件,简单来说,它将做以下工作:
- 将应用的源代码复制到容器映像中。
- 恢复所需的。net Core 运行时组件,这取决于容器的类型(Windows 或 Linux)。
- 编译应用。
- 使用编译后的应用组件创建最终的容器映像。
- 这里,我们为
UsersApi
创建的 Docker 文件如下所示:
如你所见,定义 base 的第一个阶段是引用公有 Docker 注册表中的 microsoft 管理的容器映像。 构建映像是我们拥有 ASP 源代码的地方.NET Core 应用。 最后,构建和最终映像是将应用编译(即dotnet publish
)并将其设置为容器的入口点的最后阶段。
换句话说,创建的容器映像拥有最终的应用代码以及所需的组件,而不管主机操作系统和该主机上运行的其他容器是什么。
现在,如果你在控制台或终端(取决于安装 Docker 的操作系统)导航到UsersApi
项目的父目录,并执行以下命令,Docker 将构建容器镜像:
docker build -f ./NetCore.Web.UsersApi/Dockerfile -t netcore-usersapi .
一旦 Docker 守护进程构建了容器镜像,你可以使用下面的命令来检查镜像是否可以作为容器启动:
docker image ls
如果映像在可用容器映像列表中,现在可以使用暴露的端口80
或443
运行该容器(下面的命令将容器端口80
映射到主机端口8000
):
docker run -p 8000:80 netcore-usersapi
当然,容器开发与 Windows 平台上的 Visual Studio 的集成程度更高。 事实上,ASP.NET Core 应用,一旦容器化,包含一个运行/调试 Docker 配置文件,可以直接从 Visual Studio UI 启动:
图 9.12 - Docker 启动设置
在这个阶段,我们的容器配置已经可以使用了,并且它已经可以部署到 Azure Web App for Containers 中了。 可以使用 Visual Studio 中的可用工具添加容器编排支持。
在本节中,我们测试了 PaaS 和 CaaS 模型,首先使用应用服务来托管应用,然后使用 Docker 将. net 应用容器化。 ASP.NET 应用包和容器可以托管在 App Service 上。 现在我们的应用已经准备好在云上托管了,让我们看看保护它的可用选项。
保护应用
在具有客户端特定后端的微服务设置中,可以使用多种身份验证策略来保护 web 应用。 ASP.NET Core 提供了所需的 OWIN 中间件组件来支持大多数这些场景。
根据网关和下游业务架构,可以在网关上实现身份验证/授权,用户身份可以转移到后端服务:
图 9.13 -网关标识
另一种方法是,每个服务可以在联合设置中使用相同的身份提供者。 在此设置中,客户端应用将使用专用的安全令牌服务(STS),并且需要在 STS 和应用服务之间建立信任关系:
图 9.14 -微服务身份
在选择身份验证和授权策略时,一定要记住,此设置中的身份使用者将是本地移动客户端。 当涉及移动应用时,选择的认证流程一般为 OAuth 2 授权码流:
图 9.15 - OAuth 阶段
再一次,这取决于您正在构建的应用,多个OpenID 身份连接(OIDC)提供者,如微软的 Live, Facebook 和谷歌,可以引入允许用户选择他们喜欢的身份。
**## NET Core 身份
ASP.NET Core Identity 是默认的成员系统,它可以提供相对简单但广泛的 STS 实现,以及登录、注册和管理 ui。 与它的前身相比,ASP.NET Core Identity 为开发人员提供了更广泛的身份验证场景,如 OAuth、双因素身份验证、基于时间的一次性密码二维码(TOTP)等。
ASP.NET Core Identity 默认情况下使用 SQL 数据库作为持久性存储,并且可以用其他存储库实现替换。 实体框架核心用于实现标准存储库功能。
由 ASP 支持的外部 OIDC 提供商.NET Core 身份是 Facebook, Twitter,谷歌和微软。 可以在第三方或社区提供的包中找到其他提供者实现。
使用 ASP.NET Core Identity,创建的 STS 可以由 Xamarin 应用通过一组简单的 HTTP 请求使用,以注册、验证和授权用户。 此外,Xamarin 应用可以利用可用的身份提供者 sdk,以及跨提供者包。
虽然这种身份管理应该足够了,因为需求只针对一个 ASP.NET 基于核心的解决方案,一旦将额外的 Azure 资源包括在分布式应用中,例如 Azure 无服务器组件,基于云的身份管理可能是一个更好的选择。
Azure AD
Azure 广告基于云的身份作为服务(IDaaS)提供,迄今为止,唯一的认证和身份管理过程与资源管理器集成的分布式应用开发的 Azure 的基础设施。 Azure AD 用于管理对资源组中任何 SaaS/PaaS 资源的访问。 它支持 OpenID Connect、OAuth 和 SAML 等协议,以提供对目录内资源的 SSO 和访问控制。
**可以使用目录中定义的标识原则来设置访问资源和资源之间的授权。 该原则可以表示具有单个组织(可能具有关联的本地活动目录)、应用(在目录或外部应用中设置的资源,如本地移动应用)的用户,或者来自不同 Azure 目录或外部身份提供者的外部身份。
一般来说,这种在组织单元中定义用户身份,并将来自其他目录的用户作为来宾引入的设置称为 Azure ADBusiness to Business(B2B)。
在中,为了使用 Azure AD B2B 建立一个应用范围的认证方案,遵循以下步骤:
-
Create a directory that will define the organization that will be using the application suite (that is, the mobile application and associated services).
重要提示
任何 Azure 订阅至少都附带免费的 Azure AD(取决于订阅类型),而且在大多数情况下,不需要创建新目录。
您可以使用 Azure 门户上的create a Resource接口来创建一个新目录。 一旦您选择了 Azure AD,您将需要声明一个组织名称和初始域名(例如
netcorecrossplatform.onmicrosoft.com
)。 -
Additional custom domains can be added to this declaration at a later time:
图 9.16 -创建 Azure Active Directory
-
Once the directory is created, you'll see that the organization should be available as a domain option so that you can set up the authentication for an ASP.NET Core web application using Visual Studio:
图 9.17 -添加认证
一旦应用项目被创建或使用所选的认证选项更新,它将自动向 Azure AD 添加一个应用注册表,并为应用认证添加/配置所需的中间件。 Azure AD 在应用启动时的配置看起来类似如下:
services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme) .AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
创建的配置(匹配 Azure AD 应用注册)是,如下:
"AzureAd": { "Instance": "https://login.microsoftonline.com/", "Domain": "netcorecrossplatform.onmicrosoft.com", "TenantId": "f381eb86-1781-4732-9543-9729eef9f843", "ClientId": "ababb076-abb9-4426-b7df-6b9d3922f797" },
对于 Azure AD,在客户端应用上进行身份验证(考虑到我们正在使用 Xamarin 和 Xamarin。 窗体作为开发平台)可以使用Microsoft 身份验证库(MSAL)实现。 遵循以下步骤:
-
In order for the client application to be able to use the identity federation within this organization, register (yet) another application on Azure AD. However, this registration should be declared for a native application:
图 9.18 -注册一个应用到 Azure AD
-
创建应用注册后,使用当前目录(即租户)和客户端应用(即应用注册)设置身份验证库。 在这个设置中,身份流可以简单地定义如下:
- 本机应用使用授权代码流检索访问令牌
- 本机应用执行对网关服务(即我们的 ASP. net 服务)的 HTTP 请求.NET Core 服务暴露特定于移动应用的端点)
-
The gateway service verifying the token and retrieving an on-behalf-of token to call the downstream stream services
通过这种方式,可以将用户身份传播到每个层,并且可以使用声明原则实现所需的授权过程。
-
In order to allow identity propagation, the gateway service application registration (that is, the service principal) should be given the required identity delegation permissions to the downstream service registrations:
图 9.19 -添加 API 权限
-
现在,用户标识可以访问资源,前提是它们的标识存在于目标组织中,并且具有所需的权限。
对于一个面向业务应用(即业务(LOB)应用),B2B Azure 广告可以提供一个安全的身份管理解决方案轻松,并没有额外的自定义实现。 然而,如果应用需要面向客户端,我们将需要一个更灵活的解决方案,并提供额外的注册支持。 Azure B2C 可以为个人用户帐户提供所需的支持。
Azure AD B2C
Azure AD B2C 是面向消费者场景的身份管理服务,可以选择自定义和控制客户如何注册、登录以及在使用您的应用时如何管理他们的配置文件。 这针对各种平台。
B2C 是一种现代的联合身份管理服务,其中消费者应用(即依赖方)可以使用多个身份提供者和验证方法。
在 B2C 领域中,用于注册和登录的用户流被称为用户旅程。 如果需要,可以使用策略定制用户旅程。 身份体验框架使用这些策略来实现所需的用户流。 身份体验框架是建立多方信任并完成用户旅程步骤的底层平台。
与 Azure AD 本身类似,租户描述一个用户域,其中可以定义用户和应用之间的某些关系。 然而,在 B2C 中,域是特定于客户的,而不是特定于组织的。 换句话说,租户定义一个由策略描述和链接的标识提供者控制的访问组。
在这种设置中,多个应用可以访问多个租户,这使得 B2C 非常适合开发公司,因为它们拥有一套要发布给消费者的应用。 消费者一旦注册使用一个链接的 OIDC 身份提供商,就可以访问多个面向消费者的应用。
在本节中,我们开始使用。net Core Identity 进行安全模型研究。 虽然它为较小的使用者应用提供了最主流的需求,但如果身份管理需求的数量增加,它很快就会变得过于复杂。 正如您所看到的,Azure AD 也可以很容易地集成到 ASP 中.NET 应用,并且可以为复杂的 LOB 场景提供基础设施。 最后,我们简要地介绍了 Azure AD B2C,它提供了一个完整的联邦身份管理平台,具有灵活的扩展选项。
总结
在本章中,我们浏览了 PaaS 平台,以及可用于托管和实现 ASP 的架构方法.NET Core web 服务。 使用 ASP 提供的灵活的基础设施。 对于开发人员来说,实现使用来自 Cosmos DB 集合的数据的微服务是一种解脱。 在域对象上包含 CRUD 操作的服务可以通过 Redis 和容器化进行优化和改进,并托管在多个平台和操作系统上。 安全性是我们在分布式云架构中主要关注的问题之一,可以通过在 Azure 云堆栈上使用可用的身份基础设施和 iaas 产品(如 Azure AD 和 Azure AD B2C)来确保安全性。
在下一章中,我们将转向 Azure 无服务器,这是另一个服务平台,在它上。net Core 可以被证明是至关重要的。**
版权属于:月萌API www.moonapi.com,转载请注明出处