Asp.Net Web API Error: The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8' - entity-framework

Simplest example of this, I get a collection and try to output it via Web API:
// GET api/items
public IEnumerable<Item> Get()
{
return MyContext.Items.ToList();
}
And I get the error:
Object of type
'System.Data.Objects.ObjectQuery`1[Dcip.Ams.BO.EquipmentWarranty]'
cannot be converted to type
'System.Data.Entity.DbSet`1[Dcip.Ams.BO.EquipmentWarranty]'
This is a pretty common error to do with the new proxies, and I know that I can fix it by setting:
MyContext.Configuration.ProxyCreationEnabled = false;
But that defeats the purpose of a lot of what I am trying to do. Is there a better way?

I would suggest Disable Proxy Creation only in the place where you don't need or is causing you trouble. You don't have to disable it globally you can just disable the current DB context via code...
[HttpGet]
[WithDbContextApi]
public HttpResponseMessage Get(int take = 10, int skip = 0)
{
CurrentDbContext.Configuration.ProxyCreationEnabled = false;
var lista = CurrentDbContext.PaymentTypes
.OrderByDescending(x => x.Id)
.Skip(skip)
.Take(take)
.ToList();
var count = CurrentDbContext.PaymentTypes.Count();
return Request.CreateResponse(HttpStatusCode.OK, new { PaymentTypes = lista, TotalCount = count });
}
Here I only disabled the ProxyCreation in this method, because for every request there is a new DBContext created and therefore I only disabled the ProxyCreation for this case .
Hope it helps

if you have navigation properties and you do not want make them non virtual, you should using JSON.NET and change configuration in App_Start to using JSON not XML!
after install JSON.NET From NuGet, insert this code in WebApiConfig.cs in Register method
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);

If you have navigation properties make them non virtual. Mapping will still work but it prevents the creation of Dynamic Proxy entities which cannot be serialized.]
Not having lazy loading is fine in a WebApi as you don't have a persistent connection and you ran a .ToList() anyway.

I just disabled proxy classes on a per needed basis:
// GET: ALL Employee
public IEnumerable<DimEmployee> Get()
{
using (AdventureWorks_MBDEV_DW2008Entities entities = new AdventureWorks_MBDEV_DW2008Entities())
{
entities.Configuration.ProxyCreationEnabled = false;
return entities.DimEmployees.ToList();
}
}

Add the following code in Application_Start function of Global.asax.cs:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings
.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
GlobalConfiguration.Configuration.Formatters
.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
This instruct the API to serialize every response into JSON and remove XML responses.

In my case the object being returned had a property within it with a type that did not have an argumentless/default constructor. By adding a zero-argument constructor to that type the object could be serialized successfully.

I had the same problem and my DTO was missing an parameter less constructor.
public UserVM() { }
public UserVM(User U)
{
LoginId = U.LoginId;
GroupName = U.GroupName;
}
First constructor was missing.

I got this error message and it turns out the problem was that I had accidentally set my class to use the same serialized property name for two properties:
public class ResultDto
{
//...
[JsonProperty(PropertyName="DataCheckedBy")]
public string ActualAssociations { get; set; }
[JsonProperty(PropertyName="DataCheckedBy")]
public string ExpectedAssociations { get; set; }
//...
}
If you're getting this error and you aren't sending entities directly through your API, copy the class that's failing to serialize to LINQPad and just call JsonConvert.SerializeObject() on it and it should give you a better error message than this crap. As soon as I tried this it gave me the following error message: A member with the name 'DataCheckedBy' already exists on 'UserQuery+ResultDto'. Use the JsonPropertyAttribute to specify another name.

After disable Proxy Creation, use eager loading (Include()) to load the proxy object.

In my Project EntityCollection returned from the WebApi action method.
Configuration.ProxyCreationEnabled = false not applicable. I have tried the below approach it is working fine for me.
Control Panel.
2.Turn on Windows Features on or off
Choose Internet Information Service
Check all the World Wide Web Components it would be better to check all the components in IIS.
Install the components.
Go to (IIS) type inetmgr in command prompt.
select the published code in the Virtual directory.
Convert into application
Browse it the application.

The answer by #Mahdi perfectly fixes the issue for me, however what I noticed is that if my Newtonsoft.JSON is 11.0 version then it doesn't fix the issue, but the moment I update Newtonsoft.JSON to latest 13.0 it starts working.

Related

Getting JsonSerializationException

I'm having an issue trying to convert an object to json. The error is a Newtonsoft.Json.JsonSerializationException:
Self referencing loop detected for property 'Project' with type 'System.Data.Entity.DynamicProxies.Project_F29F70EF89942F6344C5B0A3A7910EF55268857CD0ECC4A484776B2F4394EF79'. Path '[0].Categories[0]'.
The problem is that the object (it's actually a list of objects) has a property which is another object that refers back to the first object:
public partial class Project
{
...
public virtual ICollection<Category> Categories { get; set; }
...
}
public partial class Category
{
...
public virtual Project Project { get; set; }
...
}
This is all fine and dandy as far as Entity Framework is concerned, but to convert this to json would result in an infinite regress, hence the exception.
Here is my code:
public async Task<HttpResponseMessage> GetProjects()
{
var projects = _projectService.GetProjects().ToList();
string jsonString = JsonConvert.SerializeObject(projects); // <-- Offending line
return Request.CreateResponse(HttpStatusCode.OK, jsonString);
}
I've looked online for solutions to this and I found this stackoverflow post:
JSON.NET Error Self referencing loop detected for type
They suggest three solutions, none of which work:
1) Ignore the circular reference:
public async Task<HttpResponseMessage> GetProjects()
{
var projects = _projectService.GetProjects().ToList();
JsonSerializerSettings settings = new JsonSerializerSettings()
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
string jsonString = JsonConvert.SerializeObject(projects, settings);
return Request.CreateResponse(HttpStatusCode.OK, jsonString);
}
This resulted in the call to SerializeObject(...) hanging for a bit then throwing a System.OutOfMemoryException (which tells me the circular references were NOT being ignored).
Mind you, the author of this proposed solution at stackoverflow says to set the ignore setting in WebApiConfig.cs but I tried that and it has no effect.
He also says:
"If you want to use this fix in a non-api ASP.NET project, you can add the above line to Global.asax.cs, but first add: var config = GlobalConfiguration.Configuration;"
Mine's a web API with no global file so I shouldn't have to do this.
I also don't want to ignore circular references because I don't want to lose data.
2) Preserve the circular reference:
public async Task<HttpResponseMessage> GetProjects()
{
var projects = _projectService.GetProjects().ToList();
JsonSerializerSettings settings = new JsonSerializerSettings()
{
ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
PreserveReferencesHandling = PreserveReferencesHandling.Objects
};
string jsonString = JsonConvert.SerializeObject(projects, settings);
return Request.CreateResponse(HttpStatusCode.OK, jsonString);
}
This just resulted in the request timing out because it would just hang.
Again, the author says to put this in WebApiConfig.cs, but again this had no effect.
3) Add ignore/preserve reference attributes to the objects and properties:
Ignoring Categories:
public partial class Project
{
...
[JsonIgnore]
public virtual ICollection<Category> Categories { get; set; }
...
}
This has no effect. I hover over the project list and see that it still has categories, and each category still has an instance of the project. I still get the same exception.
Again, even if this worked, I don't want to ignore the categories.
Preserve Categories:
[JsonObject(IsReference = true)]
public partial class Project
{
...
public virtual ICollection<Category> Categories { get; set; }
...
}
Again, same results.
Even if this method worked, the attributes wouldn't be preserved. I'd be doing it on Entity Framework classes which are re-generated automatically every time I recompile. (Is there a way to tell it to set these attributes in the model? Can I set them on the other half of the partial class?)
Alternatively, I'm open to suggestions other than converting to json and sending back in the response. Is there another way to get the data back to the client?
What would be the fix to this problem? Thanks.
Briefly
The best way to fix this problem is to create completely brand-new Models (xxxModel, xxxViewModel, xxxResponse, etc..) on Presentation layer which will be returned to end-users. Than just cast one object to another using AutoMapper or your own custom methods.
Keep your database entities separate from real world!
In detail
There are so many problems that you will encounter:
Disclosure of sensitive data. Your database entity could/will contain sensitive data which end-users shouldn't receive;
Performance issues and waste of RAM and CPU. It would be better to load only those properties that end-users is required, instead all;
Serialization problems. EF entities almost always contain Navigation properties which will be serialized together in case lazy-loading enabled. Imagine dozens related entities, which will be lazy-loaded when your composite root is being serialized. It will cause dozens unexpected requests to database;
Fragility. Any changes related your EF entities will affect on Presentation Layer and on end-users. For instance, in case with API, new added property just extend response, but deleted or renamed will break logic in your customers' application.
There are a lot of other problems, just be careful.
I would recommend not Serializing Entity Framework classes and creating a specific class that only inherits from Object and has only the data you need

Breeze preloading unwanted nvaigation properties

I am using Entity Framework 6.1 with breeze 1.4.11. I am trying to save some data in local storage. My Breeze controller:
[HttpGet]
public object Lookups()
{
return new
{
lookupItems = _contextProvider.Context.LookupItem
};
}
My EF settings:
this.Configuration.ProxyCreationEnabled = false;
this.Configuration.LazyLoadingEnabled = false;
The class I am trying to load:
public class LookupItem : BaseEntityInt
{
public int LookupTypeId { get; set; }
public string Description { get; set; }
public int Ordinal { get; set; }
public virtual ICollection<Party> PartyCountries { get; set; }
}
My breeze client code:
_lookupsQuery = new breeze.EntityQuery.from("Lookups"),
em.executeQuery(_lookupsQuery).then(function (data) {
_lookups = data.results;
// Save data to local storage
store.setItem("Lookups", _lookups); // Fails here
});
The problem is when I save it in local storage, store uses amplifyJs to persist to local storage. AmplifyJs calls JSON.stringify on the persisted object. In the console of the browser I get the following error:
Error: cyclic object value
This is because breeze is automatically loading the navigation property of lookupitem 'partycountries' which itself links back to lookupitem. Anyone any idea why it is doing this? My understanding was you had to explicityly use eager loading or using the expand property (which I am not using) so I can't understand why it is having this behaviour.
The why it is happening can be explained here -
Calling ko.toJS on Breeze entity causes slow long running script
To get around it I believe you can over-ride the toString method on the entities that you are trying to serialize so that it ignores related navigation properties.
The reason I didn't mark this as a duplicate is you are using Amplify.js and some other users in the future might as well.
I can assure you Breeze is not loading the related PartyCountries. Either your server api is including them along with the "Lookups" query payload or you queried them into cache earlier and Breeze wired them up to you "Lookups" as they arrived. Based on the code you're showing us, I'd guess that you loaded PartyCountries earlier in the em (EntityManager) lifetime.
You might let Breeze serialize the entities for you. It takes care of circular references, won't include related entities, and also stores the changed-state with the serialized entities.
For example, with Amplify.store:
var exported = em.exportEntities(data.results, false /* exclude metadata */);
// Save data to local storage
store("Lookups", exported ); // Works!
Later you can retrieve and import them:
var imported = store("Lookups");
var importedEntities = em.importEntities(imported);
You can store an entire graph of entities (e.g., an order and its line items) with the help of the Breeze Labs "getEntityGraph" extension. Here it is applied to your model.
// graph of queried `LookupItems` and their in-cache, related 'PartyCountries'
var graph = em.getEntityGraph(data.results, 'PartyCountries');
var exported = em.exportEntities(graph , false /* exclude metadata */);
store("LookupsAndCountries", exported );

Set a key/id to a Workflow

New to Workflow Foundation, so it may be a basic question for many of you.
I have a workflow designer (client) /server application.
In the designer I can upload workflows to the server , which stores them in the DB. The designer can request to download a workflow from the server. Once downloaded , we can modify it in the designer and upload it again.
To be able to do that I need to add some sort of ID/Key to the workflow.
What's the best way to do that?
I was thinking about adding a property to the ActivityBuilder, but doing that adds it to the argument list, which doesn't seem right...
Any help would be much appreciated
Hi #Will, I gave it a go attaching the property to Activities but I can not get it working. I'm not using any models like WorkflowRecord, it's just a basic desginer.
I use _workflowDesigner.Save(path); to save it or _workflowDesigner.Load(path); to load it.
I create and add the attached property
attachProp = new AttachedProperty<int?>()
{
Name = "Key",
IsBrowsable = true,
Getter = (modelItem) => 5,
Setter = ((modelItem, keyValue) => modelItem.Properties["Key"].SetValue(keyValue)),
OwnerType = typeof(Activity)
};
_workflowDesigner.Context.Services.GetService<AttachedPropertiesService>().AddProperty(attachProp);
If I try to access the attached property, it throws me an exception (doesn't contain a definition for key)
dynamic mainActivity = ((_workflowDesigner.Context.Services.GetService<ModelService>().Root.GetCurrentValue() as ActivityBuilder).Implementation as Activity);
int? testValue = mainActivity.Key; //Exception, Activity' does not contain a definition for 'Key'
I read through this [post] (http://blogs.msdn.com/b/kushals/archive/2010/01/04/base-designer-with-additional-adornments.aspx) to add the attach property to the activity
Attached properties, via the AttachablePropertyServices Class.
public class WorkflowRecord
{
static AttachableMemberIdentifier Id =
new AttachableMemberIdentifier(typeof(Guid), "Id");
public static object GetCommentText(object instance)
{
object viewState;
AttachablePropertyServices.TryGetProperty(instance, Id, out viewState);
return viewState;
}
public static void SetCommentText(object instance, object value)
{
AttachablePropertyServices.SetProperty(instance, Id, value);
}
}
You can use this to get or set your database Id on an instance of the workflow, and it will be serialized/deserialized to/from xaml.
<Activity
xmlns:me="clr-namespace:Herp;assembly=derp"
me:WorkflowRecord.Id="This is a guid lol"
x:HideAdditionalAttributesBecauseThisIsAnExample="true" />
For more info, read this blog post on msdn

Why is my Entity Framework Code First proxy collection null and why can't I set it?

I am using DBContext and have two classes whose properties are all virtual. I can see in the debugger that I am getting a proxy object when I query the context. However, a collection property is still null when I try to add to it. I thought that the proxy would ensure that collection is initialized.
Because my Poco object can be used outside of its data context, I added a check for the collection being null in the constructor and create it if necessary:
public class DanceStyle
{
public DanceStyle()
{
if (DanceEvents == null)
{
DanceEvents = new Collection<DanceEvent>();
}
}
...
public virtual ICollection<DanceEvent> DanceEvents { get; set; }
}
That works outside the data context but if I retrieve an object using a query, although the test is true, when I try to set it, I get following exception: 'The property 'DanceEvents' on type 'DanceStyle_B6089AE40D178593955F1328A70EAA3D8F0F01DDE9F9FBD615F60A34F9178B94' cannot be set because the collection is already set to an EntityCollection.'
I can see it is null and I cannot add to it, but neither can I set it to a collection because the proxy says it is already set. Therefore I cannot use it. I'm confused.
Here is the DanceEvent class:
public class DanceEvent
{
public DanceEvent()
{
if (DanceStyles == null)
{
DanceStyles = new Collection<DanceStyle>();
}
}
...
public virtual ICollection<DanceStyle> DanceStyles { get; set; }
}
I have omitted the other value-type properties from the code above. I have no other mappings for those classes in the context class.
As you correctly observed in the answer to your own question, removing the "virtual" keyword from the collection properties works around the problem, by preventing the Entity Framework from creating a change tracking proxy. However, this is not a solution for many people, because change tracking proxies can be really convenient and can help prevent issues when you forget to detect changes at the right places in your code.
A better approach would be to modify your POCO classes, so that they instantiate the collection properties in their get accessor, rather than in the constructor. Here's your POCO class, modified to allow change tracking proxy creation:
public class DanceEvent
{
private ICollection<DanceStyle> _danceStyles;
public virtual ICollection<DanceStyle> DanceStyles
{
get { return _danceStyles ?? (_danceStyles = new Collection<DanceStyle>()); }
protected set { _danceStyles = value; }
}
}
In the above code the collection property is no longer automatic, but rather has a backing field. It's better if you leave the setter protected, preventing any code (other than the proxy) from subsequently modifying these properties. You will notice that the constructor was no longer necessary and was removed.
I found the solution to this problem here: Code First adding to collections? How to use Code First with repositories?
I removed 'virtual' from all properties except collections and lazy loaded objects, that is, all native types.
But I still don't understand how you can end up with the situation where you have a null collection that you cannot use and have no way to set it to a valid collection.
I also found this answer from Rowan Miller on an MSDN forum
Hi,
If you make all your properties virtual then EF will generate proxy classes at runtime that derives from your POCO classed, these proxies allow EF to find out about changes in real time rather than having to capture the original values of your object and then scan for changes when you save (this is obviously has performance and memory usage benefits but the difference will be negligible unless you have a large number of entities loaded into memory). These are known as 'change tracking proxies', if you make your navigation properties virtual then a proxy is still generated but it is much simpler and just includes some logic to perform lazy loading when you access a navigation property.
Because your original code was generating change tracking proxies, EF was replacing your collection property with a special collection type to help it find out about changes. Because you try and set the collection back to a simple list in the constructor you are getting the exception.
Unless you are seeing performance issues I would follow Terrence's suggestion and just remove 'virtual' from your non-navigation properties.
~Rowan
So it appears that I only have the problem with a full 'change tracking proxy' if all my properties are virtual. But given that, why can I still not use the virtual property on the change tracking proxy? This code blows up on line three because ds2.DanceEvents is null and cannot be set in the constructor:
DanceStyle ds2 = ctx.DanceStyles.Where(ds => ds.DanceStyleId == 1).Single();
DanceEvent evt = CreateDanceEvent();
ds2.DanceEvents.Add(evt);
I'm still confused, even though my code is now working because of the fix above.
Old question...
Poco class:
public partial class MyPOCO
{
public MyPOCO()
{
this.MyPocoSub = new HashSet<MyPocoSub>();
}
//VIRTUAL
public virtual ICollection<MyPocoSub> MyPocoSub { get; set; }
}
and proxy code:
public override ICollection<MyPocoSubSet> MyPocoSubSets
{
get
{
ICollection<MyPocoSubSet> myPocoSubSets = base.MyPocoSubSets;
if (!this.ef_proxy_interceptorForMyPocoSubSets(this, myPocoSubSets))
{
return base.MyPocoSubSets;
}
return myPocoSubSets;
}
set
{
if (value != this.RelationshipManager.GetRelatedEnd("WindowsFormsApplication.Models.MyPocoSubSet_MyPOCO", "MyPocoSubSet_MyPOCO_Source"))
{
// EXCEPTION
throw new InvalidOperationException("The property 'MyPocoSubSets' on type 'MyPOCO_A78FCE6C6A890855C68B368B750864E3136B589F9023C7B1D90BF7C83FD291AC' cannot be set because the collection is already set to an EntityCollection.");
}
base.MyPocoSubSets = value;
}
}
As you can see that exception raised in proxy class in ExtityFramework 5. This means that behavior still exist.

RIA Services EntitySet does not support 'Edit' operation

Making my first steps in RIA Services (VS2010Beta2) and i encountered this problem:
created an EF Model (no POCOs), generic repository on top of it and a RIA Service(hosted in an ASP.NET MVC application) and tried to get data from within the ASP.NET MVC application: worked well.
Next step: Silverlight client. Got a reference to the RIAService (through its context), queried for all the records of the repository and got them into the SL application as well (using this code sample):
private ObservableCollection<Culture> _cultures = new ObservableCollection<Culture>();
public ObservableCollection<Culture> cultures
{
get { return _cultures; }
set
{
_cultures = value;
RaisePropertyChanged("cultures");
}
}
....
//Get cultures
EntityQuery<Culture> queryCultures = from cu in dsCtxt.GetAllCulturesQuery()
select cu;
loCultures = dsCtxt.Load(queryCultures);
loCultures.Completed += new EventHandler(lo_Completed);
....
void loAnyCulture_Completed(object sender, EventArgs e)
{
ObservableCollection<Culture> temp=
new ObservableCollection<Culture>loAnyCulture.Entities);
AnyCulture = temp[0];
}
The problem is this: whenever i try to edit some data of a record (in this example the first record) i get this error:
This EntitySet of type 'Culture' does not support the 'Edit' operation.
I thought that i did something weird and tried to create an object of type Culture and assign a value to it: it worked well!
What am i missing? Do i have to declare an EntitySet? Do i have to mark it? Do i have to...what?
Thanks in advance
It turns out that in the DomainService class one has to implement (or at least to mark "placeholder methods") as "Edit", "Delete",... eg
[Delete]
public void DeleteCulture(Culture currentCulture)
{
throw new NotImplementedException("UpdateCulture not Implemented yet");
}
[Insert]
public void InsertCulture(Culture newCulture)
{
throw new NotImplementedException("InsertCulture not Implemented yet");
}
This way the OrganizationDomainContextEntityContainer class creates an EntitySet with parameter EntitySetOperations.All (meaning that all the CUD operations are available).
Hope it's useful for someone in the future!