Open mysticdotnet opened 6 years ago
@mysticdotnet
Thanks for tring our sample. I change the sample and verify that the sehexception is not from our codes. I do think it's from efcore.
Because, when I change to use the in-memory data, the same aggregate expression can work. for example:
But, when I switch to EFCore, it throws the sehexception.
Thanks a lot for your help. Should i submit a ticket to the ef core team with a reference to this issue ?
@mysticdotnet That's helpful. Let's follow up the input form EFCore. Thanks.
@xuzhg @ajcvickers can you please provide info about how to debug the underlying problem? -- see more details in https://github.com/dotnet/corefx/issues/29526#issuecomment-388932741 I can't always reproduce AV and it is not clear where things go wrong. If you have steps how to get to a failure point under debugger, I can help route it to the right place.
@karelz I was unable even to repro the issue.
@karelz @ajcvickers I think it's easy to repo using our sample project.
git clone git@github.com:OData/WebApi.git
VS2017 opens solution: https://github.com/OData/WebApi/blob/master/sln/WebApiOData.AspNetCore.sln
Build and run: AspNetCoreODataSample.Web
project
Postman file request at: http://localhost:5913/efcore/Movies?$apply=groupby((ReleaseDate))
Check the response, you will get the sehexception
Please let me know if it can't work at your side.
@xuzhg that is exactly what I tried. Attached windbg to IISExpress - no exception. Even no sehexception in VS, just 502 as I posted in https://github.com/dotnet/corefx/issues/29526#issuecomment-388932741
Werid! It can't repo at my side now. @mysticdotnet Can you repro it?
@xuzhg Sorry Sam, what do you mean by repo it ?
@xuzhg I think the same issue 1221 is reported
@mysticdotnet Sorry. I mean to reproduce it.
@xuzhg the exception occurs every time Repro:
Clone / unzip https://github.com/OData/WebApi
Open sln\WebApiOData.AspNetCore.sln
Make samples\AspNetCoreODataSamples.Web project as StartUp project
Run the project in Debug mode (F5) - Browser opens URL http://localhost:5912/efcore/Movies
Browser will show:
{"@odata.context":"http://localhost:5912/efcore/$metadata#Movies","value":[{"ID":1,"Title":"Conan","ReleaseDate":"2017-03-03T00:00:00-08:00","Genre":"Comedy","Price":1.99}]}
Use URL in browser: http://localhost:5912/efcore/Movies?$apply=groupby((ReleaseDate)) Result:
the application is in break mode
@karelz did you follow up @mysticdotnet 's step?
@xuzhg I am able to repro problem (only in first F5 run in VS), but the exception is not coming from IISExpress process (nothing shows up in windbg) - see https://github.com/dotnet/corefx/issues/29526#issuecomment-388932741. It is quite possible that the dialog is just a decoy / bug in VS itself, or it comes from other processes -- IMO we need to focus on what happens in IISExpress process (where the service runs I assume). I need area experts to find that out - once you tell me which native/managed exception to track down, I can help route it.
@karelz Repro without iisexpress:
(1b40.2688): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
System_Private_CoreLib!System.Collections.Generic.Dictionary2+KeyCollection+Enumerator[System.Runtime.InteropServices.WindowsRuntime.EventRegistrationToken,System.__Canon]..ctor(System.Collections.Generic.Dictionary
2<System.Runtime.InteropServices.WindowsRuntime.EventRegistrationToken,System.__Canon>)$##600454E+0xf7562:
00007fff`695eb392 cd68 int 68h
Can you please get a callstack from the AV? (k
command in windbg, sxe eh
or sxe av
will stop on first-chance exceptions)
@karelz With k command i have this output now: output.txt
@karelz @xuzhg I do the same test with asp.net core 2.1 release, unfortunately, i have the same error. Maybe it's a .net core clr issue !
@karelz @xuzhg I have more information now:
1-I edit AspNetCoreODataSample.Web.csproj, i add this PropertyGroup:
`
` 2-After that i run the app in Debug Mode (F5) 3-open browser with this link: localhost:5000/efcore/Movies?$apply=groupby((ReleaseDate)) 4-Line 80 of DynamicTypeWrapper.cs throw this exception:
5-I change the line 80 like this:
6- Re run the app, i get another exception here:
The stack trace above (https://github.com/OData/WebApi/issues/1413#issuecomment-392662943) is missing some symbols :( @xuzhg can you please help to get the right callstack form the repro for further routing?
@karelz With .symfix[+] [LocalSymbolCache] cmd, i have this output output.txt and this stack stack.txt
@karelz @xuzhg did you see the Jan analysis about this issue ?
@xuzhg Did you expect a fix for this issue in the beta phase ?
@mysticdotnet Sorry for later response. What do you mean beta? That's in OData side or EFCore side?
@xuzhg I mean OData.
@mysticdotnet Sorry, I am a little bit confusing.
Did you figure out the root cause?
If yes, where comes the root cause? in OData side, or EFCore side?
If that's OData problem, would you please share us what your found?
If that's EFCore problem, it's better to fix , but OData itself doesn't depend on it.
@xuzhg I don't have more information about the root cause. Sorry for that and thank you very much
I investigated based on data provided and information given by .NET team and we may have possible cause of the issue here.
Ref: thread on EF Core repo which has more details (https://github.com/aspnet/EntityFrameworkCore/issues/12733)
Particularly posting last outcome from corefx team
From @jkotas
The crash is caused by invalid IL generated via Reflection.Emit.
Method Name: DynamicClass.lambda_method(System.Runtime.CompilerServices.Closure, AspNetCoreODataSample.Web.Models.Movie)
IL_0000: newobj 6000002 Microsoft.AspNet.OData.Query.Expressions.GroupByWrapper..ctor()
IL_0005: dup
IL_0006: newobj 6000003 Microsoft.AspNet.OData.Query.Expressions.AggregationPropertyContainer+LastInChain..ctor()
IL_000b: dup
IL_000c: ldstr 70000004 "ReleaseDate"
IL_0011: callvirt 6000005
IL_0016: dup
IL_0017: ldarg.1
// This returns System.DateTimeOffset
IL_0018: callvirt 6000006 AspNetCoreODataSample.Web.Models.Movie.get_ReleaseDate()
// This passes it to method that object reference - bad type mismatch!!!!
IL_001d: callvirt 6000007 Microsoft.AspNet.OData.Query.Expressions.PropertyContainer+NamedProperty`1[[System.__Canon, System.Private.CoreLib]].set_Value(System.__Canon) IL_0022: callvirt 6000008 Microsoft.AspNet.OData.Query.Expressions.GroupByWrapper.set_GroupByContainer(Microsoft.AspNet.OData.Query.Expressions.AggregationPropertyContainer)
IL_0027: ret
The method with invalid IL is created at this callstack:
system_private_corelib!System.Reflection.Emit.DynamicMethod.GetMethodDescriptor()+0x10a
system_private_corelib!System.Reflection.Emit.DynamicMethod.CreateDelegate(System.Type, System.Object)+0x2a
DynamicClass.lambda_method(System.Runtime.CompilerServices.Closure, Microsoft.EntityFrameworkCore.Query.QueryContext)+0x1a2
microsoft_entityframeworkcore!Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[[System.Int32, System.Private.CoreLib]](System.Linq.Expressions.Expression)+0x7456ac12
microsoft_entityframeworkcore!Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[[System.Int32, System.Private.CoreLib]](System.Linq.Expressions.Expression)+0x74562e78
remotion_linq!Remotion.Linq.QueryableBase`1[[System.__Canon, System.Private.CoreLib]].System.Collections.IEnumerable.GetEnumerator()+0x21
newtonsoft_json!Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(Newtonsoft.Json.JsonWriter, System.Collections.IEnumerable, Newtonsoft.Json.Serialization.JsonArrayContract, Newtonsoft.Json.Serialization.JsonProperty, Newtonsoft.Json.Serialization.JsonContainerContract, Newtonsoft.Json.Serialization.JsonProperty)+0xe5
newtonsoft_json!Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(Newtonsoft.Json.JsonWriter, System.Object, Newtonsoft.Json.Serialization.JsonContract, Newtonsoft.Json.Serialization.JsonProperty, Newtonsoft.Json.Serialization.JsonContainerContract, Newtonsoft.Json.Serialization.JsonProperty)+0x18d
newtonsoft_json!Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(Newtonsoft.Json.JsonWriter, System.Object, System.Type)+0xf1
newtonsoft_json!Newtonsoft.Json.JsonSerializer.SerializeInternal(Newtonsoft.Json.JsonWriter, System.Object, System.Type)+0x468
newtonsoft_json!Newtonsoft.Json.JsonSerializer.Serialize(Newtonsoft.Json.JsonWriter, System.Object)+0x14
microsoft_aspnetcore_mvc_formatters_json!Microsoft.AspNetCore.Mvc.Formatters.JsonOutputFormatter.WriteObject(System.IO.TextWriter, System.Object)+0x53
microsoft_aspnetcore_mvc_formatters_json!Microsoft.AspNetCore.Mvc.Formatters.JsonOutputFormatter+<WriteResponseBodyAsync>d__11.MoveNext()+0xf6
system_private_corelib!System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start[[System.__Canon, System.Private.CoreLib]](System.__Canon ByRef)+0xffffffff`ab1048d9
microsoft_aspnetcore_mvc_formatters_json!Microsoft.AspNetCore.Mvc.Formatters.JsonOutputFormatter.WriteResponseBodyAsync(Microsoft.AspNetCore.Mvc.Formatters.OutputFormatterWriteContext, System.Text.Encoding)+0x65
microsoft_aspnetcore_mvc_core!Microsoft.AspNetCore.Mvc.Formatters.TextOutputFormatter.WriteAsync(Microsoft.AspNetCore.Mvc.Formatters.OutputFormatterWriteContext)+0x160
As @divega mentioned on that thread, EF Core does not use Reflection.Emit so bad IL is not result of something in EF Core.
I hand-crafted the query being created by OData for particular request. There is slight mismatch in what compiler generates vs what OData generated. Hand-written query (had to make some internal class public)
var query = _context.Movies.AsNoTracking()
.GroupBy(it => new GroupByWrapper
{
GroupByContainer = new AggregationPropertyContainer.LastInChain
{
Name = "ReleaseDate",
Value = it.ReleaseDate
}
})
.Select(it => new AggregationWrapper
{
GroupByContainer = it.Key.GroupByContainer
}).ToList();
IQueryable.Expression output for both the queries.
// Hand-written version
.Call System.Linq.Queryable.Select(
.Call System.Linq.Queryable.GroupBy(
.Call Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.AsNoTracking(.Constant<Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[AspNetCoreODataSample.Web.Models.Movie]>(Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[AspNetCoreODataSample.Web.Models.Movie]))
,
'(.Lambda #Lambda1<System.Func`2[AspNetCoreODataSample.Web.Models.Movie,Microsoft.AspNet.OData.Query.Expressions.GroupByWrapper]>))
,
'(.Lambda #Lambda2<System.Func`2[System.Linq.IGrouping`2[Microsoft.AspNet.OData.Query.Expressions.GroupByWrapper,AspNetCoreODataSample.Web.Models.Movie],Microsoft.AspNet.OData.Query.Expressions.AggregationWrapper]>))
.Lambda #Lambda1<System.Func`2[AspNetCoreODataSample.Web.Models.Movie,Microsoft.AspNet.OData.Query.Expressions.GroupByWrapper]>(AspNetCoreODataSample.Web.Models.Movie $it)
{
.New Microsoft.AspNet.OData.Query.Expressions.GroupByWrapper(){
GroupByContainer = .New Microsoft.AspNet.OData.Query.Expressions.AggregationPropertyContainer+LastInChain(){
Name = "ReleaseDate",
Value = (System.Object)$it.ReleaseDate
}
}
}
.Lambda #Lambda2<System.Func`2[System.Linq.IGrouping`2[Microsoft.AspNet.OData.Query.Expressions.GroupByWrapper,AspNetCoreODataSample.Web.Models.Movie],Microsoft.AspNet.OData.Query.Expressions.AggregationWrapper]>(System.Linq.IGrouping`2[Microsoft.AspNet.OData.Query.Expressions.GroupByWrapper,AspNetCoreODataSample.Web.Models.Movie] $it)
{
.New Microsoft.AspNet.OData.Query.Expressions.AggregationWrapper(){
GroupByContainer = ($it.Key).GroupByContainer
}
}
// OData Version
.Call System.Linq.Queryable.Select(
.Call System.Linq.Queryable.GroupBy(
.Call Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.AsNoTracking(.Constant<Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[AspNetCoreODataSample.Web.Models.Movie]>(Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[AspNetCoreODataSample.Web.Models.Movie]))
,
'(.Lambda #Lambda1<System.Func`2[AspNetCoreODataSample.Web.Models.Movie,Microsoft.AspNet.OData.Query.Expressions.GroupByWrapper]>))
,
'(.Lambda #Lambda2<System.Func`2[System.Linq.IGrouping`2[Microsoft.AspNet.OData.Query.Expressions.GroupByWrapper,AspNetCoreODataSample.Web.Models.Movie],Microsoft.AspNet.OData.Query.Expressions.AggregationWrapper]>))
.Lambda #Lambda1<System.Func`2[AspNetCoreODataSample.Web.Models.Movie,Microsoft.AspNet.OData.Query.Expressions.GroupByWrapper]>(AspNetCoreODataSample.Web.Models.Movie $$it)
{
.New Microsoft.AspNet.OData.Query.Expressions.GroupByWrapper(){
GroupByContainer = .New Microsoft.AspNet.OData.Query.Expressions.AggregationPropertyContainer+LastInChain(){
Name = "ReleaseDate",
Value = $$it.ReleaseDate
}
}
}
.Lambda #Lambda2<System.Func`2[System.Linq.IGrouping`2[Microsoft.AspNet.OData.Query.Expressions.GroupByWrapper,AspNetCoreODataSample.Web.Models.Movie],Microsoft.AspNet.OData.Query.Expressions.AggregationWrapper]>(System.Linq.IGrouping`2[Microsoft.AspNet.OData.Query.Expressions.GroupByWrapper,AspNetCoreODataSample.Web.Models.Movie] $$it)
{
.New Microsoft.AspNet.OData.Query.Expressions.AggregationWrapper(){
GroupByContainer = ($$it.Key).GroupByContainer
}
}
Output of query model printer in EF Core (Query Model is generated by parsing the Expression tree using Remotion.Linq)
//Hand-written version
dbug: Microsoft.EntityFrameworkCore.Query[10101]
Compiling query model:
'from IGrouping<GroupByWrapper, Movie> e in
(from Movie <generated>_1 in DbSet<Movie>
select [<generated>_1])
.AsNoTracking()
.GroupBy(new GroupByWrapper() {GroupByContainer = new LastInChain() {Name = "ReleaseDate", Value = Convert([<generated>_1].ReleaseDate, Object)}}, [<generated>_1])
select new AggregationWrapper{ GroupByContainer = [e].Key.GroupByContainer }
'
dbug: Microsoft.EntityFrameworkCore.Query[10104]
Optimized query model:
'from IGrouping<GroupByWrapper, Movie> e in
(from Movie <generated>_1 in DbSet<Movie>
select [<generated>_1]).GroupBy(new GroupByWrapper() {GroupByContainer = new LastInChain() {Name = "ReleaseDate", Value = Convert([<generated>_1].ReleaseDate, Object)}}, [<generated>_1])
select new AggregationWrapper{ GroupByContainer = [e].Key.GroupByContainer }
'
dbug: Microsoft.EntityFrameworkCore.Query[10107]
(QueryContext queryContext) => IEnumerable<AggregationWrapper> _InterceptExceptions(
source: IEnumerable<AggregationWrapper> _Select(
source: IEnumerable<IGrouping<GroupByWrapper, Movie>> _GroupBy(
source: IEnumerable<Movie> EntityQuery(
queryContext: queryContext,
entityType: EntityType: Movie,
key: Key: Movie.ID PK,
materializer: (IEntityType entityType | ValueBuffer valueBuffer) =>
{
instance = new Movie()
instance.<ID>k__BackingField = int TryReadValue(valueBuffer, 0, Movie.ID)
instance.<Genre>k__BackingField = Genre TryReadValue(valueBuffer, 1, Movie.Genre)
instance.<Price>k__BackingField = decimal TryReadValue(valueBuffer, 2, Movie.Price)
instance.<ReleaseDate>k__BackingField = DateTimeOffset TryReadValue(valueBuffer, 3, Movie.ReleaseDate)
instance.<Title>k__BackingField = string TryReadValue(valueBuffer, 4, Movie.Title)
return instance
}
,
queryStateManager: False),
keySelector: (Movie <generated>_1) => new GroupByWrapper{ GroupByContainer = new LastInChain{
Name = "ReleaseDate",
Value = (object)<generated>_1.ReleaseDate
}
}
,
elementSelector: (Movie <generated>_1) => <generated>_1),
selector: (IGrouping<GroupByWrapper, Movie> e) => new AggregationWrapper{ GroupByContainer = e.Key.GroupByContainer }
),
contextType: AspNetCoreODataSample.Web.Models.MovieContext,
logger: DiagnosticsLogger<Query>,
queryContext: queryContext)
//OData version
dbug: Microsoft.EntityFrameworkCore.Query[10101]
Compiling query model:
'from IGrouping<GroupByWrapper, Movie> $it in
(from Movie <generated>_1 in DbSet<Movie>
select [<generated>_1])
.AsNoTracking()
.GroupBy(new GroupByWrapper() {GroupByContainer = new LastInChain() {Name = "ReleaseDate", Value = [<generated>_1].ReleaseDate}}, [<generated>_1])
select new AggregationWrapper{ GroupByContainer = [$it].Key.GroupByContainer }
'
dbug: Microsoft.EntityFrameworkCore.Query[10104]
Optimized query model:
'from IGrouping<GroupByWrapper, Movie> $it in
(from Movie <generated>_1 in DbSet<Movie>
select [<generated>_1]).GroupBy(new GroupByWrapper() {GroupByContainer = new LastInChain() {Name = "ReleaseDate", Value = [<generated>_1].ReleaseDate}}, [<generated>_1])
select new AggregationWrapper{ GroupByContainer = [$it].Key.GroupByContainer }
'
dbug: Microsoft.EntityFrameworkCore.Query[10107]
(QueryContext queryContext) => IEnumerable<AggregationWrapper> _InterceptExceptions(
source: IEnumerable<AggregationWrapper> _Select(
source: IEnumerable<IGrouping<GroupByWrapper, Movie>> _GroupBy(
source: IEnumerable<Movie> EntityQuery(
queryContext: queryContext,
entityType: EntityType: Movie,
key: Key: Movie.ID PK,
materializer: (IEntityType entityType | ValueBuffer valueBuffer) =>
{
instance = new Movie()
instance.<ID>k__BackingField = int TryReadValue(valueBuffer, 0, Movie.ID)
instance.<Genre>k__BackingField = Genre TryReadValue(valueBuffer, 1, Movie.Genre)
instance.<Price>k__BackingField = decimal TryReadValue(valueBuffer, 2, Movie.Price)
instance.<ReleaseDate>k__BackingField = DateTimeOffset TryReadValue(valueBuffer, 3, Movie.ReleaseDate)
instance.<Title>k__BackingField = string TryReadValue(valueBuffer, 4, Movie.Title)
return instance
}
,
queryStateManager: False),
keySelector: (Movie <generated>_1) => new GroupByWrapper{ GroupByContainer = new LastInChain{
Name = "ReleaseDate",
Value = <generated>_1.ReleaseDate
}
}
,
elementSelector: (Movie <generated>_1) => <generated>_1),
selector: (IGrouping<GroupByWrapper, Movie> $it) => new AggregationWrapper{ GroupByContainer = $it.Key.GroupByContainer }
),
contextType: AspNetCoreODataSample.Web.Models.MovieContext,
logger: DiagnosticsLogger<Query>,
queryContext: queryContext)
Based on ExpressionTree & QueryModel output, the difference is in GroupByWrapper
creation, where assigning ReleaseDate to Value
property has Convert
node since release date is DateTime and Value
is of type object. Further, according to @jkotas 's post there is bad type mismatch happening inside IL after getting value of ReleaseDate and assigning it to Value Property. Based on missing Convert node in OData query, it is likely that that is generating invalid IL.
Compiler introduce this Convert node automatically when you hand write the query. I am not sure whether it is needed or why OData is not introducing it. And what are its implication in IL. Perhaps coreFx team can provide more information on that. If current Expression Tree generated by OData is invalid (given compiler generates slightly different then) OData team can fix it. Or if the ExpressionTree is valid then it should not be generating error in IL when evaluating in memory. (perhaps corefx issue).
Since EF Core is working correctly for compiler generated Expression Tree, I will be closing this issue on EF Core side.
Any update on the fix for this issue from the OData side?
See also: https://github.com/OData/WebApi/issues/1154#issuecomment-416420820
There is also https://github.com/OData/WebApi/issues/1221, which is a duplicate of this issue (been open longer, but still a duplicate)
I´m struggling with data problem too since I can´t make a groupby. Would be nice to have a work-around or an ETA I tracked this bug to a year ago and since groupby(aggregate) its a kind of basic query resource wouldn't this bug be a p1 blocking? Regards,
Im also facing this issue
I found solution. Just change one method in AggregationBinder class
private Expression WrapConvert(Expression expression)
{
return Expression.Convert(expression, typeof(object));
// return this._linqToObjectMode
// ? Expression.Convert(expression, typeof(object))
// : expression;
}
Now always use convert for property
Any updates on this?
I found solution. Just change one method in AggregationBinder class
private Expression WrapConvert(Expression expression) { return Expression.Convert(expression, typeof(object)); // return this._linqToObjectMode // ? Expression.Convert(expression, typeof(object)) // : expression; }
Now always use convert for property
Hi SenyaMur, Can you give example to here please.
I found solution. Just change one method in AggregationBinder class
private Expression WrapConvert(Expression expression) { return Expression.Convert(expression, typeof(object)); // return this._linqToObjectMode // ? Expression.Convert(expression, typeof(object)) // : expression; }
Now always use convert for property
Hi SenyaMur, Can you give example to here please.
What example you need? Request url or fix the bug? If you want to fix the bug, then just clone the repository, change code as i writed and build it.
Issue should be fixed by: https://github.com/OData/WebApi/pull/1728 Could you try nightly build to check that fix works for you?
It's worked on build 7.1.1-Nightly201907241245. When it will be in nuget?
It's worked on 7.2.0. Thank you!
Not work on 7.3.0 :(
Did you try to use services.AddControllers().AddNewtonsoftJson();? It seems to solve some of the issues.
When i use $apply=aggregate with your sample (https://github.com/OData/WebApi/tree/master/samples/AspNetCoreODataSample.Web) it throw sehexception
Assemblies affected
*Microsoft.AspNetCore.OData with asp.net core
Reproduce steps
I clone this project (https://github.com/OData/WebApi), i open this solution the odata core solution (WebApiOData.AspNetCore.sln) and i run the sample project (https://github.com/OData/WebApi/tree/master/samples/AspNetCoreODataSample.Web) and after i run this query: localhost:5912/odata/Movies?$apply=groupby((ReleaseDate))
Expected result
Show the result of the odata aggregate query
Actual result
sehexception