I have a single page app with Angular.js front, web api2 back end, also using Castle Windsor and SignalR.
I am using a c# component on the server that maintains server state. So, on Application_Start() I register the main component with Castle Windsor as Singleton.
IoC.Container.Register(Component.For(typeof(MainManager)).ImplementedBy(typeof(MainManager)).LifeStyle.Singleton);
(however, I tested PerWebRequest and few other lifestyles, but the main problem remains the same, the started task does not quit)
Then in my Web Api, I can execute commands against that instance.
[HttpGet]
public void StartProcess(Params p) {
IoC.Resolve<MainManager>().StartOperation(p);
}
and this also gives me opportunity to stop it from the website by calling another controller method
[HttpGet]
public void Stop() {
IoC.Resolve<MainManager>().RequestStop();
}
This works great for the most part. However, sometimes my application gets in a bad state (for a multitude of reasons, It can get restarted in prod) I can emulate this problem by modifying web.config during running the operation, so a lot of things reset (such as Signal-R connection), but the main operation does not stop running.
(In fact, once my application is in bad state I can no longer call that Stop controller method because MainManager has been reset, so the only way to stop it as of now is to reset the whole IIS. This is certainly not desired)
I am trying to figure out how to detect this state, and terminate the running process.
As one possible solution, I am experimenting with using Bound lifestyle (new in Castle Windsor 3), trying to scope my manager to my web api httpapplication, but no luck yet.
update
I tried making the main task method static
[HttpGet]
public void Start(ForceData data) {
MainManager.Start(data);
}
I believe this should take out the singleton instance out of equation, but the code still runs un-interrupted after touching web.config
update
took the MainManager class out of equation. All my web api method does now is loop + sleep
[HttpGet]
public void Start(ForceData data) {
foreach (var e in data.Members)
{
_log.Info("processing member: {0}", e.Email);
Thread.Sleep(1000);
}
}
this loop is also not interrupted after touching web.config.
So, at this point I am reading about MVC request lifecycle to figure out at which point this request goes zombie rouge
This is by design, as HttpApplication instances are not freed immediately when application restarts,
http://msdn.microsoft.com/en-us/library/vstudio/ms178473%28v=vs.100%29.aspx
When an application restart is required, ASP.NET will serve all pending requests from the existing application domain and the old assemblies before restarting the application domain and loading the new assemblies.
In all your sample Web API method, you can see the thread is still busy, which means ASP.NET runtime considers this request is still being processed.
Related
I’ve inherited an MVC that currently does some setup work with the ApplicationStart method so that when the application comes back to life with an IIS Application pool this setup has already been carried out.
As pseudo-code:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// Build Api autofac container
// Build MVC autofac container
// Resolve serviceOne from the MVC container
var serviceOne = (IServiceOne)DependencyResolver.Current.GetService(typeof(IServiceOne));
// Make setup call - includes external http calls and DbContext checking
serviceOne.syncToExternal();
// Resolve serviceTwo again from the MVC container
var serviceTwo = (IServiceTwo)DependencyResolver.Current.GetService(typeof(IServiceTwo));
// Make setup call - publishes application information to internal message queues so that we know it's running
serviceTwo.syncToInternalSystems();
}
}
In the ApplicationStart I run through the normal process of setting up Autofac containers; one for the MVC and one for the WebApi. In here the respective MVC or Api controllers, service classes and my DbContext are registered.
The setup work in the ApplicationStart needs a service and a DbContext which I resolve from the MvcContainer, as the WebApi one is not accessible at this point.
ServiceOne retrieves data from an external url and using this to seed / check the current contents of the database.
ServiceTwo reads back some of this data and publishes it to internal message queues within the company.
Once the Application_Start() has finished and the Home page has loaded: if I make a request which routes through the MVC then the DbCobntext's registered databaseInitialzer does not get called as it was run during the Application_Start, but if I make an /api request the databaseInitializer does get called.
I suspect that running the setup in ApplicationStart method is preventing a flag being set in the System.Data.Entity.Database which managed the Connection; hence when the DbContext is resolved from the Api Container it thinks the database hasn’t been initialised...?
Any help would be much appreciated.
My fallback will be to shift all of the setup into a seed method which runs when the databaseInitialiser/Migration is called; but it would be useful to know why the original version of the code was failing to execute as expected.
the ApplicationStart run every time the ApplicationPool starts, no matter what. You have to use another mechanism to populate your DB. Like Migrations.
I have an ASP.NET Core Web API project. That has one controller with a method called GetLocations
GetLocations connects to 5 other web services on the internet. Gathers some info and return a collection via json. In this method I am caching the data every 5 mins using In Memory caching.
If the cache expires, it tries to connect to all 5 services and get the info and so on.
My problem is:
I have a lot of users requesting this data constantly, 50 requests a second to this API.
When the cache expires I believe there is some kind of thread locking. I have limited visibility into the project at the moment but I suspect that all these requests are calling the method and reaching out to the 5 dependent services until one of them gets a completed response from all 5.
Is my assumption right? If so how can I go about fixing this? Will I need to make each call to the web services async? Will that help this scenario? I am not 100% sure because the requests are what triggers the method call.
You should definitely make the calls to the external services use Async / Await.
That's just a given - as the best practice is to always use async for I/O heavy operations (such as calling a third-party service).
Now, you should also create a class that manages these calls. You can add it as a Singleton in your IoCConfig. In that class, make sure you're "locking" to avoid the issue you just described and not call the underlying services numerous times while the cache is being built.
Check here:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/lock-statement
You are facing this issue because of following reason.
You are using Cache and it will expire at some definite time.
After Cache expire you call external web service method to collect the data. Now at this point of time it might happen that other request in queue get choose for execution.
Once that another request is chosen for execution it also end up checking cache and it now data in cache then execute external service and so on for other request.
Solution to this.
First Check cache contains data or not.
If Not create lock so following section only be executed by single thread.
Now in that lock section again check for cache and if cache contains data then simply return but it does not contains then call external service.
At this point of time if another thread get selected for execution then it has to wait for execlsive section to complete its works.
Once that section get completed it store data in cache and so after if any queued or new request is there it choose data from cache.
Note : It should something like this.
public List<string> GetData()
{
if(Cache[key] == null)
{
lock(obj) // obj should be static
{
if(Cache[key] == null)
{
// Load data from service
Cache[key] == data;
}
}
}
return (List<string>)Cache[Key];
}
I have a legacy application where HostingEnivronment.RegisterObject is used.
I have been tasked with converting this to asp.net core 2.0. however I am unable to find a way to either implement this or find an alternative to this in asp.net core 2.0.
the namespace Microsoft.AspNetCore.Hosting.Internal does not contain the registerobject method nor does it have the IRegisteredObject interface. I am at a loss on how to get this implemented.
The way to achieve similar goal in asp.net core is to use IApplicationLifetime interface. It has two properties two CancellationTokens,
ApplicationStopping:
The host is performing a graceful shutdown. Requests may still be
processing. Shutdown blocks until this event completes.
And ApplicationStopped:
The host is completing a graceful shutdown. All requests should be
completely processed. Shutdown blocks until this event completes.
This interface is by default registered in container, so you can just inject it wherever you need. Where you previously called RegisterObject, you instead call
// or ApplicationStopped
var token = lifeTime.ApplicationStopping.Register(OnApplicationStopping);
private void OnApplicationStopping() {
// will be executed on host shutting down
}
And your OnApplicationStopping callback will be invoked by runtime on host shutdown. Where you previously would call UnregisterObject, you just dispose token returned from CancellationToken.Register:
token.Dispose();
You can also pass these cancellation tokens to operations that expect cancellation tokens and which should not be accidentally interrupted by shutdown.
I have an issue with using a Database in a thread in my asp.net Application.
When I want to start my application I want to start a thread called "BackgroundWorker" with it, which runs in the background till the whole application is stopped.
The problem is that I have massive problems with the dbContext in the thread.
I I try to start the walker in my Startup.cs in the methods "ConfigureServices" or "Configure" and then initialize the dbContext in the constructor in the Walker like this "dbContext = new ApplicationContext()" it tells me that the connection is not configured, when I try to operate in the while(true) queue on the database.
If I write an own Controller for the Walker which receives a ApplicationContext in his constructor and then starts a Thread like this, if i call this controller once with a GET Request:
public BackgroundWorker(ChronicusContext dbContext)
{
_dbContext = dbContext;
_messageService = new MailMessageService();
}
// GET: api/backgroundworker
[HttpGet]
[Route("start")]
public void StartWorker()
{
//Thread thread = new Thread(this.DoBackGroundWork);
Thread thread = new Thread(() => DoBackGroundWork(this._dbContext));
thread.Start();
}
public void DoBackGroundWork(ChronicusContext _dbContext)
{
while (true)
{
if (_dbContext.PollModels.Any()) //Here is the exception
{
...
}
}
}
Then I receive an System.ObjectDisposedException that the object is already disposed inside the while (true) queue.
I tried those and similar things in many different ways but allways receive exceptions like these two or that the database connection is closed.
Can somebody help me and tell me, how this works?
Thank you!
Generally, server side multithreading for Web Applications does not happen often and is, most times, a huge no no.
Conceptually, your server is "multithreaded", it handles many HTTP requests from clients/users/other servers. For mobile and web architecture/design, your server(s) process multiple requests and your clients are handling asynchronous calls and dealing with waiting for responses from long running calls like your API method StartWorker.
Think of this scenario, you make a request to your WebAPI method StartWorker, the client, making the request is waiting for a response, putting the work on another thread does nothing as the client is still waiting for a response.
For example, let's consider your client an HTML web page with an Ajax call. You call StartWorker via Ajax, you will be loading data into a HTML table. You will desire, from a UX perspective, to put up a progress spinner while that long running StartWorker responds to your HTML Page Ajax call request. When StartWorker responds, the Ajax call loads the HTML table with the StartWorker response. StartWorker has to respond with the data. If StartWorker responds beforehand than you will have to send a push notification, via SignalR, for example, when the other thread completes and has the data you need for the HTML table.
Hopefully, you see, the call to the WebAPI method, takes the same amount of time from a Ajax request/response perspective, so multithreading becomes pointless in this scenario, a most common web application scenario.
You can have your client UI load other UI elements, showing a progress spinner in HTML table UI area, until your database call is complete and responds with the data to your Ajax call. This way your users know things are happening and something is still loading.
If you still need your additional thread in your API for your project needs, I believe you have to be using Entity Framework 6 or greater to support asynchronous queries, see this tutorial:
http://www.codeproject.com/Tips/805923/Asynchronous-programming-in-Web-API-ASP-NET-MVC
UPDATE
Now that I know you need to run a SQL query on a repeating frequency of time, and you have an Azure Web App, what you want to use is Azure Automation if you are using Sql Azure or create a Sql Server Job if you are using a Sql Server instance as your backend
DbContext is not thread safe. You need to create a new context from inside your thread.
public void DoBackGroundWork()
{
ChronicusContext anotherContext= new ChronicusContext();
while (true)
{
if (anotherContext.PollModels.Any())
{
...
}
}
}
Not sure if this is the right terminology, let me explain what I want.
I have a web service that's available on the network - the web service has 1 web method.
What I want is... if the web service is running and performing tasks and another call is made to this web service, I want the 2nd call to fail or pend for a certain period of time then fail. Because only 1 instance of this web service should be called at once.
I was thinking of writing a value to the application object (like in asp.net) but then I have to be very careful to make sure that this value gets updated, in case of any errors, it might not... so this is dangerous, and would leave the web service in a state where no one can get to it.
Is there not a more dynamic way to determine if the web service is getting called or not?
You cannot do this with legacy ASMX web services. They have no support for different instance schemes.
I believe you can do this with WCF, as you can configure the service to have only a single instance.
If you are using WCF, this is simple. Use the service throttling settings to specify that you want MaxConcurrentCalls = 1 and MaxInstances = 1. You'll also want to set the ConcurrencyMode to Single for your ServiceBehavior.
I dont know much about web services on whether you can configure a web server to only start 1 instance of your web service, but you could try creating a mutex within your web service.
A Mutex is an interprocess synchronization object which can be used to detect if another instance of your web service is running.
So, what you can do is create a mutex with a name, then Wait on it. If more than 1 instance of your web service is alive, then the mutex will wait.
You could implement the check inside of the webmethod since it will be running in the same IIS process
You could create a poor man's mutex and have the first instance create a file and have consecutive instances check the existence of the file. Try Catch your web method and place the deletion of the file in the finally.
If you are WCF I recommend "bobbymcr" answer, but for legacy web service you can use Monitor instead or mutex as mutex is costly (because it is a kernel object) but if you do not care about performance and responsiveness of the service use the Mutex simply.
See this sample for using Monitor class
private static object lockObject = new object();
public void SingleMethod()
{
try
{
Monitor.TryEnter(lockObject,millisecondsTimeout);
//method code
}
catch
{
}
finally
{
Monitor.Exit(lockObject);
}
}