Search code examples
c#asynchronousasp.net-web-apiasync-awaitcontroller

C# Await till object is in list, for controller


Hi i currently have a web api system where i send a command to a Machine at another location. Id like to wait for the response from the system to be available to send back to the requester. Currently when a request is made i generate a UUID and once data comes back from the other location it matches with that UUID and adds it to a response list. Is there any way i can await that a list contains x

If not is there any other way that i might be able to transfer this object from the very distant class and thread to the controller for the response to be sent back?

Code from webrequest

    [HttpGet]
    [Route("Areas")]
    public async Task<IHttpActionResult> GetArea(GetAreas getAreas)
    {
        OutScaleManager.LogRequest("Request to getAreas with ip: " + getAreas.IP + " i " + getAreas.startArea + " i " + getAreas.endArea);
        foreach (NoxApiService noxService in OutScaleManager.nUtil.connectedInstance)
        {
            if (noxService.param.IPAddress == getAreas.IP)
            {
                noxService.GetAreas(getAreas.startArea, getAreas.endArea);
                OutScaleManager.LogRequest("getAreas Sent, now moving to queue checks");
                string UUID = OutScaleManager.nRAR.NoxRequestHandler(getAreas, RequestType.GETAREAS);
                if (OutScaleManager.nRAR.GetAreasResponseSend)
                {
                    await OutScaleManager.nRAR.ResponseList.ContainsKey(UUID);
                }
                //if (OutScaleManager.nRAR.GetAreasResponseSend) { return Ok(OutScaleManager.nRAR.NoxRequestHandler(getAreas, RequestType.GETAREAS)); }
            }
        }
        OutScaleManager.LogRequest("This request was not sent, please create an instance and connected through the propper channels.");
        return Ok("This request was not sent, please create an instance and connected through the propper channels.");
    }

Solution

  • Hi i currently have a web api system where i send a command to a Machine at another location. Id like to wait for the response from the system to be available to send back to the requester. Currently when a request is made i generate a UUID and once data comes back from the other location it matches with that UUID and adds it to a response list.

    Instead of using a list of available responses, structure your request/response system as a dictionary of outstanding requests. The dictionary would map GUIDs to TaskCompletionSource<T> where the T is the type of response data. For example, if your response data was TResponse, it could look like this:

    private ConcurrentDictionary<Guid, TaskCompletionSource<TResponse>> _requests = new();
    
    public Task<TResponse> GetAreasAsync(GetAreas getAreas)
    {
      var guid = OutScaleManager.nRAR.NoxRequestHandler(getAreas, RequestType.GETAREAS);
      TaskCompletionSource<TResponse> tcs = new();
      _requests.TryAdd(guid, tcs);
      return tcs.Task;
    }
    
    // Called when a GetAreas request completes:
    public void SaveAreasResponse(Guid requestId, TResponse data)
    {
      if (!_requests.TryRemove(requestId, out var tcs))
        throw new InvalidOperationException("Response received for unknown request GUID.");
      tcs.TrySetResult(data);
    }