2017-04-07 3 views
0

일괄 전송 API 끝점을 사용하여 특정 사용자에게 여러 가지 푸시 알림을 관심사에 따라 보내려고합니다. 우리는 알림 허브의 태그 시스템이 우리에게 필요한 유연성을 제공하지 않는다고 결론을 내 렸습니다.403 Azure 알림 허브 일괄 전송을 사용할 때 금지됨

직접 보내기 끝점에서 사용할 수있는 장치 토큰을 저장하는 데이터베이스가 있지만 Microsoft에서 제공 한 표준 정보를 사용해도 403 오류가 발생하고 잘못된 정보는 제공되지 않습니다.

public class WnsNotificationService : BaseNotificationService 
{ 
    private ISubscriptionProvider subscriptionProvider; 

    /// <summary> 
    /// Initializes a new instance of the <see cref="WnsNotificationService" /> class. 
    /// </summary> 
    /// <param name="telemetryService">The telemetry service.</param> 
    /// <param name="subscriptionProvider">The subscription provider.</param> 
    public WnsNotificationService(ITelemetryService telemetryService, ISubscriptionProvider subscriptionProvider) : base(telemetryService) 
    { 
     this.subscriptionProvider = subscriptionProvider; 
    } 

    /// <summary> 
    /// Sends the new Airport Event notification to windows devices via WNS. 
    /// </summary> 
    /// <param name="airportEvent">The Airport Event.</param> 
    /// <returns> 
    /// Notification Result 
    /// </returns> 
    public override async Task<NotificationResult> SendNotification(AirportEvent airportEvent) 
    { 
     try 
     { 
      IEnumerable<IEnumerable<string>> deviceCollection = 
       this.subscriptionProvider.GetSubscribedUserPNSHandles(airportEvent, PushNotificationPlatform.wns).Batch(1000); 

      foreach (var devices in deviceCollection) 
      { 
       ServiceBusConnectionStringBuilder connectionString = new ServiceBusConnectionStringBuilder(ConfigurationManager.AppSettings["Microsoft.Azure.NotificationHubs.ConnectionString"]); 
       string serviceBusNamespace = connectionString.Endpoints.First().Host; 
       string namespaceKeyName = connectionString.SharedAccessKeyName; 
       string namespaceKey = connectionString.SharedAccessKey; 

       var uri = new Uri($"{ ConfigurationManager.AppSettings["Microsoft.Azure.NotificationHubs.Url"] }/{ ConfigurationManager.AppSettings["Microsoft.Azure.NotificationHubs.HubName"] }/messages/$batch?direct&api-version=2015-08"); 
       var request = WebRequest.CreateHttp(uri); 
       request.Method = "POST"; 
       request.ContentType = @"multipart/mixed; boundary = ""simple-boundary"""; 
       request.Headers["Authorization"] = SharedAccessSignatureTokenProvider.GetSharedAccessSignature(namespaceKeyName, namespaceKey, serviceBusNamespace, TimeSpan.FromMinutes(45)); 
       request.Headers["ServiceBusNotification-Format"] = "windows"; 
       request.Headers["X-WNS-Type"] = "wns/raw"; 

       string body = this.GenerateBatchRequestBody(airportEvent.AirportEventId, devices); 

       byte[] requestBytes = new ASCIIEncoding().GetBytes(body); 
       Stream requestStream = request.GetRequestStream(); 
       requestStream.Write(requestBytes, 0, requestBytes.Length); 

       request.GetResponse(); 
      } 

      return new NotificationResult(true); 
     } 
     catch (Exception) 
     { 
      return new NotificationResult(false); 
     } 
    } 

    /// <summary> 
    /// Sends the new Airport Event notification to a specific windows device via WNS. 
    /// </summary> 
    /// <param name="deviceId">The device identifier.</param> 
    /// <param name="airportEvent">The Airport Event.</param> 
    /// <returns> 
    /// Notification Result 
    /// </returns> 
    /// <exception cref="System.NotImplementedException">Not Implemented Exception</exception> 
    public override Task<NotificationResult> SendNotificationToDevice(string deviceId, AirportEvent airportEvent) 
    { 
     throw new NotImplementedException(); 
    } 

    /// <summary> 
    /// Generates the batch request body. 
    /// </summary> 
    /// <param name="airportEventGuid">The airport event unique identifier.</param> 
    /// <param name="devices">The devices.</param> 
    /// <returns>Request Body</returns> 
    private string GenerateBatchRequestBody(Guid airportEventGuid, IEnumerable<string> devices) 
    { 
     return @" 
--simple-boundary 
Content-type: text/xml 
Content-Disposition: inline; name=notification 

<toast><visual><binding template=""ToastText01""><text id=""1"">Hello from 
Batch Direct Send!</text></binding></visual></toast> 
--simple-boundary 
Content-type: application/json 
Content-Disposition: inline; name=devices 

['https://{foo}.notify.windows.com/?token={bar}'] 
--simple-boundary--"; 
    } 
} 

이것은 당신의 설명에 따르면 https://azure.microsoft.com/en-us/blog/push-notification-hubs-batch-direct-send/

답변

1

에 제공된 정보를 사용하고, 나는 Direct Batch Send를 확인하고 내 옆에이 문제를 테스트하기 위해이 샘플 azure-notificationhubs-samples을 따랐다.

enter image description here

이 코드를 바탕으로, 난 당신이 request.Headers["X-WNS-Type"] = "wns/toast";request.Headers["X-WNS-Type"] = "wns/raw";을 변경해야 할 것으로 가정하고 인증 토큰이 유효하지 않을 수 있습니다 : 일부 시험 후, 나는 다음과 같이 내 측면에 작업을 만들 수 있습니다. 여기에 인증 토큰을 생성하는 나의 방법이다, 당신은 그것을 참조 수 :

/// <summary> 
/// GetSharedAccessSignature 
/// </summary> 
/// <param name="SasKeyName">SharedAccessKeyName</param> 
/// <param name="SasKeyValue">SharedAccessKey</param> 
/// <param name="uri">resourceURI (e.g. https://{namespace}.servicebus.windows.net/{NotificationHub}/messages/$batch?direct&api-version=2015-08)</param> 
/// <param name="minUntilExpire">minUntilExpire</param> 
/// <returns></returns> 
private static string GetSharedAccessSignature(string SasKeyName, string SasKeyValue, string uri, TimeSpan minUntilExpire) 
{ 
    string targetUri = Uri.EscapeDataString(uri.ToLower()).ToLower(); 

    // Add an expiration in seconds to it. 
    long expiresOnDate = DateTime.Now.Ticks/TimeSpan.TicksPerMillisecond; 
    expiresOnDate += (long)minUntilExpire.TotalMilliseconds; 
    long expires_seconds = expiresOnDate/1000; 
    String toSign = targetUri + "\n" + expires_seconds; 

    // Generate a HMAC-SHA256 hash or the uri and expiration using your secret key. 
    byte[] keyBytes = System.Text.Encoding.UTF8.GetBytes(SasKeyValue); 
    HMACSHA256 hmacsha256 = new HMACSHA256(keyBytes); 
    byte[] hash = hmacsha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(toSign)); 

    // Create the token string using the base64 
    string signature = Uri.EscapeDataString(Convert.ToBase64String(hash)); 

    return "SharedAccessSignature sr=" + targetUri + "&sig=" + signature + "&se=" + expires_seconds + "&skn=" + SasKeyName; 
} 

참고 :를 여기하는 공식 코드 샘플, 당신은 it를 참조 할 수있다.

또한 Direct Batch Send 상태로 다음과 같이

직접 장치 핸들 (알림 형식에 의해 표현되는 바와 같이 유효 토큰)의 집합으로 알림을 일괄 전송. 이 API는 Basic and Standard tier Notification Hub namespaces에서 사용할 수 있습니다.

당신은 그렇지 않으면 당신은 Fiddler를 통해 다음과 같은 응답을 얻을 것입니다, 기본 또는 표준에 가격 계층을 변경해야합니다 : 종합 대답 브루스에 대한

enter image description here

+0

환상적인, 감사합니다! – JamieB