Почему асинхронный обработчик делает циклы, когда происходит исключение? - PullRequest
0 голосов
/ 19 июня 2011

У меня есть этот обработчик.У меня было исключение, возникающее в методе «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 Ответ

1 голос
/ 19 июня 2011

Я не могу честно объяснить, что вы описываете как «зацикливание», но вы не обрабатываете любые исключения в своем асинхронном коде.Вы должны обработать исключения и распространить их обратно на поток, который ожидает на 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;
    }
}
...