Почему async hadler делает циклы, когда происходит исключение?

У меня есть этот обработчик. У меня было исключение, возникающее в методе "StartTransfer" внутреннего класса (я пометил место), и по причине, я не знаю, он зацикливался на этом методе. Почему это зацикливалось, а не просто отвечало на сообщение об исключении?

public sealed class ImageUploadHandler : IHttpAsyncHandler
{
    public bool IsReusable { get { return false; } }

    public ImageUploadHandler()
    {
    }
    public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)
    {
        string token = context.Request.Form["token"];
        string albumId = context.Request.Form["albumId"];
        string imageDescription = context.Request.Form["description"];
        HttpPostedFile imageFile = context.Request.Files["image"];

        ImageTransferOperation ito = new ImageTransferOperation(cb, context, extraData);
        ito.Start(token, albumId, imageDescription, imageFile);
        return ito;
    }

    public void EndProcessRequest(IAsyncResult result)
    {
    }

    public void ProcessRequest(HttpContext context)
    {
        throw new InvalidOperationException();
    }

    private class ImageTransferOperation : IAsyncResult
    {
        private Object state;
        private bool isCompleted;
        private AsyncCallback cb;
        private HttpContext context;

        public WaitHandle AsyncWaitHandle
        {
            get { return null; }
        }

        public bool CompletedSynchronously
        {
            get { return false; }
        }

        public bool IsCompleted
        {
            get { return isCompleted; }
        }

        public Object AsyncState
        {
            get { return state; }
        }

        public ImageTransferOperation(AsyncCallback cb, HttpContext context, Object state)
        {
            this.cb = cb;
            this.context = context;
            this.state = state;
            this.isCompleted = false;
        }

        public void Start(string token, string albumId, string description, HttpPostedFile file)
        {
            Dictionary<string, Object> dictionary = new Dictionary<string,object>(3);

            dictionary.Add("token", token);
            dictionary.Add("albumId", albumId);
            dictionary.Add("description", description);
            dictionary.Add("file", file);

            ThreadPool.QueueUserWorkItem(new WaitCallback(StartTransfer), dictionary);
        }

        private void StartTransfer(Object state)
        {
            Dictionary<string, Object> dictionary = (Dictionary<string, Object>)state;

            string token = (string)dictionary["token"];
            string albumId = (string)dictionary["albumId"];
            string description = (string)dictionary["description"];
            HttpPostedFile file = (HttpPostedFile)dictionary["file"];

            var media = new Facebook.FacebookMediaObject {
                FileName = file.FileName,
                ContentType = file.ContentType                  
            };

            using (var binaryReader = new BinaryReader(file.InputStream))
            {
                media.SetValue(binaryReader.ReadBytes(Convert.ToInt32(file.InputStream.Length)));
            }

            dictionary.Clear();

            dictionary.Add("message", description);
            dictionary.Add("source", media);

            var client = new Facebook.FacebookClient(token); // <-- Here is where the exception occured

            //var result = client.Post("/" + albumId + "/photos", dictionary);

            context.Response.ContentType = "text/plain";

            context.Response.Write(token + " | " + file.FileName);
            //context.Response.Write(result.ToString());

            isCompleted = true;
            cb(this);
        }
    }
}

1 ответ

Решение

Я не могу честно объяснить, что вы описываете как "зацикливание", но вы не обрабатываете любые исключения в вашем асинхронном коде. Вы должны обработать исключения и распространить их обратно в поток, который ожидает на IAsyncResult,

Итак, во-первых, вам нужно попробовать / поймать /, наконец, вокруг большей части тела StartTransfer метод, где вы перехватываете любое потенциальное исключение, которое может произойти, сохраняете его в поле и, в блоке finally, всегда вызываете обратный вызов. Теперь, когда вы фактически захватываете любое потенциальное исключение и всегда перезваниваете, вам нужно будет проверить, произошло ли исключение в EndProcessRequest и поднять его там, чтобы обратный вызов мог "наблюдать" за ним.

Вот некоторые изменения к вашему ImageTransferOperation учебный класс:

private Exception asyncException;

public Exception Exception
{
    get
    {
        return this.asyncException;
    }
}

private void StartTransfer(Object state)
{
    try
    {
        ... rest of implementation here ...
    }
    catch(Exception exception)
    {
        this.asyncException = exception;
    }
    finally
    {
        this.isCompleted = true;
        this.cb(this);
    }
}

А потом к ImageUploadHandler распространить исключение обратно:

public void EndProcessRequest(IAsyncResult result)
{
    ImageTransferOperation imageTransferOperation = (ImageTransferOperation)result;

    Exception exception = imageTransferOperation.Exception

    if(exception != null)
    {
        throw exception;
    }
}
Другие вопросы по тегам