Web API与客户端集成开发指南
在现代软件开发中,Web API与客户端的集成是实现高效、交互性强的应用程序的关键环节。本文将详细介绍如何创建API控制器、SignalR中心,如何发布Web API,以及如何构建客户端应用程序以实现与Web API的集成。
创建API控制器
为了快速创建用于处理订单和批次数据的控制器,我们可以使用脚手架来生成DbContext和一组REST操作,实现数据的创建、读取、更新、删除和列表展示。以下是创建
OrderController
的具体步骤:
1.
添加项目引用
:在添加控制器之前,需要向
ProductionModel
项目添加引用,以便脚手架能够识别我们要使用的实体。具体操作是右键单击“References”文件夹,选择“Add Reference”,在“Solution | Projects”选项卡中勾选
ProductionModel
,然后点击“OK”。
2.
打开添加脚手架对话框
:右键单击“Controllers”文件夹,选择“Add | Controller”,打开“Add Scaffold”对话框。
3.
选择控制器类型
:在对话框中,选择“Web API 2 Controller with actions, using Entity Framework”,然后点击“Add”,此时会弹出“Add Controller”对话框。
4.
选择模型和数据上下文
:从“Model class”选择器中选择订单模型,然后点击“Data context class”旁边的“+”按钮创建新的
DbContext
(如果是创建
BatchController
,则从选择器中选择现有的
DbContext
)。
5.
配置数据上下文
:可以在此处更改数据上下文的名称,也可以使用默认名称,然后点击“Add”查看详细信息。
6.
启用异步控制器操作
:勾选“Use async controller actions”,这将标记异步操作,允许我们在
DbContext
中使用异步方法。点击“Add”生成控制器。
7.
查看生成的文件
:查看
OrdersController
、
ManagementWebApiDataContext
以及
Web.config
中的额外EF部分,然后开始进行修改以集成现有的数据库。
8.
更改数据库连接字符串
:在
Web.config
文件中,找到数据库连接字符串,将其替换为指向现有SQL Express数据库的连接字符串,以便与订单处理器共享数据。示例代码如下:
<connectionStrings>
<add name="ManagementWebApiContext"
connectionString="Data Source=localhost;Initial
Catalog= AzureBakeryProduction;Integrated
Security=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
-
禁用EF代理创建
:在
ManageMentWebApiDataContext构造函数中添加以下代码,以禁用EF代理创建:
public ManagementWebApiContext() :
base("name=ManagementWebApiContext")
{
base.Configuration.ProxyCreationEnabled = false;
}
-
修改
GetOrders方法 :修改OrdersController的GetOrders方法,使其仅返回状态为“Open”的订单:
public IQueryable<Order> GetOrders()
{
return db.Orders
.Where(o => o.Status == OrderStatus.Open)
}
-
测试控制器
:由于控制器目前未使用
Authorize属性,因此可以进行快速测试。调试Web API项目,然后在浏览器中访问/api/orders(根据实际的IIS Express端口进行调整),例如:https://localhost:44303/api/orders。 -
添加授权属性
:在确认控制器正常工作后,为控制器类添加
Authorize属性,以确保安全性:
[Authorize]
public class OrdersController : ApiController
-
创建
BatchController:使用相同的步骤创建BatchController,但使用之前创建的DbContext。
为了进一步测试控制器,可以使用浏览器进行大多数HTTP GET操作,也可以使用Fiddler(http://www.telerik.com/fiddler)或cURL(http://curl.haxx.se/)来构造其他操作,如POST或PUT,这些操作需要在请求体中插入数据。
创建SignalR中心
为了允许客户端在用户更改订单和批次状态时进行更新,并接收系统中其他客户端的更新,我们将实现一个SignalR中心。具体步骤如下:
1.
安装NuGet包
:在NuGet包管理器控制台中依次输入以下命令,安装所需的包:
Install-Package Microsoft.AspNet.SignalR
Install-Package Microsoft.AspNet.SignalR.ServiceBus
install-package windowsazure.servicebus
-
修改服务总线连接字符串
:修改由
Microsoft.AspNet.SignalR.ServiceBus包添加的Microsoft.ServiceBus.ConnectionString应用设置,并添加服务总线命名空间的ACS密钥(从门户获取)。连接字符串示例如下:
<add key="Microsoft.ServiceBus.ConnectionString"
value="Endpoint=sb://azurebakery.servicebus.windows.net/;
SharedSecretIssuer=owner;SharedSecretValue=
vxaQFgh8zGFtsqnAemCcv/NTCtLNM2qhYslQq7TIQsI=" />
-
修改
Startup类 :在App_Start/Startup.Auth.cs文件中修改Startup类,示例代码如下:
using Microsoft.AspNet.SignalR;
using Microsoft.Owin;
using Microsoft.Owin.Security.ActiveDirectory;
using Owin;
using System.Configuration;
[assembly: OwinStartup(typeof(ManagementWebApi.Startup))]
namespace ManagementWebApi
{
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Audience = ConfigurationManager.
AppSettings["ida:Audience"],
Tenant = ConfigurationManager.
AppSettings["ida:Tenant"]
});
var connectionString = ConfigurationManager.
AppSettings["Microsoft.ServiceBus.ConnectionString"];
GlobalHost.DependencyResolver.
UseServiceBus(connectionString, "ManagementApi");
app.MapSignalR();
}
}
}
- 添加中心类 :在项目中添加一个中心类,例如将其放在名为“SignalR”的解决方案文件夹下。右键单击该文件夹,选择“Add | New Item”,从“SignalR”选项卡中选择“SignalR Hub Class (v2)”,命名后点击“OK”。
-
添加更新方法
:在中心类中添加
UpdateOrder和UpdateBatch方法,用于客户端调用并更新所有连接的客户端。示例代码如下:
[Authorize]
public class ManagementHub : Hub
{
private readonly DataService _dataService = new
DataService();
private readonly MessagingService _messagingService =
new MessagingService();
public void UpdateOrder(Order order)
{
this._dataService.UpdateOrder(order);
this._messagingService.UpdateOrder(order);
Clients.All.updateOrder(order);
}
public void UpdateBatch(Batch batch)
{
this._dataService.UpdateBatch(batch);
Clients.All.updateBatch(batch);
}
}
发布Web API
可以使用常规的网站发布过程将Web API直接发布到创建时预配的网站,但需要特别注意发布设置。具体步骤如下:
1.
配置发布设置
:勾选“Enable Organizational Authentication”,输入AD租户域名,确保设置Azure数据库的数据库连接字符串,并勾选“Use this connection string at runtime (update destination web.config)”。
2.
输入登录凭据
:发布时,需要输入AD租户的登录凭据。
3.
查看发布结果
:发布完成后,会看到网站已创建,同时在AD租户工作区的“APPLICATIONS”选项卡中会出现一个新的应用程序。
Web.config
文件中的
ida:Audience
设置也会更新为新Azure Web API应用程序的ID。
修改Web API AD清单
在为客户端创建AD应用程序之前,需要修改本地和Azure
ManagementWebApi
应用程序的清单,以便其他应用程序可以使用AD授权获得访问权限。具体步骤如下:
1.
下载清单文件
:在门户中,点击AD应用程序工具栏上的“MANAGE MANIFEST | Download Manifest”,下载JSON清单文件。
2.
修改清单文件
:打开下载的JSON清单文件,将空的
"appPermissions": []
部分替换为以下代码,然后保存文件:
"appPermissions": [
{
"claimValue": "user_impersonation",
"description": "Allow the application full access to
the service on behalf of the signed-in user",
"directAccessGrantTypes": [],
"displayName": "Have full access to the service",
"impersonationAccessGrantTypes": [
{
"impersonated": "User",
"impersonator": "Application"
}
],
"isDisabled": false,
"origin": "Application",
"permissionId":
"B4B3BA55-0770-47D0-A447-C55BB6A371DF",
"resourceScopeType": "Personal",
"userConsentDescription": "Allow the application full
access to the service on your behalf",
"userConsentDisplayName": "Have full access to the
service"
}
]
- 上传清单文件 :在门户中,点击“MANAGE MANIFEST | Upload Manifest”,上传保存后的清单文件。
- 重复操作 :对第二个清单重复上述步骤。
添加客户端应用程序到AD
在客户端应用程序连接到Web API之前,需要将其添加到Azure AD并授予访问Web API应用程序的权限。具体步骤如下:
1.
导航到AD工作区
:在Azure门户中导航到AD工作区。
2.
添加应用程序
:点击“APPLICATIONS”工具栏上的“ADD”,选择“Add an application my organization is developing”。
3.
配置应用程序信息
:输入应用程序名称,选择“NATIVE CLIENT APPLICATION”,点击“下一步”箭头。
4.
输入重定向URI
:输入一个有效的重定向URI(用于OAuth2请求后的重定向,此实现中未使用),然后点击“勾选”按钮完成。
5.
添加权限
:滚动到“CONFIGURATION”选项卡底部的“permissions to other applications”部分,为
ManagementWebApi
添加新的权限,选择“Have full access to the service”作为委托权限。
6.
更改默认权限
:将默认的“Windows Azure Active Directory”权限的委托权限更改为包括“Access your organization’s directory (preview)”。
7.
添加Azure管理API权限
:添加Azure管理API的权限。
8.
保存设置
:点击工具栏上的“SAVE”完成设置。
构建客户端应用程序
为了显示批次和订单并允许更改其状态,我们将创建一个WPF客户端应用程序。使用MVVM Light帮助实现简洁的MVVM模式,并创建多个数据服务,使用Azure AD身份验证从API获取数据。
准备WPF项目
创建WPF应用程序并安装所需的NuGet包,具体步骤如下:
1.
添加WPF项目
:在解决方案中添加一个名为
ManagementApplication
的WPF项目。
2.
安装MVVM Light
:在NuGet包管理器控制台中输入以下命令安装MVVM Light:
install-package mvvmlight
-
安装AD身份验证包
:输入以下命令安装
Microsoft.IdentityModel.Clients.ActiveDirectory包:
install-package Microsoft.IdentityModel.Clients.ActiveDirectory
- 安装JSON.NET :输入以下命令安装JSON.NET:
install-package newtonsoft.json
- 安装SignalR客户端包 :输入以下命令安装SignalR客户端包:
Install-package Microsoft.AspNet.SignalR.Client
-
添加项目引用
:右键单击“References”文件夹,选择“Add Reference”,在“Solution | Projects”选项卡中勾选
ProductionModel,然后点击“OK”。同样的方法添加System.Configuraton和System.Net.Http的引用。 -
添加Token设置
:在项目的
Settings.settings文件中,添加一个名为Token的字符串设置,用于存储用户的身份验证令牌。 -
添加
appSettings块 :在App.config中添加以下appSettings块,并添加注释以帮助理解和记忆:
<appSettings>
<!-- AD Tenant -->
<add key="ida:Tenant" value="azurebakery.onmicrosoft.com" />
<!-- The target api AD application APP ID (get it from
config tab in portal) -->
<!-- Local -->
<add key="ida:Audience"
value="https://azurebakery.onmicrosoft.com/ManagementWebApi"
/>
<!-- Azure -->
<!-- <add key="ida:Audience"
value="https://azurebakery.onmicrosoft.com/
WebApp-azurebakeryproduction.azurewebsites.net" /> -->
<!-- The client id of THIS application (get it from
config tab in portal) -->
<add key="ida:ClientID" value=
"1a1867d4-9972-45bb-a9b8-486f03ad77e9" />
<!-- Callback URI for OAuth workflow -->
<add key="ida:CallbackUri"
value="https://azurebakery.com" />
<!-- The URI of the Web API -->
<!-- Local -->
<add key="serviceUri" value="https://localhost:44303/" />
<!-- Azure -->
<!-- <add key="serviceUri" value="https://azurebakeryproduction.
azurewebsites.net/" />
-->
</appSettings>
-
添加ViewModelLocator
:在
App.xaml的Application.Resources中添加MVVM Light的ViewModelLocator:
<Application.Resources>
<vm:ViewModelLocator x:Key="Locator"
d:IsDataSource="True" xmlns:vm=
"clr-namespace:AzureBakery.Production.
ManagementApplication.
ViewModel" />
</Application.Resources>
-
绑定数据上下文
:在
MainWindow.xaml中,将DataContext绑定到ViewModelLocator的Main属性:
<Window x:Class="AzureBakery.Production.ManagementApplication.
MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/
presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
DataContext="{Binding Source={StaticResource
Locator}, Path=Main}"
Title="Production Management Application"
Height="350" Width="525">
创建身份验证基类
由于Web API和SignalR中心使用Azure AD身份验证,我们将创建一个服务来与两者进行交互,并创建一个公共基类以确保所有请求都经过身份验证。以下是
AzureAdAuthBase
类的代码:
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System;
using System.Configuration;
using System.Diagnostics;
using System.Net;
namespace AzureBakery.Production.ManagementApplication.Services
{
public abstract class AzureAdAuthBase
{
protected AuthenticationResult Token = null;
protected readonly string ServiceUri = null;
protected AzureAdAuthBase()
{
this.ServiceUri =
ConfigurationManager.AppSettings["serviceUri"];
#if DEBUG
ServicePointManager.ServerCertificateValidationCallback +=
(se, cert, chain, sslerror) => true;
#endif
}
protected bool Login()
{
var tenantId =
ConfigurationManager.AppSettings["ida:Tenant"];
var resourceId =
ConfigurationManager.AppSettings["ida:Audience"];
var clientId =
ConfigurationManager.AppSettings["ida:ClientID"];
var callback = new
Uri(ConfigurationManager.AppSettings["ida:CallbackU
ri"]);
var authContext = new
AuthenticationContext(string.Format("https://login.
windows.net/{0}", tenantId));
if(this.Token == null)
{
var token = Properties.Settings.Default.Token;
if (!string.IsNullOrWhiteSpace(token))
this.Token = AuthenticationResult.
Deserialize(token);
}
if (this.Token == null)
{
try
{
this.Token =
authContext.AcquireToken(resourceId,
clientId, callback);
}
catch(Exception ex)
{
Debug.WriteLine(ex.ToString());
return false;
}
}
else if(this.Token.ExpiresOn < DateTime.UtcNow)
{
this.Token =
authContext.AcquireTokenByRefreshToken(this.Token.
RefreshToken, clientId);
}
if (this.Token != null && this.Token.ExpiresOn >
DateTime.UtcNow)
{
Properties.Settings.Default.Token =
this.Token.Serialize();
Properties.Settings.Default.Save();
return true;
}
this.Token = null;
Properties.Settings.Default.Token = null;
Properties.Settings.Default.Save();
return false;
}
}
}
该类使用
AuthenticationContext.AquireToken
方法启动内置的登录对话框,处理OAuth2工作流,并在登录成功时返回身份验证令牌。令牌存储在用户设置中,并在必要时进行刷新,因此用户不必每次使用应用程序时都登录。派生服务类每次调用服务时可以调用
Login
方法,以检查用户是否已登录以及是否有有效的令牌可供使用。
创建数据服务
我们将创建一个
DataService
类,该类继承自刚刚创建的
AzureAdAuthBase
类,并使用AD身份验证从Web API服务获取数据。首先,创建一个通用的辅助方法
GetData<T>
,该方法使用
HttpClient
类调用API的GET操作,并将返回的JSON对象反序列化为.NET类型的对象
T
:
private async Task<T> GetData<T>(string action)
{
if (!base.Login())
return default(T);
var authHeader = this.Token.CreateAuthorizationHeader();
var client = new HttpClient();
var uri = string.Format("{0}{1}", this.ServiceUri,
string.Format("api/{0}", action));
var request = new HttpRequestMessage(HttpMethod.Get, uri);
request.Headers.TryAddWithoutValidation("Authorization",
authHeader);
var response = await client.SendAsync(request);
var responseString = await response.Content.ReadAsStringAsync();
var data = await Task.Factory.StartNew(() =>
JsonConvert.DeserializeObject<T>(responseString));
return data;
}
有了这个方法后,我们可以快速创建获取订单和批次数据的方法:
public async Task<IEnumerable<Order>> GetOrders()
{
return await this.GetData<IEnumerable<Order>>("orders");
}
public async Task<IEnumerable<Batch>> GetBatches()
{
return await this.GetData<IEnumerable<Batch>>("batches");
}
该服务实现了
IDataService
接口,并在
ViewModelLocator
类中注册,以便注入到视图模型中:
SimpleIoc.Default.Register<IDataService, DataService>();
创建SignalR服务
我们将创建另一个继承自
AzureAdAuthBase
类的服务
ManagementService
,该服务将更新后的订单发送到SignalR中心,并接收来自其他客户端的更新,以实时更新UI。以下是
ManagementService
类的代码:
private IHubProxy _proxy = null;
public event EventHandler<Order> OrderUpdated;
public event EventHandler<Batch> BatchUpdated;
public ManagementService()
{
}
public async Task Register()
{
if (!this.Login())
return;
var authHeader = this.Token.CreateAuthorizationHeader();
var cnString = string.Format("{0}signalr", base.ServiceUri);
var hubConnection = new HubConnection(cnString, useDefaultUrl:
false);
this._proxy = hubConnection.CreateHubProxy("managementHub");
hubConnection.Headers.Add("Authorization", authHeader);
this._proxy.On<Order>("updateOrder", order =>
{
this.OnOrderUpdated(order);
});
this._proxy.On<Batch>("updateBatch", batch =>
{
this.OnBatchUpdated(batch);
});
await hubConnection.Start();
}
通过以上步骤,我们完成了Web API与客户端的集成开发,实现了订单和批次数据的管理、实时更新以及安全访问。
Web API与客户端集成开发指南
总结与最佳实践
在完成Web API与客户端的集成开发后,我们对整个过程进行总结,并分享一些最佳实践,以帮助开发者更好地应对类似的开发任务。
开发流程总结
| 开发步骤 | 关键操作 |
|---|---|
| 创建API控制器 | 使用脚手架生成控制器和REST操作,配置数据库连接,添加授权属性 |
| 创建SignalR中心 | 安装相关NuGet包,配置服务总线连接,添加中心类和更新方法 |
| 发布Web API | 配置发布设置,输入AD租户登录凭据 |
| 修改Web API AD清单 | 下载、修改并上传清单文件,授予其他应用程序访问权限 |
| 添加客户端应用程序到AD | 配置应用程序信息,添加权限 |
| 构建客户端应用程序 | 创建WPF项目,安装所需NuGet包,实现MVVM模式,创建数据服务和SignalR服务 |
最佳实践建议
- 安全性 :始终使用授权属性保护API和SignalR中心,确保只有经过身份验证的用户可以访问。同时,对敏感数据进行加密处理,如存储在用户设置中的身份验证令牌。
-
性能优化
:使用异步方法和任务并行处理,提高应用程序的响应性能。例如,在数据服务中使用
async和await关键字,避免阻塞线程。 - 代码可维护性 :将数据库和消息传递逻辑抽象到服务类中,使代码更易于阅读和维护。同时,遵循MVVM模式,将视图和业务逻辑分离。
- 错误处理 :在关键代码中添加适当的错误处理机制,如在登录方法中捕获异常并记录错误信息,确保应用程序的稳定性。
未来拓展方向
随着技术的不断发展,Web API与客户端的集成开发也有许多可以拓展的方向。以下是一些可能的拓展方向,供开发者参考。
多平台支持
目前我们开发的是WPF客户端应用程序,可以考虑拓展到其他平台,如移动应用(iOS和Android)、Web应用等。可以使用跨平台开发框架,如Xamarin、React Native等,实现一次开发,多平台部署。
微服务架构
将现有的Web API拆分为多个微服务,每个微服务负责一个特定的业务功能。这样可以提高系统的可扩展性和可维护性,同时便于团队协作开发。
实时数据分析
结合实时数据分析技术,对订单和批次数据进行实时监控和分析。例如,使用Azure Stream Analytics对数据进行实时处理,生成实时报表和预警信息。
人工智能与机器学习
引入人工智能和机器学习技术,对订单和批次数据进行预测和优化。例如,使用机器学习算法预测订单需求,优化生产计划。
常见问题解答
在开发过程中,开发者可能会遇到一些常见的问题。以下是一些常见问题的解答,希望能帮助开发者快速解决问题。
问题1:API请求返回401 Unauthorized错误
- 原因 :可能是授权属性配置不正确,或者身份验证令牌过期。
-
解决方法
:检查API控制器和SignalR中心是否添加了
Authorize属性,确保身份验证令牌有效。可以在登录方法中添加日志记录,查看令牌获取和刷新的情况。
问题2:SignalR连接失败
- 原因 :可能是服务总线连接配置不正确,或者网络问题。
-
解决方法
:检查
Microsoft.ServiceBus.ConnectionString配置是否正确,确保服务总线命名空间和ACS密钥有效。同时,检查网络连接是否正常,尝试重启服务。
问题3:数据服务返回空数据
- 原因 :可能是数据库连接配置不正确,或者API接口返回的数据格式不匹配。
- 解决方法 :检查数据库连接字符串是否正确,确保数据库服务正常运行。同时,检查API接口返回的数据格式,确保与客户端代码中的反序列化方法匹配。
总结
通过本文的介绍,我们详细了解了Web API与客户端集成开发的整个流程,包括创建API控制器、SignalR中心,发布Web API,构建客户端应用程序等。同时,我们分享了开发过程中的最佳实践、未来拓展方向和常见问题解答。希望这些内容能帮助开发者更好地完成Web API与客户端的集成开发任务,实现高效、安全、稳定的应用程序。
在实际开发中,开发者可以根据具体的业务需求和技术栈,对本文介绍的方法和步骤进行适当的调整和优化。同时,不断学习和掌握新的技术和工具,提高自己的开发能力和水平。
最后,祝愿开发者在Web API与客户端集成开发的道路上取得成功!
超级会员免费看
1422

被折叠的 条评论
为什么被折叠?



