I have a question regarding Task. I have a WCF app which has a method ReceiveEmpInfo which will be called from a client app.
WCF Server app:
public void ReceiveEmpInfo(string EmpName, string EmpId)
{
DifferentClass.SaveEmpToDB(string EmpName, string EmpId);
return;
}
My requirement is I want to return this method call (ReceiveEmpInfo()) once I call the method SaveEmpToDB(), I don’t want to hold the client call until the SaveEmpToDB() method saves the data to the database. I’m thinking of using Task, but I’m not sure whether it will solve my requirement.
Please give me your suggestions.
Thanks,
Joe
Yes, it will. Once you call Task.Start() your WCF method can return and the task will run in the "background". You have to be very careful, especially if you're running this WCF service inside of IIS. If these tasks are very long running and the IIS application pool shuts down (or gets restarted) your task is going to get whacked [potentially] in the middle of its work.
BTW: I'm assuming you're referring to: System.Threading.Tasks.Task
Use callbacks, and do async calls to db or whatever,
see example http://msdn.microsoft.com/en-us/library/ca56w9se.aspx
This is a lot like this post:
How to make a call to my WCF service asynchronous?
I think the links in the popular answer should help.
If this is a one-way fire-and-forget operation you can simply make the operation one-way. This will not block the client for the duration of the method execution.
[ServiceContract]
interface ISomeContract
{
[OperationContract(IsOneWay = true)]
void ReceiveEmpInfo(string EmpName, string EmpId)
}
Related
I have access to WSDL file of a specific .asmx web service that contains a SendDataAsync method - basically I specify the TimeStamp and Value to be send. I uploaded the WSDL file to my project in Visual Studio 2019 as a connected service (Add->Connected Service->Microsoft WCF Web Service Reference Provider->Browse->I added location of the WSDL file and specified the service that included SendDataAsync method). After that I created a new client and tried to use my method like that:
ServiceSoapClient client = new ServiceSoapClient(ServiceSoapClient.EndpointConfiguration.ServiceSoap);
client.SampleData sd = new client.SampleData();
sd.TStamp = DateTime.Now;
sd.Value = 10;
client.SendDataAsync(sd);
Unfortunately, it doesn't work. I don't receive any errors or exceptions so I tried to check the response from the web service via Fiddler. I found out that actually nothing is being transmitted. No connection is being made, nothing. Now I try to understand what I'm doing wrong. Is my way of using the method defined on the web service wrong? Or maybe the method doesn't actually do what the name suggests? Or could the problem be related to the fact that the method is Async? Any suggestions are welcome! :)
According your description,I made a demo.The asynchronous method in demo is automatically generated by the client-side according to SendData, that is, the server-side has no SendDataAsync method, and the server-side only has SendData.
public void SendData(SampleData data)
{
Console.WriteLine(data.TStamp);
Console.WriteLine(data.value);
Console.WriteLine("success");
}
This is the SendData method of the server-side.
public System.Threading.Tasks.Task SendDataAsync(Client_SOAP.ServiceReference1.SampleData data) {
return base.Channel.SendDataAsync(data);
}
This is an asynchronous method automatically generated by the client-side.
ServiceReference1.Service1Client service1Client = new Service1Client();
SampleData sampleData = new SampleData();
sampleData.value = 10;
sampleData.TStamp = DateTime.Now;
service1Client.SendDataAsync(sampleData);
service1Client.Close();
Console.ReadLine();
This is the client-side calling asynchronous methods.
This is the execution result of the server-side after the client-side calls.
In another case,if your asynchronous method is implemented by the server-side, there are three ways for the server to implement asynchronous operation: the task-based asynchronous pattern, the Event-based Asynchronous Pattern, the IAsyncResult asynchronous pattern.For the different asynchronous model used by the server-side, the client calls in different ways.
The following link details the asynchronous invocation of the client-side:
https://learn.microsoft.com/en-us/dotnet/framework/wcf/synchronous-and-asynchronous-operations
Okay, thanks to both the comment from Paulo Morgado and the answer from Ding peng I managed to solve my problem. The proper way of using asynchronous method, such as SendDataAsync in my case, is with the await operator. I changed the method invocation from:
client.SendDataAsync(sd);
to:
response = await client.SendDataAsync(sd);
I also had to change void Main to async Main and the method works now :)
I apologize if a variation of this question has been asked before, but I'm struggling to find an answer that applies to my current situation.
I am working on a project where I've been asked to expose the operations of a Task based provider via a WCF service. The provider interface explicitly defines Task<T> as the return type of each method, here's an example:
public interface IContactProvider
{
Task<IEnumerable<Contact>> GetAllContacts();
}
In an attempt to expose this as a WCF service, I've basically defined a "synchronous" version of the provider interface to use as a service contract resulting in a service implementation that looks like this:
public class ContactService : IContactService
{
private IContactProvider contactProvider;
public IEnumerable<Contact> GetAllContacts()
{
return contactProvider.GetAllContacts().Result;
}
}
My instinct tells me that I'm doing something wrong here and that I should be "waiting" for the Result to be available some other way. Is there a better way to do this?
What you're doing should work fine (Result will block until the task completes), but are you using .NET 4.5? If so you could simply declare your service operation contract to return the async Task<T> directly. That way your clients would automatically get the option to call it synchronously or asynchronously (via the generated service client).
Here's a post I found more useful than the MSDN docs: http://blog.vuscode.com/malovicn/archive/2012/01/21/what-is-new-in-wcf-in-net-4-5-taskt-and-async.aspx
I have an application in WCF that runs in all machines on my customer. But just one works like a server in the net.
In this model, every time the WCF "client" is called, he call your WCF "server" to obtain your response.
So, I have this configuration on my Interface:
[WebInvoke(BodyStyle = WebMessageBodyStyle.WrappedRequest)]
[OperationContract]
MyObjectReturn CheckUpdate(string foo1, string foo2, string foo3);
In my code, this:
MyObjectReturn myObjReturn = new MyObjectReturn();
if (this.Master)
{
myObjReturn.Code = 15000;
myObjReturn.Message = "New Update found";
return myObjReturn;
}
else
{
var myTask = Task<MyObjectReturn >.Factory.StartNew(() =>
{
ServerContractClient server = new ServerContractClient(master.Url);
return server.CheckUpdate(foo1, foo2, foo3);
}
return myTask.Result;
}
When the WCF "client" calls his "server", the return is always null! If I do not use the "Task . Factory.StartNew", I get a Bad Request error
Any tip?
Uh, first, "server" and "client" are the preferred nomenclatures.
Second, Servy has a point that if you want the data back immediately, there's no real point in starting a thread. That said, threads are fun! Who doesn't want to thread? To do it properly you'll have to revise your application a bit, but for now you'll at least have to design the WCF method to be asynchronous, and the client making the call needs to know it's asynchronous; otherwise the result is null, as you experienced. Best starting point is here.
I'm ashamed to say it, but the problem was not what I thought. I noticed that when I called the WCF Server via browser, my return was not null. It was then that I realized that my Binding was the real problem. I noticed that there were two errors:
1) My Bindding is created via code. As noted in my interface, I declared my WebMessageBodyStyle as WrappedRequest. But when creating the Binding Client, I was using Wrapped;
2) The namespace of my ServiceBehavior and DataContract were different, which also caused confusion in WCF.
This link helped me clarify this last point:
WCF Web Service Call to Another WCF Web Service returns no data
Anyway, thank you all who gave me very valuable tips on this problem.
We have a service to update customer information to server. One service call takes around few seconds, which is normal.
Now we have a new page where at one instance around 35-50 Costumers information can be updated. Changing service interface to accept all customers together is out of question at this point.
I need to call a method (say "ProcessCustomerInfo"), which will loop through customers information and call web service 35-50 times. Calling service asynchronously is not of much use.
I need to call the method "ProcessCustomerInfo" asynchronously. I am trying to use RegisterAsyncTask for this. There are various examples available on web, but the problem is after initiating this call if I move away from this page, the processing stops.
Is it possible to implement Fire and Forget method call so that user can move away (Redirect to another page) from the page without stopping method processing?
Details on: http://www.codeproject.com/KB/cs/AsyncMethodInvocation.aspx
Basically you can create a delegate which points to the method you want to run asynchronously and then kick it off with BeginInvoke.
// Declare the delegate - name it whatever you would like
public delegate void ProcessCustomerInfoDelegate();
// Instantiate the delegate and kick it off with BeginInvoke
ProcessCustomerInfoDelegate d = new ProcessCustomerInfoDelegate(ProcessCustomerInfo);
simpleDelegate.BeginInvoke(null, null);
// The method which will run Asynchronously
void ProcessCustomerInfo()
{
// this is where you can call your webservice 50 times
}
This was something I whipped just to do that...
public class DoAsAsync
{
private Action action;
private bool ended;
public DoAsAsync(Action action)
{
this.action = action;
}
public void Execute()
{
action.BeginInvoke(new AsyncCallback(End), null);
}
private void End(IAsyncResult result)
{
if (ended)
return;
try
{
((Action)((AsyncResult)result).AsyncDelegate).EndInvoke(result);
}
catch
{
/* do something */
}
finally
{
ended = true;
}
}
}
And then
new DoAsAsync(ProcessCustomerInfo).Execute();
Also need to set the Async property in the Page directive <%# Page Async="true" %>
I'm not sure exactly how reliable this is, however it did work for what I needed it for. Wrote this maybe a year ago.
I believe the issue is the fact is your web service is expecting a client to return the response to, that the service call itself is not a one way communication.
If you're using WCF for your webservices look at http://moustafa-arafa.blogspot.com/2007/08/oneway-operation-in-wcf.html for making a one way service call.
My two cents: IMO whoever put the construct on you that you're not able to alter the service interface to add a new service method is the one making unreasonable demands. Even if your service is a publicly consumed API adding a new service method shouldn't impact any existing consumers.
Sure you can.
I think what you are wanting is a true background thread:
Safely running background threads in ASP.NET 2.0
Creating a Background Thread to Log IP Information
I have a process where an incoming user request to our system is being handled. I also want to add some metadata about the request to a database table without impacting the responsiveness of the main process. To achieve this I added a call to an asynchronous method like this:
public static ReturnObject ResponsiveMethod(string ip, string code)
{
// ... some reasonably quick code
IPDetail.InsertAsync(ip); // <-- call to the async method
return new ReturnObject(code);
}
The InsertAsync() method looks like this:
public static void InsertAsync(string ipAddress)
{
Action action = () => IPDetail.Insert(ipAddress);
action.BeginInvoke(aResult => Log.Debug("Completed Insert"), null);
}
And finally, the normally non-asynchronous method called Insert():
private static void Insert(string ipAddress)
{
ApplicationContextHelper.LoadApplicationContext();
var helper = new GeoLocationHelper();
var result = helper.GetDetailsFromIP(ipAddress);
Log.InfoFormat("Succesfully retreived IP data {0}.", ipAddress);
result.Save();
}
In my unit tests the InsertAsync() call works perfectly. Inside the method calls in Insert() there are many operations occuring which are detailed by logging, and all the expected log messages are there, as well as the final result of the result.Save() method.
However, we have a webservice which utilizes something like the ResponsiveMethod() method above and for some reason the asynchronous calls do not complete. All of the logging in the LoadApplicationContext() method gets fired, but after that there is no log activity related to the Insert() and the result.Save() is never getting executed.
Revised summary question to be more concise
My current thinking is that the webservice has completed its task and the thread which called the asynchronous no longer exists. Would this stop the async call from completing?
I've never used BeginInvoke before, but usually where there's a Begin*, you also need the coresponding End*. Please add one, along with correct exception handling.
My first thought is that you may be throwing an exception on your async call in the web service scenario for some reason. I know you've probably pared it down to post it on the web, but is there any "more-or-less unfailable" error handling code in there?
Are you relying on the identity of the caller in the Async method call? The identity may be lost when called from the web service.