Проблемы с отправкой файла через IHttpAsyncHandler

Я использую IHttpHandler для вызова веб-службы и возврата полученного байта [] клиенту в виде загруженного вложения файла. Это работает нормально, но когда я попытался изменить IHttpHandler на IHttpAsyncHandler, отображается диалог загрузки файла, но файл не запускается / не завершает загрузку. Что я делаю неправильно?

<%@ WebHandler Language="C#" Class="PreviewPDF"  %>

using System;
using System.Web;

public class PreviewPDF : IHttpAsyncHandler
{
    public void ProcessRequest(HttpContext context)
    {
    } 

    public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)
    {
        string data = "some data";

        using (WebService.RequestService service = new WebService.RequestService())
        {
            AsyncCallback callback = new AsyncCallback(EndProcessRequest);
            return service.BeginGetFile(data, callback, context);
        }
    }
    public void EndProcessRequest(IAsyncResult result)
    {
        HttpContext context = result.AsyncState as HttpContext;
        byte[] wsoutput;
        using (WebService.RequestService service = new WebService.RequestService())
        {
            wsoutput = service.EndGetFile(result);
        }

        context.Response.ContentType = "application/octet-stream";
        context.Response.ContentEncoding = System.Text.Encoding.Unicode;
        context.Response.AddHeader("Content-Disposition", "attachment; filename=attachment.pdf");
        using (System.IO.MemoryStream ms = new System.IO.MemoryStream(wsoutput))
        {
            ms.WriteTo(context.Response.OutputStream);
        }
        context.Response.Flush();
    }


    public bool IsReusable {
        get {
            return false;
        }
    }
}

1 ответ

Решение

Несколько замечаний о вашем коде:

  1. Вам нужно позвонить EndGetFile on the same service instance on which you called BeginGetFile
  2. Вам нужно пройти cb as the AsyncCallBack instead of EndProcessRequest

Here's the code with these remarks taken into account:

private class State
{
    public HttpContext Context { get; set; }
    public RequestService Service { get; set; }
}

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

public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)
{
    // Don't use using block or it will dispose the service before you can call EndGetFile
    var state = new State
    {
        Service = new RequestService(),
        Context = context
    };
    // Pass cb here and not EndProcessRequest
    return state.Service.BeginGetFile(cb, state);
}

public void EndProcessRequest(IAsyncResult result)
{
    State state = result.AsyncState as State;
    // Be carefull as this may throw: it is best to put it in a try/finally block
    // so that you dispose properly of the service
    byte[] buffer = state.Service.EndGetFile(result);
    state.Service.Dispose();
    state.Context.Response.ContentType = "application/octet-stream";
    state.Context.Response.AddHeader("Content-Disposition", "attachment; filename=attachment.pdf");
    // Write directly into the output stream, and don't call Flush
    state.Context.Response.OutputStream.Write(buffer, 0, buffer.Length);
}

public bool IsReusable 
{ 
    get { return false; } 
}
Другие вопросы по тегам