Calling web service asynchronously (C#) - completed event breakpoint not hit - c#

Can't get to the bottom of this one and it's obviously something daft, could anyone help please?
I'm calling a web service asynchronously using a C# console application, and a breakpoint in the 'completed' event is never getting hit.
Here's the example code, really simple:
public static void CallWebservice()
{
try
{
ServiceReference1.GlobalWeatherSoapClient proxy = new GlobalWeatherSoapClient();
proxy.GetCitiesByCountryCompleted += proxy_GetCitiesByCountryCompleted;
proxy.GetCitiesByCountryAsync("France");
}
catch (FaultException faultException)
{
var error = faultException.Message;
}
}
static void proxy_GetCitiesByCountryCompleted(object sender, GetCitiesByCountryCompletedEventArgs e)
{
//Do something here
throw new NotImplementedException();
}
So the breakpoint on the line
throw new NotImplementedException();
is never hit.
However if I add an additional line after the actual asynch call:
System.Threading.Thread.Sleep(5000);
..the breakpoint is now getting hit OK. Can anyone explain what's going on here? Obviously something to do with threads and the debugger, but I don't understand what?

This is because proxy is going out of scope and so being cleaned up (therefore losing your callback).
So, you need to move your Proxy OUT of the call so that its lifetime is controlled by you:
private ServiceReference1.GlobalWeatherSoapClient _proxy;
public void CallWebservice()
{
try
{
_proxy = new GlobalWeatherSoapClient();
_proxy.GetCitiesByCountryCompleted += proxy_GetCitiesByCountryCompleted;
_proxy.GetCitiesByCountryAsync("France");
}
catch (FaultException faultException)
{
var error = faultException.Message;
}
}
public void proxy_GetCitiesByCountryCompleted(object sender, GetCitiesByCountryCompletedEventArgs e)
{
//Do something here
throw new NotImplementedException();
}
This is not a perfect example as without seeing rest of your code I can't tell you where to instantiate proxy. Not in CallWebservice but in a constructor etc but hopefully you get the idea!

You should await on the call to proxy.GetCitiesByCountryAsync("France"), otherwise you'll come out of the try block before the function completes.

Related

VS2017 doesn't give details for an exception, just crashed with null

I'm working on a UWP project and there's something funky going on with how errors are being presented to me. I don't know if it's VS2017 or how UWP is set up.
I have a piece of code that goes online and retrieves json content, sometimes the code works and sometimes it doesn't. It works when I use Expander control from UWP Community toolkit, and fails when I want to switch to GridView. When it doesn't work, it fails on GetStringAsync method of HttpClient. The strange behavior is that the exception isn't thrown in the method where the problem occurs, the code actually redirects me back without giving an error and as soon as it gets to the property that's supposed to have a value that isn't null, I get a null exception.
This is where the problem happens:
string httpContent = "";
using (HttpClient httpClient = new HttpClient())
{
try
{
httpContent = await httpClient.GetStringAsync(uri);
}
catch (Exception e)
{
// TODO: handle errors
var x = "";
}
}
This piece of code is called from within the view model. It starts with a constructor and RefreshServerKanesWrathDataAsync is the method where json is parsed.
public CncOnlinePageViewModel()
{
cnconline = new CncOnline();
cnconline.RefreshServerKanesWrathDataAsync();
}
The second I get to GetStringAsync, the code just goes back to the constructor like nothing happened, however the method never completes, it just exits back to the constructor, and therefore fails to update observable collections with data. I then get a null exception.
I wanted to test this with VS2015, but I updated some controls that are apparently only supported withing VS2017, so I can't run the code in other versions.
I also ran into an issue with the code prior to this problem, where I tried to access files in a directory without using a token. The behavior was exactly the same, the code wasn't telling me that I didn't have access to the directory I wanted to read, it was just throwing me out of the method back into the location that made the call to read the directory. Just like with the current problem, I would then run into a null exception, which wasn't where the main problem was.
I added Template10 and UWP community toolkit to the project, if that matters.
You shouldn't call an async method from a constructor unless you're willing to provide a callback.
public CncOnlinePageViewModel()
{
cnconline = new CncOnline();
var t = cnconline.RefreshServerKanesWrathDataAsync(); // assuming returns Task<string>
t.ContinueWith(OnCompleted);
}
private void OnCompleted(Task<string> task)
{
if (task.IsFaulted)
{
// Check error
var exception = task.Exception;
}
else if (task.IsCanceled)
{
// User hit cancel?
}
else
{
// All good!
var result = task.Result;
}
}
Here's a sample where RefreshServerKanesWrathDataAsync() returns just Task (not Task<result>)
public CncOnlinePageViewModel()
{
cnconline = new CncOnline();
var t = cnconline.RefreshServerKanesWrathDataAsync(); // assuming returns Task
t.ContinueWith(OnCompleted);
}
private void OnCompleted(Task task)
{
if (task.IsFaulted)
{
// Check error
var exception = task.Exception;
}
else if (task.IsCanceled)
{
// User hit cancel?
}
else
{
// All good!
}
}
On a side note, you may also need to have Visual Studio 2017 break when any exception is thrown. In VS2017, go to Debug->Windows->Exception Settings and make sure Common Language Runtime Exceptions has a check. If it has a filled box, click the box until it turns into a checkmark.
Also..., you can tap into an event raised when any task has an unobserved exception. You can do so in the constructor of App.xaml.cs
public App()
{
TaskScheduler.UnobservedTaskException += OnUnobservedException;
}
private static void OnUnobservedException(object sender, UnobservedTaskExceptionEventArgs e)
{
// Put break point here.
var ex = e.Exception;
// This will keep your app alive, but only do it if it's safe to continue.
e.SetObserved();
}

stop windows service in onStart() method

I want to stop windows service in onStart() method when customer doesn't have a license. I use service.Stop(), but it does not work.
protected override void OnStart(string[] args)
{
try
{
_bridgeServiceEventLog.WriteEntry("new OnStart");
if (LicenseValidetor.ValidCountAndTypeDevices())
{
WsInitializeBridge();
}
else
{
service = new ServiceController("BridgeService");
service.Stop();
_bridgeServiceEventLog.WriteEntry("LicenseValidetor Error");
}
_bridgeServiceEventLog.WriteEntry("end Start");
}
catch (Exception e)
{
_bridgeServiceEventLog.WriteEntry("error In onstart method ");
}
}
You cannot stop a service from within the OnStart method of that same service.
The ServiceController.Stop method internally calls ControlService (or it's Ex counterpart). Notice that one of the reasons that this function can fail is:
ERROR_SERVICE_CANNOT_ACCEPT_CTRL
The requested control code cannot be sent to the service because the state of the service is SERVICE_STOPPED, SERVICE_START_PENDING, or SERVICE_STOP_PENDING.
Well, guess what - when you're inside your OnStart method, the state of your service is SERVICE_START_PENDING.
The correct way to cope with this situation is to signal any other threads that you may have started to have them exit, and then to exit your OnStart method. The service control manager will notice that the process has exited and revert your service status to SERVICE_STOPPED. It may also notify an interactive user that "The service started and then stopped" or words to that effect.
I want to add that "simply not starting any workers" may not work (or perhaps I am being just plain stupid ;) ).
I built a service, with a try/catch(all) around my OnStart code. Because of a missing line in my .config file it crashed with an IOException, before it started any worker thread. The exception skipped over my thread starters. No thread was started by my code. Honestly.
But the service DID NOT STOP. I don't know why. As a desperate measure, I rethrew the exception, that helped.
I am still wondering if the file system watcher threads in Enterprise Library configuration were the problem. EntLib is woven to deeply into my code to remove it as an experiment, so I did not investigate further.
The accepted answer explains why what you are doing doesn't work but doesn't offer a good solution.
There are a couple of things your code isn't doing that it should.
Set the .ExitCode to indicate that your service is in an error state.
Throw an exception. Not having a license is exceptional. Throw it.
EXAMPLE:
protected override void OnStart(string[] args)
{
_bridgeServiceEventLog.WriteEntry("new OnStart");
try
{
if (LicenseValidetor.ValidCountAndTypeDevices())
{
WsInitializeBridge();
}
else
{
throw new ApplicationException("LicenseValidetor Error");
}
}
catch (Exception e)
{
this.ExitCode = e.HResult
_bridgeServiceEventLog.WriteEntry($"error In onstart method: {e.Message}");
throw
}
_bridgeServiceEventLog.WriteEntry("end Start");
}
I have noticed that your not waiting to ensure that the Service has actually stopped or if it is even running in the first instance.
Do this :-
protected override void OnStart(string[] args)
{
try
{
_bridgeServiceEventLog.WriteEntry("new OnStart");
if (LicenseValidetor.ValidCountAndTypeDevices())
{
WsInitializeBridge();
}
else
{
int time = 10000;
TimeSpan timeout = TimeSpan.FromMilliseconds(time);
service.Stop();
service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
_bridgeServiceEventLog.WriteEntry("LicenseValidetor Error");
}
_bridgeServiceEventLog.WriteEntry("end Start");
}
catch (Exception e)
{
_bridgeServiceEventLog.WriteEntry("error In onstart method ");
}
}

How to wait for an Autoreset event to occur before taking any other action?

This is about the AutoResetEvent in C#. I tried to read other answers but I could not make sense and apply to my scenario. I am not writing any threading application. Just a small application to read/validate a file and update.
So I have this requirement to write some code for reading a fixed length file, validating it and then if it is valid upload it to Database.
I got everything working until I got stuck with the AutoResetEvent. So here is what is happening. Once the data is parsed/read I validate it using Flat File Checker utility in C#. So I called the functions into my application. Here is the snippet.
private AutoResetEvent do_checks = new AutoResetEvent(false);
public bool ValidationComplete = false;
This part goes in initialization code:
this._files.Validated += new EventHandler<SchemaValidatedEventArgs>(FileSetValidated);
public bool ValidateFile()
{
try
{
RunValidation();
return true;
}
catch (Exception e)
{
log.Error("Data Validation failed because :" + e.Message);
return false;
}
}
private void RunValidation()
{
// Use Flat File Checker user interface to create Schema file.
do_checks = _files.RunChecks();
log.Debug("Validation Started");
}
This is the method that is getting called asnchronusly during the validation process:
public void FileSetValidated(Object sender, SchemaValidatedEventArgs e)
{
try
{
ValidationComplete = e.Result;
if (IsDataValid)
{
log.Debug("Data is validated and found to be valid.");
}
else
{
log.Debug("Data is validated and found to be Invalid");
}
}
finally
{
do_checks.Set();
}
}
What is happening is that even before I get any value set into ValidationComplete the code is checked for Validation complete and because it is set by default to false, it returns false. The code in the FileSetValidated gets executed after that so the database update never happens.
The reason is that I cannot change the code because the Flat File Checker only accepts an AutoResetEvent as a return variable in RunChecks method.
******Here is what I did now*******
private AutoResetEvent do_checks;
public bool ValidateFile()
{
try
{
string extFilePath = surveyFile.ExtFilePath;
File.Copy(extFilePath, localTempFolder + "ExtractFile.Dat");
RunValidation();
if (!do_checks.WaitOne(TimeSpan.FromSeconds(30))) {
// throw new ApplicationException("Validation took more than expected!");
}
return true;
}
catch (Exception e)
{
log.Error("Data Validation failed because :" + e.Message);
return false;
}
}
private void RunValidation()
{
// Use Flat File Checker user interface to create Schema file.
do_checks = _files.RunChecks();
do_checks.WaitOne();
log.Debug("Validation Started");
}
Also I moved the part where data about validation gets passed on towards the beginning of the event handler so atleast that part gets executed. This helped but I am not sure if it is correct.
I have never worked with that lib, so I just downloaded it and looked into the code.
First of all, as "500 - Internal Server Error" already mentioned, it seems that part of the code is missing, at least "try" in the FileSetValidated method. I don't see any place where you are waiting for the event via WaitOne.
You don't need to create do_checks by yourself, because _files.RunChecks() creates AutoResetEven for this particular file's processing. So if you are using the same field for that event - you will get issue if you will need to process few files at the same time. So keep separate event for each file, in any case I don't see reason to keep that references as members if you don't want to stop processing in the middle (if you will call do_checks.Set() during processing, it will cancel processing without finishing it).
As I see in the lib code, you should not call do_checks.Set() in the FileSetValidated method, because it will be set, once processing will be done, so you can just write:
var do_checks = _files.RunChecks();
do_checks.WaitOne();
Feel free to share if that helped.
UPDATE:
I am not able to check that lib now to undestand why do_checks is set after starting processing, but I can suggest you to use your initial code with next RunValidation method:
private void RunValidation()
{
do_checks.Reset(); //reset state
_files.RunChecks(); //don't store event from the lib
log.Debug("Validation Started");
do_checks.WaitOne(); //Wait for FileSetValidated to set this event
}
Before exiting the ValidateFile function you need to wait for the validation to complete (wait on the AutoResetEvent) and return the validation result.
Try something like this:
public bool ValidateFile()
{
//try
{
RunValidation();
//Allocate enough time for the validation to occur but make sure
// the application doesn't block if the _files.Validated event doesn't get fired
if(!do_checks.WaitOne(TimeSpan.FromSeconds(10)))
{
throw ApplicationException("Validation took more than expected!");
}
return ValidationComplete;
}
//I would not catch the exception since having an error doesn't mean that the file
//is invalid. Catch it upper in the call stack and inform the user that the validation
//could not be performed because of the error
//catch (Exception e)
//{
// log.Error("Data Validation failed because :" + e.Message);
// return false;
//}
}

The uncatchable exception, pt 2

Update: I've filed a bug report on Microsoft Connect: https://connect.microsoft.com/VisualStudio/feedback/details/568271/debugger-halting-on-exception-thrown-inside-methodinfo-invoke#details
If you can reproduce this problem on your machine, please upvote the bug so it can be fixed!
Ok I've done some testing and I've reduced the problem to something very simple:
i. Create a method in a new class that throws an exception:
public class Class1 {
public void CallMe() {
string blah = null;
blah.ToLower();
}
}
ii. Create a MethodInfo that points to this method somewhere else:
Type class1 = typeof( Class1 );
Class1 obj = new Class1();
MethodInfo method = class1.GetMethod( "CallMe" );
iii. Wrap a call to Invoke() in a try/catch block:
try {
method.Invoke( obj, null ); // exception is not being caught!
} catch {
}
iv. Run the program without the debugger (works fine).
v. Now run the program with the debugger. The debugger will halt the program when the exception occurs, even though it's wrapped in a catch handler that tries to ignore it. (Even if you put a breakpoint in the catch block it will halt before it reaches it!)
In fact, the exception is happening when you run it without the debugger too. In a simple test project it's getting ignored at some other level, but if your app has any kind of global exception handling, it will get triggered there as well. [see comments]
This is causing me a real headache because it keeps triggering my app's crash-handler, not to mention the pain it is to attempt to debug.
I can reproduce this on my .NET 4 box, and you're right -- it only happens on .NET 4.0.
This smells very much like a bug to me, and should go on MS Connect. Major bummer if this is tripping your crash handler. Sounds like a non-pleasing way to work around this is to wrap the invoked method inside its own handler. :-(
One thing I can not reproduce, though, is tripping the crash handler. Here's my program:
namespace trash {
public class Class1 {
public void CallMe() {
string blah = null;
blah.ToLower();
}
}
class Program {
static void Main(string[] args) {
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
var class1 = typeof(Class1);
var method = class1.GetMethod("CallMe");
try {
var obj = new Class1();
method.Invoke(obj, null); // exception is not being caught!
}
catch (System.Reflection.TargetInvocationException) {
Console.Write("what you would expect");
}
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) {
Console.Write("it would be horrible if this got tripped but it doesn't!");
}
}
}
You can't catch all exceptions. There's a few assumptions in your example. You are, for instance, assuming the exception was raised on the calling thread. Catching unhandled exceptions on other threads depends on which runtimes you're using (console, winforms, WPF, ASP.Net, etc).
Additionally, calls to System.Environment.FailFast() do not generate any handlable condition - the process is effectively terminated with no chance for intervention.

To handle exception with every form or just at main

I have a question about handling exception. I have a Winform that uses a webservice proxy on each form for data retrieval and processing. Here is where I really got confused and having a long time deciding which is better.
A. For each call in the web service do a try catch to display the error message and allow the user to re try the process by clicking the button again.
B. Since the error occurred on the web-service and the error was probably because the web service was inaccessible, just make a generic try catch in the WinMain function in the Program.cs and show an error message that web service is inaccessible before the application closes.
The main argument in this is A is more user friendly but needs a lot of try catch code. B is easier to code but just lets the application ends. I am leaning on A but am trying to search the net with options how to lessen the code needed to be written to do this. Any ideas there?
When you add a web reference, the code generator automatically adds "Async" methods to access the web service.
I would recommend that you use the Async methods rather than the synchronous methods. The nice thing about that is that the EventArgs for the Async methods provide an Error property that you can use to see if the request was successful or not.
private void CheckWebservice(string data)
{
WebService.Server server = new WebService.server();
server.methodCompleted += server_methodCompleted;
server.methodAsync(data);
}
private void server_methodCompleted(object sender, methodCompletedEventArgs e)
{
if (e.Error != null)
if (MessageBox.Show("Error", "Error", MessageBoxButtons.AbortRetryIgore) == DialogResult.Retry)
{
// call method to retry
}
else
{
if (e.Result == "OK") { // Great! }
}
}
If you must use the synchronous methods for some reason, then you could, of course, write a class to encapsulate the methods to call your web service so that you can call it from various places without duplicating the code. Your encapsulation class could do all the error handling and return a result.
class CallWebService
{
public enum Result
{ Unknown, Success, NotAvailable, InvalidData } // etc
public Call(string data)
{
Webservice.Server server = new Webservice.Server();
string result = string.Empty;
try
{
result = server.getResult(data);
}
catch (Exception ex) // replace with appropriate exception class
{
return Result.NotAvailable;
}
if (result == "OK") return Result.Success
else return Result.InvalidData;
}
}
Encapsulate the webservice call and the try/catch block inside a class =)

Categories

Resources