Azure Mobile Services (Windows Phone) - store complex object - json

I am playing around with Azure Mobile Services. Right now I am trying to store an object of my custom class in a table.
Here is a snippet from the class which represent the object which I want to store in Azure.
public class CustomItem : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public string Id { get; set; }
[JsonProperty(PropertyName = "Categorie")]
public CategorieObject Categorie { get; set; }
[JsonProperty(PropertyName = "Subcategorie")]
public SubcategorieObject Subcategorie { get; set; }
[JsonProperty(PropertyName = "Name")]
public string Name { get; set; }
...
}
My question is how to store custom types like CategorieObject or SubCategorieObject. These classes contain a String for the name and many other properties, but I only need to store the name of the Categorie and SubcategorieObject.
Maybe you can give me a hint, to solve my problem.
Thanks!

The post at http://blogs.msdn.com/b/carlosfigueira/archive/2012/09/06/supporting-arbitrary-types-in-azure-mobile-services-managed-client-complex-types.aspx shows one way to support complex objects in azure mobile service. For your scenario, you can send the data to the server and in the insert/read/update scripts you "change" the data to only store what you need. For example, assuming that you have those types on the client:
public class CustomItem : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public string Id { get; set; }
[JsonProperty(PropertyName = "Categorie")]
public CategorieObject Categorie { get; set; }
[JsonProperty(PropertyName = "Subcategorie")]
public SubcategorieObject Subcategorie { get; set; }
[JsonProperty(PropertyName = "Name")]
public string Name { get; set; }
}
public class CategorieObject
{
[JsonProperty(PropertyName = "Name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "SomethingElse")]
public string SomethingElse { get; set; }
}
public class SubcategorieObject
{
[JsonProperty(PropertyName = "Name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "SomethingElse")]
public string SomethingElse { get; set; }
}
You'd change your insert script to replace the complex object (categorie / subcategorie) with the name, which is what you want to store:
function insert(item, user, request) {
// Replace the complex object with their "Name" property.
// Omitting error / format checking here for conciseness.
item.Categorie = item.Categorie.Name;
item.Subcategorie = item.Subcategorie.Name;
request.execute({
success: function() {
// Recreate the original object
item.Categorie = { Name: item.Categorie };
item.Subcategorie = { Name: item.Subcategorie };
request.respond();
}
});
}
Likewise when updating an item you'd need to do the same:
function update(item, user, request) {
// Replace the complex object with their "Name" property.
// Omitting error / format checking here for conciseness.
item.Categorie = item.Categorie.Name;
item.Subcategorie = item.Subcategorie.Name;
request.execute({
success: function() {
// Recreate the original object
item.Categorie = { Name: item.Categorie };
item.Subcategorie = { Name: item.Subcategorie };
request.respond();
}
});
}
And the same for reading:
function read(query, user, request) {
request.execute({
success: function(results) {
results.forEach(function(item) {
item.Categorie = { Name: item.Categorie };
item.Subcategorie = { Name: item.Subcategorie };
});
request.respond();
}
});
}
Notice that any other properties in the subclasses will be lost when reading from the database (after all, you're not storing them).

Related

EF Core and Pomelo 5.0 - how to query the json column

I'm using last version of json implementation in Pomelo 5.0 and configure my maria server to use microsoft json serialisation.
var serverVersion = new MariaDbServerVersion(new Version(10, 3, 0));
services.AddDbContext<BusinessManagementDbContext>(options =>
{
options.UseMySql(databaseConfiguration.ConnectionString, serverVersion, m =>
{
m.UseMicrosoftJson(MySqlCommonJsonChangeTrackingOptions.FullHierarchyOptimizedSemantically);
m.EnableRetryOnFailure();
});
options.EnableSensitiveDataLogging(true);
});
I can save my POCO in my db but when I try to query my data, I get a null object.
Here's my data :
HeidySQL data
My query is pretty simple but I think I'm not using the right way for json query.
await Context.ValidatedSaleInvoices.AsNoTracking().FirstOrDefaultAsync(x => x.Id == id);
It seems like there is no deserialization between my data and my property "Content".
How can I do this ?
Thank you,
Edit
My model is :
public class ValidateSaleInvoiceEntity
{
public int Id { get; set; }
public ValidateSaleInvoiceContent Content { get; set; }
}
public class ValidateSaleInvoiceContent
{
public string BusinessName { get; set; }
public DateTime Date { get; internal set; }
public string Number { get; internal set; }
public Address Address { get; internal set; }
public List<ValidateSaleInvoiceLineEntity> Lines { get; internal set; } = new List<ValidateSaleInvoiceLineEntity>();
}
public class ValidateSaleInvoiceLineEntity
{
public string Description { get; internal set; }
public decimal Quantity { get; internal set; }
public decimal UnitPriceVatExcluded { get; internal set; }
public decimal VatRate { get; internal set; }
}
And my json Result was like this (empty, like there waere no deserialisation: { "BusinessName":"", "Date":"", "Number":"" etc.}
My boss stop my poc about MariaDB Json implementation so I had to go back to this good old friend pure sql column :/ . That's why I haven"t a full json result. Sorry
For a property to serialize/deserialize JSON automatically to a POCO, you need to tell Pomelo, that the table column of the property is of the MySQL/MariaDB type json:
public class ValidateSaleInvoiceEntity
{
public int Id { get; set; }
[Column(TypeName = "json")] // <-- this is one way to do it
public ValidateSaleInvoiceContent Content { get; set; }
}
public class MyContext : DbContext
{
// ...
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ValidateSaleInvoiceEntity>()
.Property(e => e.Content)
.HasColumnType("json"); // <-- this is another way to do it
}
}
Here is a fully working console project:
using System.ComponentModel.DataAnnotations.Schema;
using System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace IssueConsoleTemplate
{
// EF Core entities:
public class IceCream
{
public int IceCreamId { get; set; }
public string Name { get; set; }
// Either use this data annotation, or the corresponding Fluent API call (see
// OnModelCreating), to explicitly mark the column type as JSON.
[Column(TypeName = "json")]
public IceCreamDetails Details { get; set; }
}
// JSON class:
public class IceCreamDetails
{
public int Kilojoule { get; set; }
public int Rating { get; set; }
}
public class Context : DbContext
{
public DbSet<IceCream> IceCreams { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
var connectionString = "server=127.0.0.1;port=3306;user=root;password=;database=So68020732";
var serverVersion = ServerVersion.AutoDetect(connectionString);
optionsBuilder.UseMySql(connectionString, serverVersion, options => options
.UseMicrosoftJson(MySqlCommonJsonChangeTrackingOptions.FullHierarchyOptimizedSemantically))
.UseLoggerFactory(
LoggerFactory.Create(
configure => configure
.AddConsole()
.AddFilter(level => level >= LogLevel.Information)))
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<IceCream>(
entity =>
{
// Either use this Fluent API call, or the corresponding data annotation
// (see the IceCreamDetails class), to explicitly mark the column type as JSON.
entity.Property(e => e.Details)
.HasColumnType("json");
entity.HasData(
new IceCream {IceCreamId = 1, Name = "Vanilla", Details = new IceCreamDetails { Kilojoule = 865, Rating = 9 }},
new IceCream {IceCreamId = 2, Name = "Chocolate", Details = new IceCreamDetails { Kilojoule = 903, Rating = 10 }});
});
}
}
internal static class Program
{
private static void Main()
{
using var context = new Context();
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var iceCreams = context.IceCreams
.OrderBy(i => i.IceCreamId)
.ToList();
Trace.Assert(iceCreams.Count == 2);
Trace.Assert(iceCreams[0].Details.Kilojoule == 865);
Trace.Assert(iceCreams[1].Details.Rating == 10);
}
}
}
You can find the most comprehensive JSON sample code on our repository (see the JSON mapping and query scenarios section).

Deserialize JSON data in to a class in c#

hello people I have this Json data:
https://openexchangerates.org/api/latest.json?app_id=6cf59607a32d408eb3e04de1427a3169
and I want to deserialize in the following class
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Divisas2MVVM2.Classes
{
public class ExchangeRates
{
[JsonProperty(PropertyName = "disclaimer")]
public string Disclaimer { get; set; }
[JsonProperty(PropertyName = "license")]
public string License { get; set; }
[JsonProperty(PropertyName = "timestamp")]
public int TimeStamp { get; set; }
[JsonProperty(PropertyName = "base")]
public string Base { get; set; }
[JsonProperty(PropertyName = "rates")]
public Rates Rates { get; set; }
}
public class Rates
{
public double AED { get; set; }
public double AFN { get; set; }
public double ALL { get; set; }
public double AMD { get; set; }
// I cut the text so that it would not be to long
public double ZMW { get; set; }
public double ZWL { get; set; }
}
public class Rate
{
public double TaxRate { get; set; }
public string Code { get; set; }
}
this is my attribute
private ExchangeRates exchangeRates;
the constructor of my MainViewModel
new ObservableCollection data
Rates = new ObservableCollection<Rate>();
and in this method a get the json data
try
{
var client = new HttpClient();
client.BaseAddress = new Uri("https://openexchangerates.org");
var url = "/api/latest.json?app_id=6cf59607a32d408eb3e04de1427a3169";
var response = await client.GetAsync(url);
if (!response.IsSuccessStatusCode)
{
Message = response.StatusCode.ToString();
IsRunning = false;
return;
}
var result = await response.Content.ReadAsStringAsync();
exchangeRates = JsonConvert.DeserializeObject<ExchangeRates>(result);
}
everything works fine, the variable result has correctly the json data in a string format, but when i call JsonConvert . DeserializeObject, the data "rates" it is not assigned correctly, all the other data: disclaimer", "license", "timestamp" etc. is correctly assigned. only rates fail.
the string is correct
other data is correct in the class
rates is incorrect
sorry for my English I hope you have understood me :)
use this as your model class
namespace Rate
{
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public partial class Rates
{
[JsonProperty("disclaimer")]
public string Disclaimer { get; set; }
[JsonProperty("license")]
public string License { get; set; }
[JsonProperty("timestamp")]
public long Timestamp { get; set; }
[JsonProperty("base")]
public string Base { get; set; }
[JsonProperty("rates")]
public Dictionary<string, double> RatesRates { get; set; }
}
public partial class Rates
{
public static Rates FromJson(string json) => JsonConvert.DeserializeObject<Rates>(json, Rate.Converter.Settings);
}
public static class Serialize
{
public static string ToJson(this Rates self) => JsonConvert.SerializeObject(self, Rate.Converter.Settings);
}
internal static class Converter
{
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
Converters = {
new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
},
};
}
}
Then do this in your class
var data = Rate.Rates.FromJson("jsonresult");
var rate = data.RatesRates;
foreach (var pair in rate)
{
string symbol = pair.Key; //"AED"
double value = pair.Value; //3.673175,
}
var time = data.Timestamp;
var disclaimer = data.Disclaimer;
var license = data.License;
Tested and working

JsonProperty WebApi request and response models

I have an API that talks to another API.
The response model looks something like this:
public class AddressResponseModel
{
public string Id { get; set; }
public string SaveAs { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Phone { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string County { get; set; }
public string Country { get; set; }
public string PostCode { get; set; }
}
So, I need to send this to another API. I don't really want to play around with the response in JavaScript, I would just like to send it as it is to my endpoint and let the server handle its factorization.
So, I tried to do this:
public class AddressBindingModel
{
[Required]
[JsonProperty("address_1")]
public string Address1 { get; set; }
[JsonProperty("address_2")]
public string Address2 { get; set; }
[Required]
[JsonProperty("city")]
public string City { get; set; }
[Required]
[JsonProperty("county")]
public string County { get; set; }
[Required]
[JsonProperty("postcode")]
public string PostCode { get; set; }
[Required]
[JsonProperty("country")]
public string Country { get; set; }
[JsonProperty("save_as")]
public string SaveAs { get; set; }
}
but the problem with that is that it expects the json to follow to same property format.
How can I get it to expect my unmodified response model, but output the JSON with the underscores?
To clarify, I will post my model like this:
{
address1: '123',
address2: 'Some street',
city: 'London',
county: 'London',
country: 'GB',
saveAs: 'Home'
}
and my API will then send this to another API like this:
{
address_1: '123',
address_2: 'Some street',
city: 'London',
county: 'London',
country: 'GB',
save_as: 'Home'
}
If you want to use the same classes to automatically generate JSON with different property names, without having to write a custom JsonConverter for each one, you're going to need to create your own custom ContractResolver, for instance:
Json.NET provides CamelCasePropertyNamesContractResolver.
This Answer has a prototype PascalCaseToUnderscoreContractResolver.
If you have a deterministic way to map all .Net property names to the appropriate property names for a given usage context (post or get-from-api), you can create a contract resolver like one of the above.
If, however, there's no general rule for mapping .Net property names for JSON property names, and each context may require some per-property customization, you could create your own ContractResolver that applies in a specific named context, and your own System.Attribute that supplies a JSON context name and property name to use in this context. I.e.:
[System.AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true, Inherited = true)]
public class JsonConditionalNameAttribute : System.Attribute
{
readonly string contextName;
readonly string propertyName;
public string ContextName { get { return contextName; } }
public string PropertyName { get { return propertyName; } }
public JsonConditionalNameAttribute(string contextName, string propertyName)
{
this.contextName = contextName;
this.propertyName = propertyName;
}
}
public class ConditionalNameContractResolver : DefaultContractResolver
{
readonly string contextName;
public string ContextName { get { return contextName; } }
public ConditionalNameContractResolver(string contextName)
: base()
{
if (string.IsNullOrEmpty(contextName))
throw new ArgumentNullException();
if (string.IsNullOrEmpty(contextName))
throw new ArgumentException();
this.contextName = contextName;
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var jProperty = base.CreateProperty(member, memberSerialization);
var attrs = jProperty.AttributeProvider.GetAttributes(typeof(JsonConditionalNameAttribute), true)
.Cast<JsonConditionalNameAttribute>()
.Where(a => a.ContextName == ContextName)
.Select(a => a.PropertyName)
.Distinct()
.ToList();
if (attrs.Count == 1)
{
jProperty.PropertyName = attrs[0];
}
else if (attrs.Count > 1)
{
throw new JsonSerializationException(string.Format("Multiple conditional property attributes found for \"{0}\" in in context \"{1}\": \"{2}\"", jProperty, contextName, String.Join(",", attrs)));
}
return jProperty;
}
}
Then your binding model would look something like:
public static class AddressBindingModelContexts
{
public const string Post = "post";
public const string GetFromApi = "getFromApi";
}
public class AddressBindingModel
{
[JsonConditionalName(AddressBindingModelContexts.GetFromApi, "address_1")]
[JsonConditionalName(AddressBindingModelContexts.Post, "address1")]
public string Address1 { get; set; }
[JsonConditionalName(AddressBindingModelContexts.GetFromApi, "address_2")]
[JsonConditionalName(AddressBindingModelContexts.Post, "address2")]
public string Address2 { get; set; }
[JsonProperty("city")]
public string City { get; set; }
[JsonProperty("county")]
public string County { get; set; }
[JsonProperty("postcode")]
public string PostCode { get; set; }
[JsonProperty("country")]
public string Country { get; set; }
[JsonConditionalName(AddressBindingModelContexts.GetFromApi, "save_as")]
[JsonConditionalName(AddressBindingModelContexts.Post, "saveAs")]
public string SaveAs { get; set; }
}
To test:
var jsonFromApi = GetJsonFromApi();
var postContract = new ConditionalNameContractResolver(AddressBindingModelContexts.Post);
var getFromApiContract = new ConditionalNameContractResolver(AddressBindingModelContexts.GetFromApi);
var model = JsonConvert.DeserializeObject<AddressBindingModel>(jsonFromApi, new JsonSerializerSettings { ContractResolver = getFromApiContract });
var postJson = JsonConvert.SerializeObject(model, Formatting.Indented, new JsonSerializerSettings { ContractResolver = postContract });
Debug.WriteLine(postJson); // Verify the postJson has the necessary properties and data.
To change the contract resolver for all results returned from Web API, see JSON and XML Serialization in ASP.NET Web API: Camel Casing. To use a custom contract resolver when returning results from a specific Web Api call, see Customize Json result in Web API.

Service Stack POST-Request Body-Format / Transformation

iam using a RequestClass with the Route anotation to call a Json-Client POST method.
Now, while the paramters are structured like this
public class GetTicketRequest: IReturn<JsonObject>
{
public string CartId {
get;
set;
}
public string PriceId {
get;
set;
}
}
The BackendAPI needs them to be nesten in "data" in the json request, so more like
{
"data":[
{"cartid":123,
"priceId":11}]
}
Is there any way to transfrom the request object for the body before calling
JsonServiceClient _restClient = new JsonServiceClient(baseUrl);
JsonObject oneResponse = _restClient.Post(options);
This solution is useful where many DTOs require to be wrapped & converted, and is highly reusable, with no changes to your existing DTOs.
You can convert the requests of the JsonServiceClient by overriding the methods that handle preparing the requests for sending. Which means implementing your own extended JsonServiceClient as given below.
If you want to do this for all verbs then you override it's Send<TResponse> methods (otherwise, if it's just for POST then uncomment the commented out code, and remove the Send methods).
public class MyJsonServiceClient : JsonServiceClient
{
public Dictionary<Type, Func<object, object>> DtoConverters = new Dictionary<Type, Func<object, object>>();
public MyJsonServiceClient() {}
public MyJsonServiceClient(string baseUri) : base(baseUri) {}
public MyJsonServiceClient(string syncReplyBaseUri, string asyncOneWayBaseUri) : base(syncReplyBaseUri, asyncOneWayBaseUri) {}
public override TResponse Send<TResponse>(object request)
{
return base.Send<TResponse>(ConvertRequest(request));
}
public override TResponse Send<TResponse>(string httpMethod, string relativeOrAbsoluteUrl, object request)
{
return base.Send<TResponse>(httpMethod, relativeOrAbsoluteUrl, ConvertRequest(request));
}
/*
public override TResponse Post<TResponse>(string relativeOrAbsoluteUrl, object requestDto)
{
return base.Post(relativeOrAbsoluteUrl, ConvertRequest(requestDto));
}
*/
object ConvertRequest(object request)
{
Type dtoType = request.GetType();
return (DtoConverters.ContainsKey(dtoType)) ? DtoConverters[dtoType](request) : request;
}
}
Usage:
So given this DTO:
[Route("/test", "POST")]
public class TicketRequest : IReturnVoid
{
public string CartId { get; set; }
public string PriceId { get; set; }
}
You simply add the converter:
var client = new MyJsonServiceClient("http://localhost:9000");
// Simple converter for TicketRequest
client.DtoConverters.Add(typeof(TicketRequest), dto => {
var d = (TicketRequest)dto;
return new {
data = new {
CartId = d.CartId.ToInt(),
PriceId = d.PriceId.ToInt()
}
};
});
client.Post(new TicketRequest { CartId = "123", PriceId = "456" });
i solved this issue using a typed data property
public class GetTicketRequest: IReturn<JsonObject>
{
public class TicketCreateData
{
public int priceId {
get;
set;
}
}
public string CartId {
get;
set;
}
public string PriceId {
get;
set;
}
public List<TicketCreateData> data {
get {
var list = new List<TicketCreateData>();
list.Add(new TicketCreateData {
priceId = this.PriceId.ToInt()
});
return list;
}
set {
data = value;
}
}
}
To notes on this:
if neede, use DataContract/DataMember(Name="") to rename fields or only do partial serializing
Do never use structs for, like in this case, the data class - they are not serializeable at all
in my spefici case data even needs to be an array, thats why i used the list

Entity Framework 4.1: Data from repository not displaying via JSON

I am using Entity Framework 4.1 code first and ASP.NET MVC 3. I have a Yahoo User Interface (YUI) datatable on my view. I am getting the data (to populate the grid via JSON).
Flow of getting data:
Controller -> Service -> Repository
My context setup:
public DbSet<Category> Categories { get; set; }
Original Repositry:
public IEnumerable<Category> GetAll()
{
return db.Categories.ToList();
}
Call to this repository method from my service layer:
public IEnumerable<Category> GetAll()
{
return categoryRepository.GetAll();
}
My action method to retrieve the data and to pass it to the YUI datatable:
public ActionResult JsonCategoriesList()
{
JsonEncapsulatorDto<Category> data = new JsonEncapsulatorDto<Category>
{
DataResultSet = categoryService.GetAll()
};
return Json(data, JsonRequestBehavior.AllowGet);
}
JsonEncapsulatorDto code:
public class JsonEncapsulatorDto<T>
{
public IEnumerable<T> DataResultSet { get; set; }
}
When I use it this way then there is an error in the datatable. I don't know how to view the error. Nothing is displayed. I debugged and I saw that there is a count of 7 in the DataResultSet. So what I did was to change the repository to use some test data and then it worked. What is the difference and how do I get it to display my results?
Repository with test data:
public IEnumerable<Category> GetAll()
{
List<Category> list = new List<Category>();
list.Add(new Category { Name = "Brendan" });
list.Add(new Category { Name = "Charlene" });
return list;
//return db.Categories.ToList();
}
Not sure if you guys want to see my setup of the categories datatable:
<div id="dtCategories"></div>
<script type="text/javascript">
YAHOO.util.Event.onDOMReady(function () {
var yuiDataSource = YAHOO.util.DataSource;
var yuiPaginator = YAHOO.widget.Paginator;
var yuiDataTable = YAHOO.widget.DataTable;
var dtCategoriesColumnDefs, dtCategoriesDataSource;
var dtCategoriesConfigs, dtCategoriesDataTable;
dtCategoriesColumnDefs = [
{ key: 'Name', label: 'Name' }
];
dtCategoriesDataSource = new YAHOO.util.DataSource('#Url.RouteUrl (Url.AdministrationCategoryJsonCategoriesList())');
dtCategoriesDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
dtCategoriesDataSource.responseSchema = {
resultsList: 'DataResultSet',
fields: [
{ key: 'Name' }
]
};
dtCategoriesDataTable = new YAHOO.widget.DataTable('dtCategories', dtCategoriesColumnDefs, dtCategoriesDataSource);
});
</script>
UPDATE:
Category class:
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string MetaKeywords { get; set; }
public string MetaDescription { get; set; }
public bool IsActive { get; set; }
public int? ParentCategoryId { get; set; }
public virtual Category ParentCategory { get; set; }
public virtual ICollection<Category> ChildCategories { get; set; }
}
Context class:
public class PbeContext : DbContext
{
public DbSet<Category> Categories { get; set; }
public DbSet<Tutorial> Tutorials { get; set; }
protected override void OnModelCreating(DbModelBuilder dbModelBuilder)
{
dbModelBuilder.Entity<Category>()
.HasOptional(c => c.ParentCategory)
.WithMany(c => c.ChildCategories)
.HasForeignKey(p => p.ParentCategoryId);
}
}
UPDATE 2:
I have another view that that gets a list of Product objects (no circular references) and it populates fine. I debugged to see what the data looks like when it is returned. And this is how the objects looked like in the list:
Categories:
[0] [System.Data.Entity.DynamicProxies.Category_9E42BCEDDE8AA695F718BEBE2224E1D34291FCAF82F801F4995EEB8449479C93]
[1] [System.Data.Entity.DynamicProxies.Category_9E42BCEDDE8AA695F718BEBE2224E1D34291FCAF82F801F4995EEB8449479C93]
[2] [System.Data.Entity.DynamicProxies.Category_9E42BCEDDE8AA695F718BEBE2224E1D34291FCAF82F801F4995EEB8449479C93]
...and so on...
Products:
[0] = {MyProject.Core.DomainObjects.Product}
[1] = {MyProject.Core.DomainObjects.Product}
[2] = {MyProject.Core.DomainObjects.Product}
Can it maybe because of how the data is returned??
No idea where your error is. Maybe a recursive Category model (usually that's what happens when you don't use view models and try to pass your EF domain models to the view)? In your example you only need to show a table containing one column which is the name of the category. Passing an entire domain IEnumerable<Category> is like a crime. Maybe missing scripts? Maybe this AdministrationCategoryJsonCategoriesList extension method?
Here's a full working example that I wrote for you and that might get you started:
Model:
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string MetaKeywords { get; set; }
public string MetaDescription { get; set; }
public bool IsActive { get; set; }
public int? ParentCategoryId { get; set; }
public virtual Category ParentCategory { get; set; }
public virtual ICollection<Category> ChildCategories { get; set; }
// Obviously this will be in your repository but for the purpose of
// this demonstration let's hardcode some data
public static IEnumerable<Category> GetAll()
{
List<Category> list = new List<Category>();
list.Add(new Category { Name = "Brendan" });
list.Add(new Category { Name = "Charlene" });
return list;
}
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult JsonCategoriesList()
{
var data = Category.GetAll().Select(x => new
{
// We select only what we need for our view => the name
// if you need something else, well, select it here
Name = x.Name
}).ToList();
return Json(new { DataResultSet = data }, JsonRequestBehavior.AllowGet);
}
}
View:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>YUI Test</title>
<link type="text/css" rel="stylesheet" href="http://yui.yahooapis.com/2.9.0/build/datatable/assets/skins/sam/datatable.css">
</head>
<body>
<div id="dtCategories"></div>
<script src="http://yui.yahooapis.com/2.9.0/build/yahoo-dom-event/yahoo-dom-event.js"></script>
<script src="http://yui.yahooapis.com/2.9.0/build/element/element-min.js"></script>
<script src="http://yui.yahooapis.com/2.9.0/build/datasource/datasource-min.js"></script>
<script src="http://yui.yahooapis.com/2.9.0/build/connection/connection-min.js"></script>
<script src="http://yui.yahooapis.com/2.9.0/build/datatable/datatable-min.js"></script>
<script type="text/javascript">
YAHOO.util.Event.onDOMReady(function () {
var yuiDataSource = YAHOO.util.DataSource;
var yuiDataTable = YAHOO.widget.DataTable;
var dtCategoriesColumnDefs, dtCategoriesDataSource;
var dtCategoriesConfigs, dtCategoriesDataTable;
dtCategoriesColumnDefs = [{ key: 'Name', label: 'Name'}];
dtCategoriesDataSource = new YAHOO.util.DataSource('#Url.Action("JsonCategoriesList")');
dtCategoriesDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
dtCategoriesDataSource.responseSchema = {
resultsList: 'DataResultSet',
fields: [{ key: 'Name'}]
};
dtCategoriesDataTable = new YAHOO.widget.DataTable(
'dtCategories',
dtCategoriesColumnDefs,
dtCategoriesDataSource
);
});
</script>
</body>
</html>
Please post the Category type definition to see if there is a circular reference, This might help: Json and Circular Reference Exception