问题
I have the following scenario:
Client who is requesting a webservice to start
public bool Start(MyProject project, string error)
A web service who receives the call from the client in a method
public event EventHandler<StartEventArgs> startEvent; public bool Start(MyProject project, string error) { Task<bool> result = StartAsync(project, error); return result.Result; } protected virtual void OnStart(StartEventArgs e) { // thread safe trick, snapshot of event var se = startEvent; if (se != null) { startEvent(this, e); } } private Task<bool> StartAsync(MyProject project, string error) { var taskCompletion = new TaskCompletionSource<bool>(); this.startEvent += (p, e) => taskCompletion.TrySetResult((e.Error == string.Empty) ? true : false); this.OnStart(new StartEventArgs(project, error)); return taskCompletion.Task; }
An application that is subscribing to an event that is located in the web service:
app.Start += EventHandler(App_Start) private bool App_Start() { // does something returns true/false }
I want the web service to fire off the event in a Task, then wait for the function in the app.exe to finish and then return here to notify the user that the task has completed successfully.
I am not sure how to do this but in theory it would look something like this:
Task<bool> startTask = Task.Factory.StartNew(() => { OnStart() });
startTask.WaitAll(); // I think this is what I would need to for 4.0
return startTask.Result
I hope I am being descriptive enough for someone to see what I am trying to do. I would like the service to not have to know anything about the client and just run the task and once the event has finished its execution come back to this point and return to client a Boolean value representing success/failure.
Is this possible or am I taking a really wrong approach with this?
Update: Obviously OnStart is not an event so how do I do what you are trying to explain to me?
回答1:
You can wrap an event describing the Event based asynchronous pattern into an Task<T>
via TaskCompletionSource<T>. The basic pattern is typically something like:
Task<bool> StartAsync()
{
var tcs = new TaskCompletionSource<bool>();
// When the event returns, set the result, which "completes" the task
service.OnStarted += (o,e) => tcs.TrySetResult(e.Success);
// If an error occurs, error out the task (optional)
service.OnStartError += (o,e) => tcs.TrySetException(e.Exception);
// Start the service call
service.Start();
// Return the Task<T>
return tcs.Task;
}
回答2:
So I think I am now understanding how this needs to be done here is how I am doing it now.
Service code:
public void SetStartTask(Task<bool> startTask)
{
this.startTask = startTask;
}
public bool Start(RtProjectInfo project, string error)
{
StartEventArgs args = new StartEventArgs(project, error);
OnStart(args);
return startTask.Result;
}
protected virtual void OnStart(StartEventArgs e)
{
// thread safe trick, snapshot of event
var se = startEvent;
if (se != null)
{
startEvent(this, e);
}
}
public void StartFinished(MyProject project, string error)
{
OnStartFinish(new StartEventArgs(project, error));
}
protected virtual void OnStartFinish(StartEventArgs e)
{
var sef = startFinished;
if (sef != null)
{
startFinished(this, e);
}
}
Here is a test client implementation
public void Start_Event(object sender, StartEventArgs e)
{
Task<bool> startTask = StartAsync();
service.SetStartTask(startTask);
DoOtherWork();
DoOtherWork();
DoOtherWork();
}
private Task<bool> StartAsync()
{
var taskCompletion = new TaskCompletionSource<bool>();
service.startFinished += (p, e) =>
{
taskCompletion.TrySetResult((e.Error == string.Empty) ? true : false);
};
return taskCompletion.Task;
}
private void DoingWork()
{
for(int i = 0; i < 100; ++i)
{
}
service.StartFinished(project, error);
}
private void DoOtherWork()
{
for (int i = 0; i < 100000; ++i)
{
}
}
So obviously whenever someone client calls DoingWork() the event will be received and everyone is happy! If anyone has any suggestions that are better please provide them as I am just learning how to use TPL correctly.
来源:https://stackoverflow.com/questions/29355731/how-to-use-taskt-raising-an-event-and-waiting-for-event-to-be-finished