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

質問
-
お世話になります。
.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---
---
私と同じ現象に遭遇した方はおられますか?
仮におられましたら、どのような対策を取られたのか、知りたいです。
回答
-
こんにちは。
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の今回のエラーとはちょっと原因が異なりそうです。(結局似たようなことなのかもしれませんが)
- 編集済み k.buchiMVP, Moderator 2016年2月22日 15:35
- 回答としてマーク Akira Ueda 2016年2月23日 5:26
すべての返信
-
こんにちは。
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の今回のエラーとはちょっと原因が異なりそうです。(結局似たようなことなのかもしれませんが)
- 編集済み k.buchiMVP, Moderator 2016年2月22日 15:35
- 回答としてマーク Akira Ueda 2016年2月23日 5:26