6

What I want is to protect my developer key while making an Ajax call to a cross-domain. Before I would just go straight to the url and plug in my key. Like this

$.ajax({
    url: "https://na.api.pvp.net/api/lol/na/v2.3/team/TEAM-ID?api_key=mykey",
    type: "GET",
    data: {},
    success: function (json) {
        console.log(json);
            console.log(json[teamID].name);
            console.log(json[teamID].fullId);
            console.log(json[teamID].roster.ownerId);
            console.log(json[teamID].tag);
    },
    error: function (error) {}
});

This would give me the following Object, which I could easily parse out.

enter image description here

However, as mentioned, any person could easily grab my key during this process. So I decided to move this action to my Controller (yes I know there shouldn't be business logic here, but it is more secure and this is a quick process).

So what I am doing now is running my Javascript, which calls the Controller for a Json return.

Javascript

$.ajax({
        url: "/Competitive/teamLookUp",
        type: "POST",
        data: "ID=" + teamID,
        success: function (json) {
            console.log(json);
        }, 
        error: function(error) {
        }
   });

And my Controller takes that in and attempts to return the JSON.

[HttpPost]
public ActionResult teamLookUp(string ID)
{
    HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create("https://na.api.pvp.net/api/lol/na/v2.3/team/" + ID + "?api_key=myKey");
    myReq.ContentType = "application/json";
    var response = (HttpWebResponse)myReq.GetResponse();
    string text;

    using (var sr = new StreamReader(response.GetResponseStream()))
    {
        text = sr.ReadToEnd();
    }
    return Json(new { json = text });
}

However during this processs I return a string that is not a JSON object, thus cannot be parsed by my script.

It returns the entire json as one long string.

enter image description here

At this point I tried to add the following to my Controller.

    var json2 = JsonConvert.DeserializeObject(text);
    return Json(new { json = json2 });

But all that returned was some empty Object.

enter image description here

I have been trial and error'ing, searching, and guessing for the past 4 hours. I have no idea what to try anymore. I just want my Controller to pass back an Object that can be readable again like this. (Or at least some sort of formatted json object)

$.ajax({
        url: "/Competitive/teamLookUp",
        type: "POST",
        data: "ID=" + teamID,
        success: function (json) {
            console.log(json);
                console.log(json[teamID].name);
                console.log(json[teamID].fullId);
                console.log(json[teamID].roster.ownerId);
                console.log(json[teamID].tag);
        },
        error: function (error) {}
    });
Austin
  • 3,010
  • 23
  • 62
  • 97
  • Have you tried using a `JsonResult` instead of `ActionResult`? – Colin Bacon Aug 05 '14 at 15:17
  • Try using `$.getJSON` and returning the json string from the secondary call directly. – asawyer Aug 05 '14 at 15:17
  • @ColinBacon would this be with returning my `json2`? – Austin Aug 05 '14 at 15:19
  • @asawyer so return `text` then do `$.getJSON` instead of `$.ajax`? – Austin Aug 05 '14 at 15:20
  • If you want to de-serialise that return JSON text, then I think you need to give it the object structure to turn it into rather than `var`. json2csharp.com generates that nice and easily, just copy your JSON string and it'll generate a class for you. If the return structure isn't always the same then pass it through as text as you are doing then call JSON.parse on it at the ajax success end. – Klors Aug 05 '14 at 15:27

5 Answers5

5

Your method doesn't appear to need to be a POST as it is just getting data rather than modifying it. Therefore you could set it to be a GET instead.

Example

[HttpGet]
public JsonResult teamLookUp(string ID)
{
    // Your code

    return Json(text, JsonRequestBehavior.AllowGet); 
}
Colin Bacon
  • 15,436
  • 7
  • 52
  • 72
  • with `model` being what? (Sorry new to this stuff) – Austin Aug 05 '14 at 15:22
  • @Austin Sorry, for your example it would be `text`. Have updated the answer – Colin Bacon Aug 05 '14 at 15:24
  • I have been retrying this with no success. I feel like doing `using (var sr = new StreamReader(response.GetResponseStream())) { text = sr.ReadToEnd(); }` breaks the JSON's original object/structure... – Austin Aug 05 '14 at 17:44
  • Try returning a simple model instead of the stream result and see if that works first. e.g. `var text = { id = 1, title = "bacon"}` – Colin Bacon Aug 06 '14 at 08:03
3

Here's an excerpt from your code:

[HttpPost]
public ActionResult teamLookUp(string ID)
{

    HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create("https://na.api.pvp.net/api/lol/na/v2.3/team/" + ID + "?api_key=myKey");
    myReq.ContentType = "application/json";


    // here's how to set response content type:
    Response.ContentType = "application/json"; // that's all

    var response = (HttpWebResponse)myReq.GetResponse();
    string text;

    using (var sr = new StreamReader(response.GetResponseStream()))
    {
        text = sr.ReadToEnd();
    }

    return Json(new { json = text }); // HERE'S THE ERRING LINE
}

Based on the response you received, I could understand that text already contains you desired JSON.

Now replace return Json(new { json = text }); with Json(text); and that should fix it.

To answer your question in the comments, here's how you can read the response data:

$.ajax({
    url: "/Competitive/teamLookUp",
    type: "POST",
    data: "ID=" + teamID,
    dataType: "json", // type of data you're expecting from response
    success: function (json) {
        console.log(json);
            console.log(json[teamID].name);
            console.log(json[teamID].fullId);
            console.log(json[teamID].roster.ownerId);
            console.log(json[teamID].tag);
    },
    error: function (error) {}
});
Igwe Kalu
  • 14,286
  • 2
  • 29
  • 39
  • `cannot implicitly convert type string to actionresult` Is this still trying to modify it? – Austin Aug 05 '14 at 15:27
  • I made a mistake, but I've corrected it now. Check my edited answer. – Igwe Kalu Aug 05 '14 at 15:38
  • Okay, any idea on how to read it? I.e. If I want to read the property `name`, **[JSON Format Image](http://imgur.com/cShorEN)**. I can see the entire JSON string if I say `console.log(json["json"]);`, but usually I would just call `json[userID].name;`. Why do I need to specify json twice in my JS to see the string? And how do I pull it apart it now? – Austin Aug 05 '14 at 15:50
  • By the way, consider accepting this as the answer if it (helped) solve your problem :). – Igwe Kalu Aug 05 '14 at 15:51
  • I will once I can get it to work haha. :) I have tried doing `console.log(json["json"].userID.name);` and `console.log(json["json"][userID].name);` With `userID` being the `Team-lotsofnumbers` – Austin Aug 05 '14 at 15:53
  • @Austin, considering how you have defined your success callback function, you should rather say: `console.log(json);` because your response data is exactly inside the argument `json`. – Igwe Kalu Aug 05 '14 at 15:54
  • just calling `console.log(json)` returns a string I think. It says I cannot read the property of 'name' when I try saying `console.log(json[userID].name);` – Austin Aug 05 '14 at 16:00
  • Here is the Inspector with the error and `console.log(json)`. **[Inspector Error](http://imgur.com/vYgeE7a)** – Austin Aug 05 '14 at 16:05
  • You can force the JSON string to be converted to a JavaScript object by setting the `dataType` property of the AJAX request setting. I'll update the answer... Meanwhile, if you're getting a string, it means `myReq.ContentType = "application/json";` didn't work as expected. What you should be creating is a response object, not a request. But a quick fix would be to set `dataType` as shown in my answer.. – Igwe Kalu Aug 05 '14 at 16:10
  • Finally here's how to set response type: `Response.ContentType = "application/json";`. That done, you don't have to consider `dataType` in your request setting. – Igwe Kalu Aug 05 '14 at 16:15
  • `console.log(json[userID].name);` still can't read property of 'name'. :( And why did you comment out the HttpWebRequest? This is a cross-domain call. – Austin Aug 05 '14 at 16:16
  • ah! OK, please uncomment it, but make sure you add `Response.ContentType = "application/json";` – Igwe Kalu Aug 05 '14 at 16:20
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/58712/discussion-between-austin-and-sultanbaby). – Austin Aug 05 '14 at 16:35
0

I think the problem lies where you say return Json(new {json = text;}). That's telling the json serializer to dump all your data into a property in the json obect called 'json', which is what you're seeing in the response.

Try return Json(text) instead.

Dan Schnau
  • 1,505
  • 14
  • 17
0

Ending up using WebClient

[HttpPost]
        public ActionResult teamLookUp(string ID)
        {
            string text = "";
            try
            {
                using (var webClient = new System.Net.WebClient())
                {
                    webClient.Encoding = Encoding.UTF8;
                    var json2 = webClient.DownloadString("https://na.api.pvp.net/api/lol/na/v2.3/team/" + ID + "?api_key=myKey");
                    return Json(json2);
                }
            }
            catch (Exception e)
            {
                text = "error";
            }
            return Json(new { json = text });
        }

And I parsed it like normal,

    $.ajax({
        url: "/Competitive/teamLookUp",
        type: "POST",
        data: "ID=" + ID,
        dataType: "json", 
        success: function (resp) {
            if (resp["json"] == "error") {
                // error reaching server
            } else {
                // successfully reached server
            }                
            json = JSON && JSON.parse(resp) || $.parseJSON(resp);

            var userID = ID;
            teamName = json[userID].name;
            teamID = json[userID].fullId;
            teamCPT = json[userID].roster.ownerId;
            teamTag = json[userID].tag;
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {
             // error
        }
    });
Austin
  • 3,010
  • 23
  • 62
  • 97
0

I was having the same issue as the original poster: the ReadToEnd() call result escapes special characters and thus doesn't look like JSON to the receiving end, but then I saw a similar question answered here and thought others reading this might find it helpful as well.

To summarize: Deserializing in the Controller which the original poster tried was key, but also as others have pointed out, the return doesn't need the new {} call.

So pieced together:

using (var sr = new StreamReader(endpointResponse.GetResponseStream())) {
    var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
    var jsonObject = serializer.DeserializeObject(sr.ReadToEnd());
    return Json(jsonObject, JsonRequestBehavior.AllowGet);
}
Community
  • 1
  • 1
LoJo
  • 142
  • 2
  • 11