views:

78

answers:

2

I have a Silverlight application hosted in an ASP.NET site, through which I'm starting an HttpWebRequest to a Generic Handler in order to save a CSV file to the user's machine.

From the Silverlight app, a Uri is constructed with parameters to make the CSV file server-side. A button is clicked which triggers the following:

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);

Now here is the ProcessRequest code from the 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);
}

Here is the HttpResponse header information that comes back when the Save File Dialogue refuses to appear:

{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

When I navigate to localhost/HttpDownloadHandler.ashx while the site is up, without initiating it from within the Silverlight app - the Save File Dialogue appears just fine, it seems to be a case where Silverlight is not accepting the response header properly.

Is there anything that can be done to address this? I'm open to suggestions for changing the way I'm doing this of course.

+1  A: 

The response is going to Silverlight, not to the web browser (so the browser won't handle the CSV file and display a file save dialog). You need to initiate the request from the web browser directly (through JavaScript for example). You could use Silverlight's HTML/JavaScript bridge to do this pretty easily.

A reasonable example of the JavaScript bridge can be found here.

You need to add some logic like this:

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

And then in the 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>

Also, you probably could do the same trick through the HTML DOM, from within Silverlight entirely. The link above has the basics regarding that as well.

WPCoder
Thanks this is a much better solution for what I was trying to do. I ended up using a hidden iFrame and setting its src attribute through the suggested Javascript function - then called it from Silverlight with the .Invoke, and avoided using the HttpWebRequest altogether. Thanks!
Jeff Dalley
+1  A: 

As far as I know, Save Dialog will only be invoked in the Button click event, so when you receive http response, you will not get permission to open save dialogbox at all.

What you should do is, in your any button click event, probably download button, in the click event, you should call File Dialog and open the file stream that you will be using later on when you receive web server's response.

Akash Kava