2

I'm a total beginner with webservices and I ran in the following problem, which is about a webservice and asynchronous logging. (c#)

Problem Description

I have a webservice that returns some data to a client (asp.net website).

[WebMethod]
public MyClass getData()
{
    //Do some work
    return _myClassObject;
}

This works pretty good so far.

Because I want to know what is happening on the webservice once it is published, I tried to implement some simple logging.

The following class (simplified) handles the logging:

public static class Logwriter
{
   public static void writeToLog(string txt)
   {
       //writes log to db
   }
}

I want this to happen asynchronous, so it won't slow down the webservice.

Therefore i changed the WebMethod:

[WebMethod]
public async Task<MyClass> getData()
{
    await Task.Run(() => Logwriter.writeToLog("Someone requested the WebMethod 'GetData'"));
    //Do some work
    return _myClassObject;
}

After i updated the ServiceReference on my asp.net website I noticed that the webserver no longer returns a "MyClass"-Object, but a "TaskOffCustomClass"-Object. I have not found a solution to get the "MyClass"-Object from the "TaskOffMyClass"-Object, yet.

Questions

  1. How can I get my "MyClass" Object from "TaskOffMyClass"?

  2. Is there a possiblity to do the logging asynchronous and still return a "MyClass"-Object? (while using Task)

  3. I thought about doing the logging in a Thread, but I also read that it is recommended to use Task over Thread. How bad would be the impact of switching to Thread?

Community
  • 1
  • 1
Martin
  • 300
  • 1
  • 4
  • 15
  • 2
    `async` and `await` don't work the way you seem to think they do. All you've done in your above code is to cause some of it to run on a different thread but then *wait* for that thread to finish running before the original thread continues. I'd strongly suggest you spend more time learning about `async` and `await`. Eric Lippert's blog had a goodly number of articles explaining it. – Damien_The_Unbeliever Mar 23 '16 at 14:45
  • Hi @Damien_The_Unbliever, thank you for your comment. I will definetly have a look at Eric Lipperts's blog. – Martin Mar 24 '16 at 02:16

3 Answers3

3

I'm a total beginner with webservices

I recommend you learn a modern framework. I don't even know how old ASMX is, now... According to what I could find, it's "not dead", but I think that's the same kind of "not dead" that Silverlight is. In other words, it's dead but they don't want to officially say it's dead.

In particular, I don't think that ASMX understands async or tasks at all. I strongly recommend learning ASP.NET WebAPI (or WCF if you really want SOAP).

However, if you have existing web methods that you need to maintain, then...

The first thing to realize - as Crowcoder pointed out - is that you probably don't want to do fire-and-forget. If it works well enough, then just keep it like this:

[WebMethod]
public MyClass getData()
{
  Logwriter.writeToLog("Someone requested the WebMethod 'GetData'");
  //Do some work
  return _myClassObject;
}

If you recognize and accept the drawbacks of unprotected background operations (specifically, that they can be aborted without any way for you to detect that, meaning that your log may be missing some messages), then you can use something like HostingEnvironment.QueueBackgroundWorkItem:

[WebMethod]
public MyClass getData()
{
  HostingEnvironment.QueueBackgroundWorkItem(() => Logwriter.writeToLog("Someone requested the WebMethod 'GetData'"));
  //Do some work
  return _myClassObject;
}

I have a description of alternative approaches on my blog.

Community
  • 1
  • 1
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Hi Stephen, tank you for your support. I read your article metioned by @Crowcoder and it pushed me in the right direction. Unfortunatly I can't switch to ASP WebAPI or WCF because it's an existing webservice. As our team is fine with losing some log data I went on with HostingEnvironment. – Martin Mar 24 '16 at 02:13
2

You are very mixed up here. Hopefully Stephen Cleary will answer also, but you should never Task.Run() in ASP.Net. You would make writeToLog async. As far as returning Task, @Rene has some good advice, but also do not use .Result in ASP.Net because of potential for deadlocks. A fire and forget operation like logging is surprisingly complex to do right.. You would be better of sending your log to a queue for processing.

Crowcoder
  • 11,250
  • 3
  • 36
  • 45
0

You could either use

MyClass result = await service.getData();

or

Task<MyClass> task = service.getData();
MyClass result = task.Result;

In the first version, your method returns to the caller immediatly and is resumed after the await statement when getData finishes.
In the second version, the call to task.Result blocks execution until the Task is completed.

René Vogt
  • 43,056
  • 14
  • 77
  • 99