.NET MAUI Android App 注册 Push notifications 时返回 422
结论
这个 422 应先从后端的 CreateOrUpdateInstallationAsync 查起。现有日志只能确认请求进入了 NotificationsController.UpdateInstallation,还无法判断具体是哪项配置出了问题。
在官方示例中,只要后端服务返回 false,控制器就会返回 422 Unprocessable Entity。所以,安装信息不符合要求和调用 Azure Notification Hubs 时发生异常,都可能让客户端收到这个状态码。官方控制器示例
Android Emulator 可以接收 FCM 推送。应检查模拟器是否具备 Google Play services,以及应用是否成功取得 FCM registration token。仅凭使用了模拟器,无法解释这个 422。
为什么不应把问题直接归到 GetDeviceInstallation
这行代码用于取得设备安装信息:
var deviceInstallation =
DeviceInstallationService?.GetDeviceInstallation(tags);
官方 Android 实现会先检查 Google Play services 和 token,再构造包含 InstallationId、Platform、PushChannel 和 Tags 的对象。这个方法不发送 HTTP 请求;如果 Google Play services 不可用或 token 为空,它会先抛出本地异常。Android 实现源码
HTTP 请求在下一步发送:
await SendAsync<DeviceInstallation>(
HttpMethod.Put, RequestUrl, deviceInstallation);
示例中的 SendAsync 会调用 response.EnsureSuccessStatusCode(),在收到非成功响应时抛出异常。Response status code does not indicate success: 422 就是在这里抛出的。注册服务源码
安装信息仍需检查,但断点停在某一行,不能证明 HTTP 422 是该行产生的。后面的 SecureStorage.SetAsync 要等请求成功后才会执行。
先记录后端的失败原因
官方 NotificationHubService.CreateOrUpdateInstallationAsync 会在以下情况下返回 false:
InstallationId、Platform或PushChannel为空。Platform不在后端支持的平台映射中。_hub.CreateOrUpdateInstallationAsync抛出异常,被catch捕获。
最后一种情况没有记录异常,因此客户端只能看到 422。后端服务源码
先修改该方法中的 catch,把异常写入日志:
try
{
await _hub.CreateOrUpdateInstallationAsync(installation, token);
}
catch (Exception ex)
{
_logger.LogError(
ex,
"Notification Hubs installation update failed. Platform={Platform}",
deviceInstallation.Platform);
return false;
}
字段校验失败和平台映射失败的位置也应分别增加日志,记录进入了哪个失败分支、哪些字段为空。只在控制器中记录“注册失败”,仍然无法定位问题。
部署后再次点击 Register,查看异常类型、消息、内部异常,以及 SDK 提供的服务端错误信息,再据此排查权限、Hub 名称、请求内容或网络问题。
日志里的 IIS HTML 页面只显示了 422 和托管模块信息,没有具体的失败原因。凭这些信息,既无法认定 IIS 配置有误,也无法确认 422 是 Azure Notification Hubs 返回的原始状态码。
检查实际提交的安装信息
调用 SendAsync 前,查看 deviceInstallation 中的这些字段:
| 字段 | 应检查的内容 |
|---|---|
InstallationId | 非空,并能稳定标识当前安装 |
Platform | 与后端平台映射完全一致;此示例 Android 使用 "fcmv1" |
PushChannel | 当前应用取得的 FCM registration token |
Tags | 先使用空数组排除自定义标签的影响 |
PushChannel 应来自设备端 Firebase Messaging SDK,不能填写 Firebase API key、Project ID 或 Azure 连接字符串。
可以在原有 RegisterDeviceAsync 中增加检查,在依赖项缺失或字段为空时直接报错:
public async Task RegisterDeviceAsync(params string[] tags)
{
var service = DeviceInstallationService
?? throw new InvalidOperationException(
"IDeviceInstallationService is not registered.");
var deviceInstallation = service.GetDeviceInstallation(tags)
?? throw new InvalidOperationException(
"Device installation is null.");
if (string.IsNullOrWhiteSpace(deviceInstallation.InstallationId) ||
string.IsNullOrWhiteSpace(deviceInstallation.Platform) ||
string.IsNullOrWhiteSpace(deviceInstallation.PushChannel))
{
throw new InvalidOperationException(
"InstallationId, Platform and PushChannel are required.");
}
await SendAsync<DeviceInstallation>(
HttpMethod.Put, RequestUrl, deviceInstallation)
.ConfigureAwait(false);
await SecureStorage.SetAsync(
CachedDeviceTokenKey, deviceInstallation.PushChannel)
.ConfigureAwait(false);
await SecureStorage.SetAsync(
CachedTagsKey, JsonSerializer.Serialize(tags));
}
这些检查能尽早发现客户端数据问题,但不保证能解决后端异常。使用官方 Android 实现时,空 token 通常在构造安装信息时就会被拦截。
排查时,可以在本地调试器中对照客户端对象、发送的 JSON 和后端收到的对象,确认序列化没有丢失字段。公开日志中只记录 token 是否存在或其长度,不要输出完整 token。
检查 Azure 与 Firebase 配置
如果安装信息正常,再结合后端异常检查配置。
App Service 是否配置了正确的 Hub
本地通过 dotnet user-secrets 设置的值不会自动成为 Azure App Service 的配置。请确认实际部署的应用或部署槽中存在以下配置:
NotificationHub:Name
NotificationHub:ConnectionString
Authentication:ApiKey
核对 Hub 名称和连接字符串是否指向同一目标,并确认连接字符串具有创建、更新 installation 的权限。教程使用 DefaultFullSharedAccessSignature 对应的连接字符串配置后端。官方配置说明
客户端访问 API 使用的 Authentication:ApiKey 和后端访问 Notification Hubs 使用的连接字符串,是两项独立配置。
FCM v1 配置是否一致
检查 Notification Hub 的 Google FCM v1 配置,包括服务账号的 Project ID、Client Email 和 Private Key。这些值来自服务账号 JSON,不能用 Android 客户端的 google-services.json 代替。Notification Hubs 平台配置说明
客户端还需检查:
google-services.json是否对应当前使用的 Firebase 项目和 Android 包名。.csproj中的ApplicationId是否匹配 Firebase 注册的包名。- 文件是否以
GoogleServicesJson构建项参与当前 Android 目标的构建。
如果复制的构建配置带有特定的 TargetFramework 条件,要确认它与项目实际目标一致。文件放进了项目目录,并不代表构建时已经使用了它。
这些配置需要逐项核对,但当前的 422 不足以证明 FCM 凭据有误。部分问题可能要到后续发送通知时才会出现。
Android Emulator 需要检查什么
Firebase 支持在带 Google APIs 的 Android Emulator 上测试 FCM;该 MAUI 示例还要求 Android API 26+ 和 Google Play services。Firebase Android 接入说明、MAUI 示例运行要求
排查时,确认以下几点:
- 使用带 Google APIs 或 Google Play 的系统镜像,且 Google Play services 可用。
- 模拟器能够访问 Firebase 服务。
- 获取 token 的异步操作已成功完成,且 token 已写入注册流程使用的同一个
IDeviceInstallationService实例。 - 取得 token 后才允许点击 Register,同时记录获取 token 失败时的异常。
如果模拟器缺少 Google Play services,官方实现通常会先抛出本地检查异常。若请求已经进入后端并返回 422,就应继续追踪后端的失败分支。换成真机也不能省略这一步。
Android 13+ 的 POST_NOTIFICATIONS 权限影响通知展示,应在测试接收通知时检查,不能直接解释后端 installation 注册接口的 422。Firebase 通知权限说明
备注:内容仅供参考。
