Miscode Miscode - 22 days ago 5
C# Question

Eventhandlers in my WebApi

Currently I have to connect to a plc-terminal(tcp/sockets based). The good part is that the manufacturer has provided a dll which abstracts all this functionality for me. The bad part, everything is programmed with eventhandlers.
A simplified example of this

public void GetOutputs(string id)
{
ConfigurationManager cm = new ConfigurationManager();
cm.GetOutputResult += OnGetOutputResult;
cm.GetOutputAsync(id);
}

private void OnGetOutputResult(Output output)
{
//do something here with the output when not null
}


I want to create a WebApi project so all the 'clients'(UWP,Xamarin,ASP MVC) can access this terminal thru http and so there is no fuss with Portable or .NET Core libraries as they can't reference the full .NET Framework dll from the manufacturer.

So my question is: Is it even possible to do these things in WebApi? Is there a way to convert these callbacks nicely to awaitable Tasks?

public class OutputsController : ApiController
{
public IHttpActionResult Get(string id)
{
ConfigurationManager cm = new ConfigurationManager();
//task/async/await magic here
return Ok(output); // or NotFound();
}


Regards,
Miscode

Answer

You can use the TaskCompletionSource which was designed for this kind of scenario

private TaskCompletionSource<Output> tcs;

public Task<Output> GetOutputs(string id)
{    
    tcs = new TaskCompletionSource<Output>();

    ConfigurationManager cm = new ConfigurationManager();
    cm.GetOutputResult += OnGetOutputResult;    
    cm.GetOutputAsync(id);

    // this will be the task that will complete once tcs.SetResult or similar has been called
    return tcs.Task;
}

private void OnGetOutputResult(Output output)
{
    if (tcs == null) {
        throw new FatalException("TaskCompletionSource wasn't instantiated before it was called");
    }

    // tcs calls here will signal back to the task that something has happened.
    if (output == null) {
       // demoing some functionality
       // we can set exceptions
       tcs.SetException(new NullReferenceException());
       return;
    }

    // or if we're happy with the result we can send if back and finish the task
    tcs.SetResult(output);
}

In your api:

public class OutputsController : ApiController
{
    public async Task<IHttpActionResult> Get(string id)
    {
        ConfigurationManager cm = new ConfigurationManager();

        var output = await cm.GetOuputs(id);

        return Ok(output); // or NotFound();
    }
Comments