How to get en post nested object in asp.net webapi? - asp.net

A newbie question.
Just started on asp.net web api project that going well getting and posting plain object.
But how doe I Get and Post object with child objects. The same as Order with order items.
Who cab help me with a simple example without advance features as OData etc.
Thanks in advance
Anders Pedersen

Create your object graph and return it so that web API can serialize it for you. So, you will create an Order object like this and return it.
public Order Get(int id)
{
var order = new Order() { Id = id };
order.OrderItems.Add(new OrderItem() { ProductName = "Cool Item", Price = 12.34 };
order.OrderItems.Add(new OrderItem() { ProductName = "Cool Item", Price = 12.34 };
return order;
}
If you now look at the JSON or XML payload of this GET response, that is what you will need to post to get the binding work with your POST action method.
public HttpResponseMessage Post(Order order) { ... }

Related

Getting Error "No best type found for implicitly-typed array" using LINQ and Entity Framework

var allCategories = _db.Categories;
var result = from c in allCategories
select new[] { c.CategoryID, c.Name, c.SortOrder};
when i use select new {...}; but i get result as object array.
But when i try to use select new[] {...}; i get the following error.
No best type found for implicitly-typed array
Below is my complete Method of Controller.
public ActionResult Index(jQueryDataTableParamModel param=null)
{
if (Request.IsAjaxRequest() && param!=null)
{
var allCategories = _db.Categories;
var result = from c in allCategories
select new[] { c.CategoryID, c.Name, c.SortOrder};
return Json(new
{
sEcho = param.sEcho,
iTotalRecords = allCategories.Count(),
iTotalDisplayRecords = allCategories.Count(),
aaData = result
},
JsonRequestBehavior.AllowGet);
}
return View();
}
If i am doing wrong way please guide me to right path as i am new to ASP.NET MVC.
Update:
I am getting JSON Array like this:
{"sEcho":"1","iTotalRecords":3,"iTotalDisplayRecords":3,"aaData":[{"CategoryID":1,"Name":"Computers","SortOrder":1},{"CategoryID":2,"Name":"Laptops","SortOrder":1},{"CategoryID":3,"Name":"Mobiles","SortOrder":1}]}
where as i want Json Array like this
{"sEcho":"1","iTotalRecords":3,"iTotalDisplayRecords":3,"aaData":[["CategoryID":1,"Name":"Computers","SortOrder":1],["CategoryID":2,"Name":"Laptops","SortOrder":1],["CategoryID":3,"Name":"Mobiles","SortOrder":1]]}
The reason behind this is datatables is not showing data in grid, so i guess this is the reason behind not showing data. As i am getting the array like the second one in PHP and datatables works fine over there.
Update: 2
I Just Tried like this,
select new [] { Convert.ToString(c.CategoryID), c.Name, Convert.ToString(c.SortOrder)};
as everything will become string. but now after this error is gone i am not getting the error relating to converting of string.
LINQ to Entities does not recognize the method 'System.String
ToString(Int32)' method, and this method cannot be translated into a
store expression.
What you want is not valid JSON. You could create it using string concatenation, but it would not be possible to parse it as JSON.
If you want to produce something that is possible to parse as JSON you need to follow the syntax rules.
If you want a collection of keys and values, you use an object:
{"CategoryID":1,"Name":"Computers","SortOrder":1}
If you use an array you only have values, no keys:
[1,"Computers",1]
Ok. After many tries i finally got the result somehow in arrays rather then in objects.
Many Thanks to #Guffa Also as He helped Alot in Fixing my Problem.
He Finally gave the reply
new object[] { c.CategoryID.ToString(), c.Name, c.SortOrder.ToString() }
Which should have solved my problem but for some reason asp.net LINQ is not supporting .ToString() functions and i did got this error.
The array type 'System.Object[]' cannot be initialized in a query result. Consider using 'System.Collections.Generic.List1[System.Object]' instead.
I am not good in ASP.NET MVC specially with Databases and C# so i start back to googeling.
I think i had to call query two times.
first result is converted ToList() ToList i think supports the ToString Function.
var categories = (from category in allCategories
select category).ToList();
Then here when returning Json i wrote the query back again but here i used the Categories from First Query and then .ToString was working.
return Json(new
{
sEcho = param.sEcho,
iTotalRecords = allCategories.Count(),
iTotalDisplayRecords = allCategories.Count(),
aaData = (from category in categories
select new [] {category.CategoryID.ToString(), category.Name, category.SortOrder.ToString()}).ToArray()
},
It gave me the result i wanted but i am not sure if this is the right way. What should be the Professional way or good way to have a secure and quick response controller. As i don't want to make a mess of my Code.

How to return complex JSON object from asp.net mvc Action Method

I am working on an asp.net mvc web application, that connects to two different DB (I name them dbA & dbB). Currently I need to create a JSON object that contains values from different tables.
The two table are as follow:-
Table Technology from dbA, have the following fields:-
>> dbAID , Tag , db2ID
While table Resource from dbB have:-
>> Db2ID , Name
I have the following Action method:-
public ActionResult AutoComplete(string term)
{
var tech = dbA.Technology.Where(a=>a.Tag.StartWith(term));//select all technology that have their tags start with passed term
var db2IDList = tech.Select(a=>a.db2ID).ToArray();//create a list of db2ID
var resource = dbB.Resource.Where(db2IdList.Contains(a=>a.dbBID));//get the resource based on the db2IDList
JsonResult j = newJsonResult();
//here I want the json to contain the Technology.Tag + ResoruceNane, where the join is based on the db2Id stored insdie the technology table
}
So can anyone adivce what is the best way to construct my JSON object?
Thanks
Anonymous Types: http://msdn.microsoft.com/en-us/library/bb397696.aspx
And the framework provided JsonResult, generated by the Json(object) helper.
e.g. return Json(new { field1 = resource.fieldOne, field2 = resource.fieldTwo })
you can construct a List i think its easier :
List<Object> _return=new List<object>();
_return.Add(Technology.Tag);
_return.Add(ResoruceName);
Return Json(new {Success=true, _return});
//and then cast get these object in your Javascript , it would be an easy to use array

asp.net mvc api json wrapper

I Have an asp.net mvc api controller method that has a List as its return method. When called it returns this json data:
[
{
"AreaName": null,
"AreaId": 0,
"DestinationName": "Alanya",
"DestinationId": 14,
"CountryName": "Tyrkiet",
"CountryId": 15
},
{
"AreaName": null,
"AreaId": 0,
"DestinationName": "Antalya",
"DestinationId": 113,
"CountryName": "Tyrkiet",
"CountryId": 15
}
]
Earlier when I had this method in an asp.net mvc it would look similar to this:
earlier json data:
{
"ContentEncoding":{
"IsSingleByte":true,
"BodyName":"iso-8859-1",
"EncodingName":"Western European (Windows)",
"HeaderName":"Windows-1252",
"WebName":"Windows- 1252",
"WindowsCodePage":1252,
"IsBrowserDisplay":true,
"IsBrowserSave":true,
"IsMailNewsDisplay":true,
"IsMailNewsSave":true,
"EncoderFallback":{
"MaxCharCount":1
},
"DecoderFallback":{
"MaxCharCount":1
},
"IsReadOnly":true,
"CodePage":1252
},
"ContentType":"application/json;",
"Data":
and then the above list would be added inside of the Data wrapper
My question is - how do I get this "wrapper" format back when using the asp.net mvc web api ?
Your JSON is a normal format for list of objects and the second one, older represents an object. So when you need it - just return object.
Probably, in the older version (normal mvc) you did return something like this:
return JsonResult(new { Data = myList });
now, in WebApi, you do this:
return myList;
That explains why the old result has all that formatting around. To get back the old wrapper in your WebApi, I guess you would simply do something like this:
return new { Data = myList };
If the above does not work, try the following:
Change the return type of your method to HttpResponseMessage
use this:
return Request.CreateResponse(HttpStatusCode.OK, new { Data = myList });
I don't have anything to debug at the moment but both of the above should work. If they don't, it is probably because the serialization-deserialization does not like anonymous objects (this may give you more problems with XML than JSON actually).
Anyway, in my opinion it is a lot easier to live with the new version of your object, mainly because it does NOT have a (noisy) wrapper around :)
You can create your own returning type, something like this:
public class InvoiceResult
{
public int numberResultTotal;
public int numberResultPaged;
public List<InvoiceDTO> results;
}
ASP.NET Web API will convert it to JSON, XML or any other format and your client will get something like this:
<InvoiceResult>
<numberResultPaged>20</numberResultPaged>
<numberResultTotal>999999</numberResultTotal>
<results>
<InvoiceDTO>
<ID>110</ID>
<Active>2</Active>
<Date>01/01/2010</Date>
</InvoiceDTO>
<InvoiceDTO>...</InvoiceDTO>
<InvoiceDTO>...</InvoiceDTO>
<InvoiceDTO>...</InvoiceDTO>
</results>
</InvoiceResult>

How to improve ASP.NET MVC3 app data query performance?

There is a book management system web application based on ASP.NET MVC3. When click the book index page, data query is very slow and user has to wait for several seconds for response. The code of Action Index in BookController below:
public ViewResult Index(string sortOrder, int? page)
{
ViewBag.NameSortParam = string.IsNullOrEmpty(sortOrder) ? "desc" : "";
ViewBag.CurrentSort = sortOrder;
BookModel books = from b in db.Books select b; // db = new BookContext();
switch (sortOrder) {
case "desc":
books = books.OrderByDescending(b => b.Name);
break;
default:
books = books.OrderBy(b => b.Name);
break;
}
int pageSize = 15;
int pageNumber = (page ?? 1);
return View(books.ToPagedList(pageNumber, pageSize));
}
In my opinion, the main reason of slow is that server does not response to client until all data are ready. This process takes much time.
I do not know how to solve this problem, is there any method to improve data query performance in this case? Thank you!
update:
backend database is SQL Server Compact Edition 4.0
UPDATE
I update my logic code below, orderby is used before skip and take statements. Everything goes well. Thank you all for help.
books = (from b in db.Books
orderby b.Name descending
select b)
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToList();
You are loading in all your books before filtering the dataset to just the data you need (by using ToPagedList). Change your query and use the Skip and Take methods instead of ToPagedList.
Put index on the Books.Name column (with included columns: include those which are needed in your list), on the C# side query only the filed you are needed:
books.Select(x => new {
x.Name,
x.Author,
x.Description,
x.ID }).ToPagedList(/*....*/)./*...*/)
And i would look after the ToPagedList implementation.
Use OutputCaching on the method, varying by the two parameters. An overview of this is detailed here.
[OutputCache(Duration=60,VaryByParam="sortOrder;page;")]
public ViewResult Index(string sortOrder, int? page)

Returning a column from a linked table in LINQ to SQL

My problem is that I am trying to return a simple query that contains an object Story. The Story object has a UserId in the table which links to aspnet_users' UserId column. I have created a partial class for Story that adds the UserName property since it does not exist in the table itself.
The following query gets all stories; however, a pagination helper takes the query and returns only what's necessary once this is passed back to the controller.
public IQueryable<Story> FindAllStories(){
var stories = (from s in db.Stories
orderby s.DateEntered descending
select new Story
{
Title = s.Title,
StoryContent = s.StoryContent,
DateEntered = s.DateEntered,
DateUpdated = s.DateUpdated,
UserName = s.aspnet_User.UserName
}
);
return stories;
}
When the helper does a .count() on the source it bombs with the following exception:
"Explicit construction of entity type 'MyWebsite.Models.Story' in query is not allowed."
Any ideas? It's not a problem with the helper because I had this working when I simply had the UserName inside the Story table. And on a side note - any book recommendations for getting up to speed on LINQ to SQL? It's really kicking my butt. Thanks.
The problem is precisely what it tells you: you're not allowed to use new Story as the result of your query. Use an anonymous type instead (by omitting Story after new). If you still want Story, you can remap it later in LINQ to Objects:
var stories = from s in db.Stories
orderby s.DateEntered descending
select new
{
Title = s.Title,
StoryContent = s.StoryContent,
DateEntered = s.DateEntered,
DateUpdated = s.DateUpdated,
UserName = s.aspnet_User.UserName
};
stories = from s in stories.AsEnumerable() // L2O
select new Story
{
Title = s.Title,
StoryContent = s.StoryContent,
...
};
If you really need to return an IQueryable from your method and still need the Username of the user you can use DataContext.LoadOptions to eagerload your aspnet_user objects.
See this example.

Resources