简体   繁体   中英

Awaiting an event to complete before it gets fired again

I have the following scenario, I have an event that keeps on receiving xml's that need to be pushed into DB, the pushing code and event looks something like below :

async void signalrClient_OnXMLReceived(object value, MessageResponseEventArgs e)
{
    await SaveXML();
}

async task SaveXML(string xmlDoc)    
{    
    await SaveCustomer(GetCustomerDataFrmXML(xmlDoc));
    await SavePlantInfo(GetPlantDataFrmXML(xmlDoc))

   if(NotJobexists(GetJob(xmlDoc))
   {
    await SaveJob(GetJobInfo(xmlDoc))
   }
}

The problem is as soon as I encounter the first await in the save method, the control is taken back to the event where it receives new xml and calls save again, so My question is , how do I make sure that I execute all the code in the save method before the event gets fired again.

I do not have control over the event when it gets called, but as and when it calls I want to make sure that I handle the event fully before it gets called next time, how can I do it?

UPDATE : Thanks all for your reply, The reason why I wanted to handle the event fully before it gets fired again is, if I get one more xml which is similar to the first one in the event, I was actually inserting both which will cause the duplicate entries in DB due to the async nature, finally I reordered my saves and checked if duplicate exists before couple of await save methods. This fixed the issue. I didn't tried the queue or Recative framework suggestions as this needed to be fixed quickly.

"..I want to make sure that I handle th event fully before it gets called next time, how can I do it?"

Don't make async the method at all should meet your requirement.

You need a Queue in the event handler, where you push XML that arrives, and you need a timer, where on every tick you get an element from that queue and save it to DB .

Considering that Queue is FIFO structure, you will also maintain an order of the arrived XML s, in case it's important to you.

Microsoft's Reactive Framework would handle this nicely for you.

Instead of handling events in the normal way you create an observable from the event:

var xmlreceiveds =
    Observable.FromEventPattern<EventHandler<MessageResponseEventArgs>>(
        h => signalrClient.OnXMLReceived += h, 
        h => signalrClient.OnXMLReceived -= h);

You can now get a steady stream of events that are guaranteed to complete before the next event comes.

You handle then like this:

var xmlreceiveds =
    Observable
        .FromEventPattern<EventHandler<MessageResponseEventArgs>>(
            h => signalrClient.OnXMLReceived += h, 
            h => signalrClient.OnXMLReceived -= h);

xmlreceiveds.Subscribe(ep =>
{
    SaveCustomer(GetCustomerDataFrmXML(ep.EventArgs.XmlDoc));
    SavePlantInfo(GetPlantDataFrmXML(ep.EventArgs.XmlDoc));

    if (NotJobexists(GetJob(ep.EventArgs.XmlDoc)))
    {
        SaveJob(GetJobInfo(ep.EventArgs.XmlDoc));
    }
});

You can easily make this be handled on a different thread by including an ObserveOn method call, like so:

var xmlreceiveds =
    Observable
        .FromEventPattern<EventHandler<MessageResponseEventArgs>>(
            h => signalrClient.OnXMLReceived += h, 
            h => signalrClient.OnXMLReceived -= h)
        .ObserveOn(Scheduler.Default);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM