none
[Event Hub] メッセージングプラン BASIC の場合、Response Content:Error Code 400 が発生する現象 RRS feed

  • 質問

  • お世話になります。


    .NET アプリからAzure イベントハブサービスにEvent Hub へのメッセージ送信したところ、メッセージングプランによって送信に失敗します。

    イベント通知の方法は以下のページにある「Sending from a modern .NET application using HttpClient」です。

    http://fabriccontroller.net/iot-with-azure-service-bus-event-hubs-authenticating-and-sending-from-any-type-of-device-net-and-js-samples/


    (1) メッセージングプラン BASIC の場合

    Response:BadRequest

    Response Content:Error Code 400

    hogehoge is not allowed because the namespace is of Basic tier.


    (2) メッセージングプラン STANDARDの場合

    イベント通知に成功する


    ---

    メッセージングプラン BASIC の場合であっても、より簡単にした、以下のサンプルコードではメッセージ通知に成功するので、サーバーサイドの仕様とは考えにくく、何故 STANDARD にしないといけないのか理解できておりません。

    https://azure.microsoft.com/ja-jp/documentation/articles/event-hubs-csharp-ephcs-getstarted/


    なお、同じ疑問は海外のサイトでも報告されております。

    http://stackoverflow.com/questions/28290688/why-does-azure-service-bus-think-defaulttimetolive-property-is-not-set---

    ---

    私と同じ現象に遭遇した方はおられますか?

    仮におられましたら、どのような対策を取られたのか、知りたいです。

    2016年2月22日 10:14

回答

  • こんにちは。

    BasicプランではPublisher Policyが利用できません。
    https://azure.microsoft.com/ja-jp/pricing/details/event-hubs/

    Event Hubsでは以下の2つのREST APIを使ってメッセージを送信することができますが、BasicではPublisherを使う方法(デバイスIDを指定する方法)が使えないことになります。
    https://msdn.microsoft.com/ja-jp/library/azure/dn790664.aspx

    失敗するパターンのサンプルはPublisher(デバイスID)を指定する形のサンプルですので、Basicプランにすると失敗します。
    回避するにはデバイスIDの指定をやめて、Publisherを指定しないほうのREST APIをPost先URLとして送信します。このときSAS(認証情報)も合わせて生成する必要があります。(サンプルのコメントにあるSASジェネレーターはPublisherを強制的につけるので使えません)

    SASの生成含めたサンプルを記載しておきます(適宜URLやサービスバス名前空間、イベントハブ名、キーなどは差し替えてください)

            static void Main(string[] args)
            {
                var sas = CreateToken("https://xxxxx.servicebus.windows.net/yyyyy/messages", "sas key name", "sas key");
                // Namespace info.
                var serviceNamespace = "xxxxx";
                var hubName = "yyyyy";
    
                // Create client.
                var httpClient = new HttpClient();
                httpClient.BaseAddress =
                           new Uri(String.Format("https://{0}.servicebus.windows.net/", serviceNamespace));
                httpClient.DefaultRequestHeaders
                           .TryAddWithoutValidation("Authorization", sas);
    
                // Keep sending.
                while (true)
                {
                    var eventData = new
                    {
                        Temperature = new Random().Next(20, 50)
                    };
    
                    var postResult = httpClient.PostAsJsonAsync(
                           String.Format("{0}/messages", hubName), eventData).Result;
    
                    Console.WriteLine("Sent temperature using HttpClient: {0}",
                           eventData.Temperature);
                    Console.WriteLine(" > Response: {0}",
                           postResult.StatusCode);
                    Console.WriteLine(" > Response Content: {0}",
                           postResult.Content.ReadAsStringAsync().Result);
    
                    Thread.Sleep(new Random().Next(1000, 5000));
                }
            }
    
            private static string CreateToken(string resourceUri, string keyName, string key)
            {
                TimeSpan sinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1);
                var expiry = Convert.ToString((int)sinceEpoch.TotalSeconds + 3600); //EXPIRES in 1h 
                string stringToSign = HttpUtility.UrlEncode(resourceUri) + "\n" + expiry;
                HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));
    
                var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
                var sasToken = String.Format(CultureInfo.InvariantCulture,
                "SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}",
                    HttpUtility.UrlEncode(resourceUri), HttpUtility.UrlEncode(signature), expiry, keyName);
    
                return sasToken;
            }

    ※SASキーの生成はこちらを参考

    http://developers.de/blogs/damir_dobric/archive/2013/10/17/how-to-create-shared-access-signature-for-service-bus.aspx

    ※補足:海外のStackOverflowで挙がっている問題はServiceBusのもので、EventHubsの今回のエラーとはちょっと原因が異なりそうです。(結局似たようなことなのかもしれませんが)

    2016年2月22日 15:25
    モデレータ

すべての返信

  • こんにちは。

    BasicプランではPublisher Policyが利用できません。
    https://azure.microsoft.com/ja-jp/pricing/details/event-hubs/

    Event Hubsでは以下の2つのREST APIを使ってメッセージを送信することができますが、BasicではPublisherを使う方法(デバイスIDを指定する方法)が使えないことになります。
    https://msdn.microsoft.com/ja-jp/library/azure/dn790664.aspx

    失敗するパターンのサンプルはPublisher(デバイスID)を指定する形のサンプルですので、Basicプランにすると失敗します。
    回避するにはデバイスIDの指定をやめて、Publisherを指定しないほうのREST APIをPost先URLとして送信します。このときSAS(認証情報)も合わせて生成する必要があります。(サンプルのコメントにあるSASジェネレーターはPublisherを強制的につけるので使えません)

    SASの生成含めたサンプルを記載しておきます(適宜URLやサービスバス名前空間、イベントハブ名、キーなどは差し替えてください)

            static void Main(string[] args)
            {
                var sas = CreateToken("https://xxxxx.servicebus.windows.net/yyyyy/messages", "sas key name", "sas key");
                // Namespace info.
                var serviceNamespace = "xxxxx";
                var hubName = "yyyyy";
    
                // Create client.
                var httpClient = new HttpClient();
                httpClient.BaseAddress =
                           new Uri(String.Format("https://{0}.servicebus.windows.net/", serviceNamespace));
                httpClient.DefaultRequestHeaders
                           .TryAddWithoutValidation("Authorization", sas);
    
                // Keep sending.
                while (true)
                {
                    var eventData = new
                    {
                        Temperature = new Random().Next(20, 50)
                    };
    
                    var postResult = httpClient.PostAsJsonAsync(
                           String.Format("{0}/messages", hubName), eventData).Result;
    
                    Console.WriteLine("Sent temperature using HttpClient: {0}",
                           eventData.Temperature);
                    Console.WriteLine(" > Response: {0}",
                           postResult.StatusCode);
                    Console.WriteLine(" > Response Content: {0}",
                           postResult.Content.ReadAsStringAsync().Result);
    
                    Thread.Sleep(new Random().Next(1000, 5000));
                }
            }
    
            private static string CreateToken(string resourceUri, string keyName, string key)
            {
                TimeSpan sinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1);
                var expiry = Convert.ToString((int)sinceEpoch.TotalSeconds + 3600); //EXPIRES in 1h 
                string stringToSign = HttpUtility.UrlEncode(resourceUri) + "\n" + expiry;
                HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));
    
                var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
                var sasToken = String.Format(CultureInfo.InvariantCulture,
                "SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}",
                    HttpUtility.UrlEncode(resourceUri), HttpUtility.UrlEncode(signature), expiry, keyName);
    
                return sasToken;
            }

    ※SASキーの生成はこちらを参考

    http://developers.de/blogs/damir_dobric/archive/2013/10/17/how-to-create-shared-access-signature-for-service-bus.aspx

    ※補足:海外のStackOverflowで挙がっている問題はServiceBusのもので、EventHubsの今回のエラーとはちょっと原因が異なりそうです。(結局似たようなことなのかもしれませんが)

    2016年2月22日 15:25
    モデレータ
  • k.buchi 様

    お世話になります。

    ご提示いただいた方法とサンプルコードで、メッセージングプラン BASIC で EventHub にイベント通知されていることを確認しました。

    ご丁寧な解説、ありがとうございました。

    2016年2月23日 5:26