I am writing a basis class to simplify REST API calls. I am now at the point to decide how to handle the requests and responses from the perspective of the Serialize/Deserialize objects.
Below is a POST request example. Basically it receives the path and handle the response using as JToken.Parse.
Example
public async Task<Uri> PostCreateAsync(string entitySetName, object body)
{
try
{
using (var message = new HttpRequestMessage(HttpMethod.Post, entitySetName))
{
message.Content = new StringContent(SystemTextJson.SerializeToString(body));
message.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
using (HttpResponseMessage response = await SendAsync(message))
{
return new Uri(response.Headers.GetValues("OData-EntityId").First());
}
}
}
catch (Exception ex)
{
throw ex;
}
}
Usage
public interface IRecord
{
Guid Id { get; set; }
string Name { get; set; }
}
public class Contact : IRecord
{
public Guid Id { get; set; } = Guid.Empty;
public string FullName { get; set; } = null!;
public string LastName { get; set; } = null!;
public string JobTitle { get; set; } = null!;
}
var contact = new Contact()
{
LastName = "Gil",
JobTitle = "Developer",
FullName = "Andre Gil"
};
var response = await _api.PostCreateAsync("contacts", contact);
First problem here. How to provide the api name "contacts" generic? Json decoration?
Second, the Id attribute cannot be sent through on POST operation. Of course, I could use JsonIgnore. But the "Id" must be sent through in case of PATCH or PUT.
Related
I'm trying to get response a external API using httpclint in .netcore5.0.
Initially I got timeout exception. So I add client.Timeout = Timeout.InfiniteTimeSpan; after adding this response is come. but it takes more than 20 mins.
But I browser I can get API result within milliseconds.
How can I get response from API with a short time. Any idea to decrease this responding time?
startup.cs
services.AddHttpClient<IHolidayService, HolidayService>("PublicHolidaysApi", c => c.BaseAddress = new Uri("https://api.xmltime.com"));
service.cs
public class HolidayService : IHolidayService
{
private readonly IHttpClientFactory _clientFactory;
private readonly HttpClient _client;
public HolidayService(HttpClient client)
{
_client = client;
client.Timeout = Timeout.InfiniteTimeSpan;
}
public HolidayService(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
_client = clientFactory.CreateClient("PublicHolidaysApi");
}
public async Task<Holiday> GetHolidays(string country,int year)
{
string url = string.Format($"/holidays?accesskey="MyAccessKey"&secretkey="MySecretKey"&version=3&country=ro&year=2021&lang=en");
var result = new Holiday();
using (var cts = new CancellationTokenSource(Timeout.InfiniteTimeSpan))
{
var response = await _client.GetAsync(url, cts.Token).ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
using var responseStream = await response.Content.ReadAsStreamAsync();
result = await JsonSerializer.DeserializeAsync<List<Holiday>>(responseStream);
}
else
{
throw new HttpRequestException(response.ReasonPhrase);
}
}
return result;
}
}
}
model
public class Holiday
{
[JsonPropertyName("urlid")]
public string UrliId { get; set; }
[JsonPropertyName("url")]
public string Url { get; set; }
[JsonPropertyName("country")]
public Country Country { get; set; }
[JsonPropertyName("name")]
public Name Name { get; set; }
[JsonPropertyName("oneliner")]
public OneLiner OneLiner { get; set; }
[JsonPropertyName("date")]
public Date Date { get; set; }
[JsonPropertyName("types")]
public List<string> Types { get; set; }
[JsonPropertyName("uid")]
public string UId { get; set; }
}
public class Country
{
[JsonPropertyName("id")]
public string Id { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; }
}
public class Name
{
[JsonPropertyName("lang")]
public string Lang { get; set; }
[JsonPropertyName("text")]
public string Text { get; set; }
}
public class OneLiner
{
[JsonPropertyName("lang")]
public string Lang { get; set; }
[JsonPropertyName("text")]
public string Text { get; set; }
}
public class Date
{
[JsonPropertyName("iso")]
public string iso { get; set; }
[JsonPropertyName("datetime")]
public DateTime? Datetime { get; set; }
}
}
There are so many possibilities in this situation and I can only give you a way to solve the problem.
First of all, we need to locate the reason why it is so slow. Is it the server or the client?
We can use packet capture tools such as Fiddler ,and then observe the corresponding network requests.
If client had send but server not response , you should think about the api limit...
And if not, the request are not send at all, may be you should the check the connection pool of the HttpClient, or the WorkThreadPool of dotnet.
there are a few problems with your question.
it doesn't compile.
it is incomplete.
it has sensitive data.
but I can get the data from API in no time. just open this link https://dotnetfiddle.net/ryjakT and run the program.
I changed few things
Return Type, it should be List
var result = new Holiday(); to var result = new List();
I am using Newtonsoft.Json for Deserialization.
you were trying to Deserialize to an incorrect model, it should be Root.
I am doing server to server communication and I am getting data back from my api. I using Http web client to do that. This is my code
public async Task<List<Report>> GetReports(string tokenType, string token, int page, int count)
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(tokenType, token);
var builder = new UriBuilder(ApiEndPointBase + "api/" + ApiVersion + "/LibraryDocument");
builder.Port = -1;
var query = HttpUtility.ParseQueryString(builder.Query);
query["page"] = page.ToString();
query["count"] = count.ToString();
builder.Query = query.ToString();
string url = builder.ToString();
var result = await client.GetAsync(url);
if (!result.IsSuccessStatusCode)
throw new Exception("");
List<Report> reports = new List<Report>();
await result.Content.ReadAsAsync<List<Report>>().ContinueWith(response =>
{
reports = response.Result;
});
return reports;
}
The issue I am having is that I am getting data from server in this format
public class Report
{
public int pK_LibraryDocument { get; set; }
public string fileName { get; set; }
public List<string> AvailableForModules { get; set; }
}
But I want data like this
public class Report
{
public int id{ get; set; }
public string fileName { get; set; }
public List<string> AvailableForModules { get; set; }
}
I would probably have other variable name changes as well. The reason for that is that I would have multiple data sources with same data but the format or name would be different. So I want to have a centralize naming for my self.
Is it possible in a not expensive (time consuming) way.
JSON.NET that is used by default for deserialization supports JsonProperty attribute for adjusting JSON field name:
public class Report
{
[JsonProperty("pK_LibraryDocument")]
public int id { get; set; }
public string fileName { get; set; }
public List<string> AvailableForModules { get; set; }
}
I am retrieving the following JSON via a POST to an API
{
"State":"Andhra_Pradesh",
"District":"Guntur",
"Fact":"SELECT",
"Description":"",
"FactDate":"",
"FactNumber":"",
"FactType":"SELECT",
"Fact":{"Id":"1"}
}
I am able to execute the Ajax request via javascript, but I also want to consume the API through C# code.
I am using the below code, but I'm not quite sure on how to add the Fact object?
var values = new Dictionary<string, string>
{
{ "State", selectedState },
{ "District", selectedDistrict },
{ "Fact", ""},
{ "FactType", ""},
{ "FactNumber", ""},
{ "Description", ""},
{"Fact", "{Id,1}" },
{"FactDate", factDate.Date.ToString() }
};
using (var httpClient = new HttpClient())
{
var content = new FormUrlEncodedContent(values);
var response = await httpClient.PostAsync("http://api.in/" + "test", content);
}
How do I add the Fact object to Dictionary?
You'll probably need to define the data you are sending as actual class before using httpclient.
If you had only name value pairs then you could have used the NameValueCollection and sent as a formurlencoded but since you have a complex type, you might consider this below.
See below.
public class Rootobject
{
public string State { get; set; }
public string District { get; set; }
public Fact Fact { get; set; }
public string Description { get; set; }
public string CaseDate { get; set; }
public string FactNumber { get; set; }
public string FactType { get; set; }
}
public class Fact
{
public string Id { get; set; }
}
Usage is as below. be sure to include a reference to System.Net.Http.Formatting.dll
var client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var model = new Rootobject { State = "Andhra_Pradesh", District = "Guntur", FactType = "SELECT", Description = "", CaseDate = "", FactNumber = "", Fact = new Fact { Id = "1"} };
var data = await client.PostAsJsonAsync("http://api.in/" + "test", model);
I think this is just a json object, you can either create a class which have the same properties of (state, district etc ..) and use json serializer
or you can create JObject using Json.Net
You can use Newtonsonft.Json to to the serializaton/deserialization job and the code will be like that.
public class Rootobject
{
[JsonProperty("State")]
public string State { get; set; }
[JsonProperty("District")]
public string District { get; set; }
[JsonProperty("Fact")]
public Fact Fact { get; set; }
[JsonProperty("Description")]
public string Description { get; set; }
[JsonProperty("CaseDate")]
public string CaseDate { get; set; }
[JsonProperty("FactNumber")]
public string FactNumber { get; set; }
[JsonProperty("FactType")]
public string FactType { get; set; }
}
public class Fact
{
[JsonProperty("Id")]
public string Id { get; set; }
}
And then, after instatiating your object, just serialize it.
Rootobject example = new Rootobject();
//Add values to the variable example.
var objectSerialized = JsonConvert.SerializeObject(example);
After that, you will have a json ready to be send wherever you want.
Just change {"Fact", "{Id,1}" } to {"Fact.Id", "1" },
I've tried other answers with people who had the same issue, but I can't get it to work. Plus I'm new to this. Any help is appreciated.
When I run this, my phone data is null.
Here's the JSON data I get back from my service.
{"GetDirectoriesResult":"[{\"id\":1,\"department\":\"Admitting\",\"subdepartment\":\"\",\"phone\":\"555-444-4013\",\"comments\":\"Press 1\"},{\"id\":2,\"department\":\"Ambulatory Surgery Center\",\"subdepartment\":\"\",\"phone\":\"555-444-4013\",\"comments\":\"\"}]"}
My Code
public class PhoneList
{
// public string GetDirectoriesResult { get; set; }
public List<Phone> Phones { get; set; } //- can't get this working
}
public class Phone
{
public int id { get; set; }
public string department { get; set; }
public string subdepartment { get; set; }
public string phone { get; set; }
public string comments { get; set; }
}
public IRestResponse<PhoneList> Execute<PhoneList>(RestRequest request) where PhoneList : new()
{
PhoneList ro = new PhoneList();
var client = new RestClient();
client.BaseUrl = BaseUrl;
// var request = new RestRequest();
request.RequestFormat = DataFormat.Json;
request.AddHeader("Content-Type", "application/json");
request.AddJsonBody(ro);
IRestResponse<PhoneList> response = client.Execute<PhoneList>(request);
if (response.ErrorException != null)
{
const string message = "Error retrieving response. Check inner details for more info.";
var Exception = new ApplicationException(message, response.ErrorException);
throw Exception;
}
return response;
}
I'm using Facebook Graph API to return user information for my app. So far I only needed to get the email as an extended property and I never had any problem with it. However, now I have to get the user birthday, but it is not working as expected. I am getting a null value.
Here is part of the class I use to return the information
using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.OAuth2;
namespace Contoso.Web.Mvc.Controls.Authentication.IdentityProviders
{
public class FacebookIdentityProvider : IdentityProvider
{
public override ActionResult Authenticate(Func<LoginParameters, ActionResult> CallbackFunction)
{
var authorization = fbClient.ProcessUserAuthorization();
var urlHelper = new UrlHelper(System.Web.HttpContext.Current.Request.RequestContext);
if (authorization == null && String.IsNullOrWhiteSpace(Parameters.AccessToken))
{
//Kick off authorization request
fbClient.RequestUserAuthorization(scope: new string[] { "email", "user_birthday"});
}
else
{
if(authorization != null)
Parameters.AccessToken = authorization.AccessToken;
var request = WebRequest.Create("https://graph.facebook.com/me?access_token=" + Uri.EscapeDataString(Parameters.AccessToken));
using (var response = request.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
var graph = FacebookGraph.Deserialize(responseStream);
var user = GetUser(graph);
var requiresExtraInformation = false;
DoFormAuthenticationAndCreateUserIfNeeded(user, out requiresExtraInformation);
if (requiresExtraInformation)
{
return RedirectToExtraInformationPage(user);
}
return CallbackFunction(Parameters);
}
}
}
return new RedirectResult(urlHelper.Action("Index"));
}
}
[DataContract]
public class FacebookGraph
{
private static DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(FacebookGraph));
[DataMember(Name = "id")]
public long Id { get; set; }
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "first_name")]
public string FirstName { get; set; }
[DataMember(Name = "last_name")]
public string LastName { get; set; }
[DataMember(Name = "email")]
public string Email { get; set; }
[DataMember(Name = "gender")]
public string Gender { get; set; }
[DataMember(Name = "user_birthday")]
public string UserBirthday { get; set; }
public static FacebookGraph Deserialize(string json)
{
if (string.IsNullOrEmpty(json))
{
throw new ArgumentNullException("jsonStream");
}
return Deserialize(new MemoryStream(Encoding.UTF8.GetBytes(json)));
}
public static FacebookGraph Deserialize(Stream jsonStream)
{
if (jsonStream == null)
{
throw new ArgumentNullException("jsonStream");
}
return (FacebookGraph)jsonSerializer.ReadObject(jsonStream);
}
}
}
When I deserialize the response I get from facebook I get all the information I need except for the user birthday (it appears as null). I checked and my facebook profile does have the user birthday.
Ok, I finally found the problem and it was a little bit silly, but I'm leaving it here in case someone else stumbles upon this.
The problem was that even though I was requesting the correct scope "user_birthday", the property in the graph object is just called "birthday", so instead of having this
[DataMember(Name = "user_birthday")]
public string UserBirthday { get; set; }
I should have this
[DataMember(Name = "birthday")]
public string UserBirthday { get; set; }
And that's it. It's working now!