📜 ⬆️ ⬇️

ASP.NET MVC Lesson B. Json

The purpose of the lesson. Learn to work with json format. Tools for working with json. Writing third-party requests, authorization through receiving data from facebook and vkontakte. Ajax to work with json (rewrite authorization). Site API

Json and Json.net

Json is a textual data format based on Javascript.
Sample data in Json:
{ "firstName": "", "lastName": "", "address": { "streetAddress": " ., 101, .101", "city": "", "postalCode": 101101 }, "phoneNumbers": [ "812 123-1234", "916 123-4567" ] } 



In my practice I worked with json with such applications as yandex.maps api, facebook api, vk api, bronni api (this is such a travel portal), and even when working with a bitcoin wallet. To do this, use the JSON.net library from http://james.newtonking.com/pages/json-net.aspx .
We study it in more detail:

')
Eliminate
 PM> Get-Package Json.net Id Version Description/Release Notes -- ------- ------------------------- Newtonsoft.Json 4.5.1 Json.NET is a popular high-performance... PM> Install-Package Newtonsoft.Json Successfully installed 'Newtonsoft.Json 4.5.11'. Successfully added 'Newtonsoft.Json 4.5.11' to LessonProject. 


Documentation
This link is documentation. We will start with a simple conversion of an object to json format and back. Create LessonProject.Console and make it a default project. Add a User type:

 public class User { public string Id { get; set; } public string Name { get; set; } public string FirstName { get; set; } public string MiddleName { get; set; } public string LastName { get; set; } public string UserName { get; set; } public string Gender { get; set; } public string Email { get; set; } } 


Create an object and convert to json:
 var user = new User() { Id = "404", Email = "chernikov@gmail.com", UserName = "rollinx", Name = "Andrey", FirstName = "Andrey", MiddleName = "Alexandrovich", LastName = "Chernikov", Gender = "M" }; var jsonUser = JsonConvert.SerializeObject(user); System.Console.Write(jsonUser); System.Console.ReadLine(); 


Result:
 {"Id":"404","Name":"Andrey","FirstName":"Andrey","MiddleName":"Alexandrovich","LastName":"Chernikov","UserName":"rollinx","Gender":"M","Email":"chernikov@gmail.com"} 

Let's try the opposite:
  var jsonUserSource = "{\"Id\":\"405\",\"Name\":\"Andrey\",\"FirstName\":\"Andrey\",\"MiddleName\":\"Alexandrovich\",\"LastName\":\"Chernikov\",\"UserName\":\"rollinx\",\"Gender\":\"M\",\"Email\":\"chernikov@gmail.com\"}"; var user2 = JsonConvert.DeserializeObject<User>(jsonUserSource); 


And we get the result:



Those. works in both directions. But a little complicate. For example, let's set Gender through the enumerated types Male and Female, and it is Male and Female that must be passed to json. And Id is a numeric value:
 public class User { public enum GenderEnum { Male, Female } public int Id { get; set; } public string Name { get; set; } public string FirstName { get; set; } public string MiddleName { get; set; } public string LastName { get; set; } public string UserName { get; set; } public GenderEnum Gender { get; set; } public string Email { get; set; } } 


We try the first part:
 var user = new User() { Id = 404, Email = "chernikov@gmail.com", UserName = "rollinx", Name = "Andrey", FirstName = "Andrey", MiddleName = "Alexandrovich", LastName = "Chernikov", Gender = User.GenderEnum.Male }; var jsonUser = JsonConvert.SerializeObject(user); 


Result:
 {"Id":404,"Name":"Andrey","FirstName":"Andrey","MiddleName":"Alexandrovich","LastName":"Chernikov","UserName":"rollinx","Gender":0,"Email":"chernikov@gmail.com"} 

Add:
 [JsonConverter(typeof(StringEnumConverter))] public enum GenderEnum { Male, Female } 


Result:
 {"Id":404,"Name":"Andrey","FirstName":"Andrey","MiddleName":"Alexandrovich","LastName":"Chernikov","UserName":"rollinx","Gender":"Male","Email":"chernikov@gmail.com"} 


Already better. Check back - everything is ok. We study other attributes that define fine tuning rules. For example, in json-format there will be names in the Hungarian record of the type first_name:
 [JsonObject] public class User { [JsonConverter(typeof(StringEnumConverter))] public enum GenderEnum { Male, Female } [JsonProperty("id")] public int Id { get; set; } [JsonProperty("name")] public string Name { get; set; } [JsonProperty("first_name")] public string FirstName { get; set; } [JsonProperty("middle_name")] public string MiddleName { get; set; } [JsonProperty("last_name")] public string LastName { get; set; } [JsonProperty("user_name")] public string UserName { get; set; } [JsonProperty("gender")] public GenderEnum Gender { get; set; } [JsonProperty("email")] public string Email { get; set; } } 


Result:
 {"id":404,"name":"Andrey","first_name":"Andrey","middle_name":"Alexandrovich","last_name":"Chernikov","user_name":"rollinx","gender":"Male","email":"chernikov@gmail.com"} 


To describe the list, add the Photo class:
 [JsonObject] public class Photo { [JsonProperty("id")] public int Id { get; set; } [JsonProperty("name")] public string Name { get; set; } } 


And add to User:
 [JsonProperty("photo_album")] public List<Photo> PhotoAlbum { get; set; } 


Result:
 {"id":404,"name":"Andrey","first_name":"Andrey","middle_name":"Alexandrovich","last_name":"Chernikov","user_name":"rollinx","gender":"Male","email":"chernikov@gmail.com","photo_album":[{"id":1,"name":"  "},{"id":2,"name":"    "}]} 

Everything is simple and predictable.
Let us consider a difficult case, for example, when for Gender we need to describe not Male \ Female, but M \ F. To do this, create a class for parsing GenderEnumConverter:
 public class GenderEnumConverter : JsonConverter { public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var value = reader.Value.ToString(); if (string.Compare(value, "M", true) == 0) { return User.GenderEnum.Male; } if (string.Compare(value, "F", true) == 0) { return User.GenderEnum.Female; } return User.GenderEnum.Male; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var obj = (User.GenderEnum)value; // Write associative array field name writer.WriteValue(value.ToString().Substring(0,1)); } public override bool CanConvert(Type objectType) { return false; } } 


And install this converter to handle
 [JsonConverter(typeof(GenderEnumConverter))] public enum GenderEnum { Male, Female } 


In general, converters can be infinitely difficult to parse json data. You can handle atypical records of dates, complex data structures, form the serialization of their classes.

Work with facebook

All this is understandable and boring, so we are working with the facebook API. Entertainment to all! For a start we will get the project LessonProject.FacebookAPI. Add Json.NET there and link it with the main project.

On facebook you need to get ApplicationID at:
https://developers.facebook.com/apps



We create, we receive:


We will be interested in AppID and AppSecret.
Add this data to Config / FacebookSetting.cs (we already know how to do it):
 public class FacebookSetting : ConfigurationSection { [ConfigurationProperty("AppID", IsRequired = true)] public string AppID { get { return this["AppID"] as string; } set { this["AppID"] = value; } } [ConfigurationProperty("AppSecret", IsRequired = true)] public string AppSecret { get { return this["AppSecret"] as string; } set { this["AppSecret"] = value; } } } 


Communication with Facebook is as follows:


Create an interface that will implement our FacebookSetting (to be backward compatible) (LessonProject.FacebookAPI / IFbAppConfig.cs):
 public interface IFbAppConfig { string AppID { get; } string AppSecret { get; } } 

Add to FacebookSetting (/Global/Config/FacebookSetting.cs):
 public class FacebookSetting : ConfigurationSection, IFbAppConfig 

Using our AppID, we go through the type string:
 https://www.facebook.com/dialog/oauth?client_id=136398216534301&redirect_uri=http%3A%2F%2Flocalhost%3A54484%2FFacebook%2FToken&scope=email 

And it looks like this:



If we click "Go to application" - then we are forwarded to the page
localhost:54484/Facebook/Token localhost:54484/Facebook/Token with the code parameter by which we can get the token (which is valid for a while). We execute such request:
 https://graph.facebook.com/oauth/access_token?client_id=136398216534301&redirect_uri=http://localhost:54484/Facebook/Token&client_secret=e6de78fd40596f00e225dce861b34a1a&code=AQAScKUYKGpzwijzT3Y3SHjNOd4Q5nsyrYPdJaPhX-88r-wBOuMrdimL8h82bGv3HAh7TL6oJyZ0gNgiB8BcCeH8G_Zj7h6hlft_BFbOfIJIZJB9nKW6Q4iR3a0VVImxM0QYJas3eVg4qtYNkqUcWbgXDSK2JENcuomUX38haxFUFdKXrVjL1acNZSocESsx6nfx_FyF_QlbwnUO5cwogrLp 

What we get the answer:
 access_token=AAAB8Da8ZBmR0BAMCOx5293ZArYvFu5oRkmZCrwZAbvpWZB3ZCLBeiooslyYPZBVwHjxSpe3KzJ4VLFPIxwwf0D6TIEiM5ApzU8EMoDpOxE4uAZDZD&expires=5183977 

We need this access_token, save it, and with it we request the data by reference:
 https://graph.facebook.com/me?access_token=AAAB8Da8ZBmR0BAImiTO9QwuUXbgHPLZBQWmAyZBUkjR2A37aVNs4vaqaFmt6h1ZBvurUpvN95EXddy5d6J1ldZA2jWTxSd3eZBHlYMzKwdxgZDZD 


To which he answers us:
 {"id":"708770020","name":"Andrey Chernikov","first_name":"Andrey","last_name":"Chernikov","link":"http:\/\/www.facebook.com\/chernikov1","username":"chernikov1","gender":"male","email":"chernikov\u0040gmail.com","timezone":2,"locale":"ru_RU","verified":true,"updated_time":"2013-03-06T15:01:28+0000"} 


And this we will bring to the class FbUserInfo (LessonProject.FacebookAPI / FbUserInfo.cs):
 [JsonObject] public class FbUserInfo { [JsonProperty("id")] public string Id { get; set; } [JsonProperty("name")] public string Name { get; set; } [JsonProperty("first_name")] public string FirstName { get; set; } [JsonProperty("last_name")] public string LastName { get; set; } [JsonProperty("link")] public string Link { get; set; } [JsonProperty("username")] public string UserName { get; set; } [JsonProperty("gender")] public string Gender { get; set; } [JsonProperty("email")] public string Email { get; set; } [JsonProperty("locale")] public string Locale { get; set; } [JsonProperty("timezone")] public double? Timezone { get; set; } [JsonProperty("verified")] public bool? Verified { get; set; } [JsonProperty("updated_time")] public DateTime? updatedTime { get; set; } } 

All the above work is concluded in FbProvider.cs (LessonProject.FacebookAPI / Provider.cs):
 public class FbProvider { private static string AuthorizeUri = "https://graph.facebook.com/oauth/authorize?client_id={0}&redirect_uri={1}&scope=email"; private static string GetAccessTokenUri = "https://graph.facebook.com/oauth/access_token?client_id={0}&redirect_uri={1}&client_secret={2}&code={3}"; private static string GetUserInfoUri = "https://graph.facebook.com/me?access_token={0}"; private static string GraphUri = "https://graph.facebook.com/{0}"; public IFbAppConfig Config { get; set; } public string AccessToken { get; set; } public string Authorize(string redirectTo) { return string.Format(AuthorizeUri, Config.AppID, redirectTo); } public bool GetAccessToken(string code, string redirectTo) { var request = string.Format(GetAccessTokenUri, Config.AppID, redirectTo, Config.AppSecret, code); WebClient webClient = new WebClient(); string response = webClient.DownloadString(request); try { var pairResponse = response.Split('&'); AccessToken = pairResponse[0].Split('=')[1]; return true; } catch (Exception ex) { return false; } } public JObject GetUserInfo() { var request = string.Format(GetUserInfoUri, AccessToken); WebClient webClient = new WebClient(); string response = webClient.DownloadString(request); return JObject.Parse(response); } } 


Where


Notice how we use WebClient.DownloadString - and op-pa, we obtained the necessary data from the depths of the Internet.

We go further. Create a FacebookController controller (/Areas/Default/Controllers/FacebookController.cs):
 public class FacebookController : DefaultController { private FbProvider fbProvider; protected override void Initialize(System.Web.Routing.RequestContext requestContext) { fbProvider = new FbProvider(); fbProvider.Config = Config.FacebookSetting; base.Initialize(requestContext); } public ActionResult Index() { return Redirect(fbProvider.Authorize("http://" + HostName + "/Facebook/Token")); } public ActionResult Token() { if (Request.Params.AllKeys.Contains("code")) { var code = Request.Params["code"]; if (fbProvider.GetAccessToken(code, "http://" + HostName + "/Facebook/Token")) { var jObj = fbProvider.GetUserInfo(); var fbUserInfo = JsonConvert.DeserializeObject<FbUserInfo>(jObj.ToString()); return View(fbUserInfo); } } return View("CantInitialize"); } } 


In Initialize we transfer to FbProvider AppID and AppSecret . After entering - we redirect to facebook with a request for user rights (permission window). If the user has already allowed us to do this so as not to ask 100 times, facebook will forward us to / Facebook / Token. If the code to get the token could not be obtained, return the View CantInitialize (/Areas/Default/Views/Facebook/CantInitialize.cshtml):
 @{ ViewBag.Title = "CantInitialize"; Layout = "~/Areas/Default/Views/Shared/_Layout.cshtml"; } <h2>CantInitialize</h2> <h3>   -  </h3> 


Otherwise, when everything is fine, then we get our token (it is saved in fbProvider) and ask for data about the user. When we receive it, we convert it into an object of the FbUserInfo class and output it to View (/Areas/Default/Views/Facebook/Token.cshtml):
 @model LessonProject.FacebookAPI.FbUserInfo @{ ViewBag.Title = "Token"; Layout = "~/Areas/Default/Views/Shared/_Layout.cshtml"; } <h2></h2> <p>      :</p> <dl class="dl-horizontal"> <dt>ID</dt> <dd>@Model.Id</dd> <dt>FirstName</dt> <dd>@Model.FirstName</dd> <dt>LastName</dt> <dd>@Model.LastName</dd> <dt>Link</dt> <dd>@Model.Link</dd> </dl> 


Client Code / Server Code (Access-Control-Allow-Origin)


Consider another situation where all this interaction is concluded in js-files, we only perform ajax requests. Change the token method code. We receive user data not by server code from facebook, but are passed to View a token (/Areas/Default/Controllers/FacebookController.cs:Token):
 public ActionResult Token() { if (Request.Params.AllKeys.Contains("code")) { var code = Request.Params["code"]; if (fbProvider.GetAccessToken(code, "http://" + HostName + "/Facebook/Token")) { /* var jObj = fbProvider.GetUserInfo(); var fbUserInfo = JsonConvert.DeserializeObject<FbUserInfo>(jObj.ToString()); */ ViewBag.Token = fbProvider.AccessToken; return View(); } } return View("CantInitialize"); } 


Let's change Token.cshtml (/Areas/Default/Views/Facebook/Token.cshtml):
 @{ ViewBag.Title = "Token"; Layout = "~/Areas/Default/Views/Shared/_Layout.cshtml"; } @section scripts { @Scripts.Render("~/Scripts/default/facebook-token.js") } @Html.Hidden("Token", ViewBag.Token as string) <h2></h2> <p>      :</p> <dl class="dl-horizontal"> <dt>ID</dt> <dd id="ID"></dd> <dt>FirstName</dt> <dd id="FirstName"></dd> <dt>LastName</dt> <dd id="LastName"></dd> <dt>Link</dt> <dd id="Link"></dd> </dl> 


Add facebook-token.js (/Scripts/default/facebook-token.js):
 function FacebookToken() { _this = this; this.ajaxGetUserInfo = "https://graph.facebook.com/me?access_token="; this.init = function () { var token = $("#Token").val(); $.ajax({ type: "GET", dataType: 'json', url: _this.ajaxGetUserInfo + token, success: function (data) { $("#ID").text(data.id); $("#FirstName").text(data.first_name); $("#LastName").text(data.last_name); $("#Link").text(data.link); } }) } } var facebookToken = null; $().ready(function () { facebookToken = new FacebookToken(); facebookToken.init(); }); 


We start, we check. All perfectly. But pay attention to this parameter in the http-answer:



Access-control-allow-origin is a parameter that, when set, allows you to make ajax requests from a browser to a site hosted on another domain.
Those. if we are accessing $ .ajax () from the browser and there is no response in this header, an error is generated:
Origin localhost:8080 is not allowed by Access-Control-Allow-Origin
To do this, create an attribute that will add this header if we want to organize access to our site from other sites (/Atribute/AllowCrossSiteJson.cs):
 public class AllowCrossSiteJsonAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { filterContext.RequestContext.HttpContext.Response.AddHeader("Access-Control-Allow-Origin", "*"); base.OnActionExecuting(filterContext); } } 


Add use. For example, the action method OK, which will always return {“result”: “OK”} (/Areas/Default/Controllers/HomeController.cs):
 [AllowCrossSiteJson] public ActionResult OK() { return Json(new { result = "OK" }, JsonRequestBehavior.AllowGet); } 


That's all for Json and work with facebook. You can practice and work with authorization and interaction with vk api. Documentation here: http://vk.com/developers.php .

All sources are located at https://bitbucket.org/chernikov/lessons

Source: https://habr.com/ru/post/176087/


All Articles