Background worker blocking UI when using web service call - windows

For some reason when i put a long running web service call (doesn't matter if its a legacy one or WCF) in a background thread it seems to be locking up the UI main thread.
I cant see anything wrong with the code im putting in.
workerThreadInitialNotify = new BackgroundWorker();
workerThreadInitialNotify.WorkerSupportsCancellation = true;
workerThreadInitialNotify.DoWork += new DoWorkEventHandler(workerThreadInitialNotify_DoWork);
workerThreadInitialNotify.RunWorkerCompleted += new RunWorkerCompletedEventHandler(workerThreadInitialNotify_RunWorkerCompleted);
workerThreadInitialNotify.RunWorkerAsync();
Then in my do work i have a webservice call like:
void workerThreadInitialNotify_DoWork(object sender, DoWorkEventArgs e)
{
if (!(sender as BackgroundWorker).CancellationPending)
{
try
{
TestWebService service = new TestWebService();
service.RunLongRunningMethod();
}
catch(Exception ex)
{
}
}
}
When this thread is called, it occasionally locks up the UI thread, now i have setup the RunLongRunningMethod to purposely run slow and timeout (for testing purposes), but technically this shouldn't lockup the UI thread at all as its in a seperate thread.
Here is what the method contains:
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["customConnection"].ConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand("TestDelay", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
try
{
cmd.ExecuteNonQuery();
}
catch (Exception ee)
{
}
}
}
and TestDelay stored proc just contains this to simulate a delay so that the web service times out:
ALTER PROCEDURE [dbo].[TestDelay]
AS
WAITFOR DELAY '00:05:20';
The strange thing is that if i replace the web service call with a Thread.Sleep(20000); in the dowork, it runs perfectly, or even if i put a long running while loop it runs perfectly also.
I have no idea why specifically the webservice makes it lock up the UI.
ps: if i set up the webservice to be hosted locally to the Win Forms app, it runs ok, only when the webservice is running on another service, the strange lockup occurs.
ps (2): i am using devexpress library for ui controls of forms while the background thread runs in the background, not sure if this is related. I cant imagine why, if this is run in a seperate thread correctly

This ended up being a maxconnection .net setting in the App.config (its defaulted to a very low 2 by microsoft)
<system.net>
<connectionManagement>
<add address="*" maxconnection="40"/>
</connectionManagement>
</system.net>
Its now set to 40 and the issue has gone away.
There was multiple threads running at the same time, each calling web services, each of them were blocking each other.
There is more information in these links:
http://blogs.msdn.com/b/adarshk/archive/2005/01/02/345411.aspx
What is limiting the # of simultaneous connections my ASP.NET application can make to a web service?
http://msdn.microsoft.com/en-us/library/fb6y0fyc.aspx

Related

Cannot run cmd.exe through service. No commands appear to be working [duplicate]

Hey, I am trying to get a service to start my program but it isn't showing the GUI. The process starts but nothing is shown. I have tried enabling 'Allow service to interact with desktop' but that still isn't working.
My program is a computer locking device to stop unauthorised users from accessing the computer. I am running windows 7 with a 64 bit OS.
Here is the code for my service:
protected override void OnStart(string[] args)
{
Process p = new Process();
p.StartInfo.FileName = "notepad.exe";
p.Start();
FileStream fs = new FileStream(#"C:\Users\David\Documents\Visual Studio 2010\Projects\LockPCService\LockPCService\bin\Debug\ServiceLog.dj",
FileMode.OpenOrCreate, FileAccess.Write);
StreamWriter m_streamWriter = new StreamWriter(fs);
m_streamWriter.BaseStream.Seek(0, SeekOrigin.End);
m_streamWriter.WriteLine(" LockPCService: Service Started " + DateTime.Now + "\n" + "\n");
m_streamWriter.Flush();
m_streamWriter.Close();
}
protected override void OnStop()
{
FileStream fs = new FileStream(#"C:\Users\David\Documents\Visual Studio 2010\Projects\LockPCService\LockPCService\bin\Debug\ServiceLog.dj",
FileMode.OpenOrCreate, FileAccess.Write);
StreamWriter m_streamWriter = new StreamWriter(fs);
m_streamWriter.BaseStream.Seek(0, SeekOrigin.End);
m_streamWriter.WriteLine(" LockPCService: Service Stopped " + DateTime.Now + "\n"); m_streamWriter.Flush();
m_streamWriter.Close();
}
To try and get the service working I am using notepad.exe. When I look at the processes notepad is running but there is no GUI. Also the ServiceLog is there and working each time I run it.
Any ideas on why this isn't working?
Thanks.
This article explains Session 0 Isolation which among other things disallows services from creating a UI in Windows Vista/7. In your service starts another process, it starts in Session 0 and also will not show any UI. (By the way, the UI is created, it's just that Session 0 is never displayed). This article on CodeProject can help you create a process from a service on the user's desktop and show its UI.
Also, please consider wrapping you stream objects in a using statement so that they are properly disposed.
Services run under different account so notepad is run by another user and on another desktop so that's why you cannot see it. 'Allow service to interact with desktop' is not supported anymore starting from Vista.
I know this is a late post, but I found that this article was very helpful to me. I am running Windows 7 and the solution provided in this article works great.
If you download the code, there is a class called ApplicationLoader. Include that class in your project and then it's as simple as this:
// the name of the application to launch
String applicationName = "cmd.exe";
// launch the application
ApplicationLoader.PROCESS_INFORMATION procInfo;
ApplicationLoader.StartProcessAndBypassUAC(applicationName, out procInfo);
Services run in a different logon session and have a different window station from the user. That means that all GUI activity is segregated from the user's programs, not that the service can't display a GUI. Actually, this design makes it much easier to temporarily block access to the user's programs.
You'll need to call SwitchDesktop.

Background service confusion

I'm trying to find out how to keep an Android service running after the starting app is closed. I've tried looking at samples for background services (e.g this one, and some on the Xamarin site) but in every case the service stops running if the minimised app is 'swiped' off the screen. I don't want the service to accidently stop like this, it should run continually until a confirmed stop is requested. The service does not consume much in the way of resources, just gets a GPS location and posts it to a website every 2 minutes.
By way of background, I am a newbie to Xamarin/Android, but have in the past created several successful services in Windows with C#
(Later)
One sample I tried did leave an item in the Settings list of running apps, but didn't actually perform any service tasks once swiped off the screen. Additionally there was no icon in the status bar. After doing some reading it seems that my androidmanifest file is missing a 'service' attribute (although none of the samples I tried have this); what I have now tried is this
<service
android:name=".LocationService"
android:icon="#drawable/icon"
android:label="#string/service_name"
>
<intent-filter>
<action android:name="android.service.LocationService" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
...but still no luck.
Have you had a look at the Xamarin sample here the source is here
They create a service like so:
[Service]
public class SimpleService : Service
{
System.Threading.Timer _timer;
public override StartCommandResult OnStartCommand (Android.Content.Intent intent, StartCommandFlags flags, int startId)
{
Log.Debug ("SimpleService", "SimpleService started");
DoStuff ();
return StartCommandResult.Sticky;
}
public override void OnDestroy ()
{
base.OnDestroy ();
_timer.Dispose ();
Log.Debug ("SimpleService", "SimpleService stopped");
}
public void DoStuff ()
{
_timer = new System.Threading.Timer ((o) => {
Log.Debug ("SimpleService", "hello from simple service");}
, null, 0, 4000);
}
public override Android.OS.IBinder OnBind (Android.Content.Intent intent)
{
throw new NotImplementedException ();
}
}
And start and stop it with this:
StartService (new Intent (this, typeof(SimpleService)));
StopService (new Intent (this, typeof(SimpleService)));
Also it sounds like you want a Sticky service Docs
When the system is under memory pressure, Android may stop any running services. The exceptions to this rule are services explicitly started in the foreground, which are discussed later in this article.
When a service is stopped by the system, Android will use the value returned from OnStartCommand to determine how or if the service should be restarted. This value is of type StartCommandResult, which can be any of the following:
Sticky – A sticky service will be restarted, and a null intent will be delivered to OnStartCommand at restart. Used when the service is continuously performing a long-running operation, such as updating a stock feed.
RedeliverIntent – The service is restarted, and the last intent that was delivered to OnStartCommand before the service was stopped by the system is redelivered. Used to continue a long-running command, such as the completion of a large file upload.
NotSticky – The service is not automatically restarted.
StickyCompatibility – Restart will behave like Sticky on API level 5 or greater, but will downgrade to pre-level 5 behavior on earlier versions.
Hope this helps.
Solved it now. The confusion was mainly due to many samples being out-of-date (using deprecated methods) and different suggestions for 'pure' Android projects and Xamarin ones. Certainly don't need to modify the androidmanifest file as I suggested above.
If anyone is trying to find something similar, my project is here.
Solving the initial issue has now raised some new questions, of course, but I will post separately about that if needed.

SignalR Hub method is not called

I have a SignalR hub and two clients (Windows and PCL for Android and iOS). Neither of the clients is able to call some methods on the server. This behaviour is quite odd, since the methods look very similar. Moreover, a colleague of mine is able to call methods I cannot call, and vice versa, does not invoke methods that I invoke with no problems.
Here is an example of a method, which works for me and does not work for my colleague:
public override async Task<bool> RefreshArray(User user, int waitMilis)
{
var cts = new CancellationTokenSource();
try
{
cts.CancelAfter(waitMilis);
await Proxy.Invoke("RefreshArray", user);
return true;
}
catch (Exception ex)
{
OnExceptionOccured(ex);
return false;
}
}
And a method which does not work for me, but works for my colleague:
public override async Task<bool> RequestInformation(User user, Product product, int waitMilis)
{
var cts = new CancellationTokenSource();
try
{
cts.CancelAfter(waitMilis);
await Proxy.Invoke("RequestInformation", user, product);
return true;
}
catch (Exception ex)
{
OnExceptionOccured(ex);
return false;
}
}
Yes, me and my colleague have exactly the same code. And no, there are no typos or different arguments. I have tried to get as much data from the client connection as possible, by setting _connection.TraceLevel = TraceLevels.All; However, I did not get any information on the invoked methods, just on the replies from the hub. When calling RefreshArray, I got exactly the data I requested. When calling RequestInformation, the debugger never even hit the breakpoint in the hub method and the _connection.Trace displayed only this: 11:22:45.6169660 - 7bc57897-489b-49a2-8459-3fcdb8fcf974 - SSE: OnMessage(Data: {})
Has anybody solved a similar issue? Is there a solution?
UPDATE 1
I just realized that I have encountered almost the same issue about a year ago (Possible SignalR bug in Xamarin Android). StackOverflow has also pointed me to a question with almost the same issue (SignalR on Xamarin.iOS - randomly not able to call Hub method), just related to iOS and Azure. However, I got the same proble even outside Xamarin, on Windows Phone 8.1 and and Windows 10 Universal App. Moreover, I am running the server just locally, so it is not an issue od Azure. Is it really possible, that a 2 years old bug has no solution?
UPDATE 2
I have just created a simple console application with SignalR.Client. In the console application every method worked just fine. Amazingly, also the Windows 10 Universal Application started to behave as expected - every hub method was invoked correctly. Windows Phone 8.1 also improved its behaviour (all hub methods invoked). However, every now and then the connection tried to reconnect periodically (for no apparent reason), leading to Connection started reconnecting before invocation result was received. error. The Android application still behaved as before.
So I tried to replicate my previous steps and created another console application, but this time with SignalR.Client.Portable library. To my dissapointment, there was no change in the Android application behaviour.
Next week we will start to test our application on iOS, so I really wonder what new oddities will we encounter.
I have managed to solve the problem (at least so it seems). As it turned out, there is some weird stuff going around, when an application receives an answer from SignalR hub. It seems as if the HubProxy was blocked for a certain period of time on Android, while it drops the connection and starts to reconnect periodically on Windows Phone, not waiting for an asnwer from the hub.
The implementation of RefreshArray on the hub was something like this:
public async Task RefreshArray(User user)
{
await Clients.Caller.SendArray(_globalArray);
await Clients.Caller.SendMoreInformation(_additionalInfo);
}
Because the method sent two methods as an answer, the client Proxy got stuck and each platform handled it in its own unexpected way. The reason why some methods were called on my computer and not on colleagues was, simply, because we had different position of breakpoints, which enabled the application to resolve at least some requests and responses.
The ultimate solution was to add some synchronization into the invokation of methods. Now my hub calls only await Clients.Caller.SendArray(_globalArray);. This is then handled on the client with a ArraySent(string[] array) event, which then subsequently invokes the SendMoreInformation() method on the hub.

Azure CloudBlockBlob.DownloadTextAsync() in asp.net Web API project never returns but same works in console application

I've created one Asp.Net Web API project which uses Azure CloudBlockBlob to download some text asynchronous, but the call never returns.
I tried to run the same code in Console App and it works fine.
Following is the code which has issue:-
public async Task<string> DownloadTextAsync(IBlobRef blobRef, CancellationToken cancellationToken)
{
var container = this.GetContainerReference(blobRef);
try
{
this.Logger.Log("Downloading " + blobRef.BlobName);
return await container.GetBlockBlobReference(blobRef.BlobName).DownloadTextAsync();
}
catch (Microsoft.WindowsAzure.Storage.StorageException e)
{
if (e.RequestInformation.HttpStatusCode == 404)
return null;
Console.WriteLine("Error reading " + blobRef.BlobName + " " + e.Message);
return null;
}
}
This same code if I run in console application or asp.net web form application then it runs perfectly fine.
Kindly help if I'm doing anything wrong.
You're almost certainly calling Task<T>.Result or Task.Wait further up your call stack. This causes a common deadlock issue that I describe on my blog.
The reason it deadlocks is because await (by default) will capture the current "context" - in this case, an ASP.NET request context. Then, when the operation completes, it will resume the async method within that context. However, the ASP.NET request context will only allow one thread in at a time. So, if there's a thread blocked in the ASP.NET request context (e.g., by calling Task.Wait), then the async method cannot resume executing when the await completes.
It doesn't deadlock in a Console app because Console apps do not have a "context". In this case, the async method resumes on a thread pool thread.
To resolve this issue, replace any calls to Result or Wait with await, and allow async to grow through your code. For more information, see my MSDN article on async best practices.

How to make a synchronous web call from within a background agent

I am fairly new to wp7 development, and currently developing an app that has a background agent to update values based upon responses it gets from a web call to an api.
My problem is that the response to the web call is an asynchronous call and I can not access the results returned from within the background agent.
Is there any way that i can make a synchronous call from within the background agent so as to allow me to deal with the results within the same agent?
I have tried dealing with the web call within a class in a shared library but the Asynchronous call is only made after the onInvoke method of the agent has finished and so no use. Any Ideas would be great.
You simply need to call the NotifyComplete() method in your async call's Completed handler, and not before. Remove the call at the end of Invoke.
you could use an AutoResetEvent like this:
protected override void OnInvoke(ScheduledTask task)
{
AutoResetEvent are = new AutoResetEvent(false);
//your asynchronous call, for example:
WebClient wc = new WebClient();
wc.OpenReadCompleted += new OpenReadCompletedEventHandler(wc_OpenReadCompleted);
wc.OpenReadAsync(searchUri, channel);
// lock the thread until web call is completed
are.WaitOne();
//finally call the NotifyComplete method to end the background agent
NotifyComplete();
}
and your callback method should look like:
void wc_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
//do stuff with the web call response
//signals locked thread that can now proceed
are.Set();
}
remember that you should check if a connection is available and handle possible exceptions, if your background agent gets killed twice consecutively (due to memory consumed or duration) it will be disabled by the OS.

Resources