WebApi HttpClient help getting collection (version .6) - wcf-web-api

I am calling on a WCF Data Services v3 Odata service.
I am having trouble getting my collection filled in the below example. I am able to get a json string of the 3 people, but if I try and get a custom collection filled, the collection has a count = 0.
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.BaseAddress = new Uri("http://localhost:7500/Wcf1.svc/People");
HttpResponseMessage resp = client.GetAsync("").Result;
string jsonString = resp.Content.ReadAsStringAsync().Result;
List<Person> personCollection = resp.Content.ReadAsAsync<List<Person>>().Result;
jsonString has 3 people in it.
personCollection has a count = 0.
the jsonString looks like this:
{"d":[
{"__metadata":{"id":"http://localhost:7500/Wcf1.svc/People(1)",
"uri":"http://localhost:7500/Wcf1.svc/People(1)",
"type":"WcfService1.Person"},
"ID":1,"Fname":"Fred","Lname":"Peters","Address1":"123 Main"},
{"__metadata":{"id":"http://localhost:7500/Wcf1.svc/People(2)",
"uri":"http://localhost:7500/Wcf1.svc/People(2)",
"type":"WcfService1.Person"},
"ID":2,"Fname":"John","Lname":"Smith","Address1":"123 Oak"},
{"__metadata":{"id":"http://localhost:7500/Wcf1.svc/People(3)",
"uri":"http://localhost:7500/Wcf1.svc/People(3)",
"type":"WcfService1.Person"},
"ID":3,"Fname":"Tom","Lname":"Anders","Address1":"123 Hill St."}]}
I must be doing something wrong, please point out my error if you can.
Thanks.
Terrence

Your content is not a List<Person>
Paste your Json into json2csharp and you'll see it.
To get a better overview what your response content is, download Json Viewer - this is a screenshot of your data:
As you can see: the Persons are a property of the Json root object.
If you wanted to use your code from above, the Json should have to look like this (or you need to access the data in the given structure mapping you classes according to the Json):
[{"__metadata":{"id":"http://localhost:7500/Wcf1.svc/People(1)",
"uri":"http://localhost:7500/Wcf1.svc/People(1)",
"type":"WcfService1.Person"},
"ID":1,"Fname":"Fred","Lname":"Peters","Address1":"123 Main"},
{"__metadata":{"id":"http://localhost:7500/Wcf1.svc/People(2)",
"uri":"http://localhost:7500/Wcf1.svc/People(2)",
"type":"WcfService1.Person"},
"ID":2,"Fname":"John","Lname":"Smith","Address1":"123 Oak"},
{"__metadata":{"id":"http://localhost:7500/Wcf1.svc/People(3)",
"uri":"http://localhost:7500/Wcf1.svc/People(3)",
"type":"WcfService1.Person"},
"ID":3,"Fname":"Tom","Lname":"Anders","Address1":"123 Hill St."}]}]
Update:
You should be able to parse your initially posted Json like this:
var json = JsonValue.Parse(response.Content.ReadAsStringAsync().Result);
var arr = json["d"];
var contact1 = arr[0];
var fname = result1["Fname"];
I have done a blog post on JsonValue and JsonArray recently. It's server side, but it should point you the direction.
2nd Update:
Using the classes from the json2csharp.com output, you can do this:
public class Metadata
{
public string id { get; set; }
public string uri { get; set; }
public string type { get; set; }
}
public class D
{
public Metadata __metadata { get; set; }
public int ID { get; set; }
public string Fname { get; set; }
public string Lname { get; set; }
public string Address1 { get; set; }
}
public class RootObject
{
public List<D> d { get; set; }
}
Usage:
var root = resp.Content.ReadAsAsync<RootObject>().Result;
var persons = root.d;
var person1 = persons[0];

Related

Sending byte array to API

I am converting web application to mobile app. We were using AjaxAsyncFileUpload in web application to save a document to the server, where AjaxAsyncFileUpload use to do the work for me. This was the code
Dim fileData As Byte() =new Byte(AjaxAsyncFileUpload.FileContent.Length-1){}
AjaxAsyncFileUpload.FileContent.Read(fileData, 0, fileData.Length)
InvestmentDeclare.DocSize = AjaxAsyncFileUpload.FileContent.Length
InvestmentDeclare.DocFileName = AjaxAsyncFileUpload.FileName
InvestmentDeclare.DocFileType = AjaxAsyncFileUpload.PostedFile.ContentType
InvestmentDeclare.Document = fileData
And then simply save this to my database.
Now while Converting this to mobile app (I am also using c# for mobile app), I am not able to pass the byte array. I am using fiddler for testing.
I have attached an image of how I'm passing it through fiddler. In my API POST method I'm getting a null value to my document variable while I'm able to get rest of my values properly.
What could be the issue? Am I not passing the byte in proper Json format?
In API:
public class AddInvestmentDeclare
{
public int EmployeeId { get; set; }
public int YearId { get; set; }
public int InvestmentId { get; set; }
public List<EmpDocument> EmpDocuments { get; set; }
}
public class EmpDocument
{
public byte[] Document { get; set; }
public string DocumentFileName { get; set; }
public long DocumentSize { get; set; }
public string DocumentType { get; set; }
}
public HttpResponseMessage Post(int YearId, [FromBody]List<AddInvestmentDeclare> InvestmentDeclared)
{
When I check my InvestDeclared list on run time I see that document variable is not filled and it is showing null. I have attached an image of that as well.
First, setup your API method in a way that it accepts just one object containing all data instead of each parameter individually.
Instead of:
public HttpResponseMessage Post([FromUri]string AccordDbName, [FromUri]String PayCareDbName, [FromUri]...)
Set it up like:
public HttpResponseMessage Post(Data dataObject)
Secondly, try sending file as a base64string.
Here is example how to do it.
Your file in JSON request should look something like this:
{ "ID":46,
"Content":"JVBERi0xLjQNCjEgMCBvYm......"
}

Using ReadAsAsync<T>() to deserialize complex Json object

I want to use ReadAsAsync() in my mvc project with .net 4.0. The result comes as null.
If I enter the uri to address bar, the result in chrome as(tag names are changed):
<ns2:MyListResponse xmlns:ns2="blablabla">
<customerSessionId>xxcustomerSessionIdxx</customerSessionId>
<numberOfRecordsRequested>0</numberOfRecordsRequested>
<moreResultsAvailable>false</moreResultsAvailable>
<MyList size="1" activePropertyCount="1">
<MySummary order="0">
<id>1234</id>
<name>...</name>
.
.
</MySummary>
</MyList>
</ns2:MyListResponse>
If I use the statement in code :
using (var client = new HttpClient())
{
var response = client.GetAsync(apiUri).Result;
var message = response.Content.ReadAsStringAsync().Result;
var result1 = JsonConvert.DeserializeObject<MyListResponse>(message);
var result2 = response.Content.ReadAsAsync<MyListResponse>().Result;
}
the message comes in string format as "{\"MyListResponse\":{\"customerSessionId\"...}" which corresponds to a json object as:
{"MyListResponse":
{"customerSessionId":"xxcustomerSessionIdxx",
"numberOfRecordsRequested":0,
"moreResultsAvailable":false,
"MyList":
{"#size":"1",
"#activePropertyCount":"1",
"MySummary":
{"#order":"0",
"id":1234,
"name":"...",
.
.
}
}
}
}
and the properties of result1 and result2 came as null or default values. Class definitions are below. I want to read the content as an object but I couldn't. What do you advice to solve this? What am I doing wrong? Thanks in advance.
public class MySummary
{
public int #Order { get; set; }
public string Id { get; set; }
public string Name { get; set; }
.
.
}
public class MyList
{
public int #Size { get; set; }
public int #ActivePropertyCount { get; set; }
public MySummary MySummary{ get; set; }
}
public class MyListResponse
{
public string CustomerSessionId { get; set; }
public int NumberOfRecordsRequested { get; set; }
public bool MoreResultsAvailable { get; set; }
public MyList MyList { get; set; }
}
I defined a new class as:
public class ResponseWrapper
{
public MyListResponse MyListResponse { get; set; }
}
then I used this wrapper with,
var result1 = JsonConvert.DeserializeObject<ResponseWrapper>(message);
var result2 = response.Content.ReadAsAsync<ResponseWrapper>().Result;
then it worked. I need only MySummary object but I should write more classes to make it work.
After reading your solution I came up with one that doesn't need an extra class:
private static async Task<U> Execute<U>(HttpClient client, string path)
{
U output = default(U);
HttpResponseMessage response = await client.GetAsync(path);
if (response.IsSuccessStatusCode)
{
var jsonAsString = await response.Content.ReadAsStringAsync();
output = JsonConvert.DeserializeObject<U>(jsonAsString);
}
else
{
throw new ApplicationException(string.Format("Response message is not OK. Issues in action: {0}", path));
}
return output;
}
For the sake of future readers, I think the correct approach is using ReadAsAsync overload that takes IEnumerable<MediaTypeFormatter> and provide a formatter with the same settings used on the server for serialization. That should fix it.
It is possible to use at client ReadAsAsync with MyListResponse directly (in consequence without ResponseWrapper). To do this, you can define "BodyStyle = WebMessageBodyStyle.Bare" in the operation contract of "apiuri" in stead of "BodyStyle = WebMessageBodyStyle.Wrapped" (server side, i.e. service contract).

RavenDB Include though collection

I'm struggling with the include function in RavenDB. In my model I have a blog post that holds a list of comments. The comment class that's used in this list holds a reference to a user.
public class BlogPost
{
public string Id { get; set; }
public List<Comment> Comments { get; set; }
public BlogPost()
{
Comments = new List<Comment>();
}
}
public class Comment
{
public string Id { get; set; }
public string Text { get; set; }
public string UserId { get; set; }
}
What I want to do is to get the blogpost and get a list of comments with the details of the user that wrote the comment to display in the UI, without querying the server for every single user (N+1).
I would be happy with some pointers on how to solve this. Thanks!
You can do that using something like:
session.Include<BlogPost>(b=>b.Comments.Select(x=>x.UserId)).Load(1);
I think this page would answer your question.
You can load multiple documents at once:
var blogSpots = session.Include<BlogPost>(x => x.Comments.Select(x=>x.UserId))
.Load("blogspot/1234", "blogspot/4321");
foreach (var blogSpot in blogSpots)
{
foreach (var userId in blogSpot)
// this will not require querying the server!!!
var cust = session.Load<User>(userId);
}

Best practices for binding MVC model to WCF service through "datamodule"?

I'm somewhat of a noob, so bear with me please.
I'm building an MVC project that gets data from a web service (WCF) as exposed by a "datamodule" class that passes parameters to the service. Right now what I have is a viewmodel that looks like this:
public String FirstName { get; set; }
public String LastName { get; set; }
public String DisplayName { get; set; }
public String Role { get; set; }
A "datamodule" class that looks like this:
private readonly ServiceClient _serviceClient = new ServiceClient();
public List<Info> GetStuff(int Id)
{
return _serviceClient.GetStuff(Id);
}
And a controller action that looks like this:
var dm = new DataModule();
var members = dm.GetStuff(96);
var team = from member in members
select new TeamModel
{
FirstName = member.FirstName,
LastName = member.LastName,
Role = member.Role,
DisplayName = member.DisplayName
};
return PartialView(team.ToList());
I don't feel like it's very clean (or MVC like) to manually bind data like this in every one of my controllers. Is there a best practices way to bind data like this?

Does Order Matter in the XML Read by the DataContractSerializer?

I have the following code:
[DataContract(Namespace = "")]
public class User
{
[DataMember]
public string UserName { get; set; }
[DataMember]
public string FullName { get; set; }
}
//Deserialization test
public void Test()
{
//CASE 1.
//string xml = "<User><UserName>john</UserName>" +
// "<FullName>John Lennon</FullName></User>";
//CASE 2.
string xml = "<User><FullName>John Lennon</FullName>" +
"<UserName>john</UserName></User>";
byte[] byteArray = Encoding.UTF8.GetBytes(xml);
User user = null;
using (MemoryStream stream = new MemoryStream(byteArray))
{
DataContractSerializer serializer =
new DataContractSerializer(typeof(User), "User", "");
user = (User)serializer.ReadObject(stream);
}
}
In case 1, FullName property isn't deserialized, but in case 2 it is deserialized properly. Why?
Because order is significant. Alphabetic order is used unless you specify the order in your DataMember attributes.
This is explained in this MSDN article.
In general, it's a good practice to always explicitly specify Order on your DataMember attributes:
[DataMember(IsRequired=true, Order=0)]
public string FullName { get; set; }
[DataMember(IsRequired=true, Order=1)]
public string UserName { get; set; }