I have several BusinessObject classes that refer to each other and I need to serialize one in a JsonResponse and return it to my view. I keep getting a circular reference exception and I cannot get rid of it. I have placed the [ScriptIgnore()] decorator on every property that is not a simple data type property and I am still getting the exception. I cant figure out where the problem is, as I am blocking the serializer from just about everything and it is still blowing up on me.
Is there any way to see what they current state of the serialized object is?
[HttpPost]
public JsonResult GetAnalysisInfo(int id)
{
ProjectContext myDB = db;
SearchAnalysis searchanalysis = SearchAnalysis.Find(myDB, id);
//searchanalysis.Results = searchanalysis.SearchResultsPrototype(myDB);
return this.Json(searchanalysis);
}
Update
I have also tried implementing ISerializable to no avail. My GetObjectData is very simple:
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("SearchAnalysisId", this.SearchAnalysisId);
info.AddValue("Created", this.Created);
}
Still getting a CircularRefernce error. DateTime data types don't cause problems with Serialization right?
What I'm doing to prevent that error is to return an anonymouse type that reflects my object's properties like this :
public JsonResult CompanyListJson()
{
var list = (from companies in appContext.Companies
where companies.Active.Equals(true)
select new
{
Name = companies.DbName,
Id = companies.Id,
Active = companies.Id.Equals(CurrentCompany.Id)
});
return Json(list, JsonRequestBehavior.AllowGet);
}
Maybe it's not the best way, but it allows me to keep my JSON thin and push only the data I need ( and avoid that circular reference exception of course )
Looking at your sample, I would select new anonymouse type from SearchAnalysis, taking the properties I need. That should work
Related
I was working on ASP.NET MVC web API, I'm having this error:
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.
My controller is:
public Employee GetEmployees()
{
Employee employees = db.Employees.First();
return employees;
}
why I m getting this error?
For me this was a problem with circular referencing.
The accepted answer did not work for me because it only changes the behaviour of the JSON formatter, but I was getting XML when I called the service from the browser.
To fix this, I switched off XML and forced only JSON to be returned.
In the Global.asax file, put the following lines at the top of your Application_Start method:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
Now only JSON results will be returned. If you need XML results, you will need to find a different solution.
in your global.asax file, in the Application_start() method add this line:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
I hope that helps you!
I got the same problem. And I solved it. I put the default constructor to the DTO class.
Ex:
public class User
{
public User()
{
}
}
Hope it work with you!
Put this in constructor. Hope this solve the problem:
public MyController()
{
db.Configuration.ProxyCreationEnabled = false;
}
I found two solutions to this. The first and easiest to implement is to change any IEnumerables, ICollections to a type of List. The WebAPI can serialize this objects, it however cannot serialize interface types.
public class Store
{
[StringLength(5)]
public string Zip5 { get; set; }
public virtual List<StoreReport> StoreReports { get; set; } //use a list here
}
The other option is to not use the native JSON serializer and run this override in the Register method of the WebApi Config:
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
Solution is simple.
After LINQ query add .ToList() (or ToDictionary if need).
It will do eager loading than lazy loading of the data
**
this bug occur when calling from request web api/wcf/... from client side, but as side effect, you will need to include depending relations by include keyword.
**
public CustomerPortalContext()
: base("Name=CustomerPortalContext")
{
base.Configuration.ProxyCreationEnabled = false;
}
If you are working with EF, besides adding the code below on Global.asax
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
Dont`t forget to import
using System.Data.Entity;
Then you can return your own EF Models
please check the web api documentation for this problem, Handling Circular Object References
Regards
If you use web api with Entity Framework, a solution can be
Failed to serialize the response in Web API with Json
Basically, you need to create a model corresponding to each EF model, this removes dependencies between classes and allow easy serialization.
Code: (taken from the referenced link)
Create a UserModel
public class UserModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
Change my method GetAll()
public IEnumerable<UserModel> GetAll()
{
using (Database db = new Database ())
{
List<UserModel> listOfUsers = new List<UserModel>();
UserModel userModel = new UserModel();
foreach(var user in db.Users)
{
userModel.FirstName = user.FirstName;
userModel.LastName = user.LastName;
listOfUsers.Add(userModel);
}
IEnumerable<UserModel> users = listOfUsers;
return users;
}
}
Default Entity 6 use XML to apis, in your project, find the file "Global.asax" File and add this line:
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
This line remove the XML Formatter.
but if you found this problem with other entities/classes, you have to create a new DTO for each class, and if you have a lot of them, you can find a problem, also I think that create a DTO only for solving this problem is no the best way...
Did you try this?
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling =
Newtonsoft.Json.PreserveReferencesHandling.All;
Regards
hmmm, Following may help.
I was getting the same exception, and in my case I was passing the actual poco entity created for entity code first. Since, it contains relation with other entities, I just created the viewmapper/dto entity on top of it to return.
It works fine now.
Poco Entity:
public class Tag
{
public int Id{get;set;}
public string Title{get;set;}
public IList<Location> Locations{get;set;}
}
ViewMapper/Dto
public class TagResultsViewMapper
{
public int Id{get;set;}
public string Title{get;set;}
//just remove the following relationship
//public IList<Location> Locations{get;set;}
}
Your question is quite similar to mine. You must not return data from database directly. For this, you must create Model and associate data you want show.
In my example, There are data about User that Json couldn't serialize, I had create a userModel and, in my API, I return userModel instead User from database.
The logic of convert or associate data between User and UserModel must be in API.
Failed to serialize the response in Web API with Json
This was the specific error I was getting back from my odata Web API call:
The 'ObjectContent`1' type failed to serialize the response
body for content type 'application/json; odata.metadata=minimal'.
I finally figured out that my dbContext class had a poorly formatted table name being assigned in onModelCreating.. so the SqlClient was dying looking for a table that didn't exist in my db!!
I access data in a database through a Web-Api and send it back as Json string to an UWP-App.
MessageRepository.cs:
public List<Message> GetByRecipientId(int id)
{
var listOfMsg = new List<Message>();
using (var ctx = new ShowcaseContext())
{
var recipientWithId = ctx.Recipients.Where(rec => rec.UserId == id);
foreach (var recipient in recipientWithId.ToList())
{
var msgWithId = ctx.Messages.Where(msg => msg.Id == recipient.MessageId);
listOfMsg.Add(msgWithId.Single());
}
return listOfMsg;
}
}
MessageController.cs:
[Route("api/message/recipient/{id}")]
public IEnumerable<Message> GetByRecipientId(int id)
{
return messageRepository.GetByRecipientId(id);
}
The problem is that I'm getting an
"Newtonsoft.Json.JsonSerializationException" Error
when trying to return listOfMsg to the UWP-App.
But if I look at the List<> and it items in debug mode, or access a specific message in the List<> before returning it, the error disappeares and I get the right data in the UWP-App.
It seems like the List<> has a different format before accessing it specifically which can't be serialized.
Has anyone an idea why?
Edit
Message.cs:
public class Message
{
public int Id { get; set; }
public virtual Collection<Recipient> Recipients { get; set; }
public MessageTrigger Trigger { get; set; }
public string Body { get; set; }
public DateTime CreatedTs { get; set; }
}
The StackTrace is null, but the error message is
The "ObjectContent`1" type failed to serialize the response body for content type "application/json; charset=utf-8".
Most probably you have lazy loading enabled. That means that when you access a navigation property, EF will try to hit the database to get the related entity, and this will work if the DbContext is still "alive".
After the API call returns the data, JSON.NET will visit all the properties to serialize them, including the navigation properties. And, at that point, the DbContext has already been disposed of. That's why you get your error.
To avoid it you can:
disable lay loading for a particular query: Entity Framework: How to disable lazy loading for specific query?
completely disable it, if you're not using it: Disable lazy loading by default in Entity Framework 4
For more info on disabling lazy loading.
Alternative: Json configuration
You can also instruct JSON.NET to skip some properties. But there are mabny ways of doing so, and you have to add attributes to your entities. For example:
JsonObjectAttribute opt-in serialization
JsonIgnoreAttribute
Alternative: projection to anonymus class with .Select()
And I forgot a final, easy option: you can project your query to an anonymous class, getting read of all problems, and returning the JSON that you exactly want to return.
.Select(new { /* your projection */ });
Although this answers are for older versions, it still works in the same way.
NOTE: while you're debugging you're still inside the DbContext using block, and that's why you don't get errors while debugging. If you put this line: return listOfMsg; outside the using block, add a breakpoint in that line, and watch navigation properties, you'll also get errors in the debugger.
My simple wcf returning some data as dto object (MyDataDto). This dto is ofcourse created using MyData object which is created using data returned from repository.
public MyDataDto GetData(string filter)
{
MyData data = repository.GetData(filter);
return new MyDataDto(data);
}
If this data object is null (no data returned from repository) then I'm getting exception (ofcourse).
Question is: Should I decorate my OperationContract method with ObjectNotFoundException and to handle that exception at client side or to add new property at MyDataDto object with property bool IsEmpty and to return empty object?
Since I'm pretty new using wcf service what you consider as better practice or you suggest something else.
We can not use a normal .net exception in order to propagate the error to the client you can use a customized exception through the use of the FaultContract Attribute something like this
[DataContractAttribute]
public class MyDataDtoFault
{
private string report;
public MyDataDtoFault(string message)
{
this.report = message;
}
[DataMemberAttribute]
public string Message
{
get { return this.report; }
set { this.report = value; }
}
}
[OperationContract]
[FaultContract(typeof(MyDataDtoFault))]
public MyDataDto GetData(string filter)
{
MyData data = repository.GetData(filter);
if (data==null)
throw new MyDataDtoFault("No result Was found");
return new MyDataDto(data);
}
or you can use a simple FaultException by default which is serilizable and represents a SOAP fault.
but creating a property IsEmpty it will be correct but the client who would like to consume the service must be aware that this property means no result was found
personally I prefer raising an exception which is more convenient way of doing this
The best practice and recommended way is to NOT throw exceptions if you have found data and then have your program flow the exceptions. This not only produces performance hits and issues but also is just bad flow of logic. Also means difficult to maintain and lengthy code blocks/spaghetti junction.
The best practice is to create a class which has a Success property for example to indicate if the operation was a success (i.e no SQL Errors or any other exceptions) and then return the data in an exposed property in this custom class. If there is no data then really MyData is null and therefore the client side can check to see if it is null (or if collection... make sure the items are 0 in count/length and instantiated as empty). Example...
[DataContract]
public sealed Class MyDataResults
{
public MyDataResults()
{
this.Success = false;
this.FailureInformation = string.Empty;
this.Results = new MyData();
}
[DataMember(IsRequired = true)]
public bool Success {get; set;}
[DataMember(IsRequired = true)]
public MyData Results {get; set;}
[DataMember(IsRequired = true)]
public string FailureInformation {get; set;}
}
you return MyDataResults instead.
this also means you have a nice POCO object to deal with and has more meaning of a contract in that "I guarantee the client will receive this object and not something they don't expect and maybe even produce contract breakage"
So if you have an exception on server side (like FileNotFound for example), set the Success to false, set the FailureInformation to a nice friendly message to return back.
The client would check to see if the operation was a Success and if not, display the FailureInformation.
My practice is to return a fault if the operation cannot do what it was requested to do. However, one then needs to examine what it was that the operation was requested to do:
public MyDto GetEntityById(int id)
This operation has been requested to return the entity with the given ID. If it cannot do that, then I feel it is appropriate to return a fault.
public List<MyDTO> GetEntitiesMatchingFilter(string filter)
This operation is being asked to return a list of entities matching the filter. If there are no entities matching the filter, then this is not a reason to return a fault. It's a normal, expected result.
On the other hand, if the operation cannot return any entities because of a failure to connect to the database, that's a good reason to return a fault.
Alright, so I have spend LITERALLY five or six hours working on this to no avail. I'm working in C# with ASP.NET MVC 4 and EF 5.0, I believe. Here's my problem: I have a method in my controller takes a custom class as a parameter (these names have been candy-themed obfuscated :P). The ViewError class looks like so:
public class ViewError<T> where T : class
{
public T ModelObject { get; set; }
public string Message { get; set; }
public ViewError(string message, T modelObject)
{
Message = message;
ModelObject = modelObject;
}
public ViewError()
{
Message = null;
ModelObject = default(T);
}
}
(It's a generic so I can figure out what type the ModelObject is from within the code. It's irrelevant, though; I've already tested it taking a generic 'object' and the same problem happens.)
The controller method looks like this. All it does is ask who is eating the candy, and if there's a ViewError, it displays the message. (The view has a paragraph that displays the ViewBag.Message).
public ActionResult EatCandy(ViewError<EatCandyViewModel> error)
{
ViewBag.BrandList = new SelectList(db.Brands, "ID", "Name");
// If there's a notification, pass it to the view, along with the model
if(error.Message != null)
{
ViewBag.Message = error.Message;
return View(error.ModelObject);
}
return View();
}
On the post:
[HttpPost]
public ActionResult EatCandy(EatCandyViewModel viewModel)
{
if(ModelState.IsValid)
{
CandyEater eater = (CandyEater)viewModel;
db.CandyEaters.Add(eater);
db.SaveDatabase(); // Custom convenience wrapper for SaveChanges()
return RedirectToAction("ChooseCandyToEat", eater);
}
return View(viewModel);
}
Pretty standard stuff. Now, in the ChooseCandyToEat method, it brings up a list of candy available to eat of a specific brand. If that brand doesn't have any available candy, I want it to send an error back to the EatCandy method (via ViewError object) telling that eater that they have no candy to eat, and send the model back so that the eater doesn't have to type in their info again, merely select a different brand of candy.
public ActionResult ChooseCandyToEat(CandyEater eater)
{
// Get the list of candy associated with the brand.
IEnumerable<Candy> candyList = db.Candies.Where(b => b.Brand == eater.DesiredBrand)
.Where(e => !e.Eaten);
// If the brand has no candy, return an error message to the view
if(candyList.Count() == 0)
{
EatCandyViewModel viewModel = (EatCandyViewModel)eater;
ViewError<EatCandyViewModel> viewError = new ViewError<EatCandyViewModel>("Oh noes! That brand has no candy to eat!", viewModel.Clone()); // This is a deep clone, but even if it wasn't, it would still be weird. Keep reading.
return RedirectToAction("EatCandy", viewError);
}
return View(candyList);
}
According to my understanding, this should all work. Now here's the weird part - I can confirm, through debug messages and the Watch window (using Visual Studio) that the ViewError is created properly and holds a deep clone of the viewModel in its ModelObject (I have to convert it back because the EatCandy method expects an EatCandyViewModel as a parameter). However, when I step forward and the ViewError is passed to EatCandy, the ModelObject within it is null! I originally thought this was because it only passed a reference of viewModel into the object and it was getting garbage collected, which is why I added the Clone() method. The string, which is also a reference type, is getting through okay, though. Why isn't the object? Does anyone know?
If you need more info, just ask. And disregard the ridiculousness of this database - I obfuscated it intentionally, not just to be silly.
This won't work. RedirectToAction results in a 302 to the browser which just is not capable of carrying complicated models.
There are some alternatives, you could use the TempData to store the model, do the redirect and retrieve the data. You could probably even call the EatCandy action directly instead of redirecting, however the auto matching the view won't work and you'd have to force the "EatCandy" view name at the end of the EatCandy action.
I need advice on how to return a limited set of data from an MVC controller.
Lets say I have a class that is constructed like so:
public interface ICustomerExpose
{
string Name {get; set;}
string State {get; set;}
}
public interface ICustomer: ICustomerExpose
{
int Id {get; set;}
string SSN {get; set;}
}
public class Customer: ICustomer
{
...
}
In my MVC project I have a controller action that returns customer data. The project is actually more like a web service as there is no View associated with the data... we use the XmlResult (provided by the MVCContrib project). The controller action looks like this:
// GET: /Customer/Show/5
public ActionResult Show(int id)
{
Customer customer = Customer.Load(id);
... // some validation work
return new XmlResult((ICustomerExpose)customer);
}
The above controller code does not work like I want it to. What I want to happen is that only the Name and State properties are serialized and returned in the XmlResult. In practice the whole customer object is serialized including the data I definitely don't want exposed.
I know the reason this doesn't work: you can't serialize an interface.
One idea floated around the office was to simply mark the properties Name and State as [XmlIgnore]. However, this doesn't seem like a good solution to me. There might be other instances where I want to serialize those properties and marking the properties on the class this way prohibits me.
What is the best way to achieve my goal of only serializing the properties in the ICustomerExpose interface?
Addendum:
For those interested in what XmlResult does here are the relevant parts of it:
public class XmlResult : ActionResult
{
private object _objectToSerialize;
public XmlResult(object objectToSerialize)
{
_objectToSerialize = objectToSerialize;
}
/// <summary>
/// Serialises the object that was passed into the constructor
/// to XML and writes the corresponding XML to the result stream.
/// </summary>
public override void ExecuteResult(ControllerContext context)
{
if (_objectToSerialize != null)
{
var xs = new XmlSerializer(_objectToSerialize.GetType());
context.HttpContext.Response.ContentType = "text/xml";
xs.Serialize(context.HttpContext.Response.Output, _objectToSerialize);
}
}
}
You can try this, however I am not sure if it works with xml serializers:
return new XmlResult(new { customer.Name, customer.State });
See this related question which recommends using an anonymous type.
// GET: /Customer/Show/5
public ActionResult Show(int id)
{
Customer customer = Customer.Load(id);
... // some validation work
var result = from c in cusomter
select new
{
Name = c.Name,
State = c.State,
};
// or just
var result = new
{
Name = customer.Name,
State = customer.State,
};
return new XmlResult(result);
}
Consider using, just for this one problem, XML literals in VB9 rather than serialization. Seriously. Just give it 20 minutes of your time. There's many options.
http://www.hanselman.com/blog/TheWeeklySourceCode30VBNETWithXMLLiteralsAsAViewEngineForASPNETMVC.aspx
http://www.hanselman.com/blog/XLINQToXMLSupportInVB9.aspx
http://blogs.msdn.com/dmitryr/archive/2008/12/29/asp-net-mvc-view-engine-using-vb-net-xml-literals.aspx
http://haacked.com/archive/2008/12/29/interesting-use-of-xml-literals-as-a-view-engine.aspx
http://www.infoq.com/news/2009/02/MVC-VB
For what you're doing, returning XML as a poor-man's Web Service, this is tailor-made.
I ended up just doing the XmlIgnore as co-workers suggested, even though this left me with some undesirable (or so I thought) behaviors.
To get around the fact that XmlIgnore would continue hiding properties that I might want serialized later I asked another question trying to find a way to around that issue. Cheeso came up with a great answer making the XmlIgnore the best route (in my opinion) to take.