views:

1335

answers:

3

I have an ASP.net web service that I'm using for a web application which returns a either XML or JSON data to me, depending on the function I call. This has been working well thus far, but I've run into a problem. I want to create an "export" link on my page that will download a JSON file. The link is formatted very simply:

<a href="mywebserviceaddress/ExportFunc?itemId=2">Export This Item</a>

As you might imagine, this should export item 2. So far so good, yes?

Problem is that since I'm not specifically requesting that the accepted content type is JSON, ASP.net absolutely refuses to send back anything but XML, which just isn't appropriate for this situation. The code is essentially as follows:

    [WebMethod]
    [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
    public Item ExportItem(int itemId)
    {
        Context.Response.AddHeader("content-disposition", "attachment; filename=export.json"); //Makes it a download

        return GetExportItem(itemId);
    }

Despite my specifying the ResponseFormat as JSON, I always get back XML unless I request this method via AJAX (using Google Web Toolkit, BTW):

    RequestBuilder builder = new RequestBuilder(RequestBuilder.POST, "mywebserviceaddress/ExportFunc");
    builder.setHeader("Content-type","application/json; charset=utf-8");
    builder.setHeader("Accepts","application/json");
    builder.sendRequest("{\"itemId\":2}", new RequestCallback(){...});

That's great, but AJAX won't give me a download dialog. Is there any way to force ASP.net to give me back JSON, regardless of how the data is requested? It would seem to me that not having a manual override for this behavior is a gross design oversight.


QUICK ANSWER:

First off, let me say that I think that womp's answer is probably the better way to go long term (Convert to WCF), but deostroll led me to the answer that I'll be using for the immediate future. Also, it should be noted that this seems to work primarily because I wanted just a download, may not work as well in all situations. In any case, here's the code that I ended up using to get the result I wanted:

    [WebMethod]
    [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
    public void ExportItem(int itemId)
    {
        Item item = GetExportItem(itemId);            

        JavaScriptSerializer js = new JavaScriptSerializer();
        string str = js.Serialize(item);

        Context.Response.Clear();
        Context.Response.ContentType = "application/json";
        Context.Response.AddHeader("content-disposition", "attachment; filename=export.json");
        Context.Response.AddHeader("content-length", str.Length.ToString());
        Context.Response.Flush();
        Context.Response.Write(str);
    }

Please note the return type of void (which means that your WDSL will be next to useless for this function). Returning anything will screw up the response that is being hand-built.

+1  A: 

Here are two forums threads for your reference:

http://forums.asp.net/t/1118828.aspx

http://forums.asp.net/p/1054378/2338982.aspx#2338982

I have no clear idea. They say on concentrating on setting the content type to application/json. I haven't worked with wcf before, but I think you can make use of the Response object.

Set the content type on the response object. Do a response.write passing your json data as string and then do a response.end.

deostroll
Both of those links show how to correctly retrieve JSON data when using AJAX requests. As I mentioned my AJAX is working correctly but I need to get JSON back in a situation where AJAX is not an option. The question is, at it's heart, on the server side how do I force AJAX to always be returned.
Toji
to be clear u want it after a postback, right?
deostroll
Yes, that's a much simpler way of putting it, thanks :)
Toji
(Oh, and in my previous comment it should have read "on the server side how do I force *JSON* to always be returned"
Toji
have u tried manipulating the response object. Look at the code mentioned in the following url for ref http://www.example-code.com/vbdotnet/aspdotnet_zip_response.aspYou can access the response object using httpcontext.current.response. Hope this helps.
deostroll
That last link did it for me. Took a small bit of tweaking but it works (code posted in the question for reference). Thanks!
Toji
hey instead of editing ur own question, u cud hve answered ur own question...they give u badges for that !
deostroll
+3  A: 

Asp.net web services are SOAP-based web services. They'll always return XML. The Ajax libraries came along and the ScriptMethod stuff was introduced, but it doesn't change the underlying concept of it.

There's a couple things you can do.

WebMethods are borderline obsolete with the introduction of WCF. You might consider migrating your web services to WCF, in which you'll have much greater control over the output format.

If you don't want to do that, you can manually serialize the result of your webservice calls into JSON, and the service will wrap that in a SOAP header. You would then need to strip out the SOAP stuff.

womp
I definitely consider this to be the "better" answer, but unfortunately I don't have the time available to me to to a full-fledged conversion right now. This is the route I will take on future projects, though. Thanks for the tip.
Toji
A: 

Just thought I'd throw this out there since it wasn't mentioned previously... if you use WebServices with ASP.NET 3.5, JSON is the default return format. It also comes along with JSON serializer so you can stop using the JavascriptSerializer.

This article on Rick Strahl's blog talks about the strongly-typed conversion you can do between server side classes and JSON objects from the client.

I've recently completed a project using this new JSON stuff in .NET 3.5, and I'm extremely impressed with the performance. Maybe it's worth a look...

Cory Larson
Thanks! I'll take a look!
Toji