通过Azure NotificationHub REST Api从设备发送推送通知

时间:2017-02-15 20:22:41

标签: c# xamarin.ios apple-push-notifications azure-mobile-services azure-notificationhub

我正在尝试通过Azure NotificationHub REST Api从iOS设备(iPhone)发送推送通知。我是根据我在网上找到的Azure文档从Xamarin.iOS解决方案尝试这个。

响应返回以下信息:

Error: '50002: Provider Internal Error' Status code: 500

用于调用NotificationHub REST Api的代码(来自iOS客户端应用程序):

var hubUtil = new NotificationHubUtility("Endpoint=sb://company-name.servicebus.windows.net/;SharedAccessKeyName=DefaultFullSharedAccessSignature;SharedAccessKey=00000000000000011111111111111122222222222222");
hubUtil.SendNotificationMessage("This is a TEST Notification!").ConfigureAwait(false);

public class NotificationHubUtility
{
    public string Endpoint { get; private set; }
    public string SasKeyName { get; private set; }
    public string SasKeyValue { get; private set; }
    public string HubName { get; private set; }
    public string ApiVersion { get; private set; }

    public NotificationHubUtility(string connectionString)
    {
        //Parse Connectionstring
        string[] parts = connectionString.Split(new char[] {';'});
        for (int i = 0; i < parts.Length; i++)
        {
            if (parts[i].StartsWith("Endpoint", StringComparison.CurrentCulture))
                Endpoint = "https" + parts[i].Substring(11);
            if (parts[i].StartsWith("SharedAccessKeyName", StringComparison.CurrentCulture))
                SasKeyName = parts[i].Substring(20);
            if (parts[i].StartsWith("SharedAccessKey", StringComparison.CurrentCulture))
                SasKeyValue = parts[i].Substring(16);
        }

        HubName = "my-hub";
        ApiVersion = "?api-version=2014-09-01";
    }

    public string GetSaSToken(string uri, int minUntilExpire)
    {
        string targetUri = Uri.EscapeDataString(uri.ToLower()).ToLower();

        // Add an expiration in seconds to it.
        long expiresOnDate = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
        expiresOnDate += minUntilExpire * 60 * 1000;
        long expires_seconds = expiresOnDate / 1000;
        var toSign = targetUri + "\n" + expires_seconds;

        // Generate a HMAC-SHA256 hash or the uri and expiration using your secret key.
        IMacAlgorithmProvider hasher = WinRTCrypto.MacAlgorithmProvider.OpenAlgorithm(MacAlgorithm.HmacSha256);
        var messageBuffer = WinRTCrypto.CryptographicBuffer.ConvertStringToBinary(toSign, Encoding.UTF8);
        var keyBuffer = WinRTCrypto.CryptographicBuffer.ConvertStringToBinary(SasKeyValue, Encoding.UTF8);
        var hmacKey = hasher.CreateKey(keyBuffer);
        var signedMessage = WinRTCrypto.CryptographicEngine.Sign(hmacKey, messageBuffer);

        string signature = Uri.EscapeDataString(WinRTCrypto.CryptographicBuffer.EncodeToBase64String(signedMessage));

        var token = "SharedAccessSignature sig=" + signature + "&se=" + expires_seconds + "&skn=" + SasKeyName + "&sr=" + targetUri;

        return token;
    }

    public async Task SendNotificationMessage(string message)
    {
        try
        {
            // basic http client (if needed)
            var httpClient = new HttpClient();
            httpClient.MaxResponseContentBufferSize = 1024000;

            var notificationPayload = "{\"aps\":{\"alert\":\"" + message + "\"}}";
            var notificationHubUrl = $"{Endpoint}{HubName}/messages/{ApiVersion}";
            var authToken = GetSaSToken(notificationHubUrl, 10);

            var request = new HttpRequestMessage(HttpMethod.Post, notificationHubUrl);
            //request.Headers.Add("Content-Type", "application/json;charset=utf-8");
            request.Headers.Add("ServiceBusNotification-Format", "apple");
            request.Headers.Add("ServiceBusNotification-Apns-Expiry", DateTime.UtcNow.AddYears(1).ToString("YYYY-MM-DDThh:mmTZD"));
            request.Headers.Add("Authorization", authToken);
            var requestBody = new StringContent(notificationPayload, Encoding.UTF8, "application/json");
            request.Content = requestBody;

            var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseContentRead);

        }
        catch (Exception ex)
        {
            Console.Error.WriteLine(@"ERROR - Sending Notification {0}", ex.Message);
        }
    }
}

连接字符串示例:

Endpoint=sb://company-name.servicebus.windows.net/;SharedAccessKeyName=DefaultFullSharedAccessSignature;SharedAccessKey=00000000000000011111111111111122222222222222

环境和假设:

  • 使用C#的Xamarin.iOS解决方案
  • 使用PCLCrypto库进行加密
  • 我正在尝试重新创建在Azure示例github repo中的Example中演示但使用Xamarin.iOS
  • 的解决方案
  • 连接字符串直接来自Azure门户
  • 生成SaS令牌的代码改编自Azure NotificationHub REST Api Documentation
  • 通知中心工作正常,我可以通过集线器用户界面发送测试推送通知,我看到它进入设备

我在这里缺少什么?我无法在线找到此错误的相关文档。任何帮助将不胜感激。

使用修复更新:

以上代码的以下2个更改为我解决了问题:

更改

ApiVersion = "?api-version=2014-09-01";

ApiVersion = "?api-version=2016-07";

更改

request.Headers.Add("ServiceBusNotification-Apns-Expiry", DateTime.UtcNow.AddYears(1).ToString("YYYY-MM-DDThh:mmTZD"));

request.Headers.Add("ServiceBusNotification-Apns-Expiry", DateTime.UtcNow.AddYears(1).ToString("yyyy-MM-ddTHH:mm:sszzz"));

2 个答案:

答案 0 :(得分:1)

Api版本2014-09-01不正确。请使用2016-07作为Api版本,你应该是好的。

由于

苏赫拉布

答案 1 :(得分:0)

我已经找到了问题:

  1. +1给Sohrab指出Api版本,我将其更新为ApiVersion = "?api-version=2016-07";
  2. ServiceBusNotification-Apns-Expiry 标头值格式出错,日期未正确格式化为字符串。更正后的格式字符串为ToString("yyyy-MM-ddTHH:mm:sszzz")