Read existing messages from a Subscription/Topic in Azure ServiceBus - .net-core

I am trying to read all existing messages on an Azure ServiceBus Subscription, using the Microsoft.Azure.ServiceBus.dll (in .Net Core 2.1) but am struggling.
I've found many examples that the following should work, but it doesn't:
var client = new SubscriptionClient(ServiceBusConnectionString, topicName, subscription, ReceiveMode.PeekLock, null);
var totalRetrieved = 0;
while (totalRetrieved < count)
{
var messageEnumerable = subscriptionClient.PeekBatch(count);
//// ... code removed from this example as not relevant
}
My issue is that the .PeekBatch method isn't available, and I'm confused as to how I need to approach this.
I've downloaded the source for the ServiceBusExplorer from GitHub (https://github.com/paolosalvatori/ServiceBusExplorer) and the above code example is pretty much as it's doing it. But not in .Net Core / Microsoft.Azure.ServiceBus namespace.
For clarity though, I'm trying to read messages that are already on the queue - I've worked through other examples that create listeners that respond to new messages, but I need to work in this disconnected manner, after the message has already been placed on the queue.

ServiceBusExplorer uses WindowsAzure.ServiceBus Library, which is a .Net Framework Library and you cannot use it in .Net Core applications. You should use Microsoft.Azure.ServiceBus (.Net Standard Library) in .Net Core applications.
Check here for samples of Microsoft.Azure.ServiceBus

var client = new SubscriptionClient(ServiceBusConnectionString, topicName, subscription, ReceiveMode.PeekLock, null);
client .RegisterMessageHandler(
async (message, token) =>
{
await subscriptionClient.CompleteAsync(message.SystemProperties.LockToken);
}
);
Try using RegisterMessageHandler. It will
receive messages continuously from the entity. It registers a message handler and
begins a new thread to receive messages. This handler is awaited
on every time a new message is received by the receiver.

Related

Is it possible to determine whether a Thrift TBaseClient is currently busy or available?

In our system, we have one C++ component acting as a Thrift Server, and one .netCore/C# component as a client.
So far, I was managing a single connection, so using a singleton to create my ThriftPushClientWrapper which implements TBaseClient. (via the generated object from the thrift interface)
.AddSingleton<IThriftPushClientWrapper>(sp =>
{
var localIpAddress = IPAddress.Parse(serverIp);
var transport = new TSocketTransport(localIpAddress, dataPort);
var protocol = new TBinaryProtocol(transport);
return new ThriftPushClientWrapper(protocol);
});
(so far using 0.13 version of the Thrift library, need to update to 0.14.1 soon, but wonder if the server part must be updated too/first).
This is working great.
Now, I want multiple clients that can connect to the server simultaneously, all on the same ip:port
So I am starting a ClientFactory, but wonder how to deal with the creation of the client.
To be more precise, the server part is configured for 5 threads, so I need 5 clients.
One simple approach would be to create a new client each time, but probably inefficient.
A better approach is to have a collection of 5 clients, and using the next available free one.
So I started with the following factory, where I should get the index from outside.
private readonly ConcurrentDictionary<int, IThriftPushClientWrapper> _clientDict;
public IThriftPushClientWrapper GetNextAvailablePushClient(int index)
{
IThriftPushClientWrapper client;
if (_clientDict.ContainsKey(index))
{
if (_clientDict.TryGetValue(index, out client) && client != null)
return client;
else // error handling
}
// add new client for the expecting index
client = CreateNewPushClient();
_clientDict.TryAdd(index, client);
return client;
}
private IThriftPushClientWrapper CreateNewPushClient()
{
var localIpAddress = IPAddress.Parse(serverIp);
var transport = new TSocketTransport(localIpAddress, dataPort);
var protocol = new TBinaryProtocol(transport);
return new ThriftPushClientWrapper(protocol);
}
My next issue it to determine how to set the index from outside.
I started with a SemaphoreSlim(5,5) using the semaphore.CurrentCount as index, but probably not the best idea. Also tried with a rolling index from 0 to 5. But apparently, a CancellationToken is used to cancel further procceesing. Not sure the root cause yet.
Is it possible to determine whether a TBaseClient is currently busy or available?
What is the recommended strategy to deal with a pool of clients?
The easiest solution to solve this is to do it right. If you are going to use some resource from a pool of resources, either get it off the pool, or mark it used in some suitable way for that time.
It's notable that the question has nothing to do with Thrift in particular. You are trying to solve a weak resource management approach by trying to leverage other peoples code that was never intended to work in such a context.
Regarding how to implement object pooling, this other question can provide further advice. Also keep in mind that especially on Windows platforms not all system resources can be shared freely across threads.

Azure Service Bus - Use multiple senders in a web API

We are trying to implement Azure service bus for managing user "Work Queues"
Background:
We have a web UI pushing new items to a Web API which are persisted to a DB and then pushed to a Service Bus Queue. All messages have a property which denote who can work on the message. For providing a user with the ability to pick messages assigned to them, I am thinking about creating a topic with subscriptions that filter on that property.
Approach
To achieve the above mentioned capability:
I need to register a sender for the queue and a sender for the topic all within the same Web API. I have tried adding the two senders as Singletons but during DI, how do I pick which sender to use ?
services.TryAddSingleton(implementationFactory =>
{
var serviceBusConfiguration = implementationFactory.GetRequiredService<IMessagingServiceConfiguration>();
var serviceBusClient = new ServiceBusClient(serviceBusConfiguration.IntakeQueueSendConnectionString);
var serviceBusSender = serviceBusClient.CreateSender(serviceBusConfiguration.IntakeQueueName);
return serviceBusSender;
});
services.TryAddSingleton(implementationFactory =>
{
var serviceBusConfiguration = implementationFactory.GetRequiredService<IMessagingServiceConfiguration>();
var serviceBusClient = new ServiceBusClient(serviceBusConfiguration.TopicConnectionString);
var topicSender = serviceBusClient.CreateSender(serviceBusConfiguration.TopicName);
return topicSender;
});
I am using the above setup to add the services as singletons and individually I am able to send and receive messages from either the topic or the queue.
How can I register both the implementations and pick which one should be injected when I use DI in the constructor to consume it.
With respect to resolving DI registration for multiple instances of the same type, the first answer to this question illustrates using a service resolver with ASP.NET Core. To my knowledge, that is still the best approach.
For the senders, you could differentiate by checking their EntityPath property to identify whether they point to your queue or topic.

How can I open database connection at runtime?

I am working on ASP.Net MVC project. I am making my database transactions with;
using (ISession session = FluentNHibernateHelper.OpenSession())
{
var user = session.Query<User>()
.FirstOrDefault(x => x.UserEmail == email && x.UserPassword == password); }
Instead of using this type of code block which is like open-close connection everytime, I want to open connection at runtime and I want to use that session variable everywhere. Maybe some codes in Application_Start()in Global.asax.cs?
I am open to your valuable ideas. Thank you for your help!
It's poor practice to leave a connection open nor maintain the state in the ORM across multiple transactions as state issues can crop up rather quickly as you make multiple requests against the same object & connection.
However, if you must, you could inject it as a Singleton service which would live longer than a single request. This is problematic for scaling and not recommended.
services.AddSingleton<ISession>(provider =>
{
return FluentNHibernateHelper.OpenSession()
});
More information: What is the difference between services.AddTransient, service.AddScoped and service.AddSingleton methods in ASP.NET Core?

SignalR not working correctly after deployment on windows server 2012

I am facing issues in live environment. When ever a ever a page is loaded signal r connection is created but connectionids of other connects are not available for the new connectionids and also for old connectionId this newly created connection is not available. To make it better understand see the code below
My method in chathub.vb which is called from server side
Public Sub getGonnected()
Clients.Client(Context.ConnectionId).hello("Connection is connected CONNECTIONID = " + Context.ConnectionId)
Dim heartBeat = GlobalHost.DependencyResolver.Resolve(Of ITransportHeartbeat)()
Dim connectionAlive = heartBeat.GetConnections().Where(Function(c) c.ConnectionId <> Context.ConnectionId).ToList()
Clients.Client(Context.ConnectionId).hello("Other Connections Available ..............................................................")
For Each item In connectionAlive
Clients.Client(Context.ConnectionId).hello(".................................................................. " + item.ConnectionId)
Next
Clients.Client(Context.ConnectionId).hello("End of other connections available ........................................................")
Clients.All.hello("Total Number of users available ..................................................................")
Clients.All.hello("........................................................................... " + connectionAlive.Count().ToString())
Clients.All.hello("End total Number of users available ...............................................................")
End Sub
And in my clients side
chat.client.hello = function(ping)
{
console.log(ping);
}
$.connection.hub.start().done(function () {
});
setInterval(function () {
chat.server.getGonnected().done(function (result) {
console.log('connectionRequestsent')
});
}, 5000);
Also in my web.config I have added following settings
target framework 4.5
As per above example code above
I am not able to see a new connection in the borwsers console when some new user registers will signalr. And also that new user is unable to see the ConnectionId's of already present users in signalr in the browser console.
This thing is only happening on server. An help would be much appretiated. I have already enabled websockets and my websockets handshake is successfull. Moreover the spefic conntectionId is able to send and recieve messages to and from server. But not with other connectionId as the are not availble.
In simple words some times
Dim connectionAlive = heartBeat.GetConnections().Where(Function(c)
c.ConnectionId <> Context.ConnectionId).ToList()
Length is 0 where as there are already other connections in the app. Which I am not sure why is happening.
Any help or guidance will be much appreciated.
SignalR version is 2.1.0
Regards
Abdul
I don't think this has anything to do with WIndows Server 2012. You will have to implement this yourself in either a dictionary, database or something else suitable to your situation.
Using the OnConnect event, you can broadcast to every currently connected client an update that someone has joined or with the OnDisconnect that someone has left as well. If you want it to be a list of currently connected users you would query your dictionary/database/else... and broadcast.
SignalR Documentation has some examples.
Download working signalr project at https://github.com/aspnet/SignalR-samples from the developer
After downloading select any of the examples in the directory which you will run through your visual studio.
I select ChatSample run and follow the on-screen instruction
After that go through the documentation to read through each files how it works at
https://learn.microsoft.com/en-us/aspnet/core/signalr/
Please install the latest version of .Net Framework, in my case this solve the problem, I installed 4.8 and all broadcast messages were sent.

Can asp.net web application communicate with standalone visual c++ application?

Can I integrate a asp.net website with Visual c++ standalone application?
The request should go from asp.net website to visual c++ application and the result should be used by asp.net website?
You can execute a process in the filesystem, independently of the language it was written on.
Like this:
ProcessStartInfo processInfo = new ProcessStartInfo("C++App.exe", "command line arguments like /page getdata.aspx ... ");
processInfo.ErrorDialog = false;
processInfo.UseShellExecute = false;
processInfo.RedirectStandardOutput = true;
processInfo.RedirectStandardError = true;
Process proc = Process.Start(processInfo);
proc.ErrorDataReceived += (sender, errorLine) => { if (errorLine.Data != null) Trace.WriteLine(errorLine.Data); };
proc.OutputDataReceived += (sender, outputLine) => { if (outputLine.Data != null) Trace.WriteLine(outputLine.Data); };
proc.BeginErrorReadLine();
proc.BeginOutputReadLine();
proc.WaitForExit();
Regards.
Your question actually includes part of the answer. The two processes, regardless of the language they are written in, they would have to communicate exchanging data in a client-server fashion. Therefore, the C++ process would have to act as a server and ASP.NET as a client requesting data from the server.
Therefore, you could build a web service, either SOAP or REST using C++ and reference this web service through your ASP.NET process asking for data from the C++ server. Here you could find a tutorial on how to build a web service using C++. Here you could find a .NET tutorial on web services.
Another, simpler but less structured approach would be to use something like a vault, perhaps a file or a database. The results would be written in the vault anyway (even if they were not asked and the ASP.NET process would retrieve them whenever it wants.
Hope I helped!

Resources