EF Core Customize JSON Serialization with LINQ - c#

I am building out a demo for an API in .NET Core and constructing a nested JSON object that needs to get constructed through a series of LINQ queries.
My current issue is that when i get about 4 layers deep, I want to customize what actually gets serialized, more specifically, i want to "Not Include" specific navigation properties for this query specifically, but not for general purpose, only for this specific query.
My first thought was to do a DTO, but that seems like an unnecessary extra model just for this one specific case...i'd like to work with LINQ directly to manipulate for my result.
I have already added the following to my Startup.cs file to avoid cycles:
services.AddControllers().AddNewtonsoftJson(options =>
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);
I have 5 models currently in action that look like this:
public class Hotel
{
public int ID { get; set; }
public string Name { get; set; }
public string StreetAddress { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Phone { get; set; }
public List<HotelRooms> HotelRooms { get; set; }
}
public class Room
{
public int ID { get; set; }
public string Name { get; set; }
public Layout Layout { get; set; }
public List<RoomAmenities> RoomAmenities { get; set; }
public List<HotelRooms> HotelRooms { get; set; }
}
public class HotelRooms
{
public int HotelID { get; set; }
public int RoomNumber { get; set; }
public int RoomID { get; set; }
public decimal Rate { get; set; }
public bool PetFriendly { get; set; }
public Hotel Hotel { get; set; }
public Room Room { get; set; }
}
public class Amenities
{
public int ID { get; set; }
public string Name { get; set; }
// Navigation Properties
public List<RoomAmenities> RoomAmenities { get; set; }
}
public class RoomAmenities
{
public int RoomID { get; set; }
public int AmenitiesID { get; set; }
public Room Room { get; set; }
public Amenities Amenity { get; set; }
}
In my services, i have this logic that is actually doing the querying:
public async Task<Hotel> GetById(int id)
{
var hotel = await _context.Hotel.FindAsync(id);
// Get a list of rooms
var rooms = await _context.HotelRooms.Where(r => r.HotelID == id)
.Include(d => d.Room)
.ThenInclude(a => a.RoomAmenities)
.ThenInclude(x => x.Amenity).ToListAsync();
hotel.HotelRooms = rooms;
return hotel;
}
The current output is:
{
"id": 1,
"name": "Amanda's Hotel",
"streetAddress": "123 CandyCane Lane",
"city": "Seattle",
"state": "WA",
"phone": "123-456-8798",
"hotelRooms": [
{
"hotelID": 1,
"roomNumber": 101,
"roomID": 2,
"rate": 75.00,
"petFriendly": false,
"room": {
"id": 2,
"name": "Queen Suite",
"layout": 2,
"roomAmenities": [
{
"roomID": 2,
"amenitiesID": 1,
"amenity": {
"id": 1,
"name": "Coffee Maker",
"roomAmenities": [
{
"roomID": 1,
"amenitiesID": 1,
"room": {
"id": 1,
"name": "Princess Suite",
"layout": 1,
"roomAmenities": [
{
"roomID": 1,
"amenitiesID": 2,
"amenity": {
"id": 2,
"name": "Mini Bar",
"roomAmenities": []
}
}
],
"hotelRooms": [
{
"hotelID": 1,
"roomNumber": 123,
"roomID": 1,
"rate": 120.00,
"petFriendly": true
}
]
}
}
]
}
}
],
"hotelRooms": []
}
},
{
"hotelID": 1,
"roomNumber": 123,
"roomID": 1,
"rate": 120.00,
"petFriendly": true,
"room": {
"id": 1,
"name": "Princess Suite",
"layout": 1,
"roomAmenities": [
{
"roomID": 1,
"amenitiesID": 1,
"amenity": {
"id": 1,
"name": "Coffee Maker",
"roomAmenities": [
{
"roomID": 2,
"amenitiesID": 1,
"room": {
"id": 2,
"name": "Queen Suite",
"layout": 2,
"roomAmenities": [],
"hotelRooms": [
{
"hotelID": 1,
"roomNumber": 101,
"roomID": 2,
"rate": 75.00,
"petFriendly": false
}
]
}
}
]
}
},
{
"roomID": 1,
"amenitiesID": 2,
"amenity": {
"id": 2,
"name": "Mini Bar",
"roomAmenities": []
}
}
],
"hotelRooms": []
}
}
]
}
This is much too nested for me, i'd like the inner "roomAmenities" inside the "amenity" object to not be included. I'd like my object to look like this:
{
"id": 1,
"name": "Amanda's Hotel",
"streetAddress": "123 CandyCane Lane",
"city": "Seattle",
"state": "WA",
"phone": "123-456-8798",
"hotelRooms": [
{
"hotelID": 1,
"roomNumber": 101,
"roomID": 2,
"rate": 75,
"petFriendly": false,
"room": {
"id": 2,
"name": "Queen Suite",
"layout": 2,
"roomAmenities": [
{
"roomID": 2,
"amenitiesID": 1,
"amenity": {
"id": 1,
"name": "Coffee Maker"
}
}
],
"hotelRooms": []
}
},
{
"hotelID": 1,
"roomNumber": 123,
"roomID": 1,
"rate": 120,
"petFriendly": true,
"room": {
"id": 1,
"name": "Princess Suite",
"layout": 1,
"roomAmenities": [
{
"roomID": 1,
"amenitiesID": 1,
"amenity": {
"id": 1,
"name": "Coffee Maker"
}
},
{
"roomID": 1,
"amenitiesID": 2,
"amenity": {
"id": 2,
"name": "Mini Bar"
}
}
],
"hotelRooms": []
}
}
]
}
Does anyone have any guidance on how i can achieve this with EFCore and LINQ?

you can check this post
What is the difference between PreserveReferencesHandling and ReferenceLoopHandling in Json.Net?
I see that you have already implemented referenceloopHandling, but even when you are using that you can only make the inner reference as null but not totally remove the key- value pair from json

Related

Why is Entity Framework behaving as expected in a MVC app and totally diferent in a WebAPI?

I've been working with Entity Framework 6 for some time now and today I started with a new Web API project and as soon as I execute a query that includes some other entity I receive an error like this:
System.Text.Json.JsonException: A possible object cycle was detected. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 32.
The thing and do not understand is that, when I used the same Eager Loading while running a regular MVC App it will bring me exactly what I need, nothing else.
So far this is the relevant code I'm working with:
Beer.cs
public class Beer
{
public int Id { get; set; }
[Required, StringLength(100)]
public string Name { get; set; } = null!;
public int BrandId { get; set; }
public virtual Brand Brand { get; set; } = null!;
}
Brand.cs
public class Brand
{
public int Id { get; set; }
[Required, StringLength(100)]
public string Name { get; set; } = null!;
public virtual ICollection<Beer> Beers { get; set;} = null!;
}
BeerRepository.cs
public class BeerRepository : IBeerRepository
{
private readonly BeerContext _context;
public BeerRepository(BeerContext context)
{
_context = context;
}
public async Task CreateBeerAsync(Beer beer)
{
if(beer == null)
throw new ArgumentNullException(nameof(beer));
await _context.Beers.AddAsync(beer);
}
//BUG: This is the one causing me issues!
public async Task<ICollection<Beer>> GetAsync() => await _context.Beers.Include(b => b.Brand).ToListAsync();
public async Task<Beer> GetByIdAsync(int id) => await _context.Beers.FirstAsync(b => b.Id == id);
public async Task SavaChangesAsync()
{
await _context.SaveChangesAsync();
}
}
BeerContext.cs
#nullable disable
public partial class BeerContext : DbContext
{
public DbSet<Beer> Beers { get; set; }
public DbSet<Brand> Brands { get; set; }
public BeerContext(DbContextOptions opt) : base(opt)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//BEER ENTITY
modelBuilder.Entity<Beer>(entity => {
entity.HasData(
new Beer { Id = 1, BrandId = 1, Name = "Torobayo" },
new Beer { Id = 2, BrandId = 1, Name = "Bock" },
new Beer { Id = 3, BrandId = 1, Name = "Lager Sin Filtrar" },
new Beer { Id = 4, BrandId = 2, Name = "Super Dry" },
new Beer { Id = 5, BrandId = 2, Name = "Soukai" }
);
});
//BRAND ENTITY
modelBuilder.Entity<Brand>(entity => {
entity.HasData(
new Brand{ Id = 1, Name = "Kunstman" },
new Brand{ Id = 2, Name = "Asahi" }
);
});
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
BeersController.cs
[Route("api/[controller]")]
[ApiController]
public class BeersController : ControllerBase
{
private readonly IBeerRepository _repository;
private readonly IMapper _mapper;
public BeersController(IMapper mapper, IBeerRepository repository)
{
_mapper = mapper;
_repository = repository;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<BeerReadDTO>>> GetAllBeers()
{
var beers = await _repository.GetAsync();
return Ok(_mapper.Map<IEnumerable<BeerReadDTO>>(beers));
}
}
I also changed the Program.cs file like this:
builder.Services.AddControllers().AddJsonOptions(opt => {
opt.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
});
It works (at least it will remove the error) but instead I'm getting this "nice" data!
[
{
"id": 1,
"name": "Torobayo",
"brand": {
"id": 1,
"name": "Kunstman",
"beers": [
{
"id": 1,
"name": "Torobayo",
"brandId": 1,
"brand": null
},
{
"id": 2,
"name": "Bock",
"brandId": 1,
"brand": null
},
{
"id": 3,
"name": "Lager Sin Filtrar",
"brandId": 1,
"brand": null
}
]
}
},
{
"id": 2,
"name": "Bock",
"brand": {
"id": 1,
"name": "Kunstman",
"beers": [
{
"id": 1,
"name": "Torobayo",
"brandId": 1,
"brand": null
},
{
"id": 2,
"name": "Bock",
"brandId": 1,
"brand": null
},
{
"id": 3,
"name": "Lager Sin Filtrar",
"brandId": 1,
"brand": null
}
]
}
},
{
"id": 3,
"name": "Lager Sin Filtrar",
"brand": {
"id": 1,
"name": "Kunstman",
"beers": [
{
"id": 1,
"name": "Torobayo",
"brandId": 1,
"brand": null
},
{
"id": 2,
"name": "Bock",
"brandId": 1,
"brand": null
},
{
"id": 3,
"name": "Lager Sin Filtrar",
"brandId": 1,
"brand": null
}
]
}
},
{
"id": 4,
"name": "Super Dry",
"brand": {
"id": 2,
"name": "Asahi",
"beers": [
{
"id": 4,
"name": "Super Dry",
"brandId": 2,
"brand": null
},
{
"id": 5,
"name": "Soukai",
"brandId": 2,
"brand": null
}
]
}
},
{
"id": 5,
"name": "Soukai",
"brand": {
"id": 2,
"name": "Asahi",
"beers": [
{
"id": 4,
"name": "Super Dry",
"brandId": 2,
"brand": null
},
{
"id": 5,
"name": "Soukai",
"brandId": 2,
"brand": null
}
]
}
}
]
This is the query running in the background...
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (49ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT [b].[Id], [b].[BrandId], [b].[Name], [b0].[Id], [b0].[Name]
FROM [Beers] AS [b]
INNER JOIN [Brands] AS [b0] ON [b].[BrandId] = [b0].[Id]
And what I actually need is this:
[
{
"id": 1,
"name": "Torobayo",
"brand":"Kunstman"
},
{
"id": 2,
"name": "Bock",
"brand":"Kunstman"
},
{
"id": 3,
"name": "Lager Sin Filtrar",
"brand":"Kunstman"
},
{
"id": 4,
"name": "Super Dry",
"brand":"Asahi"
},
]
Any help will be a good start since I ran out of ideas. Thank you very much!
EDIT:
So, i decided to also post my DTO File and also the Automapper configuration... looks like it is not clear that i'm actually mapping from Beer entity to the corresponding DTO.
BeerReadDTO.cs
public class BeerReadDTO
{
public int Id { get; set; }
public string Name { get; set; }
public Brand Brand { get; set; }
}
AutoMapperConf.cs
public class AutoMapperConf : Profile
{
public AutoMapperConf()
{
// Source -> Target
CreateMap<Beer,BeerReadDTO>();
}
}
Okay.. thanks to Kamran Khan who pointed me in the right direction!... the issue was fixed just by removing the navigation property from Brands to Beers and changing the Brands for the DTO to a string.
Here are the files i changed and it worked fine!
public class Brand
{
[Key]
public int Id { get; set; }
[Required, StringLength(100)]
public string Name { get; set; } = null!;
//public virtual ICollection<Beer> Beers { get; set;} = null!;
}
public class BeerReadDTO
{
public int Id { get; set; }
public string Name { get; set; }
public string Brand { get; set; }
}
public class AutoMapperConf : Profile
{
public AutoMapperConf()
{
// Source -> Target
CreateMap<Beer,BeerReadDTO>()
.ForMember(d => d.Brand, opt => opt.MapFrom(src => src.Brand.Name));
}
}
Thank you very much!

Deserialization by JSON.NET of a list of interfaces inside another class

I already surfed thorough other questions, but I can't solve this.
The JSON is the following
[
{
"$type": "UWP.Model.Management.VirtualCarPark.Item.AggregatorItem, UWP.Model",
"UId": 17,
"Name": "K2 BDB-INCON4-U",
"IsPublished": true,
"Items": [{
"$type": "UWP.Model.Management.VirtualCarPark.Item.Item, UWP.Model",
"IsPublished": true,
"UId": 18,
"OwnerUId": 17,
"Name": "1: Root - I/O Modules K2 Switch 1",
"UIdStreet": 1,
"UIdArea": 1
},
{
"$type": "UWP.Model.Management.VirtualCarPark.Item.Item, UWP.Model",
"IsPublished": true,
"UId": 19,
"OwnerUId": 17,
"Name": "2: Root - I/O Modules K2 Switch 2",
"UIdStreet": 1,
"UIdArea": 1
}
]
},
{
"$type": "UWP.Model.Management.VirtualCarPark.Item.AggregatorItem, UWP.Model",
"UId": 41,
"Name": "K3 SH2INDI424",
"IsPublished": true,
"Items": [{
"$type": "UWP.Model.Management.VirtualCarPark.Item.Item, UWP.Model",
"IsPublished": true,
"UId": 42,
"OwnerUId": 41,
"Name": "1: Root - Switches K3 Switch 1",
"UIdStreet": 1,
"UIdArea": 1
},
{
"$type": "UWP.Model.Management.VirtualCarPark.Item.Item, UWP.Model",
"IsPublished": true,
"UId": 43,
"OwnerUId": 41,
"Name": "2: Root - Switches K3 Switch 2",
"UIdStreet": 1,
"UIdArea": 1
},
{
"$type": "UWP.Model.Management.VirtualCarPark.Item.Item, UWP.Model",
"IsPublished": true,
"UId": 44,
"OwnerUId": 41,
"Name": "3: Root - Switches K3 Switch 3",
"UIdStreet": 1,
"UIdArea": 1
},
{
"$type": "UWP.Model.Management.VirtualCarPark.Item.Item, UWP.Model",
"IsPublished": true,
"UId": 45,
"OwnerUId": 41,
"Name": "4: Root - Switches K3 Switch 4",
"UIdStreet": 1,
"UIdArea": 1
}
]
}
]
As you can see I put the type thanks
TypeNameHandling = TypeNameHandling.Auto
So, I can't understand why I can't deserialize as the following
var lstAggregatorItem = JsonConvert.DeserializeObject<List<AggregatorItem>>(tokenAggregators.ToString());
The class AggregatorItem has only interfaces, none implementation of Item since I want to work only with interfaces and no direct implementation
public class AggregatorItem : IAggregatorItem
{
public int UId { get; set; }
public string Name { get; set; }
public bool IsPublished
{
get { return Items.Any(i => i.IsPublished); }
}
public AggregatorItem()
{
Items = new List<IItem>();
}
public IList<IItem> Items { get; set; }
public IItem GetItem(int itemUId)
{
return Items.SingleOrDefault(i => i.UId == itemUId);
}
public void Remove(int itemUId)
{
var itemToRemove = Items.SingleOrDefault(i => i.UId == itemUId);
if (itemToRemove == null)
return;
itemToRemove.Reset();
Items.Remove(itemToRemove);
}
public void AddItem(IItem item)
{
Items.Add(item);
}
public void Reset()
{
foreach (var item in Items)
{
item.Reset();
}
Items.Clear();
}
}
So, is there something to teach to serializer "use this implementation of this class"? Because this exception is annoying me
Newtonsoft.Json.JsonSerializationException: 'Could not create an instance of type UWP.Model.Management.VirtualCarPark.Item.IItem. Type is an interface or abstract class and cannot be instantiated. Path '[0].Items[0].IsPublished', line 10, position 22.
you must pass a "model" instead of "AggregatorItem" here:
// Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
public class Item
{
[JsonProperty("$type")]
public string Type { get; set; }
public bool IsPublished { get; set; }
public int UId { get; set; }
public int OwnerUId { get; set; }
public string Name { get; set; }
public int UIdStreet { get; set; }
public int UIdArea { get; set; }
}
public class Root
{
[JsonProperty("$type")]
public string Type { get; set; }
public int UId { get; set; }
public string Name { get; set; }
public bool IsPublished { get; set; }
public List<Item> Items { get; set; }
}
var lstAggregatorItem = JsonConvert.DeserializeObject<List<Root>>(tokenAggregators.ToString());

C# Extract JSON from nested array

I'm trying to iterate through nested JSON arrays using C# and JSON.NET. The JSON represents categories for an online webstore - below is an example. My goal is to create a list of all of the names of categories.
{
"id": 2,
"parent_id": 1,
"name": "Main Category List",
"is_active": true,
"position": 1,
"level": 1,
"product_count": 0,
"children_data": [
{
"id": 9,
"parent_id": 2,
"name": "Mens Clothing",
"is_active": true,
"position": 6,
"level": 2,
"product_count": 0,
"children_data": []
},
{
"id": 8,
"parent_id": 2,
"name": "Womens Clothing",
"is_active": true,
"position": 7,
"level": 2,
"product_count": 0,
"children_data": [
{
"id": 223,
"parent_id": 8,
"name": "Outdoor Clothing",
"is_active": true,
"position": 1,
"level": 3,
"product_count": 0,
"children_data": []
},
{
"id": 224,
"parent_id": 8,
"name": "Hiking Clothing",
"is_active": true,
"position": 2,
"level": 3,
"product_count": 0,
"children_data": []
},
{
"id": 596,
"parent_id": 8,
"name": "Dresses",
"is_active": true,
"position": 3,
"level": 3,
"product_count": 0,
"children_data": [
{
"id": 694,
"parent_id": 596,
"name": "Summer Dresses",
"is_active": true,
"position": 13,
"level": 4,
"product_count": 0,
"children_data": [
{
"id": 720,
"parent_id": 694,
"name": "Accessories",
"is_active": true,
"position": 1,
"level": 5,
"product_count": 0,
"children_data": [ ]
}
]
}
]
}
]
},
{
"id": 10,
"parent_id": 2,
"name": "Sale & Clearance",
"is_active": true,
"position": 8,
"level": 2,
"product_count": 0,
"children_data": []
}
]
}
There could be varying levels of categories and I need to parse every one. I want to get every category and create a map. For example (Main Category List --> Women's Clothing --> Outdoor Clothing). I'm thinking I can check the depth of children data but I don't know how to keep checking deeper and deeper into the next Json object.
JObject responseObject = JObject.Parse(response.Content);
foreach (JObject category in getCatResponseObj.SelectToken("children_data"))
{
while loop checking depth of children_data
}
Were it me, I would create the most complete JSON file I can come up with (including all possible entries), then use json2csharp or an equivalent tool to create c# classes then deserialize the Json and work with it natively. You may have to massage the results a bit - but I think you can get there. If that didn't work, I would use Newtonsofts JSON LINQ Features (documentation). JToken gives you parent / children combinations that allows you to traverse up and down the tree. The samples in the documentation are really good, so no need of my filling up the page with duplicate info.
(Generated from your example)
public class ChildrenData
{
public int id { get; set; }
public int parent_id { get; set; }
public string name { get; set; }
public bool is_active { get; set; }
public int position { get; set; }
public int level { get; set; }
public int product_count { get; set; }
public List<object> children_data { get; set; }
}
public class RootObject
{
public int id { get; set; }
public int parent_id { get; set; }
public string name { get; set; }
public bool is_active { get; set; }
public int position { get; set; }
public int level { get; set; }
public int product_count { get; set; }
public List<ChildrenData> children_data { get; set; }
}
This appears to be a recursively defined structure. You should create a function to extract the values of each of the children so you could reuse it recursively.
IEnumerable<string> GetCategoryNames(JObject data)
{
yield return (string)data["name"];
foreach (var name in data["children_data"].Cast<JObject>().SelectMany(GetCategoryNames))
yield return name;
}
Then call it on the root object to get your names putting in a list or whatever.
var obj = JObject.Parse(response.Content);
var names = GetCategoryNames(obj).ToList();
Otherwise, if you want to indiscriminately get all names in the object tree, just keep in mind that SelectToken()/SelectTokens() also takes json path queries. So to get all names of all descendants, you'd just do this:
let names = obj.SelectTokens("..name").ToList();

Web Api; Entity Framework; Data returns recursive

im facing a problem with probably selfreference Looping:
Model:
public class ProtectedAccount
{
public int Id { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime Created { get; private set; }
public DateTime? Changed { get; set; }
public bool Disabled { get; set; }
public virtual ICollection<ProtectedAccountMember> Members { get; set; }
public virtual ProtectedAccountType Type { get; set; }
}
public class ProtectedAccountMember
{
public int Id { get; set; }
[StringLength(300)]
public string Name { get; set; }
[Index]
public virtual ProtectedAccount ProtectedAccount { get; set; }
}
Controller:
[ResponseType(typeof(ProtectedAccount))]
[Route("ProtectedAccounts/{id}/Members")]
[HttpGet]
public IHttpActionResult GetProtectedAccountMembers(int id)
{
var protectedAccount = db.ProtectedAccounts.Find(id);
if (protectedAccount == null)
{
return NotFound();
}
return Ok(protectedAccount.Members.ToList());
}
the data wich i receive for an GET seems to Loop recursive through all navigations:
[
{
"ProtectedAccount": {
"Members": [
{
"Id": 2,
"Name": "XXX, XX",
},
{
"Id": 3,
"Name": "XX, XX",
}
],
"Type": null,
"Id": 25,
"ObjectGUID": "76bf65e7-af60-4fe8-b3e1-90afbfd65b65",
"Name": "XXX",
},
"Id": 1,
"Name": "test",
},
{
"ProtectedAccount": {
"Members": [
{
"Id": 1,
"Name": "test",
},
{
"Id": 3,
"Name": "XX, XX",
"SamAccountName": "XX",
"Disabled": false
}
],
"Type": null,
"Id": 25,
"ObjectGUID": "76bf65e7-af60-4fe8-b3e1-90afbfd65b65",
"Name": "XXXX",
},
"Id": 2,
"Name": "XX, XX",
},
{
"ProtectedAccount": {a
"Members": [
{
"Id": 1,
"Name": "test",
"SamAccountName": "XXX",
"Disabled": false
},
{
"Id": 2,
"Name": "XX, XX",
"SamAccountName": "XX",
"Disabled": false
}
],
"Type": null,
"Id": 25,
"ObjectGUID": "76bf65e7-af60-4fe8-b3e1-90afbfd65b65",
"Name": "XXX",
},
"Id": 3,
"Name": "XX, XX",
}
]
There is only one "ProtectedAccount" in the database. DO i have to use DTO to overcome this issue? I tried some configuration via the json formatsettings but didnt get any better results.
From your code, you are only returing the protectedAccount.Members, hence you could do a projection query as below
var results = ctx.ProtectedAccountMembers
.Where(member => member.ProtectedAccount.Id == protectedAccount.Id)
.Select(member => new { member.Id, member.Name }).ToList();

Setting JSON object name in WCF REST

I am sending JSON:
[
{
"Description": "A kud ces bolje",
"ItemID": 1,
"Name": "Banane",
"NewPrice": 91.99,
"OldPrice": 161.99,
"SaleEnds": "9/1/2013",
"SaleStarts": "9/1/2012"
},
{
"Description": "Rastu na stablu",
"ItemID": 2,
"Name": "Kruske",
"NewPrice": 93.99,
"OldPrice": 117.99,
"SaleEnds": "9/1/2013",
"SaleStarts": "9/1/2012"
},
]
But I want to have a name so that it looks like
"Some_Name":[
{
"Description": "A kud ces bolje",
"ItemID": 1,
"Name": "Banane",
"NewPrice": 91.99,
"OldPrice": 161.99,
"SaleEnds": "9/1/2013",
"SaleStarts": "9/1/2012"
},
{
"Description": "Rastu na stablu",
"ItemID": 2,
"Name": "Kruske",
"NewPrice": 93.99,
"OldPrice": 117.99,
"SaleEnds": "9/1/2013",
"SaleStarts": "9/1/2012"
},
]
I return List<Item>:
[OperationContract]
[WebGet(UriTemplate = "/items/{id}", ResponseFormat = WebMessageFormat.Json)]
List<ItemService> GetItems(string id);
and the Item is:
[DataContract]
public class ItemService
{
[DataMember]
public int ItemID { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string Description { get; set; }
[DataMember]
public Decimal OldPrice { get; set; }
[DataMember]
public Decimal NewPrice { get; set; }
[DataMember]
public string SaleStarts { get; set; }
[DataMember]
public string SaleEnds { get; set; }
}
You can't name the JSon data itself. You would need a small wrapper class containing the name:
class Wrapper { public Some_Name List<ItemService> {get;set;}
Wrap your list in the wrapper and return the wrapper.
The resulting JSon would be somehting like:
{
"Some_Name":[
{
"Description": "A kud ces bolje",
"ItemID": 1,
"Name": "Banane",
"NewPrice": 91.99,
"OldPrice": 161.99,
"SaleEnds": "9/1/2013",
"SaleStarts": "9/1/2012"
},
{
"Description": "Rastu na stablu",
"ItemID": 2,
"Name": "Kruske",
"NewPrice": 93.99,
"OldPrice": 117.99,
"SaleEnds": "9/1/2013",
"SaleStarts": "9/1/2012"
},
]}

Categories