Babak Sekandari
asked on
Serialization Exception in .NET WEB API.
I have an ASP.NET WEB API project in Framework 7 using Entity Framework.
(I would have preferred .NET Core but my manager chose this.)
I'm able to make a successful call if I make my Get verb like this:
public string Get(int id)
{
User sr = new DataAccess.User();
using (var ent = new DevDataEntities())
{
sr = ent.Users.FirstOrDefault(x => x.UserId == id);
return sr.DisplayName;
}
}
But I get an error when I try any of these methods I get an error:
1.
public User Get(int id)
{
User sr = new ACH_DataAccess.User();
using (var entities = new ACH_DevDataEntities())
{
sr = entities.Users.FirstOrDefault(x => x.UserId == id);
return sr;
}
}
2.
public User Get(int id)
{
User sr = new ACH_DataAccess.User();
using (var entities = new ACH_DevDataEntities())
{
sr = entities.Users.FirstOrDefault(x => x.UserId == id);
}
return sr;
}
3.public User Get(int id)
{
using (var entities = new ACH_DevDataEntities())
{
var sr = entities.Users.FirstOrDefault(x => x.UserId == id);
return sr;
}
}
Here is the page I get:
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.
</ExceptionMessage>
<ExceptionType>System.InvalidOperationException</ExceptionType>
<StackTrace/>
<InnerException>
<Message>An error has occurred.</Message>
<ExceptionMessage>
Type 'System.Data.Entity.DynamicProxies.User_9A7F08A3597175E07FDCEE95052760F3C97BAD33B600B22C35ACEF344C52B7D2' with data contract name 'User_9A7F08A3597175E07FDCEE95052760F3C97BAD33B600B22C35ACEF344C52B7D2:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies' is not expected. Consider using a DataContractResolver if you are using DataContractSerializer or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to the serializer.
</ExceptionMessage>
<ExceptionType>
System.Runtime.Serialization.SerializationException
</ExceptionType>
<StackTrace>
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeAndVerifyType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, Boolean verifyKnownType, RuntimeTypeHandle declaredTypeHandle, Type declaredType) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithXsiTypeAtTopLevel(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle originalDeclaredTypeHandle, Type graphType) at System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.DataContractSerializer.WriteObject(XmlWriter writer, Object graph) at System.Net.Http.Formatting.XmlMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content) at System.Net.Http.Formatting.XmlMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken) --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__22.MoveNext()
</StackTrace>
</InnerException>
</Error>
When I call it through Postman, I get a "Satus: 400 Bad Request. The request cannot be fullfilled due to bad syntax."
When I step through the debugger, I see that data is returned; but getting it to the browser or to Postman fails.
One of the User properties in the database is varbinary(max) but that comes back as null.
Oddly, when I remove it from the EF model, it continues to appear in the debugger.
I got this to work:
public Dictionary<string, string> Get(int id)
{
User sr = new ACH_DataAccess.User();
StringBuilder sb = new StringBuilder();
using (var entities = new ACH_DevDataEntities())
{
sr = entities.Users.FirstOrDefault(x => x.UserId == id);
}
sr.AvatarImg = new byte[] { 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 };
Dictionary<string, string> dctUser = new Dictionary<string, string>();
dctUser.Add("Display Name", sr.DisplayName);
dctUser.Add("Email", sr.Email);
return dctUser;
}
But that seems like a lot of work if the User class has many properties.
The DataContractResolver example here seemed unrealisticly complex for what seems like what should be an easy solution:
https://docs.microsoft.com/en-us/dotnet/framework/wcf/samples/datacontractresolver
(I would have preferred .NET Core but my manager chose this.)
I'm able to make a successful call if I make my Get verb like this:
public string Get(int id)
{
User sr = new DataAccess.User();
using (var ent = new DevDataEntities())
{
sr = ent.Users.FirstOrDefault(x => x.UserId == id);
return sr.DisplayName;
}
}
But I get an error when I try any of these methods I get an error:
1.
public User Get(int id)
{
User sr = new ACH_DataAccess.User();
using (var entities = new ACH_DevDataEntities())
{
sr = entities.Users.FirstOrDefault(x => x.UserId == id);
return sr;
}
}
2.
public User Get(int id)
{
User sr = new ACH_DataAccess.User();
using (var entities = new ACH_DevDataEntities())
{
sr = entities.Users.FirstOrDefault(x => x.UserId == id);
}
return sr;
}
3.public User Get(int id)
{
using (var entities = new ACH_DevDataEntities())
{
var sr = entities.Users.FirstOrDefault(x => x.UserId == id);
return sr;
}
}
Here is the page I get:
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.
</ExceptionMessage>
<ExceptionType>System.InvalidOperationException</ExceptionType>
<StackTrace/>
<InnerException>
<Message>An error has occurred.</Message>
<ExceptionMessage>
Type 'System.Data.Entity.DynamicProxies.User_9A7F08A3597175E07FDCEE95052760F3C97BAD33B600B22C35ACEF344C52B7D2' with data contract name 'User_9A7F08A3597175E07FDCEE95052760F3C97BAD33B600B22C35ACEF344C52B7D2:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies' is not expected. Consider using a DataContractResolver if you are using DataContractSerializer or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to the serializer.
</ExceptionMessage>
<ExceptionType>
System.Runtime.Serialization.SerializationException
</ExceptionType>
<StackTrace>
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeAndVerifyType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, Boolean verifyKnownType, RuntimeTypeHandle declaredTypeHandle, Type declaredType) at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithXsiTypeAtTopLevel(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle originalDeclaredTypeHandle, Type graphType) at System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver) at System.Runtime.Serialization.DataContractSerializer.WriteObject(XmlWriter writer, Object graph) at System.Net.Http.Formatting.XmlMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content) at System.Net.Http.Formatting.XmlMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken) --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__22.MoveNext()
</StackTrace>
</InnerException>
</Error>
When I call it through Postman, I get a "Satus: 400 Bad Request. The request cannot be fullfilled due to bad syntax."
When I step through the debugger, I see that data is returned; but getting it to the browser or to Postman fails.
One of the User properties in the database is varbinary(max) but that comes back as null.
Oddly, when I remove it from the EF model, it continues to appear in the debugger.
I got this to work:
public Dictionary<string, string> Get(int id)
{
User sr = new ACH_DataAccess.User();
StringBuilder sb = new StringBuilder();
using (var entities = new ACH_DevDataEntities())
{
sr = entities.Users.FirstOrDefault(x => x.UserId == id);
}
sr.AvatarImg = new byte[] { 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 };
Dictionary<string, string> dctUser = new Dictionary<string, string>();
dctUser.Add("Display Name", sr.DisplayName);
dctUser.Add("Email", sr.Email);
return dctUser;
}
But that seems like a lot of work if the User class has many properties.
The DataContractResolver example here seemed unrealisticly complex for what seems like what should be an easy solution:
https://docs.microsoft.com/en-us/dotnet/framework/wcf/samples/datacontractresolver
Type 'System.Data.Entity.DynamicProxies.User_9A7F08A3597175E07FDCEE95052760F3C97BAD33B600B22C35ACEF344C52B7D2' with data contract name 'User_9A7F08A3597175E07FDCEE95052760F3C97BAD33B600B22C35ACEF344C52B7D2EF generated proxy version of model so it tracks when the object is changed when you save changes.
You can turn off Proxy object creation in DbConext for all model.
DbContext.Configuration.ProxyCreationEnabled = false;
or you can disable tracking for each model/query:
entities.Users.AsNoTracking().FirstOrDefault(x => x.UserId == id);
ASKER
Thank you Prakash,
In what file do I put the code you showed for turning off Proxy object creation in DbConext?
In what file do I put the code you showed for turning off Proxy object creation in DbConext?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
re: "You can either pass the namespace"
In which file and how is that passed in?
re: "Or switch to XmlSerializer in your Web API configuration"
Is that in the Web.config file? The WebAPIConfig file? Where in there?