PlatformNotSupportedException при сохранении файла из Silverlight через универсальный обработчик

У меня есть приложение Silverlight, размещенное на сайте ASP.NET, через которое я запускаю HttpWebRequest для универсального обработчика, чтобы сохранить файл CSV на компьютере пользователя.

В приложении Silverlight создается Uri с параметрами, чтобы сделать CSV-файл на стороне сервера. Нажимается кнопка, которая вызывает следующее:

string httpHandlerName = "HttpDownloadHandler.ashx";
// CustomUri handles making it an absolute Uri wherever we move the handler.
string uploadUrl = new CustomUri(httpHandlerName).ToString();

UriBuilder httpHandlerUrlBuilder = new UriBuilder(uploadUrl);
httpHandlerUrlBuilder.Query = string.Format("{3}startdate={0}&enddate={1}&partnerId={2}", startDate, endDate, partnerId, string.IsNullOrEmpty(httpHandlerUrlBuilder.Query) ? "" : httpHandlerUrlBuilder.Query.Remove(0, 1) + "&");

HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(httpHandlerUrlBuilder.Uri);
webRequest.Method = "POST";
webRequest.BeginGetResponse(new AsyncCallback(GetResponseCallback), webRequest);

Теперь вот код ProcessRequest из HttpDownloadHandler.ashx

public void ProcessRequest(HttpContext context)
{
    _httpContext = context;

    string partnerId = _httpContext.Request.QueryString["partnerId"];
    string startDate = _httpContext.Request.QueryString["startDate"];
    string endDate = _httpContext.Request.QueryString["endDate"];

    ExportCsvReport exportCsv = new ExportCsvReport();
    _csvReport = exportCsv.ExportMemberRegistrationReport(partnerId, startDate, endDate);

    context.Response.Clear();
    context.Response.AddHeader("content-disposition", "attachment; filename=Report.csv");
    context.Response.ContentType = "text/csv";
    context.Response.Write(_csvReport);
}

Вот информация заголовка HttpResponse, которая возвращается, когда диалоговое окно сохранения файла отказывается появляться:

{System.Web.HttpResponse}
Buffer: true
BufferOutput: true
Cache: {System.Web.HttpCachePolicy}
CacheControl: "private"
Charset: "utf-8"
ContentEncoding: {System.Text.UTF8Encoding}
ContentType: "text/csv"
Cookies: {System.Web.HttpCookieCollection}
Expires: 0
ExpiresAbsolute: {1/1/0001 12:00:00 AM}
Filter: {System.Web.HttpResponseStreamFilterSink}
HeaderEncoding: {System.Text.UTF8Encoding}
Headers: 'context.Response.Headers' threw an exception of type 'System.PlatformNotSupportedException'
IsClientConnected: true
IsRequestBeingRedirected: false
Output: {System.Web.HttpWriter}
OutputStream: {System.Web.HttpResponseStream}
RedirectLocation: null
Status: "200 OK"
StatusCode: 200
StatusDescription: "OK"
SubStatusCode: 'context.Response.SubStatusCode' threw an exception of type 'System.PlatformNotSupportedException'
SuppressContent: false
TrySkipIisCustomErrors: false

Когда я перехожу к localhost/HttpDownloadHandler.ashx, когда сайт работает, не инициируя его из приложения Silverlight, диалоговое окно «Сохранить файл» отображается просто отлично, похоже, это тот случай, когда Silverlight не принимает заголовок ответа должным образом.

Можно ли что-нибудь сделать, чтобы решить эту проблему? Я открыт для предложений по изменению того, как я это делаю, конечно.


person Jeff Dalley    schedule 30.07.2010    source источник


Ответы (2)


Ответ поступает в Silverlight, а не в веб-браузер (поэтому браузер не будет обрабатывать файл CSV и отображать диалоговое окно сохранения файла). Вам необходимо инициировать запрос из веб-браузера напрямую (например, через JavaScript). Вы можете использовать мост Silverlight HTML/JavaScript, чтобы сделать это довольно легко.

Разумный пример моста JavaScript можно найти < strong>здесь.

Вам нужно добавить некоторую логику, подобную этой:

HtmlPage.Window.Invoke("startDownload", httpHandlerUrlBuilder.Uri.ToString());

А затем в JavaScript:

<script type="text/javascript">
function startDownload(url){
    // you'll probably need to redirect
    // to a hidden iFrame to actually 
    // kick off the download, by
    // setting the location to
    // the url
    // or ... some other option
    // there are a number of 
    // different ways.
}
</script>

Кроме того, вы, вероятно, могли бы проделать тот же трюк через HTML DOM, полностью из Silverlight. В приведенной выше ссылке также есть основные сведения об этом.

person WiredPrairie    schedule 31.07.2010
comment
Спасибо, это гораздо лучшее решение для того, что я пытался сделать. В итоге я использовал скрытый iFrame и установил его атрибут src с помощью предложенной функции Javascript, а затем вызвал его из Silverlight с помощью .Invoke и вообще избегал использования HttpWebRequest. Спасибо! - person Jeff Dalley; 03.08.2010

Насколько я знаю, диалог сохранения будет вызываться только в событии нажатия кнопки, поэтому, когда вы получите ответ http, вы вообще не получите разрешения на открытие диалогового окна сохранения.

Что вы должны сделать, так это в событии нажатия любой кнопки, возможно, кнопки загрузки, в событии щелчка вы должны вызвать диалоговое окно файла и открыть поток файла, который вы будете использовать позже, когда получите ответ веб-сервера.

person Akash Kava    schedule 01.08.2010