How to make api request to Github repository using restapi? - c#

I am new to C# and .Net and I am struggling to understand this issue that I have. I feel like what I have is enough but not sure myself. SO if someone can just review the codes that I have below and tell me were to correct and what is wrong.Thank you
This is my Model Class
namespace github_project.Models
{
public class GithubItem
{
public int Id { get; set; }
public string UserName { get; set; }
public string FullName { get; set; }
public string City { get; set; }
public string ProjectName { get; set; }
public string Commits { get; set; }
public double Rating { get; set; }
public string AvatarUrl { get; set; }
}
}
and this is my database context
namespace github_project.Database
{
public class GithubContext : DbContext
{
public DbSet<GithubItem> Github { get; set; }
public GithubContext(DbContextOptions<GithubContext> options) : base(options)
{
}
public GithubItem ItemsList()
{
List<GithubItem> build = Build();
GithubItem itemsList = JsonConvert.DeserializeObject<GithubItem>(build);
return itemsList;
}
public List<GithubItem> Build()
{
var getData = GetGithubData();
return System.Text.Json.JsonSerializer.Deserialize<List<GithubItem>>(getData);
}
private string GetGithubData()
{
string username = "**test**";
var url = "https://api.github.com/users/" + username + "/repos?page=1";
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.Method = "GET";
request.ContentType = "application/json";
request.UserAgent = "TestApp";
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
StreamReader reader = new StreamReader(response.GetResponseStream());
return reader.ReadToEnd();
}
}
public List<GithubItem> getGithub() => Github.Local.ToList<GithubItem>();
}
}
finally this is my controller
[HttpGet("/github")]
public GithubItem GetAll()
{
return _context.ItemsList();
}
I am making a request to github in order to get all the data and use it in my request. I am getting an here here of converting Collection.List to String on this method below:
public GithubItem ItemsList()
{
List<GithubItem> build = Build();
GithubItem itemsList = JsonConvert.DeserializeObject<GithubItem>(**build**);
return itemsList;
}
Can someone help me and and someone tell me what is wrong here??? Thank you

You cannot deserialize an object or convert an object from List<GithubItem> to single GithubItem. That is what you are doing.
As you can see, you have build:
List<GithubItem> build = Build();
This build variable is a List<GithubItem. Now you want to convert it to single using Deserialize of JsonConvert?
You can just get one record, whatever your requirements is using this code:
GithubItem itemsList = build.FirstOrDefault();
That would build fine. But this is just an example since I am not sure what is your requirement. If you need to filter your record, you can also pass a argument on FirstOrDefault:
GithubItem itemsList = build.FirstOrDefault(x => x.UserName == "John");
That would also work fine.

Related

JSON string will not deserialize into the type specified

I have the following bit of code whihc sends a Http POST request to the server. The server reurns a 400 Bad request response along with a error object in the form of Json:
namespace MyApp.Shared.Dtos.Response
{
public class ErrorItem
{
public string Message { get; set; }
public string Tag { get; set; }
}
public class ErrorDto
{
public string Title { get; set; }
public List<ErrorItem> Errors { get; set; } = new();
}
}
namespace Accounting.Web.Services
{
public interface IHttpService
{
Task<T> Get<T>(string uri);
Task<T> Post<T>(string uri, object value, bool addBearerToken = false);
public ErrorDto Error { get; set; }
}
public class HttpService: IHttpService
{
private HttpClient _httpClient;
public ErrorDto Error { get; set; }
public HttpService(HttpClient httpClient)
{
_httpClient = httpClient;
_stateService = stateService;
}
public async Task<T> Post<T>(string uri, object value)
{
var request = new HttpRequestMessage(HttpMethod.Post, uri);
request.Content = new StringContent(JsonSerializer.Serialize(value), Encoding.UTF8, "application/json");
return await sendRequest<T>(request, addBearerToken);
}
private async Task<T> sendRequest<T>(HttpRequestMessage request)
{
using var response = await _httpClient.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.BadRequest)
{
var result = await response.Content.ReadAsStringAsync();
Error = JsonSerializer.Deserialize<ErrorDto>(result);
//..
}
else
{
//..
}
}
}
}
The result correctly recieves the following response from the server as a JSON string:
{"title":"Username or password is incorrect","errors":[]}
And I can confirm by inspecting var result, it has the above value.
However, It doesn't seem deserialize into the ErrorDto class as one would expect it to:
Error = JsonSerializer.Deserialize(result);
But I simply cannot see any problems with the code, it looks like it should be working.
*** UPDATE ***
My server API code returrns the JSOn using the same DTO class (It's a shared class) using the following code:
[HttpPost("authenticate")]
public ActionResult Authenticate(AuthenticateRequest loginRequest)
{
var auth = _userService.Authenticate(loginRequest);
ErrorDto error = new()
{
Title = "Username or password is incorrect"
};
if (auth.user == null || auth.token == null)
{
return BadRequest(error);
}
return Ok(auth.user.ConvertToDto(auth.token));
}
By default System.Text.Json is case-sensitive. There are multiple options to handle this, for example by providing corresponding JsonSerializerOptions:
var json = #"{""title"":""Username or password is incorrect"",""errors"":[]}";
var errorDto = JsonSerializer.Deserialize<ErrorDto>(json, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
Or marking properties with corresponding JsonPropertyNameAttribute:
public class ErrorItem
{
[JsonPropertyName("message")]
public string Message { get; set; }
[JsonPropertyName("tag")]
public string Tag { get; set; }
}
public class ErrorDto
{
[JsonPropertyName("title")]
public string Title { get; set; }
[JsonPropertyName("errors")]
public List<ErrorItem> Errors { get; set; } = new();
}
UPD
From How to customize property names and values with System.Text.Json doc:
Note
The web default is camel case.
If you want to switch from camel case to the naming policy used for DTOs you can do the following:
builder.Services.AddControllers()
.AddJsonOptions(opts => opts.JsonSerializerOptions.PropertyNamingPolicy = null);

ASP.NET Core - Post requests using [HttpPost] not working for objects

I am trying to do a simple POST request but it seems like [FromBody] cannot seem to understand more than 2 parameters.
The request:
[HttpPost]
public IEnumerable<EnergyMarket> addEnergy([FromBody] EnergyMarket energyMarket)
{
_energyMarketService.addEnergy(energyMarket.Name, energyMarket.StockIPO, energyMarket.EnergyPrice);
return _energyMarketService.Energies;
}
The object:
public class EnergyMarket
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("stockipo")]
public string StockIPO { get; set; }
[JsonProperty("price")]
public double EnergyPrice { get; set; }
public EnergyMarket() { }
public EnergyMarket(string name, string stockIPO, double val)
{
this.Name = name;
this.StockIPO = stockIPO;
this.EnergyPrice = val;
}
}
Request (Content-type is application/json)
{
"name": "Air Canada",
"stockipo": "AC.TO",
"price": 13.12
}
When I go on POSTMAN and put the following request, it works fine for the first two parameters, but the price is always 0. When I changed the price from a double to string, the string was always null.
Default ASP.NET Core model binder does not use Newtonsoft.Json property attributes. Therefore, we should implement it ourselves.
Firstly, create implementation of IModelBinder that would read request body and deserialize it using Newtonsoft JsonConvert.DeserializeObject method
public class NewtonsoftModelBinder : IModelBinder
{
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
string valueFromBody = string.Empty;
using (var sr = new StreamReader(bindingContext.HttpContext.Request.Body))
{
valueFromBody = await sr.ReadToEndAsync();
}
if (string.IsNullOrEmpty(valueFromBody))
{
return;
}
try
{
var model = JsonConvert.DeserializeObject(valueFromBody, bindingContext.ModelType);
bindingContext.Result = ModelBindingResult.Success(model);
}
catch
{
bindingContext.ModelState.TryAddModelError(
"", "Model can not be deserialized.");
}
return;
}
}
Then there are multiple ways how we can apply it to our code, but the easiest one is to put it as attribute on your EnergyMarket class
[ModelBinder(BinderType = typeof(NewtonsoftModelBinder))]
public class EnergyMarket
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("stockipo")]
public string StockIPO { get; set; }
[JsonProperty("price")]
public double EnergyPrice { get; set; }
public EnergyMarket() { }
public EnergyMarket(string name, string stockIPO, double val)
{
this.Name = name;
this.StockIPO = stockIPO;
this.EnergyPrice = val;
}
}
Finally, we can see correct data in controller after Postman request

RestSharp StatusCode vs IsSuccessful

I have the following class
public class Customer
{
public Customer()
{
Project = new HashSet<Project>();
}
public uint Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
public HashSet<Project> Project { get; set; }
}
And the following method
protected async Task<IRestResponse> ApplyRequest<T>(string resource,
Method method, T data) where T: class, new()
{
var client = new RestClient(_connectionConfig.BaseUrl);
client.FollowRedirects = false;
var request = new RestRequest(resource, method);
request.RequestFormat = RestSharp.DataFormat.Json;
request.AddParameter("application/json",
JsonConvert.SerializeObject(data), ParameterType.RequestBody);
//request.AddJsonBody(data);
//This also doesn't work
var response2 = await client.ExecuteTaskAsync<T>(request);
return response2;
}
Now if I call this method with Post method, the return statuscode is "created" (and it is actually created). However, the property IsSuccessful gives "false" and the error message is
"Unable to cast object of type 'SimpleJson.JsonArray' to type
'System.Collections.Generic.IDictionary`2[System.String,System.Object]'."
Is this usual, or am I doing something wrong?
Thanks
It's not successful because you had a serialisation error. I also see you logged it on GiTHub and got the same response. https://github.com/restsharp/RestSharp/issues/1064

How dererialize response json in controller

i want to deserialize var in controller
how can i deserialize string s
public Boolean ajoutermodule(string nom, string s, int cv)
{
return true;
}
string s is sent from javascript after stringify var s = JSON.stringify(table)
can someone help me how fix this issue and thank you very much
put this in your controller :
JavaScriptSerializer js = new JavaScriptSerializer();
modules[] persons = js.Deserialize<modules[]>(s);
and creat class modules
public class modules
{
public int id { get; set; }
public string nom { get; set; }
}

Add root element to json serialization in C#

I am creating a webservice to interact with a JSON API.
This API needs me to set a root element in the string, but I just cannot get this to happen.
The place where it all happens - right now just made to just show me the json output:
public static string CreateServiceChange(ServiceChange change)
{
string json = JsonConvert.SerializeObject(change);
return json;
}
This is the ServiceChange class:
public class ServiceChange
{
[JsonProperty("email")]
public string requesterEmail { get; set; }
[JsonProperty("description_html")]
public string descriptionHtml { get; set; }
[JsonProperty("subject")]
public string subject { get; set; }
[JsonProperty("change_type")]
public int changeType { get; set; }
}
And the method binding those two together:
public string copyTicketToChange(int ticketId)
{
HelpdeskTicket.TicketResponseActual ticket = getHelpdeskTicket(ticketId);
ServiceChange change = new ServiceChange();
change.descriptionHtml = ticket.Response.DescriptionHtml;
change.requesterEmail = ticket.Response.Email;
change.subject = ticket.Response.Subject;
change.changeType = 1;
string Response = Dal.CreateServiceChange(change);
return Response;
}
The json output looks like this right now:
{"email":"test#test.com","description_html":"This is a test","subject":"Testing","change_type":1}
And the expected output:
{ "itil_change": {"email":"test#test.com","description_html":"This is a test","subject":"Testing","change_type":1}}
How can I achieve this?
Wrap your ServiceChange into another object and serialize it:
public class ServiceChangeWrapper
{
public ServiceChange itil_change { get; set; }
}
...
public static string CreateServiceChange(ServiceChange change)
{
ServiceChangeWrapper wrapper = new ServiceChangeWrapper { itil_change = change};
string json = JsonConvert.SerializeObject(wrapper);
return json;
}

Categories