getting unauthorized error trying to listen to Azure Event Hub - azure

i have a simple EventHub listener sample code trying to listen to event hub
public class Program
{
private const string EventHubConnectionString = "Endpoint=sb://fake.servicebus.windows.net/;SharedAccessKeyName=SendETB;SharedAccessKey=JcvVeX5KsGHfJkPNmdns5jvNYVpB9Wc05jDuMaV3NW8=";
private const string EventHubName = "myhub";
private const string StorageContainerName = "my-own-container";
private const string StorageAccountName = "mystorage";
private const string StorageAccountKey = "fakeZn8WUV1mcsh0MVbmea/ypxDs+No2tzrhr0kUmjxvA0a0jUxfZ29hHoY/yopVvGLEn/stEQbBEAyjYMX9g==";
private static readonly string StorageConnectionString = string.Format("DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}", StorageAccountName, StorageAccountKey);
public static void Main(string[] args)
{
MainAsync(args).GetAwaiter().GetResult();
}
private static async Task MainAsync(string[] args)
{
Console.WriteLine("Registering EventProcessor...");
var eventProcessorHost = new EventProcessorHost(
EventHubName,
PartitionReceiver.DefaultConsumerGroupName,
EventHubConnectionString,
StorageConnectionString,
StorageContainerName);
// Registers the Event Processor Host and starts receiving messages
await eventProcessorHost.RegisterEventProcessorAsync<SimpleEventProcessor>();
Console.WriteLine("Receiving. Press enter key to stop worker.");
Console.ReadLine();
// Disposes of the Event Processor Host
await eventProcessorHost.UnregisterEventProcessorAsync();
}
}
}
with the above mentioned code i get an error.
Error on Partition: 0, Error: Unauthorized access. 'Listen' claim(s) are required to perform this operation. Resource: 'sb://fake.servicebus.windows.net/etbhub/consumergroups/$default/partitions/0'. TrackingId:fakef417d94238ba36d41d32b83341_G9, SystemTracker:gateway5, Timestamp:2020-01-27T22:06:49

Error message is pretty self-descriptive. Make sure SharedAccessKeyName SendETB allows 'Listen' permission. You can check it on the portal like below.

Make sure you have added a Shared Access Policy for Listen for your Event Hub Namespace.
For Event Hub it should be Send
For Event Hub Namespace it should have all three Manage, Sen, Listen as per the need.

Related

Azure Service Bus | Enable Session | Session does not receive

I have a requirement to process the same set of messages together and for this, I was trying Azure Service Bus Sessions Enabled feature. To test this, I created a very simple application, a message is submitted successfully in a queue, however, while trying to receive the message in "ReceiveSessionMessage" function, a message session is not returned and the program exits after this line.
I am not able to figure out the exact root cause, any help would be much appreciated. Thanks
[var messageSession = await
sessionClient.AcceptMessageSessionAsync();]
Program
using Microsoft.Azure.ServiceBus;
using System;
using System.Text;
using System.Threading.Tasks;
namespace TestSendReceiveMessagesAzure
{
class Program
{
static string connectionString = "";
static string queueName = "demosessionqueue";
static void Main(string[] args)
{
Console.WriteLine("Test Service Bus Session! enable feature");
SendMessage();
Console.WriteLine("Message Pushed");
ReceiveSessionMessage();
}
private static void SendMessage()
{
QueueClient queueClilent = new QueueClient(connectionString, queueName, ReceiveMode.PeekLock);
string msgJson = "{PizzaType:Veggie,SessionID:SessionId0101}";
Message message = new Message(Encoding.UTF8.GetBytes(msgJson))
{
SessionId = "SessionId0101"
};
Console.WriteLine(msgJson);
queueClilent.SendAsync(message).Wait();
}
private static async Task ReceiveSessionMessage()
{
var sessionClient = new SessionClient(connectionString, queueName, ReceiveMode.PeekLock);
Console.WriteLine("Accepting a message session...");
try
{
var messageSession = await sessionClient.AcceptMessageSessionAsync();
Console.WriteLine($"Message.SessionID={messageSession.SessionId}");
}
catch (Exception ex)
{
Console.WriteLine(ex.StackTrace);
}
}
}
}
Console Output
The issue is with the declaration of
static void Main(string[] args) , and the calling method "ReceiveSessionMessage()" in it. The correct way of calling this function from the Program.cs was
static async Task Main(string[] args)
{
Console.WriteLine("Message Session Handler..");
await MessageSessionReceiver();
}
"ReceiveSessionMessage" function was an async function and the calling function did not have the await keyword mentioned due to which the program exited. After changing the syntax to add await, it worked.

Returned Azure service bus queue sequence number different in my consumer than what was returned in the producer and shown in the Azure portal?

When I create a scheduled service bus message, both in Azure Portal and in my app using the Service bus producer code (below) and I receive a sequence number. I save it in my db.
Problem - When my Service bus consumer code is triggered by the dequeue of the scheduled message the sequence number is different than the one that was initially given to me by both the service bus producer code and through the Azure portal.
Shown here, where '13' is the sequnce number shown in Azure Portal screen.
Here is the code that receives the scheduled message and you can see the sequence number is different!
Here is my consumer code (don't think it matters)
private async Task MessageHandler(ProcessMessageEventArgs args)
{
string body = args.Message.Body.ToString();
JObject jsonObject = JObject.Parse(body);
var eventStatus = (string)jsonObject["EventStatus"];
await args.CompleteMessageAsync(args.Message);
// fetch row here by sequence number
// edit some data from entity, then save
int result = await dbContext.SaveChangesAsync();
}
Here is my producer code
public async Task<long> SendMessage(string messageBody, DateTimeOffset scheduledEnqueueTimeUtc)
{
await using (ServiceBusClient client = new ServiceBusClient(_config["ServiceBus:Connection"]))
{
ServiceBusSender sender = client.CreateSender(_config["ServiceBus:Queue"]);
ServiceBusMessage message = new ServiceBusMessage(messageBody);
var sequenceNumber = await sender.ScheduleMessageAsync(message, scheduledEnqueueTimeUtc);
return sequenceNumber;
}
}
From the documentation:
The SequenceNumber for a scheduled message is only valid while the message is in this state. As the message transitions to the active state, the message is appended to the queue as if had been enqueued at the current instant, which includes assigning a new SequenceNumber.
This is the code on my side:
using System;
using System.Threading;
using System.Threading.Tasks;
using Azure.Messaging.ServiceBus;
namespace ConsoleApp3
{
class Program
{
static string connectionString = "xxxxxx";
static string queueName = "myqueue";
static ServiceBusClient client;
static ServiceBusProcessor processor;
static async Task Main(string[] args)
{
client = new ServiceBusClient(connectionString);
processor = client.CreateProcessor(queueName, new ServiceBusProcessorOptions());
try
{
processor.ProcessMessageAsync += MessageHandler;
processor.ProcessErrorAsync += ErrorHandler;
await processor.StartProcessingAsync();
Console.WriteLine("Wait for a minute and then press any key to end the processing");
Console.ReadKey();
Console.WriteLine("\nStopping the receiver...");
await processor.StopProcessingAsync();
Console.WriteLine("Stopped receiving messages");
}
finally
{
await processor.DisposeAsync();
await client.DisposeAsync();
}
}
static async Task MessageHandler(ProcessMessageEventArgs args)
{
string body = args.Message.Body.ToString();
Console.WriteLine($"Received: {body}");
Console.WriteLine($"ID: {args.Message.MessageId}");
await args.CompleteMessageAsync(args.Message);
}
static Task ErrorHandler(ProcessErrorEventArgs args)
{
Console.WriteLine(args.Exception.ToString());
return Task.CompletedTask;
}
}
}
And it seems no problem on my side:
Message Id changed should be the message be thrown back by some reasons.

How to solve Unhandle Exception:System.Net Socket.SocketException in azure iot readmessage device?

Hi i have the following code, that reads the message to the device. I have azure portal running. But i get the following exception when running on a command prompt;
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using Microsoft.Azure.EventHubs;
using System.Threading.Tasks;
using System.Threading;
using System.Text;
using System.Collections.Generic;
namespace read_d2c_messages
{
class ReadDeviceToCloudMessages
{
// Event Hub-compatible endpoint
// az iot hub show --query properties.eventHubEndpoints.events.endpoint --name {your IoT Hub name}
private readonly static string s_eventHubsCompatibleEndpoint ="sb://iothub-ns-mydeviceco......";
// Event Hub-compatible name
// az iot hub show --query properties.eventHubEndpoints.events.path --name {your IoT Hub name}
private readonly static string s_eventHubsCompatiblePath = "mydeviceconnection";
// az iot hub policy show --name service --query primaryKey --hub-name {your IoT Hub name}
private readonly static string s_iotHubSasKey = "";
private readonly static string s_iotHubSasKeyName = "service";
private static EventHubClient s_eventHubClient;
// Asynchronously create a PartitionReceiver for a partition and then start
// reading any messages sent from the simulated client.
private static async Task ReceiveMessagesFromDeviceAsync(string partition, CancellationToken ct)
{
// Create the receiver using the default consumer group.
// For the purposes of this sample, read only messages sent since
// the time the receiver is created. Typically, you don't want to skip any messages.
var eventHubReceiver = s_eventHubClient.CreateReceiver("$Default", partition, EventPosition.FromEnqueuedTime(DateTime.Now));
Console.WriteLine("Create receiver on partition: " + partition);
while (true)
{
if (ct.IsCancellationRequested) break;
Console.WriteLine("Listening for messages on: " + partition);
// Check for EventData - this methods times out if there is nothing to retrieve.
var events = await eventHubReceiver.ReceiveAsync(100);
// If there is data in the batch, process it.
if (events == null) continue;
foreach(EventData eventData in events)
{
string data = Encoding.UTF8.GetString(eventData.Body.Array);
Console.WriteLine("Message received on partition {0}:", partition);
Console.WriteLine(" {0}:", data);
Console.WriteLine("Application properties (set by device):");
foreach (var prop in eventData.Properties)
{
Console.WriteLine(" {0}: {1}", prop.Key, prop.Value);
}
Console.WriteLine("System properties (set by IoT Hub):");
foreach (var prop in eventData.SystemProperties)
{
Console.WriteLine(" {0}: {1}", prop.Key, prop.Value);
}
}
}
}
private static async Task Main(string[] args)
{
Console.WriteLine("IoT Hub Quickstarts - Read device to cloud messages. Ctrl-C to exit.\n");
// Create an EventHubClient instance to connect to the
// IoT Hub Event Hubs-compatible endpoint.
var connectionString = new EventHubsConnectionStringBuilder(new Uri(s_eventHubsCompatibleEndpoint), s_eventHubsCompatiblePath, s_iotHubSasKeyName, s_iotHubSasKey);
s_eventHubClient = EventHubClient.CreateFromConnectionString(connectionString.ToString());
// Create a PartitionReciever for each partition on the hub.
var runtimeInfo = await s_eventHubClient.GetRuntimeInformationAsync();
var d2cPartitions = runtimeInfo.PartitionIds;
CancellationTokenSource cts = new CancellationTokenSource();
Console.CancelKeyPress += (s, e) =>
{
e.Cancel = true;
cts.Cancel();
Console.WriteLine("Exiting...");
};
var tasks = new List<Task>();
foreach (string partition in d2cPartitions)
{
tasks.Add(ReceiveMessagesFromDeviceAsync(partition, cts.Token));
}
// Wait for all the PartitionReceivers to finsih.
Task.WaitAll(tasks.ToArray());
}
}
}
On my command prompt, the exception is System.Net.Sockets.SocketException:A connection attempt failed because the connected party did not properly respond after a period of time, or established failed because host has failed to respond at Microsoft.Azure.EventHub.Amqp.AmqpHubClient.CreateConnectionAsync(TimeSpan, Timeout); What kind of error is this? Is had to do with firewall connectivity issue on my connection string not to receive message? Or hence i am using Free Trail cant be able to create Service-Bus-Messsage on my EndPoint?
I think the way you construct your connection string is not quite correct. When you copy the connection string from your IoT Hub in the full format, this should already work:
s_eventHubClient = EventHubClient.CreateFromConnectionString("Endpoint=sb://iothub-xxxxxx-1180347-e18a7c8824.servicebus.windows.net/;SharedAccessKeyName=iothubowner;SharedAccessKey=qya62bOiN0********gIyEQ=;EntityPath=myiothubname");

Requesting a DbContext from a scope in a SignalR Core hub, passing it a connection string

I have an ASP .Net Core 2.2 Web API with a SignalR hub.
When the API receives a message form the client, it needs to save this message to the database. It does this as follows:
The SignalR Hub:
public class ChatHub : Hub
{
public async Task SendMessageToGroup(int clientId, int groupName, string message)
{
await SaveMessage(clientId, groupName, message);
await Clients.Group(groupName).SendAsync("ReceiveMessage", message);
}
private async Task<bool> SaveMessage(int clientId, string groupName, string message)
{
using (var scope = _serviceProvider.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<TenantContext>();
Message newMessage = new Message()
{
Message = message,
GroupName = groupName,
Timestamp = DateTime.Now
};
dbContext.Messages.Add(pwMessage);
dbContext.SaveChanges();
}
return true;
}
}
All would be well except for the fact that this is a multi-tenant application. Normally, when the client calls the API's controller methods using HTTP requests, the client sends through a "TenantId" header with each request. I then have middleware that intercepts this request, grabs the TenantId from the header, calls a service to retrieve this Tenant using the tenantId, and saves the Tenant object in the HttpContext. Then, on the DbContext's OnConfiguring() method, I use this Tenant Object (stored in the HttpContext) to set the connectionString of the dbContext to whatever database this tenant uses. So:
Middleware:
public class TenantIdentifier
{
private readonly RequestDelegate _next;
public TenantIdentifier(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
string tenantId = httpContext.Request.Headers["tenantId"].FirstOrDefault();
Tenant tenant = await GetTenant(tenantId);
httpContext.Items["Tenant"] = tenant;
await _next.Invoke(httpContext);
}
}
DbContext.cs:
public TenantContext(DbContextOptions<TenantContext> options) : base(options)
{
}
public TenantContext(DbContextOptions<TenantContext> options, IHttpContextAccessor httpContextAccessor) : base(options)
{
_httpContextAccessor = httpContextAccessor;
}
protected override async void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
Tenant tenant = (Tenant)_httpContextAccessor.HttpContext.Items["Tenant"];
string connectionString = $"server={tenant.DbUrl};user id={tenant.DbUserName};Pwd={tenant.DbPassword};database={tenant.DbName};persistsecurityinfo=True;TreatTinyAsBoolean=false";
optionsBuilder.UseMySql(connectionString);
}
Now, when the client calls the SignalR hub, and I create a new scope in the hub and request the DbContext, it's connection string is null. This appears to be because, unlike an HTTP request, calling a SignalR hub doesn't trigger the middleware (which is responsible fro identifying the tenant)
How can I, when requesting a DbContext from the scope, manually pass it the connection string, instead of relying on it to try and generate the connectionString in the OnConfiguring() event (which won't work)
Hope this makes sense :/ Thank you
If you add the IHttpContextAccessor to your Hub class constructor - are you able to access the current context (and headers) there?
public class ChatHub : Hub
{
private IHttpContextAccessor currentContext;
public ChatHub(IHttpContextAccessor currentContext)
{
this.currentContext = currentContext;
}
}
Of course, remembering to register the HttpContextAccessor in the DI too:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddHttpContextAccessor();
services.AddTransient<IUserRepository, UserRepository>();
}

Azure Notification HUB with FCM - NullPointerException

I am trying to register my FCM service with Azure Notification hub.
I am getting a valid FCM token using my Instance Id Service which extends FirebaseMessagingService().
Below is my InstanceIdService which is returning a valid token and starts my registrationIntentService
class FCMInstanceIdService : FirebaseMessagingService() {
companion object {
private const val TAG = "FCMInstanceIDService"
}
init {
Log.i(TAG, "init")
}
override fun onNewToken(refreshedToken: String?) {
FirebaseInstanceId.getInstance().instanceId.addOnSuccessListener { instanceIdResult ->
instanceIdResult.token
// Log the event
Log.i(TAG, "Refreshing GCM Registration Token")
// Declare our intent to start the service
val intent = Intent(this, FCMRegistrationIntentService::class.java)
// Start the service!
startService(intent)
}
}
}
Below is the portion of code where-in I try to register this token with my notification hub.
// Declare the azure notification hub
val notificationHub = NotificationHub(
// Provide our notification hub name
CentreMK.FCM_NOTIFICATION_HUB_NAME,
// Provide our notification hub connection string
CentreMK.FCM_NOTIFICATION_HUB_LISTEN_CONNECTION_STRING,
// The context of this service
this)
// Log the event
Log.i(TAG, "Attempting to register with NH using token : $token")
// Update the registration id by registering our token with the notification hub
// This provides us with the registration id
regID = notificationHub.register(token).registrationId
This is the exception I get :
Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference
Any help is appreciated cause I dont know how I could possibly get a null pointer exception when I've configured everything correctly.
In your initialisation of the String HubListenConnectionStringin class:
public class NotificationSettings {
public static String SenderId = "<Your project number>";
public static String HubName = "<Your HubName>";
public static String HubListenConnectionString = "<Enter your DefaultListenSharedAccessSignature connection string>";
}
you did not add "Endpoint=sb://"to the beginning of the string (i.e: public static String HubListenConnectionString ="Endpoint=sb://......". After which you might encounter a "Resource not found" exception error. That's where I am stuck at now.

Resources