Querying entities throws "Invalid Operation Exception" on enum field - entity-framework

I was just trying some features of entity framework 5 and kendo ui. I have a following ProductType enum
public enum ProductType {
[Description("Hazardous")]
Hazardous,
[Description("Non Hazardous")]
NonHazardous
}
This enum type is one of the field in the Product Entity.
[Table("Products")]
public class Product {
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
//Other Fields ...
[Required(ErrorMessage="Product Type is Required")]
public ProductType ProductType {get;set;}
}
The ProductType column in the underlying SQL Server Database is defined as (tinyint, not null).
I access list of Products in the following Controller Action of MVC
public ActionResult _ProductList(int pageSize, int skip) {
using (WorkUnit workUnit = new WorkUnit()) {
IQueryable<Product> products = workUnit.ProductRepository.GetAllProducts()
.Include(p => p.Category);
int total = products.Count();
List<Product> productList = products.ToList<Product>(); //Throws InvalidOperationException
return Json(new { total = total, data = productList }, JsonRequestBehavior.AllowGet);
}
}
Here is the description of the InvalidOperationException that is thrown on products.ToList() in the above controller action.
The 'ProductType' property on 'Product' could not be set to a 'Byte' value.
You must set this property to a non-null value of type 'ProductType'.
Any guesses why ToList() is throwing an InvalidOperationException.
Just for info, the Database existed previously, and the Entities were manually coded based on the Database as POCO's.
Edit
Here is the complete exception details
System.InvalidOperationException was unhandled by user code
HResult=-2146233079
Message=The 'ProductType' property on 'Product' could not be set to a 'Byte' value. You must set this property to a non-null value of type 'ProductType'.
Source=System.Data.Entity
StackTrace:
at System.Data.Common.Internal.Materialization.Shaper.ErrorHandlingValueReader`1.GetValue(DbDataReader reader, Int32 ordinal)
at System.Data.Common.Internal.Materialization.Shaper.GetPropertyValueWithErrorHandling[TProperty](Int32 ordinal, String propertyName, String typeName)
at lambda_method(Closure , Shaper )
at System.Data.Common.Internal.Materialization.Shaper.HandleEntityAppendOnly[TEntity](Func`2 constructEntityDelegate, EntityKey entityKey, EntitySet entitySet)
at lambda_method(Closure , Shaper )
at System.Data.Common.Internal.Materialization.Coordinator`1.ReadNextElement(Shaper shaper)
at System.Data.Common.Internal.Materialization.Shaper`1.SimpleEnumerator.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at KendoUI_Web_Demo.Controllers.HomeController._ProductList(Int32 pageSize, Int32 skip) in d:\Practice\ASP.NET_MVC\KendoUI_Web_Demo\KendoUI_Web_Demo\Controllers\HomeController.cs:line 52
at lambda_method(Closure , ControllerBase , Object[] )
at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass42.<BeginInvokeSynchronousActionMethod>b__41()
at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.End()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass37.<>c__DisplayClass39.<BeginInvokeActionMethodWithFilters>b__33()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49()
InnerException:

There is a mismatch between the enum type which in your case is int based and your database where the column is byte (tinyint) based. You can fix this by setting the correct underlying type of your enum type:
public enum ProductType : byte
{
...
}

Related

Automapper ProjectTo and JSON column

I have some simple models in EF Core (with a Postgres backend using Npgsql).
public class Test : Model
{
public string Id { get; set; }
public TestInfo Info { get; set; }
public string Name { get; set; }
}
public class TestInfo
{
public string[] Tags { get; set; }
public string Name { get; set; }
public int[] Counts { get; set; }
}
public class TestDTO
{
public string[] Tags { get; set; }
public string Name { get; set; }
public string InfoName{ get; set; }
public int[] Counts { get; set; }
}
The EF Core config and Autommaper profile are
public class TestConfig
{
public override void Configure(EntityTypeBuilder<Test> builder)
{
builder.HasKey(m => m.Id);
builder.Property(s => s.Info)
.HasConversion(
v => JsonConvert.SerializeObject(v),
v => JsonConvert.DeserializeObject<TestInfo>(v)
)
.HasColumnType("jsonb");
builder.HasIndex(s => s.Info)
.HasMethod("gin")
.HasOperators("jsonb_ops");
}
}
public class TestProfile : Profile
{
public TestProfile()
{
CreateMap<Test, TestDTO>()
.ForMember(dest => dest.InfoName, opt => opt.MapFrom(src => src.Info.Name))
.ForMember(dest => dest.Tags, opt => opt.MapFrom(src => src.Info.Tags))
.ForMember(dest => dest.Counts, opt => opt.MapFrom(src => src.Info.Counts))
.ReverseMap();
}
}
I have been trying to use Automapper's ProjectTo to query but unable to figure out how to make it work. The below controller code throws coercion errors
[HttpGet]
[Route("/test/{id}")]
public async Task<IActionResult> GetTest([FromRoute (Name = "id")][Required]string id)
{
var t = await _mapper.ProjectTo<TestDTO>(
_context.Tests.Where(s => s.Id == id)
)
.ToListAsync();
return Ok(t);
}
Errors (there is another error from System.String to System.string[] for Tags but I left out for brevity)
System.InvalidOperationException: No coercion operator is defined between types 'System.String' and 'System.Int32[]'.
at System.Linq.Expressions.Expression.GetUserDefinedCoercionOrThrow(ExpressionType coercionType, Expression expression, Type convertToType)
at System.Linq.Expressions.Expression.Convert(Expression expression, Type type, MethodInfo method)
at System.Linq.Expressions.Expression.Convert(Expression expression, Type type)
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.CreateGetValueExpression(ParameterExpression dbDataReader, Int32 index, Boolean nullable, RelationalTypeMapping typeMapping, Type type, IPropertyBase property)
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.VisitExtension(Expression extensionExpression)
at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at System.Linq.Expressions.ExpressionVisitor.VisitMemberAssignment(MemberAssignment node)
at System.Linq.Expressions.ExpressionVisitor.VisitMemberBinding(MemberBinding node)
at System.Linq.Expressions.ExpressionVisitor.Visit[T](ReadOnlyCollection`1 nodes, Func`2 elementVisitor)
at System.Linq.Expressions.ExpressionVisitor.VisitMemberInit(MemberInitExpression node)
at System.Linq.Expressions.MemberInitExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.ProcessShaper(Expression shaperExpression, RelationalCommandCache& relationalCommandCache, LambdaExpression& relatedDataLoaders)
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.VisitShapedQuery(ShapedQueryExpression shapedQueryExpression)
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.VisitExtension(Expression extensionExpression)
at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass12_0`1.<ExecuteAsync>b__0()
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetAsyncEnumerator(CancellationToken cancellationToken)
at System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable`1.GetAsyncEnumerator()
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
at dms_apis.Controllers.OrganisationController.GetTest(String id) in /home/viet/src/dms-apis/Controllers/OrganisationController.cs:line 62
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
I tried manual mapping using Select in the controller and that appears to work but ProjectTo seems to be much nicer
[HttpGet]
[Route("/test/{id}")]
public async Task<IActionResult> GetTest([FromRoute (Name = "id")][Required]string id)
{
var t = _context.Tests
.Select(s => new TestDTO{
Id = s.Id,
Name = s.Info.Name
})
.Where(s => s.Id == id)
.ToList();
return Ok(t);
}
What is the correct way to use ProjectTo in this case? Thanks a lot.

AutoMapper ProjectTo() can't construct protobuf RepeatedField<> property

I have an gRPC application with EF core as ORM. AutoMapper's ProjectTo method is used to construct DTOs. But I get error when constructing collection properties. I prepared the following example:
Database entities:
public sealed class Horse
{
public Guid Id { get; init; }
public ICollection<Workout> Workouts { get; } = new HashSet<Workout>();
}
public sealed class Workout
{
public Guid Id { get; init; }
}
Context:
public sealed class MyDbContext : DbContext
{
public MyDbContext(DbContextOptions<MyDbContext> options) : base(options) { }
public DbSet<Horse> Horse { get; private init; } = null!;
}
DTOs:
public sealed class HorseDto
{
public Guid Id { get; init; }
public RepeatedField<WorkoutDto> Workouts { get; init; } = new RepeatedField<WorkoutDto>();
}
public sealed class WorkoutDto
{
public Guid Id { get; init; }
}
Mapping:
var mapperConfiguration =
new MapperConfiguration(_ =>
{
_.CreateMap<Horse, HorseDto>();
_.CreateMap<Workout, WorkoutDto>();
});
When I do:
var horseDto = await context.Horse
.Where(_ => _.Workouts.Count > 0)
.ProjectTo<HorseDto>(mapperConfiguration)
.FirstAsync();
I get:
System.ArgumentException: Argument types do not match
at System.Linq.Expressions.Expression.Bind(MemberInfo member, Expression expression)
at AutoMapper.QueryableExtensions.Impl.EnumerableExpressionBinder.BindEnumerableExpression(IConfigurationProvider configuration, PropertyMap propertyMap, ExpressionRequest request, ExpressionResolutionResult result, IDictionary`2 typePairCount, LetPropertyMaps letPropertyMaps)
at AutoMapper.QueryableExtensions.Impl.EnumerableExpressionBinder.Build(IConfigurationProvider configuration, PropertyMap propertyMap, TypeMap propertyTypeMap, ExpressionRequest request, ExpressionResolutionResult result, IDictionary`2 typePairCount, LetPropertyMaps letPropertyMaps)
at AutoMapper.QueryableExtensions.ExpressionBuilder.<>c__DisplayClass10_0.<CreateMapExpressionCore>g__CreateMemberBinding|4(PropertyExpression propertyExpression, <>c__DisplayClass10_1& )
at AutoMapper.QueryableExtensions.ExpressionBuilder.<>c__DisplayClass10_0.<CreateMapExpressionCore>g__CreateMemberBindings|1()
at AutoMapper.QueryableExtensions.ExpressionBuilder.CreateMapExpressionCore(ExpressionRequest request, Expression instanceParameter, IDictionary`2 typePairCount, TypeMap typeMap, LetPropertyMaps letPropertyMaps)
at AutoMapper.QueryableExtensions.ExpressionBuilder.CreateMapExpressionCore(ExpressionRequest request, Expression instanceParameter, IDictionary`2 typePairCount, LetPropertyMaps letPropertyMaps, TypeMap& typeMap)
at AutoMapper.QueryableExtensions.ExpressionBuilder.CreateMapExpression(ExpressionRequest request, IDictionary`2 typePairCount, LetPropertyMaps letPropertyMaps)
at AutoMapper.QueryableExtensions.ExpressionBuilder.CreateMapExpression(ExpressionRequest request)
at AutoMapper.Internal.LockingConcurrentDictionary`2.<>c__DisplayClass2_1.<.ctor>b__1()
at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
at System.Lazy`1.CreateValue()
at System.Lazy`1.get_Value()
at AutoMapper.Internal.LockingConcurrentDictionary`2.GetOrAdd(TKey key)
at AutoMapper.QueryableExtensions.ExpressionBuilder.GetMapExpression(Type sourceType, Type destinationType, Object parameters, MemberInfo[] membersToExpand)
at AutoMapper.QueryableExtensions.ProjectionExpression.ToCore(Type destinationType, Object parameters, IEnumerable`1 memberPathsToExpand)
at AutoMapper.QueryableExtensions.ProjectionExpression.ToCore[TResult](Object parameters, IEnumerable`1 memberPathsToExpand)
at AutoMapper.QueryableExtensions.ProjectionExpression.To[TResult](Object parameters, Expression`1[] membersToExpand)
at AutoMapper.QueryableExtensions.Extensions.ProjectTo[TDestination](IQueryable source, IConfigurationProvider configuration, Object parameters, Expression`1[] membersToExpand)
at AutoMapper.QueryableExtensions.Extensions.ProjectTo[TDestination](IQueryable source, IConfigurationProvider configuration, Expression`1[] membersToExpand)
at RepeatedFieldExample.Sandbox.Run()
Everything works fine if I replace RepeatedField<> with IEnumerable<>.
Workable direct LINQ Select:
var horseDto = await ctx.Horse
.Where(h => h.Workouts.Count > 0)
.Select(h => new HorseDto()
{
Id = h.Id,
Workouts = new RepeatedField<WorkoutDto>()
{
h.Workouts.Select(w => new WorkoutDto() {Id = w.Id})
}
})
.FirstAsync();
AutoMapper version is 10.1.1

Executing Stored Procedure with Entity Framework

We are currently developing an internal system, using the repository pattern and Entity Framework 5 as our ORM.
We have a bunch of stored procedures in our database that we call. Some of these procedures have similar parameter names. So when we make a call to execute the stored procedure, like so:
DbContext.Database.SqlQuery<ReturnType>(query, parameters)
The resulting enumerable fails on the second call to another procedure with a similar parameter name, saying:
ArgumentException was unhandled by user code: The SqlParameter is already contained by another SqlParameterCollection.
We have tried putting all SqlParameters into a collection which we loop through and null out all the items in the collection, but this fails as well....gloriously.
Is there a way to reach and manipulate the Object array in this stack trace?
at System.Data.SqlClient.SqlParameterCollection.Validate(Int32 index, Object value)
at System.Data.SqlClient.SqlParameterCollection.AddRange(Array values)
at System.Data.Objects.ObjectContext.CreateStoreCommand(String commandText, Object[] parameters)
at System.Data.Objects.ObjectContext.ExecuteStoreQueryInternal[TElement](String commandText, String entitySetName, MergeOption mergeOption, Object[] parameters)
at System.Data.Objects.ObjectContext.ExecuteStoreQuery[TElement](String commandText, Object[] parameters)
at System.Data.Entity.Internal.InternalContext.ExecuteSqlQuery[TElement](String sql, Object[] parameters)
at System.Data.Entity.Internal.InternalContext.ExecuteSqlQueryAsIEnumerable[TElement](String sql, Object[] parameters)
at System.Data.Entity.Internal.InternalContext.ExecuteSqlQuery(Type elementType, String sql, Object[] parameters)
at System.Data.Entity.Internal.InternalSqlNonSetQuery.GetEnumerator()
at System.Data.Entity.Internal.InternalSqlQuery1.GetEnumerator()
at System.Linq.Enumerable.First[TSource](IEnumerable1 source)
you can do something like that:
List<ReturnType> obj = DbContext.Database.SqlQuery<ReturnType>(query, parameters).ToList();
it will bind the variable obj, after that you can call the obj how many times you want without problem with sqlParameter.
I have not been able to resolve the issue, the command object in the built in SqlQuery method does not seem to clear the sql parameters, however I have a work around.
you can create your own command based on the current connection - but you will lose the ability to easily map out a return type.
public void CallStoredProc(string query, List<SqlParameter> parameters)
{
//this.Database.Connection (this = DBContext)
System.Data.Common.DbCommand cmd = this.Database.Connection.CreateCommand();
cmd.CommandText = query;
// add params
foreach (var item in parameters)
{
cmd.Parameters.Add(item);
}
// execute query (not differed)
var reader = cmd.ExecuteReader();
// attempt to read rows
if (reader.HasRows)
{
while (reader.Read())
{
// row level data
}
}
// cleanup
cmd.Parameters.Clear();
cmd.Dispose();
}
Are you able to make a copy of your parameters collection and each parameter that in rather than reusing the same instances of the parameters? Maybe have a helper method somewhere that automatically duplicates it for you.
Create Stored Procedure
ALTER PROCEDURE [dbo].[sp_GelUserContactDetails]
(
#Id INT=0,
#UserId int=0
)
AS
BEGIN
SELECT M.Id AS UserID, M.FirstName as Name,M.Designation,M.CompanyName FROM dbo.Flo_MemberShip M
WHERE ID=#Id
END
// Creating Stored Procedure that hold result of class MyContacts
public class MyContacts
{
public int UserID { get; set; }
public string Designation { get; set; }
public string Name { get; set; }
public string Organization { get; set; }
public string Image { get; set; }
public string RequestDate { get; set; }
public string IsContact { get; set; }
}
here I am creating a Entity that`s name is MyContacts. Here the MyContacts properties name must be the same as the returned column of the select statement of the Stored Procedure.
using (var context = new FLOEntities())
{
string query = "sp_GelUserContactDetails #Id,#UserId";
SqlParameter Id = new SqlParameter("#Id", selfId);
SqlParameter UserId = new SqlParameter("#UserId", userId);
obj = context.Database.SqlQuery<MyContacts>(query, Id, UserId).FirstOrDefault();
}
return obj;
click here
I found a solution, sort of a work around this issue. The stored proc call is made to instantiate a new DbContext that will be disposed after execution, like so.
IEnumerable<ReturnType> Results = null;
using (DbContext NewContext = new PrometheusEntities())
{
Results = NewContext.Database.SqlQuery<ReturnType>(query, parameters).ToList();
}
return Results;
I haven't experienced any issues since employing this method.

Failed to serialize the response body for content type

I'm building a MVC4 application that uses both Controllers and ApiControllers. I modified the default Web API route to include action names. When I try to get a list of Benchmarks, I'm getting this error message:
The 'ObjectContent`1' type failed to serialize the response body for
content type 'application/json; charset=utf-8'
The InnerException is this (I'm returning JSON in that case, same happens with XML):
"InnerException": {
"Message": "An error has occurred.",
"ExceptionMessage": "Error getting value from 'IdentityEqualityComparer' on 'NHibernate.Proxy.DefaultLazyInitializer'.",
"ExceptionType": "Newtonsoft.Json.JsonSerializationException",
"StackTrace": " at Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeISerializable(JsonWriter writer, ISerializable value, JsonISerializableContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter writer, IWrappedCollection values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value) at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value) at System.Net.Http.Formatting.JsonMediaTypeFormatter.<>c__DisplayClassd.<WriteToStreamAsync>b__c() at System.Threading.Tasks.TaskHelpers.RunSynchronously(Action action, CancellationToken token)",
"InnerException": {
"Message": "An error has occurred.",
"ExceptionMessage": "Common Language Runtime detected an invalid program.",
"ExceptionType": "System.InvalidProgramException",
"StackTrace": " at GetIdentityEqualityComparer(Object ) at Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target)"
}
This is the code that I run:
// GET api/benchmark/getincomplete
[HttpGet]
public IList<Benchmark> GetIncomplete()
{
var s = HibernateModule.CurrentSession;
var benchList = s.QueryOver<Benchmark>()
.Where(b => !b.Completed)
.Where(b => !b.Deleted)
.OrderBy(b => b.Id).Asc
.List<Benchmark>();
return benchList;
}
And this is the Benchmark model:
public class Benchmark
{
public virtual int Id { get; set; }
[Required]
[DataType(DataType.Date)]
public virtual DateTime Date { get; set; }
[Required, ScriptIgnore]
public virtual IList<TestResult> Results { get; set; }
[Required]
public virtual IList<TestCase> TestCases { get; set; }
[AllowHtml]
public virtual string Description { get; set; }
public virtual Device Device { get; set; }
public virtual bool Published { get; set; }
[Display(Name = "Deleted"), ScriptIgnore]
public virtual bool Deleted { get; set; }
public virtual bool Completed { get; set; }
public Benchmark()
{
Results = new List<TestResult>();
TestCases = new List<TestCase>();
Published = false;
Deleted = false;
Completed = false;
}
}
I'm not quite sure where the problem lies. Could it be the NHibernate Proxy (I use Fluent NHibernate)? The odd thing is that if I don't use an ApiController, and manually return JSON, this works just perfectly!
Update:
As per the answer below, this is the code I had to add in Application_Start() :
HttpConfiguration config = GlobalConfiguration.Configuration;
((DefaultContractResolver)config.Formatters.JsonFormatter.SerializerSettings.ContractResolver).IgnoreSerializableAttribute = true;
This fixes the JSON error, good luck with XML. Add this to the WebApiConfig class under the Register Method.
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling=Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
UPDATE:
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 the first method I posted still works.
The IdentityEqualityCompairer in the NHibernate framework appears to have the [SerializableAttribute] annotation.
Taken from a comment on an answer here Why won't Web API deserialize this but JSON.Net will? it looks like JSON.NET is configured a little differently between WebApi usage and it's standalone usage.
Json.NET serializer by default set the IgnoreSerializableAttribute to true. In WebAPI, we set that to false.
So given you cannot take the [SerializableAttribute] off (as it is not within your code) you could try changing the default WebApi JSON.NET setting to ignore it using this answer here:
((DefaultContractResolver)config.Formatters.JsonFormatter.SerializerSettings.ContractResolver).IgnoreSerializableAttribute = true;
Perhaps also consider Using a DTO for your results being sent over in the response - this will give you full control over the object being sent over the wire.
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 navigation properties such as IList Locations, I just created the viewmapper/dto entity on top of it to return.
It works find 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;}
}

Entity Framework and System.Data.Sqlite Datetime issue

I have a problem with mapping existing sqlite3 database (over system.data.sqlite) with entity framework (version 5) code first.
There is a table in database called notes that I map to my entity class:
public class Note
{
[Column("ZNAME")
public string Name { get; set; }
[Column("ZDATE")]
public DateTime Date { get; set; }
[Column("ZNOTE")]
public string Description { get; set; }
}
In database for example I have 2 rows, one has ZDATE field empty, other has some date (example: 30/12/1899 21:00:05).
When I unit test it, and when trying to get whole collection or this first row with empty datetime field I get the infamous exception: "String was not recognized as a valid DateTime." Trying to get only other row (with date), my test passes.
At first I thought that changing DateTime to string will solved the problem, but it gives me the same exception. I tried using DateTime?, same error.
It looks like, maybe I'm wrong, that System.Data.Sqlite tries to convert that field to datetime (because of name or something).
This is the stacktrace of my exception:
at System.DateTimeParse.ParseExactMultiple(String s, String[] formats, DateTimeFormatInfo dtfi, DateTimeStyles style)
at System.DateTime.ParseExact(String s, String[] formats, IFormatProvider provider, DateTimeStyles style)
at System.Data.SQLite.SQLiteConvert.ToDateTime(String dateText, SQLiteDateFormats format, DateTimeKind kind)
at System.Data.SQLite.SQLiteConvert.ToDateTime(String dateText)
at System.Data.SQLite.SQLiteConvert.ToDateTime(IntPtr ptr, Int32 len)
at System.Data.SQLite.SQLite3.GetDateTime(SQLiteStatement stmt, Int32 index)
at System.Data.SQLite.SQLite3.GetValue(SQLiteStatement stmt, Int32 index, SQLiteType typ)
at System.Data.SQLite.SQLiteDataReader.GetValue(Int32 i)
at System.Data.Common.Internal.Materialization.Shaper.ErrorHandlingValueReader`1.GetUntypedValueDefault(DbDataReader reader, Int32 ordinal)
at System.Data.Common.Internal.Materialization.Shaper.ErrorHandlingValueReader`1.GetValue(DbDataReader reader, Int32 ordinal)
at System.Data.Common.Internal.Materialization.Shaper.GetPropertyValueWithErrorHandling[TProperty](Int32 ordinal, String propertyName, String typeName)
at lambda_method(Closure , Shaper )
at System.Data.Common.Internal.Materialization.Shaper.HandleEntityAppendOnly[TEntity](Func`2 constructEntityDelegate, EntityKey entityKey, EntitySet entitySet)
at lambda_method(Closure , Shaper )
at System.Data.Common.Internal.Materialization.Coordinator`1.ReadNextElement(Shaper shaper)
at System.Data.Common.Internal.Materialization.Shaper`1.SimpleEnumerator.MoveNext()
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
Can someone give me some insight how to solve this problem.
You need to use DateTime? as the type
[Column("ZDATE")]
public DateTime? Date { get; set; }
This will allow null values for the Date field
In SQLite, dates must have the format yyyy-mm-dd.