You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core Web API推送通知报错:注册推送系统句柄无效

推送通知失败排查:"The Push Notification System handle for the registration is invalid"错误分析

我正在通过ASP.NET Core Web API向Android和Apple设备推送通知,但多数时候推送失败,收到错误提示:

The Push Notification System handle for the registration is invalid

我无法理解该错误原因,项目中使用的是版本4.0.0的NotificationHub NuGet包,现将相关代码附上,恳请帮忙排查该问题。

public async static Task SendPushNotificationToDevice(HubNotification hubNotification) 
{
    if (hubNotification != null) 
    {
        try 
        {
            NotificationHubClient hub = NotificationHubClient.CreateClientFromConnectionString
  (ConfigurationManager.AppSettings["HubConnectionString"],
  ConfigurationManager.AppSettings["HubName"], true);
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

            if (!string.IsNullOrEmpty(hubNotification.DeviceId) &&
                !string.IsNullOrEmpty(hubNotification.DeviceType))
            {
                // check if the already registered device
                var registationDescriptions = hub.GetRegistrationsByTagAsync(hubNotification.ToUserEmail, 100)
               .Result;

               foreach (var registrationDescription in registationDescriptions) 
               {
                   // We shouldn't have any extra registrations; delete if we do.
                   hub.DeleteRegistrationAsync(registrationDescription);
               }

               // set message
               hubNotification.Message = string.Format(hubNotification.Message);

               if (!string.IsNullOrEmpty(hubNotification.Message)) 
               {
                   string jsonPayLoad = string.Empty;

                   NotificationOutcome outcome;

                   if (hubNotification.DeviceType.ToLower().Contains("android")) 
                   {
                       var registeredNewDevice = hub.CreateGcmNativeRegistrationAsync(
                      hubNotification.DeviceId.Replace("-", ""),
                      new[]{hubNotification.ToUserEmail})
                           .Result;

                      jsonPayLoad = "{ \"data\": " +
                                    "{ \"message\""
                                    ": \""
                                    " + hubNotification.Message.Trim() + "\""
                                    "," +
                                    "\"ListId\""
                                    ": \""
                                    " + hubNotification.ListId + "\""
                                    "," +
                                    "\"notificationType\""
                                    ": \""
                                    " + hubNotification.NotificationType + "\""
                                    "," +
                                    "\"IsOwner\""
                                    ": \""
                                    " + hubNotification.IsOwner + "\""
                                    "," +
                                    "\"ListName\""
               ": \""
               " + hubNotification.ListName + "\""
               "," +
               "\"ListType\""
               ": \""
               " + hubNotification.ListType + "\""
               "," +
               "\"badge\""
               ": \""
               " + hubNotification.badge + "\""
               "," +
               "\"inProgress\""
               ": \""
               " + hubNotification.InProgress + "\""
               "," +
               "\"headercolor\""
               ": \""
               " + hubNotification.ListHeaderColor + "\""
               "," +
               "\"titlecolor\""
               ": \""
               " + hubNotification.ListHeaderTitleColor + "\""
               "," +
               "\"sound\""
               ":\""
               " + hubNotification.Sound + "\""
               "," +
               "\"userProfileId\""
               ":\""
               " + hubNotification.ToUserProfileId.ToString().Trim() + "\""
               "," +
               "\"type\":\"sendfriend\"}}";

           outcome = hub.SendGcmNativeNotificationAsync(
                            jsonPayLoad, hubNotification.ToUserEmail)
                         .Result;
         } else {
           hubNotification.Sound = hubNotification.Sound + ".caf";
           var registeredNewDevice =
               hub.CreateAppleNativeRegistrationAsync(
                      hubNotification.DeviceId.Replace("-", ""),
                      new[]{hubNotification.ToUserEmail})
                   .Result;

          jsonPayLoad = "{ \"aps\": " +
          "{ \"alert\""
          ": \""
          " + hubNotification.Message.Trim() + "\""
          "," +
          "\"ListId\""
          ": \""
          " + hubNotification.ListId + "\""
          "," +
          "\"notificationType\""
          ": \""
          " + hubNotification.NotificationType + "\""
          "," +
          "\"IsOwner\""
          ": \""
          " + hubNotification.IsOwner + "\""
          "," +
          "\"ListName\""
          ": \""
          " + hubNotification.ListName + "\""
          "," +
          "\"ListType\""
          ": \""
          " + hubNotification.ListType + "\""
          "," +
          "\"badge\""
          ": \""
          " + hubNotification.badge + "\""
          "," +
          "\"InProgress\""
          ": \""
          " + hubNotification.InProgress + "\""
          "," +
          "\"headercolor\""
          ": \""
          " + hubNotification.ListHeaderColor + "\""
          "," +
          "\"titlecolor\""
          ": \""
          " + hubNotification.ListHeaderTitleColor + "\""
          "," +
          "\"sound\""
          ":\""
          " + hubNotification.Sound + "\""
          "," +
          "\"userProfileId\""
          ":\""
          " + hubNotification.ToUserProfileId.ToString().Trim() + "\""
          "," +
          "\"type\":\"sendfriend\"}}";
         outcome = hub.SendAppleNativeNotificationAsync(jsonPayLoad,
                                           hubNotification.ToUserEmail)
          .Result;
         }

         // check the response
         if (outcome != null) 
         {
             if (!((outcome.State == NotificationOutcomeState.Abandoned) ||
                   (outcome.State == NotificationOutcomeState.Unknown))) 
             {
                 // Message send successfully!!
                         }
                    }
                }
            }
        } 
        catch (Exception ex) 
        {
             // LogError(ex.Message, "SendPushNotificationToDevice");
        }
    }
}

核心错误原因及修复方案

1. 设备令牌处理错误

Apple的APNS设备令牌原生包含连字符,是合法格式,代码中统一执行Replace("-", "")会直接破坏APNS令牌的有效性,触发"无效注册句柄"错误。
修复:仅针对Android设备处理令牌(若原始令牌确实带连字符,通常FCM令牌无连字符):

string deviceToken = hubNotification.DeviceType.ToLower().Contains("android") 
    ? hubNotification.DeviceId.Replace("-", "") 
    : hubNotification.DeviceId;

2. 异步代码滥用.Result

所有异步方法用.Result阻塞调用,容易引发死锁或未捕获的异常,导致注册/推送流程中断,间接引发注册状态异常。
修复:替换所有.Result为await,保持方法异步特性:

var registationDescriptions = await hub.GetRegistrationsByTagAsync(hubNotification.ToUserEmail, 100);
foreach (var registrationDescription in registationDescriptions) 
{
    await hub.DeleteRegistrationAsync(registrationDescription);
}
// 其他Create/Update/Send类异步调用同理替换为await

3. 注册逻辑缺陷

每次推送前删除用户所有注册再重建,存在时间窗口问题,且频繁删除重建会导致Notification Hub注册状态不一致,引发无效句柄错误。
修复:先查询设备是否已注册,存在则更新,不存在再创建:

var existingRegistrations = await hub.GetRegistrationsByChannelAsync(deviceToken, 100);
if (existingRegistrations.Any())
{
    var existingReg = existingRegistrations.First();
    existingReg.Tags = new HashSet<string> { hubNotification.ToUserEmail };
    await hub.UpdateRegistrationAsync(existingReg);
}
else
{
    if (hubNotification.DeviceType.ToLower().Contains("android"))
    {
        await hub.CreateGcmNativeRegistrationAsync(deviceToken, new[]{hubNotification.ToUserEmail});
    }
    else
    {
        await hub.CreateAppleNativeRegistrationAsync(deviceToken, new[]{hubNotification.ToUserEmail});
    }
}

4. 手动拼接JSON语法错误

代码中手动拼接JSON存在引号闭合、格式错误等问题,生成的Payload会被APNS/FCM拒绝,间接触发注册无效错误。
修复:使用强类型类+JSON序列化生成Payload:

// 定义Android Payload类
public class AndroidPayload
{
    public AndroidData data { get; set; }
}
public class AndroidData
{
    public string message { get; set; }
    public string ListId { get; set; }
    // 补充其他所需字段
}

// 序列化生成JSON
var payload = new AndroidPayload 
{ 
    data = new AndroidData 
    { 
        message = hubNotification.Message.Trim(),
        ListId = hubNotification.ListId
        // 赋值其他字段
    } 
};
string jsonPayLoad = JsonConvert.SerializeObject(payload);

5. 异常捕获不完整

catch块仅记录消息,丢失堆栈和内部异常信息,无法定位具体失败环节。
修复:记录完整异常信息:

catch (Exception ex) 
{
    LogError($"推送失败: {ex.Message}, 堆栈: {ex.StackTrace}, 内部异常: {ex.InnerException?.Message}", "SendPushNotificationToDevice");
}

内容的提问来源于stack exchange,提问作者pratapsingh845

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 13:17:09