Self referencing loop detected serialization exception - json

This is my class:
public partial class Event
{
public Event()
{
this.Comments = new HashSet<Comment>();
this.Rates = new HashSet<Rate>();
this.RawDates = new HashSet<RawDate>();
}
public int ID { get; set; }
public string Title { get; set; }
public string Summary { get; set; }
public string SiteURL { get; set; }
public string ContactEmail { get; set; }
public string LogoURL { get; set; }
public int EventType_ID { get; set; }
public Nullable<int> Location_ID { get; set; }
public Nullable<System.DateTime> BegginingDate { get; set; }
public string nTrain { get; set; }
public string Content { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
public virtual Conference Conference { get; set; }
public virtual ICollection<Rate> Rates { get; set; }
public virtual ICollection<RawDate> RawDates { get; set; }
public virtual EventType EventType { get; set; }
public virtual Location Location { get; set; }
}
When I call web api post method, exception mentioned in the title is thrown in this line:
var response = await client.PostAsJsonAsync("api/event", event);
I added [JsonIgnore] above every virtual field in Event class. This time serialization worked, but ignored fields were not serialized, their value is null. I really need all information contained in Event object. How can I solve this problem?

Adding below configuration in WebAPIConfig.cs resolves the bug.
var json = config.Formatters.JsonFormatter;
//Below configuration to mandatory to resolve the Self referencing loop detected with
"Newtonsoft.Json.JsonSerializationException" ,
json.SerializerSettings.PreserveReferencesHandling =
Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);

Circular referencing objects cannot be JSON serialized. I would recommend you using a view model in which you will include the properties you need and then have your action return this view model instead of the actual domain model.

Related

When i JsonConvert.DeserializeObject its just stops working in asp.net core

I'm trying to DeserializeObject my data to User class and when i do that, the method acts like nothing happend and finishing himself.
And that's my User class:
public class User
{
public int UserID { get; set; }
public string UserName { get; set; }
public string UserSurname { get; set; }
[Required, StringLength(50), DataType(DataType.EmailAddress)]
public string UserEMail { get; set; }
public string UserToken { get; set; }
public string UserPassword { get; set; }
public bool UserIsActive { get; set; }
public bool UserIsEmailConfirmed { get; set; }
}
Here it's my code :
firebaseClient = new FireSharp.FirebaseClient(firebaseConfig);
FirebaseResponse response = firebaseClient.Get("Users/");
User data = JsonConvert.DeserializeObject<User>(response.Body);//That's the point where i get the problem.
I'm working with Firebase,FireSharp and Asp.Net Core 5.0

How to get certain properties of the array from Model to ViewModel without Json parseerror (Asp.Net Core MVC)

I'm currently working on the Asp.Net Core MVC project and have the following Message class
public class Message
{
public int Id { get; set; }
public string SenderId { get; set; }
[ForeignKey("SenderId")]
public virtual User Sender { get; set; }
public string RecipientId { get; set; }
[ForeignKey("RecipientId")]
public virtual User Recipient { get; set; }
public string Content { get; set; }
public bool IsRead { get; set; }
public DateTime? DateRead { get; set; }
public DateTime MessageSent { get; set; }
public bool SenderDeleted { get; set; }
public bool RecipientDeleted { get; set; }
}
Using the mapper, I get the below ViewModel for the Message review:
public class MessageReviewViewModel
{
public int Id { get; set; }
public string SenderId { get; set; }
[ForeignKey("SenderId")]
public virtual User Sender { get; set; }
public string RecipientId { get; set; }
[ForeignKey("RecipientId")]
public virtual User Recipient { get; set; }
public string Content { get; set; }
public bool IsRead { get; set; }
public DateTime? DateRead { get; set; }
public DateTime MessageSent { get; set; }
}
Now, I would like to get actually the Recipient and Sender users, however the reason I have such a simple MessageReviewViewModel is because I'm getting the list of this view models and with this users json throws an error & without it I have successfull result.
However, the problem is, that for the proper display in the Inbox view I still need the certain properties of Recipient and Sender user's (their main photo url, username & etc).
My mapper configuration is as below to get the messages from the repository:
public async Task<IEnumerable<MessageReviewViewModel>> GetMessagesForUserByUserId(string userId)
{
var messages = await messageRepository.GetMessagesForUser(userId);
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Message, MessageReviewViewModel>();
cfg.IgnoreUnmapped();
});
IMapper mapper = config.CreateMapper();
var messageList = mapper.Map<IEnumerable<Message>, IEnumerable<MessageReviewViewModel>>(messages);
return messageList;
}
In the react component (I have integrated react.js in the asp.net core mvc) once it did mount I make a get request to get the messages list as below and setState messagesList to the received array.
componentDidMount() {
const xhr = new XMLHttpRequest();
xhr.open('get', "/Messages/GetMessages", true);
xhr.onload = () => {
const data = JSON.parse(xhr.responseText);
this.setState({ messagesList: data });
console.log(this.state.messagesList);
};
xhr.send();
}
And this is the action in the controller, that is being called:
[HttpGet]
public async Task<IActionResult> GetMessages()
{
var userFromRepo = await userManager.FindByNameAsync(User.Identity.Name);
var messages = await messagesService.GetMessagesForUserByUserId(userFromRepo.Id);
var sortedMessageList = messages.OrderByDescending(m => m.MessageSent);
return Json(sortedMessageList);
}
As I mentioned, it all works without any problem unless there are no virtual User Sender and virtual User Recipient in the MessageReviewViewModel. Once I have them in code, this is the error I get:
Probably it is worth to mention, that the User class objects (in my scenario Sender & Recipient for example) also have the virtual properties inside and I thought that it may be problem for Json parse these objects, which have other objects as property.
Could you please advise how I can include these properties in the ViewModel so neither mapper nor JSON throw any error? I'm okay even to get only selected properties of the obje (for example just string username, mainphoto url & etc).
It is also ok, if there is any Json method, that will solve this parseError with virtual users included in the ViewModel
I figured it out after finding that mapper can also be configured to the level that is required by the user
The Message model is as below as previously
public class Message
{
public int Id { get; set; }
public string SenderId { get; set; }
[ForeignKey("SenderId")]
public virtual User Sender { get; set; }
public string RecipientId { get; set; }
[ForeignKey("RecipientId")]
public virtual User Recipient { get; set; }
public string Content { get; set; }
public bool IsRead { get; set; }
public DateTime? DateRead { get; set; }
public DateTime MessageSent { get; set; }
public bool SenderDeleted { get; set; }
public bool RecipientDeleted { get; set; }
}
And the MessageReviewViewModel changed to below:
public class MessageReviewViewModel
{
public int Id { get; set; }
public string SenderId { get; set; }
public string SenderUsername { get; set; }
public string SenderMainPhotoUrl { get; set; }
public string RecipientId { get; set; }
[ForeignKey("RecipientId")]
public string RecipientUsername { get; set; }
public string RecipientMainPhotoUrl { get; set; }
public string Content { get; set; }
public bool IsRead { get; set; }
public DateTime? DateRead { get; set; }
public DateTime MessageSent { get; set; }
}
Only for the mapper the configuration was required as below:
public async Task<IEnumerable<MessageReviewViewModel>> GetMessagesForUserByUserId(string userId)
{
var messages = await messageRepository.GetMessagesForUser(userId);
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Message, MessageReviewViewModel>()
.ForMember(destination=>destination.RecipientUsername,map=>map.MapFrom(
source=>source.Recipient.UserName)) //gets only string for username instead of whole User model
.ForMember(destination=> destination.RecipientMainPhotoUrl,map=>map.MapFrom(
source=>source.Recipient.MainProfilePicture)) //gets only string for profile picture instead of whole User model
.ForMember(destination=>destination.SenderUsername,map=>map.MapFrom(
source=>source.Sender.UserName))
.ForMember(destination=>destination.SenderMainPhotoUrl,map=>map.MapFrom(
source=>source.Sender.MainProfilePicture));
cfg.IgnoreUnmapped();
});
IMapper mapper = config.CreateMapper();
var messageList = mapper.Map<IEnumerable<Message>, IEnumerable<MessageReviewViewModel>>(messages);
return messageList;
}
As all received data now are only strings, Json has no problem parsing it

Trying to check a json file for the correct parameters using JsonConvert.DeserisalizeObject<t>

I'm using the ACE code editor to gather Json and send it to my application. Once the Json hits the application, I need to make sure there are certain key's inside the json so I am using JsonConvert.DeserisalizeObject<t> to do this. Here's how:
public void SubmitReport(string JsonStringSend)
{
try
{
ReportItem RptItem = JsonConvert.DeserializeObject<ReportItem>(JsonStringSend);
}
catch(err)
{
return View(err);
}
}
and:
public class ReportItem
{
public Guid ReportID;
public bool RequiresFilter;
public string MimeType { get; set; }
public string ExternalID { get; set; }
public DateTime CreatedBy { get; set; }
public string ExecutionScript { get; set; }
public string ExecutionParameter { get; set; }
public string ExecutionOrderBy { get; set; }
public List<DynamicFilter> DynamicFilters { get; set; }
public bool RequiresOrgID { get; set; }
public QueryFilter ReportFilter { get; set; }
public QueryRule ReportRules { get; set; }
public List<QueryColumn> Columns { get; set; }
}
But for some reason, it bounces right over the catch even when I make sure some of the key's are incorrect. Am I not understanding the correct usage JsonConvert.DeserisalizeObject<t>? Or, is there a better way to be doing this check?
By default, the deserializer "tries it's best" to deserialize the object. But JSon.NET supports validation, the "straightforward" way is probably JSon Schema: http://www.newtonsoft.com/jsonschema.
Simple case can be handled with JSon.NET directly:
public class ReportItem
{
[JsonProperty(Required = Required.Always)]
public bool RequiresFilter;
[JsonProperty(Required = Required.Always)]
public string MimeType { get; set; }
public DateTime CreatedBy { get; set; }
public string ExecutionScript { get; set; }
public string ExecutionParameter { get; set; }
public string ExecutionOrderBy { get; set; }
public bool RequiresOrgID { get; set; }
}

Breezejs entity save failing because json data is too large

Breeze seems to be creating a very large file considering the object model I am passing it to save.
I am only saving one instance of a drug with 1 Drug option with 1 available route and some text fields with a single word in each.
When I grab the bundle from debug.breeze.js from line 14705 and save it to a text file the file is 35+ mb. This seems like an aweful lot of data for this straight forward object model.
Is there any way to slim down the json with just the objects? So I don't have to alter the IIS settings?
****************** Link to exported json that breeze is sending to the server ***********
Sample of json that's causing the problem
****************Here is a screen shot of the graph *************
my datacontext.saveChanges code......
function saveDictionaryChanges(entity) {
var graph = manager.getEntityGraph(entity, 'drugIndications, ' +
'drugOptions, ' +
'drugOptions.concentrations, ' +
'drugOptions.availableRoutes, ' +
'drugOptions.availableDrugForms, ' +
'drugOptions.availableUnits');
// Filter for changes only
graph = graph.filter(function (entity) {
return entity.entityAspect.entityState.isAddedModifiedOrDeleted();
});
return manager.saveChanges(graph)
.then(saveSucceeded, saveFailed);
function saveSucceeded(result) {
//TODO: Commented out because WIP is on the back burner
//zStorage.save();
logSuccess('Saved Data', result, true);
}
function saveFailed(error) {
var msg = config.appErrorPrefix + 'Save failed: ' +
breeze.saveErrorMessageService.getErrorMessage(error);
error.message = msg;
logError(msg, error);
throw error;
}
}
my object model is
There are 4 other inherited available route types liquid,inhalation,injectable and topical. I only included AvailableSolidRoutes to help shorten he question.
public class AvailableRoute {
public int Id { get; set; }
public int DrugOptionId { get; set; }
public int RouteId { get; set; }
public virtual Route Route { get; set; }
}
public class AvailableSolidRoute : AvailableRoute {
public AvailableSolidRoute( ) { }
}
There is also a Inhalation,Injectable & topical concentration object that inherit from concentration. I've only include LiquidConcentration to help shorten the question.
public abstract class Concentration {
public int Id { get; set; }
public int DrugOptionId { get; set; }
public DrugOption DrugOption { get; set; }
public decimal Measure{ get; set; }
public int MassUnitId { get; set; }
public virtual Unit MassUnit { get; set; }
public int VolumeUnitId { get; set; }
public virtual Unit VolumeUnit { get; set; }
public int? DrugFormId { get; set; }
public virtual DrugForm DrugForm { get; set; }
public int DisplayOrder { get; set; }
}
public class LiquidConcentration : Concentration {
public LiquidConcentration( ) {}
}
There 4 other inherited types like solid option Liquid,Inhalation,Injectable & Topical
public class DrugOption {
public int Id { get; set; }
public int DrugId { get; set; }
public Drug Drug { get; set; }
public List<AvailableDrugForm> AvailableDrugForms { get; set; }
public List<AvailableRoute> AvailableRoutes{ get; set; }
public List<AvailableUnit> AvailableUnits { get; set; }
public List<Concentration> Concentrations { get; set; }
public string SpecialInstructions { get; set; }
}
public class SolidOption : DrugOption {
public SolidOption( ) { }
}
Drug is the root class that all the previous classes relate to:
public class Drug {
public int Id { get; set; }
public string Name { get; set; }
public string Alias{ get; set; }
public string Directions { get; set; }
public bool DirectionsIsEditable { get; set; }
public string SpecialDirections { get; set; }
public bool SpecialDirectionsIsEditable { get; set; }
public int? DisplayOrder { get; set; }
public IList<DrugIndication> DrugIndications { get; set; }
public IList<DrugOption> DrugOptions { get; set; }
public Drug( ) { }
}
***************** I fixed this issue (Was self induced hehe!) *************
So in order to make it easier to bind my "DrugOptions" to the UI. I created
clientside properties on the drug for each type of drug options.
I did not understand what this code was actually doing.. I added it thinking it would
remove the clientside property before sending entity changes to breeze. That is not it's purpose.
Rightly so breeze was confused about the clientside properties because it does not know about them.
if (changedProp === 'solidOption') {
delete changeArgs.entity.entityAspect.originalValues[changedProp];
}
I moved these properties to the Controller and it's perfectly fine now :)

EF Problems with Navigation Properties and Mapping

At start i wanted to mention that i've been fighting this thing for a few days and tried many of the answers more or less related to this problem. Yet I could not resolve it.
I have two classes that represent tables in a DB. These are the existing tables used by legacy application and I cannot change them.
Message can have multiple MessageRecipients.
Environment: MVC3, EF4.1
Classes are:
public class Message
{
[ForeignKey("MessageReciepients")]
public virtual int MessageID { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public DateTime Recieved { get; set; }
[ForeignKey("User")]
public int AuthorUserID { get; set; }
//P\\ Navigation properties
public virtual IList<MessageRecipient> MessageReciepients { get; set; }
public virtual User User { get; set; }
}
public class MessageRecipient
{
//[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int MessageID { get; set; }
public int UserID { get; set; }
public bool Read { get; set; }
public bool Important { get; set; }
public bool Deleted { get; set; }
public bool Destroyed { get; set; }
//P\\ Navigation Properties
public virtual User User { get; set; }
}
The error I have is:
The foreign key component 'MessageID' is not a declared property on
type 'MessageRecipient'. Verify that it has not been explicitly
excluded from the model and that it is a valid primitive property.
How to correctly map these classes, relationships to load the recipients of a message?
I can add that the navigation property User works correctly for a Message and loads a User's data correctly.
I'm not too experienced with .NET and I learn while doing this.
I tried some EF API config to map these i tried swearing at it, curse it, and been close to cry and pray at the same time. No Joy!!
I would really appreciate the help.
It turned out that the problem was with the composite key that i needed to use and it all could be solved with some attributes:
This is how it looks now:
public class Message
{
public int MessageID { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public DateTime Recieved { get; set; }
[ForeignKey("User")]
public int AuthorUserID { get; set; }
//P\\ Navigation properties
public virtual ICollection<MessageRecipient> MessageRecipients { get; set; }
public virtual User User { get; set; }
}
public class MessageRecipient
{
[Key, Column(Order=0), ForeignKey("User")]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int UserID { get; set; }
[Key, Column(Order = 1)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int MessageID { get; set; }
public bool Read { get; set; }
public bool Important { get; set; }
public bool Deleted { get; set; }
public bool Destroyed { get; set; }
//P\\ Navigation Properties
public virtual User User { get; set; }
}
fill in the missing properties:
public class Message
{
public int MessageID { get; set; }
}
public class MessageRecipient
{
public int MessageID { get; set; }
[ForeignKey("MessageID")]
public Message Message { get; set; }
}