I have a web API controller method that is returning an object which is giving the client a 500 internal server error. On the server, the output windows says "Newtonsoft.Json.JsonSerializationException". But I cannot see anything wrong with the class I am returning.. and I am sure this has historically been working. Any help would be greatly appreciated!
EDIT: Is this a problem with the web API not being able to serialize a 'dynamic entity'? The code that generates the class is here:
var id = User.Identity.GetUserId();
var user = db.Users
.Where(u => u.Id == id)
.Include(u => u.Friends)
.FirstOrDefault();
return user;
I am returning the following class;
public class User : IdentityUser
{
public User()
{
this.Friends = new List<UserFriend>();
}
public string PhoneNumber { get; set; }
public string Email { get; set; }
public List<UserFriend> Friends { get; set; }
public bool HasRegistered { get; set; }
public string LoginProvider { get; set; }
}
The 'UserFriend' class looks like this;
public class UserFriend
{
public int UserFriendId { get; set; }
public string Id { get; set; }
public string FriendUserId { get; set; }
public string FriendUserName { get; set; }
public string FriendPhoneNumber { get; set; }
}
Strangely, when I hover over the returned object on the server, the type is: {System.Data.Entity.DynamicProxies.User_7283E76A736B4DD47E89120E932CD5C04B62F84C316961F02CDAE3EEF4786504}. I am not sure what this is.. :-O
I used AutoMapper to create a DTO instead of just returning the User class. The DynamicProxies class is because the query uses lazy loading and it has not got the object yet.
After installing automapper (Install-Package AutoMapper);
Mapper.CreateMap<User, UserDto>();
UserDto dto = Mapper.DynamicMap<UserDto>(user);
Then return the dto.
Related
I'm building REST API server in .NET core. I'm testing my code via Postman software. I have a problem with Include() method that enables me to attach navigation property data. I'm trying to get data in [HttpGet] action and objects that are being returned are wrong.
My code :
MODELS
Session model
public class Session
{
[Key]
public int IDSession { get; set; }
[Required]
public DateTime LogInTime { get; set; }
public DateTime LogOutTime { get; set; }
[Required]
public int IDUser { get; set; }
public User User { get; set; }
[Required]
public int IDMachine { get; set; }
public Machine Machine { get; set; }
}
User model
public class User
{
[Key]
public int IDUser { get; set; }
[Required]
public string Forename { get; set; }
[Required]
public string Name { get; set; }
public string AvatarPath { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public string Password { get; set; }
public User CreatedBy { get; set; }
public DateTime CreatedAt { get; set; }
public List<UserGroup> UsersGroups { get; set; }
public List<Alarm> ExecutedAlarms { get; set; }
public List<Alarm> ResetedAlarms { get; set; }
public List<AccessCard> Cards { get; set; }
public List<AccessCard> UserCardsAdded { get; set; }
public List<User> UsersAdded { get; set; }
public List<Session> Sessions { get; set; }
public List<EventsLog> Events { get; set; }
public List<Reference> References { get; set; }
public List<UserPermission> UsersPermissions { get; set; }
}
Session controller
[Produces("application/json")]
[Route("api/Sessions")]
public class SessionsController : Controller
{
private readonly DBContext _context;
#region CONSTRUCTOR
public SessionsController(DBContext context)
{
_context = context;
}
#endregion
#region HTTP GET
// GET: api/sessions
[HttpGet]
public async Task<IActionResult> GetSessions()
{
var sessions = await _context.Sessions.Include(s => s.User). ToListAsync();
if (sessions.Any())
{
return new ObjectResult(sessions);
}
else
{
return NotFound();
}
}
// GET: api/sessions/1
[HttpGet("{id}", Name = "GetSessionByID")]
public async Task<IActionResult> GetSessionByID(Int32 id)
{
var session = await _context.Sessions.Include(s => s.User).FirstOrDefaultAsync(s => s.IDSession == id);
if (session == null)
{
return NotFound();
}
else
{
return new ObjectResult(session);
}
}
#endregion
}
The idea is that User model contains List<Session> collection that he/she created. I want to be able to return users with its sessions
Of course Session model contains a single User because every session is related with a specific, single User.
Now, when I need to get all sessions objects in SessionController with GetSessions() or GetSessionsByID() I use POSTMAN [HttpGet] action like this : http://localhost:8080/api/sessions which returns me wrong data :
A session contains a user and in turn a single user is related with its sessions. It looks like it tries to return me Session object properly, includes User object but then it tries to include all sessions for that User. That's not what I want. It looks like some kind of a loop. Sessions shoud be returned with its User objects and that's it. How can I achieve that ? Am I doing some logical mistake in my models ?
Thanks !
I met also this issue recently. So, I've fixed it by adding this script in the Startup.cs file and ConfigureServices method :
services.AddMvc().AddJsonOptions(
options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);
So, you suffix services.AddMvc() by this code who means that you have to make JSON.Net to ignore cycles finded to the nested object request. And of course having Newtonsoft.Json package installed to your project and referenced in each concerned file
For much clearer information, see this link at Related Data and Serialization section :
https://learn.microsoft.com/en-us/ef/core/querying/related-data
Hope this is helpfull for you
I have a self referencing model called Folder and also an Entity called Content which contains the Folder Entity.
public class Folder : BaseEntity
{
public int Id { get; set; }
public string Name { get; set; }
public int? ParentId { get; set; }
public virtual Folder Parent { get; set; }
public virtual ICollection<Folder> Children { get; set; }
}
public class Content : BaseEntity
{
[Key]
public int Id { get; set; }
public string Title { get; set; }
public string HTML { get; set; }
public string Summary { get; set; }
public int XmlConfigId { get; set; }
public int FolderId { get; set; }
public virtual Folder Folder { get; set; }
}
Here is my Application Db context
public class ApplicationDbContext: DbContext
{
public DbSet<Folder> Folders { get; set; }
public DbSet<Content> Contents { get; set; }
public ApplicationDbContext() : base("ProjectDB") {
Database.SetInitializer<ApplicationDbContext>(null);
}
}
Everything works fine if i am using a razor view to display the data and also i am able to access the The Folder property that is inside the Content Entity.
The problem is when i try to display the data using Web API.
My web API
public class ContentApiController : ApiController
{
[HttpGet]
public IEnumerable<Content> GetAllContents()
{
return _unitofwork.Contents.GetAllContents();
}
}
On the Web API, the GetAllContents() function just returns the Entity models coming directly from the Folders DBSet. It is not calling the ToList() function since i want to do lazy loading. Here is the code for the GetAllContents() function.
public IEnumerable<Content> GetAllContents()
{
return ApplicationDbContext.Contents.Include(c=>c.Folder);
}
So in order for this to work i have to add.
Configuration.LazyLoadingEnabled = false;
to my applicationDbContext constructor which i really don't want.
and also
Global.asax
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
WebApiConfig
JsonMediaTypeFormatter jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().Single();
jsonFormatter.UseDataContractJsonSerializer = false;
jsonFormatter.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;
jsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
jsonFormatter.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.None;
Is there any way to expose the json data without out turning off Lazy loading. Thanks.
Just call ToList on your query, or, even better, ToListAsync:
[HttpGet]
public async Task<IEnumerable<Content>> GetAllContents()
{
return await _unitofwork.Contents.GetAllContents().ToListAsync;
}
Even if you enable LazyLoading, you cannot avoid to materialize your data before returning it to the client (and let the Serializer do its work).
In your MVC example, the framework itself enumerates the result in your View (I suppose), and thus you are not directly calling ToList, but in your scenario you have to materialize your Entities explicitly.
Please note that there is no performance issue in calling ToList/ToListAsync in your controller.
Hi firends i'm getting error when i tried to Serialize JSON. I have a model and it have List property;
MyModel:
public virtual int Kod { get; set; }
public virtual string Ad { get; set; }
public virtual string TrafikKod { get; set; }
public virtual int TapuKod { get; set; }
public virtual bool AktifMi { get; set; }
[JsonIgnore]
public virtual IList<TapuIlceModel> IlceList { get; set; }
public TapuIlModel()
{
IlceList = new List<TapuIlceModel>();
}
MyApiController:
[Route("api/TapuZeminApi/GetZemins")]
[HttpPost]
public string GetZeminsFromZeminArg(object arg)
{
ZeminArg zemArg = SConvert.DeserializeJSON<ZeminArg>(arg.ToString());
List<TapuZeminModel> zeminList = TapuModule.GetZeminListFromArgs(zemArg);
string jsonResult = SConvert.SerializeJSON(zeminList);
return jsonResult;
Here is a picture about my reciving data error;
And this my inner exc.;
.{"Error getting value from 'ReadOnly' on 'NHibernate.Proxy.DefaultLazyInitializer'."}
.{"Proxy is detached (i.e, session is null). The read-only/modifiable setting is only accessible when the proxy is associated with an open session."}
What should i do? I need all data... Thanks
when i check again i found something like that:
Why is there 2 base??? And why name is different? Anyone know?
I geting same error when serilize SerializeJSON(object) , i have try JsonConvert.SerializeObject with JsonSerializerSettings and ContractResolver, it will work.
string jsonResult = JsonConvert.SerializeObject(object, new JsonSerializerSettings() {
ContractResolver = new NHibernateContractResolver()
});
I have run into another issue that apparently deals with inherited classes:
I have for instance this super class.
public class Person
{
public string Firstname { get; set; }
public string Lastname { get; set; }
public string Email { get; set; }
}
And then a sub class:
public class Member : Person
{
public int MembershipId { get; set; }
public string Password { get; set; }
public List<Foo> Foos { get; set; }
}
When I return a Member with the following code, I get nothing useful:
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
public Member GetMember()
{
return new Member
{
Firstname = "Jane",
Lastname = "Doe",
Email = "jane.doe#doe.com",
MembershipId = 10,
Password = "*****",
Foos = new List<Foo> { };
};
}
Classes / objects that are not inherited are serialized and returned in json format without any problems.
Is there anyway to get my Member object returned correctly, please? I have been messing with this issue and my conclusion was that it must have something to do with inherited classes and json.
try this fix
[DataContract]
public class Person
{
[DataMember]
public string Firstname { get; set; }
[DataMember]
public string Lastname { get; set; }
[DataMember]
public string Email { get; set; }
}
[DataContract]
public class Member : Person
{
[DataMember]
public string MembershipId { get; set; }
[DataMember]
public string Password { get; set; }
[DataMember]
public List<Foo> Foos { get; set; }
}
Actually my theory about inherited classes and JSON serialization was flawed.
It works and I do not need the [Datacontrac] and [Datamember] decorators. Something else is wrong. Perhaps my structure is too deep and too lenghty.
I wonder whether JSON has some limits regarding size.
I ended using JSON.net from Newtonsoft. I would recommend to use that instead of wasting time on the native json feature in .net.
http://json.codeplex.com/
I have a class department inheriting from activeentity
public class ActiveEntity : Entity, IActive
{
public ActiveEntity()
{
IsActive = true;
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public Guid Id { get; set; }
public bool IsActive { get; set; }
[Timestamp, ScaffoldColumn(false), DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.Computed)]
public Byte[] Timestamp { get; set; }
[ScaffoldColumn(false)]
public string CreationUserId { get; set; }
[ScaffoldColumn(false)]
public string LastModifiedUserId { get; set; }
}
public class Department:ActiveEntity
{
public Department()
{
this.Address = new DepartmentAddress();
}
[StringLength(9),MinLength(9),MaxLength(9)]
public string Name { get; set; }
public Guid ManagerId { get; set; }
[UIHint("AjaxDropdown")]
public User Manager { get; set; }
public Guid? AddressId { get; set; }
public DepartmentAddress Address { get; set; }
public ICollection<OverheadRate> OverheadRates { get; set; }
}
I am just using annotations no Fluent API. The data saves to the data Sql Server 2008 just fine however the address object never gets instantiated, even though I have the context use the include
return c.Set<Department>().Include(d => d.Address).Include(d => d.Manager).Where(predicate);
The data is returned I run sql profiler and then run the query it returns the correct data.
Any thoughts or suggestions?
Remove instantiating the address (this.Address = new DepartmentAddress();) in the Department constructor. Instantiating navigation references in the default constructor is evil and has nasty side effects like these:
What would cause the Entity Framework to save an unloaded (but lazy loadable) reference over existing data?
EF 4.1 Code First: Why is EF not setting this navigation property?