Can I run a Hosted Service in the ASP.NET Core Web Host? (getting System.ObjectDisposedException ) - asp.net-core

I have an ASP.net Core web API running the ASP.net Core Web Host.
In the ServiceCollection, I register a HostedService to run a worker that subscribes to a message bus.
Some messages come from web API. Some messages come from the message bus through the worker.
They all get written to a database.
Presently I'm having problems where when I write messages coming from the worker to the database I get System.ObjectDisposedException on my dependency injected data access Scoped service.
It feels like my worker is somehow using the HTTP request scopes for the DI injected services.
So, could this be caused by using a Hosted Service in the ASP.NET Core Web Host

Do not read messages in a ServiceHosted, you should read it seperately (maybe in a singleton scenario)
If you're reading messages from service-bus manually you should not have that problem otherwise you should not use scoped services for that. for example in RabbitMQ the best practice is to open a connection for each app

Related

Hosted service in ASP.NET Core vs Worker Service

For background process listening to a service bus topic, what would be the considerations for choosing between running a hosted service in ASP.NET core VS creating a worker service?
I'm seeing several options from the internet and I'm wondering which scenarios would make one go for each of these options:
Running API & Worker service separately
Running API with hosted service
Running worker service with API inside (not for us)
Our system will have an ASP.NET Core API as well, so I'm wondering whether to add a hosted service to this API or to separate the application as a worker service.
We also want to run this in container and deploy it in Azure container app (if that makes a difference to the considerations)
I saw someone mentioned if health check is needed for the background process then it's better to go with ASP.NET with hosted service implementation. But then I found this lib https://github.com/bruceharrison1984/TinyHealthCheck which seems to add health check functionality to worker service
The API and the worker should be separated. You can then scale the two separately. Especially if you plan to deploy the worker on Azure Container App, you can scale automatically the worker depending on the message number on the bus using KEDA. When no message is in the queue it will automatically scale down to 0 !
Your API in the other hand should be always up.
To create a worker you should consider using the generic host of .Net.
In my opinion, this is related with the relationship with the web api and the worker service.
If this worker service is just used for this asp.net core web api, I suggest you could choose 2 or 3.
If this work service is also used for other web api or else, I suggest you should run API & Worker service separately.
From the comments you have added I can see that the API and the worker service are separate and that you are deploying using docker. For those reasons I would suggest that you deploy these two things separately in their own containers. I would choose this because it makes each application simpler and easier to maintain. A good place to start is here Background tasks with hosted services in ASP.NET Core. There is a simple dotnet cli template to create the project
dotnet new worker -o [your project name]

Azure SignalR and Azure Web Application with multiple instances

We are developing ASP.Net core that is hosted as Azure Web Application.
We also use Azure SignalR service
Everything works great as long as we have single instance of the Web App, but once we scale it out we have the following problem:
From the Controller's action we resolve IHubContext and we send message to Hub's client. Everything works great so far
Hub's client accepts response and sends it TheHub endpoint.
The problem here is that response could be sent to another instance of Web App. So we send request from instance #1 but response is sent to instance #2 with 50% chance and instance #1 never receives response
Any ideas of how we could make it work so instance that emitted request actually received response?
SignalR has support for scaleout scenarios out of the box, it's called backplanes. The idea is that with help of one of backplane components, it will spread out SignalR events accross all instances. For Asp.Net framework, use one of these packages
Microsoft.AspNet.SignalR.ServiceBus3
Microsoft.AspNet.SignalR.ServiceBus
Microsoft.AspNet.SignalR.StackExchangeRedis
Microsoft.AspNet.SignalR.SqlServer
For ASP.Net Core only Redis is ported with Microsoft.AspNetCore.SignalR.StackExchangeRedis package, but there are some provided by community, see https://github.com/thomaslevesque/AspNetCore.SignalR.AzureServiceBus
public void ConfigureServices(IServiceCollection services)
{
services.AddSignalR()
.AddAzureSignalR(options =>
{
options.ApplicationName = "app1";
}
);
}
You could specify an ApplicationName in the server SDK for different server groups.
It will help your server generate access tokens like ......?hub=app1_<your_hub> during negotiation which can help our ASRS instances differentiate connections coming from different server groups
Unfortunately I didn't find reliable solution that wouldn't require a bit clumsy workarounds
But there are 2 solutions I could offer for this scenario
#LexLi suggested a good approach to solve this problem. So you basically can make your web app a SignalR client as well and make it a member of a group. This way every instance of web app is also a client and then instance that receives response for Hub's client can pass this response to group of web app instances
You could leverage Azure Service Bus topics. So once started instance will start subscribe to listen a topic. And then once any instance receives a response from Hub's client it would place response into Service Bus Topic and then every instance will receive this response from the topic
I was hoping that there could be a better solution for such problem

WCF listen to Service Bus

I’m new to WCF and are having problems by finding the solution to my problem.
I have WCF set up that handles some logic (simple database handling).
I then have a web page (ASP.NET) that gets it data from WCF (and also sends it data to WCF).
Now I’m trying to use an Azure Service Bus to send data to WCF. It works fine when I go through the ASP.NET website. It works like this:
1, Client application sends data to Service Bus.
2, ASP.NET Webpage reads data from Service Bus.
3, ASP.NET Sends data to WCF.
4, WCF updates the database.
Everything works fine.
But, I would like the WCF to constantly listen to the Service Bus.
How do I do that?
In this scenario you have 2 options:
Use the WCF endpoint of the Service Bus Queues: http://blogs.msdn.com/b/tomholl/archive/2011/10/07/using-service-bus-queues-with-wcf.aspx
Use the service bus relay: https://www.windowsazure.com/en-us/develop/net/how-to-guides/service-bus-relay/
Depending on your scenario you'll use one of these options. The first scenario uses queueing. If your WCF service should be unavailable for any reason your client will still keep working (messages are delivered to the queue and picked up by the WCF service whenever available).
The second scenario will create a bridge between your client and a WCF service (could be on premises, in an other data center, ...). Since it's a direct connection you can receive a response. But keep in mind, if your WCF service is offline, your client will receive an exception and you'll need to handle that.

SignalR - Sending a Message from a WCF Project

I've followed the instructions from https://github.com/SignalR/SignalR/wiki/Hubs
entitled "Broadcasting over a Hub from outside of a Hub".
I got this method working from within an MVC Action in the same project. Requesting the Action sends the update to connected clients.
My problem is that I need to be able to send updates from another project, in particular a WCF Web Services project. My app has an API and a web component and when API users make calls that change things, these updates need to be pushed out to the Web clients via SignalR. And calling a web service with the same code as my Test Action doesn't work.
I also tried the same code inside an nunit unit test that didn't work either.
What do I need to do to make this same method described on the Wiki work for a WCF Project?
The easiest solution is probably to provide an API on your Web Application (use MVC or the new WebAPI) that broadcasts to all connected clients. Any other application (an NT Service, an NUnit test, ...) can call that API if it wants to send a message to the clients.
You can't expect SignalR to do anything if you aren't hosting a Hub either in a Web Application running under IIS, or another application hosting it directly.
If you need two-way communication from your separate application to your clients then simply make your application into a SignalR client too and have it communicate via the Web Application hosted SignalR to the clients and have it listen to messages from them too.
For example, here's how I have configured a complex Service + WebSite + Clients solution (ignore the purple for now):
The Live Web Server allows NT Services to connect and create SignalR Groups. NT Services send to those groups. Web browsers connect to a group and receive messages send to that group. In effect the middle box becomes a pubsubhub.
I cannot get exactly what you aim. But if I understood correctly you're trying to send some kind of notifications raised inside WCF services to SignalR clients.
If that's the case; I can suggest you my approach:
I have some WCF services and a SignalR hub in the same application server. IMHO, the best way to communicate WCF with SignalR hub is by using MSMQ.
When a notification occurs inside a WCF service, it puts the notification payload into MSMQ.
On the other end, SignalR hub listens the same queue. When a message put into the queue, it gets the content and broadcasts to the hub clients. Very easy and straightforward. No extra service/hub call at the server side.
SignalR hub can listen for new queue items by using System.Messaging.MessageQueue#ReceiveCompleted method. When this event raised, SignalR hub gets the queue item and broadcasts to its clients.

Can you pass data from HttpModule to IIS hosted WCF without aspNetCompatibility enabled

I currently have a HttpModule that generates a unique ID per external client request, appends it to the IIS log, and adds it to the HttpContext.Items collection in order to pass in on the thw web service.
I am currently replacing the web service with a WCF service (still hosted under IIS). I can successfully do the same process by enabling AspNet compatibility, but I would prefer not to. Is there any way to pass data from a HttpModule to say the OperationContext of the WCF service without enabling AspNet compatibility?
This is what MSDN has to say,
HttpModule extensibility: The WCF hosting infrastructure intercepts WCF requests when the PostAuthenticateRequest event is raised and does not return processing to the ASP.NET HTTP pipeline. Modules that are coded to intercept requests at later stages of the pipeline do not intercept WCF requests.
I suggest you go through this MSDN documentation completely to understand how ASP.Net and WCF coexist