I'm using RestRequest to make a POST to web service. Response is in JSON format, but I get it in response.Content as ASCII, and Data is null. code is:
var request = new RestRequest(api, Method.POST);
request.RequestFormat = DataFormat.Json;
request.AddObject(data);
RestClient client = new RestClient("http://IP:PORT/proto");
client.ExecuteAsync<jLoginResponse>(request, (response) =>
{
var resource = response.Data;
});
and here response.Data is empty, and Content is
{"uid":"1234"}
jLoginResponse is declared as
[DataContract]
public class jLoginResponse
{
public string uid { get; set; }
}
but it's not getting deserialized automatically as it should.
The class should have the members marked with DataMember, like this:
[DataContract]
public class jLoginResponse
{
[DataMember]
public string uid { get; set; }
}
Related
I am trying to consume my api from another api, so I am using an HttpClient. My code Looks as follows:
public async Task<List<TeamName>> GetIpAddressDetails()
{
HttpClient client = new HttpClient();
try
{
HttpResponseMessage httpResponse = await client.GetAsync(adminURL);
var content = await httpResponse.Content.ReadAsStringAsync();
var resp = new StringContent(JsonConvert.SerializeObject(content), System.Text.Encoding.UTF8, "application/json");
return content
What I am trying to achieve is map the response which gets returned as JSON from my other API into a list of TeamName, the TeamName POCO matches exactly to what is in the API. It looks like this:
public class TeamName
{
[JsonProperty("guid")]
public Guid Guid { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("priorityNumber")]
public int PriorityNumber { get; set; }
}
I am confused on how to return the content as a list of TeamName
You can use DeserializeObject method from Newtonsoft.Json.JsonConvert class like this:
var response = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<List<TeamName>>(response);
I have deployed a REST API in IIS, in which a GET method returns an Arraylist of Student Class. How can I consume XML root Element "ArrayOfStudent" in c# using HttpClient? Below is the code I have written so far.
API get method
[HttpGet]
[ResponseType(typeof(IEnumerable<Student>))]
public IHttpActionResult Get()
{
using (handler) //handler is just EF code to get data
{
return Ok(handler.Get());
}
}
API XML response
<ArrayOfStudent xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/Com.CompanyName.Component.Entity">
<Student>
<Id>1</Id>
<Name>John</Name>
</Student>
</ArrayOfStudent>
Http Client Code
static void Main(string[] args)
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:55587/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
Task<HttpResponseMessage> responseTask = client.GetAsync("api/Student");
responseTask.Wait();
///////Error is on this line of code ////////
var ListTask = responseTask.Content.ReadAsAsync<IEnumerable<Student>>();
ListTask.Wait();
IEnumerable<Student> list = ListTask.Result;
return list;
}
Inner Exception
Inner Exception 1:
SerializationException: Error in line 1 position 150. Expecting element 'ArrayOfStudent' from namespace 'http://schemas.datacontract.org/2004/07/Com.CompanyName.ApiAgent.Entity'.. Encountered 'Element' with name 'ArrayOfStudent', namespace 'http://schemas.datacontract.org/2004/07/Com.CompanyName.Component.Entity'.
Student class -- Simple
using System;
namespace Com.CompanyName.Entity
{
public class Student
{
public long Id { get; set; }
public string Name { get; set; }
}
}
Your xml is being serialized by the server with the DataContractSerializer. You can tell, because the namespace in your xml is http://schemas.datacontract.org/2004/07/Com.CompanyName. By default, the DataContractSerializer creates an xml namespace of http://schemas.datacontract.org/2004/07/{namespace}, where {namespace} is the C# namespace your class is defined in.
So on the server side, your student class is defined like so:
namespace Com.CompanyName
{
public class Student
{
public long Id { get; set; }
public string Name { get; set; }
}
}
Notice the difference in namespace. Your Student class is defined in namespace Com.CompanyName.Entity, which is why the DataContractSerializer has difficulty understanding the returned xml. Simply changing the namespace for your Student class to Com.CompanyName would solve your problem.
However, this is pretty annoying, because that would mean you'd have to define all those classes in the same namespace as the server, and that would couple client and server very tightly. Fortunately, you can define your xml namespaces, and that is what I'd recommend you to do. Always use explicit namespace for your xml data contracts, to make the interchange more robust for future internal changes.
On both the server and client side, define your Student class like this:
[DataContract(Namespace = "http://companyname.com/schemas/student")]
public class Student
{
[DataMember]
public long Id { get; set; }
[DataMember]
public string Name { get; set; }
}
Now, we've defined a new namespace, and the xml would be serialized with the specified namespace. Because of this, it does not matter in which C# namespace you've defined your class anymore. Your xml would become something like this:
<ArrayOfStudent xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://companyname.com/schemas/student">
<Student>
<Id>1</Id>
<Name>John</Name>
</Student>
</ArrayOfStudent>
You could also generate your C# classes from your xml. There are several tools available for this.
I apologize for the irrelevance earlier I needed to see the student class before I give you the answer, you must change your student class or create new ones as models and pass them to your entity, you need to include the following two classes in order to serialize your XML to your desired object / list
[XmlRoot("ArrayOfStudent")]
public class ArrayOfStudent
{
[XmlElement("Student")]
public IEnumerable<Student> Students { get; set; }
}
public class Student
{
[XmlElement("Id")]
public int Id { get; set; }
[XmlElement("Name")]
public string Name { get; set; }
}
The Code you need to serialize from xml to object:
HttpResponseMessage response = client.GetAsync("api/Student");
var readAsStringAsync = response.Content.ReadAsStringAsync();
string result = readAsStringAsync.Result;
XmlSerializer serializer = new XmlSerializer(typeof(ArrayOfStudent));
using (TextReader reader = new StringReader(result))
{
ArrayOfStudent result = (ArrayOfStudent) serializer.Deserialize(reader);
}
The below is just to improve your design it is not necessary.
It is always recommended to use generic code for this kind of requests as the below class it saves you alot of time and u can use it almost anywhere.
public class ApiResult<T>
{
public IEnumerable<T> List { get; set; }
public T Object { get; set; }
public string Message { get; set; }
public bool Success { get; set; }
public HttpStatusCode StatusCode { get; set; }
public string Url { get; set; }
public static ApiResult<T> Post(string uri, string url, string token = null)
{
using (var client = new HttpClient())
{
client.Timeout = TimeSpan.FromMilliseconds(1800000);
client.BaseAddress = new Uri(uri);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
if (!string.IsNullOrEmpty(token))
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", token);
}
HttpResponseMessage response = client.PostAsync(url, null).Result;
return Result(response);
}
}
public static ApiResult<T> Get(string uri, string url, string token = null)
{
using (var client = new HttpClient())
{
client.Timeout = TimeSpan.FromMilliseconds(1800000);
client.BaseAddress = new Uri(uri);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
if (!string.IsNullOrEmpty(token))
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", token);
}
HttpResponseMessage response = client.GetAsync(url).Result;
return Result(response);
}
}
private static ApiResult<T> Result(HttpResponseMessage response)
{
ApiResult<T> result = response.Content.ReadAsAsync<ApiResult<T>>().Result;
if (response.StatusCode == HttpStatusCode.Unauthorized || response.StatusCode == HttpStatusCode.Forbidden)
{
result.StatusCode = response.StatusCode;
}
if (response.IsSuccessStatusCode)
{
result.Success = true;
}
return result;
}
}
now you can write your main method this way if you implement the above class:
static void Main(string[] args)
{
// both Uri & Url u can get it from ur app.config or web.config to make it easier to edit on publish saves you alot of time.
string Uri = "http://localhost:55587";
string Url = "api/Student";
string token = "yourtoken"; //(optional)
ApiResult<Student> result = ApiResult<Student>.Get(Uri, "/" + Url, token);
if(result.Success && result.List.Any())
{
IEnumerable<Student> list = result.List;
return list;
}
else
//return error if result.success is false else there are no records...
}
In my api I have a class with a few fields including one of type object. I insert an object of another class into that field. Then I return the entire class back to the program calling the api. In that program, I can convert the entire result to the class it was originally, but I can't convert the object field back to it's original class. What am I missing?
API
public class APIResponse
{
public int statusCode { get; set; }
public string errorMessage { get; set; }
public object returnObject { get; set; }
}
[HttpPost("CompleteCustomFilterOrder")]
[Produces("application/json", Type = typeof(APIResponse))]
public APIResponse GetItem
{
ItemDTO item = new ItemDTO();
item.ID = 12345
item.Name = "Widget";
item.Status = "Active";
APIResponse response = new APIResponse();
response.statusCode = 98765;
response.errorMessage = "Success!";
response.returnObject = item;
return response;
}
Program calling API
var client = new RestClient(url + "GetItem");
var request = new RestRequest(Method.GET);
var apiResponse = client.Execute<APIResponse>(request);
APIResponse response = apiResponse.Data;
ItemDTO item = (ItemDTO)response.returnObject;
Response correctly gets converted back to a class, but item throws the error
Unable to cast object of type 'System.Collections.Generic.Dictionary`2[System.String,System.Object]' to type 'ProjectName.BusinessLogicLayer.Classes.ItemDTO'.
The ItemDTO class is identical in both programs except for the namespace.
You are reciving JSON object as a response so direct cast won't work. You need to deserialize this object using eg. JsonConvert from Newtonsoft.Json.
Btw. did you consider making APIResponse a generic class ?
public class APIResponse<T> where T: class
{
public int statusCode { get; set; }
public string errorMessage { get; set; }
public T returnObject { get; set; }
}
I've been struggling for quite a while, but now I managed to successfully pull JSON data from a web API.
My code so far (only a test snippet thus far):
var url = "http://www.trola.si/bavarski";
string text;
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.Method = WebRequestMethods.Http.Get;
request.Accept = "application/json";
var json = (HttpWebResponse)request.GetResponse();
using (var sr = new StreamReader(json.GetResponseStream()))
{
text = sr.ReadToEnd();
}
As far as pulling data goes, this is ok, right?
Well here's where it gets a bit confusing. There are a lot resources online and all of them differ quite a bit. Do I need to create a class that will hold the data and { get; set; } too?
Would RESTsharp or Json.NET make my job easier? Any suggestions are appreciated.
You do not need any third party JSON libs.
Get the data to a string. You have already done this.
Create your data classes. I like igrali's idea of using Visual Studio to do it. But if the data is simple just write the class yourself:
[DataContract]
public class PersonInfo
{
[DataMember]
public string FirstName { get; set; }
[DataMember]
public string LastName { get; set; }
}
Deserialize from the string to the classes:
I like to use this generic helper:
public static T Deserialize<T>(string json)
{
using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(json)))
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
T obj = (T)serializer.ReadObject(stream);
return obj;
}
}
And then call it like this:
PersonInfo info = (PersonInfo)JsonHelper.Deserialize<PersonInfo>(s);
First of all, you will want to create classes that represent the JSON model you received. There's more than one way to do it - you can use json2csharp or even better, the Visual Studio feature called Paste JSON As Classes (find it in: Edit -> Paste Special -> Paste JSON As Classes).
Once you have the classes, you can use Json.NET to help you with the JSON response. You probably want to deserialize the string (JSON) you received to C# objects. To do it, you can just call the JsonConvert.DeserializeObject method.
var myObject = JsonConvert.DeserializeObject<MyClass>(json);
where MyClass is any kind of type you are deserializing to.
There's a WebApi client that will take care of all of the serialization for you.
http://www.asp.net/web-api/overview/advanced/calling-a-web-api-from-a-net-client
Here's a sample:
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:9000/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// New code:
HttpResponseMessage response = await client.GetAsync("api/products/1");
if (response.IsSuccessStatusCode)
{
Product product = await response.Content.ReadAsAsync<Product>();
Console.WriteLine("{0}\t${1}\t{2}", product.Name, product.Price, product.Category);
}
}
Json.net helps a lot with this. You can deserialize to anonymous types or POCO objects. I hope below solution helps you get started.
async Task Main()
{
using (var client = new HttpClient())
{
using (var request = new HttpRequestMessage())
{
request.RequestUri = new Uri("http://www.trola.si/bavarski");
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Method = HttpMethod.Get;
var result = await client.SendAsync(request);
string jsonStr = await result.Content.ReadAsStringAsync();
Result obj = JsonConvert.DeserializeObject<Result>(jsonStr);
obj.Dump();
}
}
}
// Define other methods and classes here
public class Result
{
[JsonProperty(PropertyName = "stations")]
public Station[] Stations { get; set;}
}
public class Station
{
[JsonProperty(PropertyName = "number")]
public string Number { get; set; }
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "buses")]
public Bus[] Buses { get; set; }
}
public class Bus
{
[JsonProperty(PropertyName = "direction")]
public string Direction { get; set; }
[JsonProperty(PropertyName = "number")]
public string Number { get; set; }
[JsonProperty(PropertyName = "arrivals")]
public int[] Arrivals { get; set; }
}
I have read one answer on atlassian https://answers.atlassian.com/questions/79902/using-httpclient-c-to-create-a-jira-issue-via-rest-generates-bad-request-response where one user created a JIRA issue by the following code. I adapted it but get an error by using a self-build class issue with ObjectContent
Http.HttpContent content = new Http.ObjectContent<Issue>(data, jsonFormatter);
The compiler wont accept it. Does anybody know why?
public string CreateJiraIssue()
{
string data= #"{ ""fields"": {
""project"":
{
""key"": ""HELP""
},
""summary"": ""Test Ticket"",
""description"": ""Creating of an issue using project keys and issue type names using the REST API"",
""issuetype"": {
""name"": ""Ticket""
},
""assignee"": { ""name"": ""user"" }
}
}";
string postUrl = "https://xxx.jira.com/rest/api/2/";
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
client.BaseAddress = new System.Uri(postUrl);
byte[] cred = UTF8Encoding.UTF8.GetBytes("username:password");
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(cred));
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
System.Net.Http.Formatting.MediaTypeFormatter jsonFormatter = new System.Net.Http.Formatting.JsonMediaTypeFormatter();
System.Net.Http.HttpContent content = new System.Net.Http.ObjectContent<Issue>(data, jsonFormatter);
System.Net.Http.HttpResponseMessage response = client.PostAsync("issue", content).Result;
if (response.IsSuccessStatusCode)
{
string result = response.Content.ReadAsStringAsync().Result;
return result;
}
else
{
return response.StatusCode.ToString();
}
And using
namespace IOnotification_System
{
public class Issue
{
public Fields fields { get; set; }
public Issue()
{
fields = new Fields();
}
}
public class Fields
{
public Project project { get; set; }
public string summary { get; set; }
public string description { get; set; }
public Assignee assignee { get; set; }
public IssueType issuetype { get; set; }
public Fields()
{
project = new Project();
issuetype = new IssueType();
}
}
public class Project
{
public string key { get; set; }
}
public class IssueType
{
public string name { get; set; }
}
public class Assignee
{
public string name { get; set; }
}
}
EDIT
The message clearly says that System.Net.Http.ObjectContent() expects an Issue object for its first parameter. I expect there is another message right after that saying that there is no conversion possible from a string to an Issue.
You are passing a string to a method that expects an Issue object. The formatter is used to convert an Issue object to a Json string.
You already have the string, so there is no point in trying to convert it. You only need the formatter if you have an Issue instance which you want to convert to a Json string. You can use the StringContent class and use its Headers property to add any headers not already set on the client, eg:
var content=new StringContent(data);
Original
What is the error message and what kind of project are you using? The System.Net.Http.Formatting namespace is part of ASP.NET Web API. Are you building an ASP.NET application, a console application, something else?
Unless you ARE building an ASP.NET site this code won't work. If your only issue is how to parse Json requests, just use another Json deserialization class. Json.NET is a very popular choice.
In any case there is no reason to use a Json class to convert a string to an HttpContent object containing that exact same string. You can use the StringContent class and use its Headers property to add any headers not already set on the client.
The following does the magic:
var content = new StringContent(data, Encoding.UTF8, "application/json");