Pergunta

This is about the AutoResetEvent in C#. I tried to read other answers but I could not make sense and apply to my scenario. I am not writing any threading application. Just a small application to read/validate a file and update. So I have this requirement to write some code for reading a fixed length file, validating it and then if it is valid upload it to Database.

I got everything working until I got stuck with the AutoResetEvent. So here is what is happening. Once the data is parsed/read I validate it using Flat File Checker utility in C#. So I called the functions into my application. Here is the snippet.

private AutoResetEvent do_checks = new AutoResetEvent(false);
public bool ValidationComplete = false;

This part goes in initialization code:

this._files.Validated += new EventHandler<SchemaValidatedEventArgs>(FileSetValidated);

public bool ValidateFile()
{
    try
    {
        RunValidation(); 
        return true;
    }
    catch (Exception e)
    {
        log.Error("Data Validation failed because :" + e.Message);
        return false;
    }
}

private void RunValidation()
{
    // Use Flat File Checker user interface to create Schema file.
    do_checks = _files.RunChecks();
    log.Debug("Validation Started");
}

This is the method that is getting called asnchronusly during the validation process:

public void FileSetValidated(Object sender, SchemaValidatedEventArgs e)
{   
    try
    {                 
        ValidationComplete = e.Result;

        if (IsDataValid)
        {
            log.Debug("Data is validated and found to be valid.");
        }
        else
        {
            log.Debug("Data is validated and found to be Invalid");
        }
    }
    finally
    {
        do_checks.Set();
    }
}

What is happening is that even before I get any value set into ValidationComplete the code is checked for Validation complete and because it is set by default to false, it returns false. The code in the FileSetValidated gets executed after that so the database update never happens.

The reason is that I cannot change the code because the Flat File Checker only accepts an AutoResetEvent as a return variable in RunChecks method.

******Here is what I did now******* private AutoResetEvent do_checks;

public bool ValidateFile()
    {

        try
        {

            string extFilePath = surveyFile.ExtFilePath;
            File.Copy(extFilePath, localTempFolder + "ExtractFile.Dat");
            RunValidation();

            if (!do_checks.WaitOne(TimeSpan.FromSeconds(30))) { 

            //    throw new  ApplicationException("Validation took more than expected!"); 
            }    

            return true;
        }
        catch (Exception e)
        {
            log.Error("Data Validation failed because :" + e.Message);
            return false;

        }



    }


    private void RunValidation()
    {
        // Use Flat File Checker user interface to create Schema file.
        do_checks = _files.RunChecks();
        do_checks.WaitOne();
        log.Debug("Validation Started");


    }

Also I moved the part where data about validation gets passed on towards the beginning of the event handler so atleast that part gets executed. This helped but I am not sure if it is correct.

Foi útil?

Solução

I have never worked with that lib, so I just downloaded it and looked into the code.

First of all, as "500 - Internal Server Error" already mentioned, it seems that part of the code is missing, at least "try" in the FileSetValidated method. I don't see any place where you are waiting for the event via WaitOne.

You don't need to create do_checks by yourself, because _files.RunChecks() creates AutoResetEven for this particular file's processing. So if you are using the same field for that event - you will get issue if you will need to process few files at the same time. So keep separate event for each file, in any case I don't see reason to keep that references as members if you don't want to stop processing in the middle (if you will call do_checks.Set() during processing, it will cancel processing without finishing it).

As I see in the lib code, you should not call do_checks.Set() in the FileSetValidated method, because it will be set, once processing will be done, so you can just write:

var do_checks = _files.RunChecks();
do_checks.WaitOne(); 

Feel free to share if that helped.

UPDATE: I am not able to check that lib now to undestand why do_checks is set after starting processing, but I can suggest you to use your initial code with next RunValidation method:

private void RunValidation()
{
    do_checks.Reset(); //reset state
    _files.RunChecks(); //don't store event from the lib
    log.Debug("Validation Started");
    do_checks.WaitOne(); //Wait for FileSetValidated to set this event
}

Outras dicas

Before exiting the ValidateFile function you need to wait for the validation to complete (wait on the AutoResetEvent) and return the validation result.

Try something like this:

public bool ValidateFile()
{
    //try
    {
        RunValidation();

        //Allocate enough time for the validation to occur but make sure 
        // the application doesn't block if the _files.Validated event doesn't get fired
        if(!do_checks.WaitOne(TimeSpan.FromSeconds(10)))
        {
            throw ApplicationException("Validation took more than expected!");
        }            

        return ValidationComplete;
    }
    //I would not catch the exception since having an error doesn't mean that the file 
    //is invalid. Catch it upper in the call stack and inform the user that the validation 
    //could not be performed because of the error
    //catch (Exception e)
    //{
    //     log.Error("Data Validation failed because :" + e.Message);
    //     return false;
    //}
 }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top