Skip to content
This repository has been archived by the owner on Dec 14, 2018. It is now read-only.

ViewComponent View() fails on CoreCLR with IEnumerable<> passed in #1354

Closed
BrennanConroy opened this issue Oct 14, 2014 · 11 comments
Closed
Assignees
Milestone

Comments

@BrennanConroy
Copy link
Member

I have a ViewComponent and on InvokeAsync I grab some data from a database and give it to the View.

var query = Context.SomeTable.ToArray();

return View(query.Select(e => new Model
{
Value = e.Val;
Count = e.Count;
}));

A stack trace is at the bottom for the above.

If I Instead do:

var temp = query.Select(e => new Model
{
Value = e.Val;
Count = e.Count;
}).ToArray();

return View(temp);
That will work on Core now.

Stack trace:
System.MethodAccessException: Attempt by method 'Microsoft.AspNet.Mvc.PropertyHelper.MakeFastPropertyGetter(System.Reflection.PropertyInfo)' to access method 'System.Linq.Enumerable+Iterator1<System.__Canon>.get_Current()' failed. at System.Delegate.BindToMethodInfo(Object target, IRuntimeMethodInfo method, RuntimeType methodType, DelegateBindingFlags flags) at System.Delegate.UnsafeCreateDelegate(RuntimeType rtType, RuntimeMethodInfo rtMethod, Object firstArgument, DelegateBindingFlags flags) at System.Delegate.CreateDelegateInternal(RuntimeType rtType, RuntimeMethodInfo rtMethod, Object firstArgument, DelegateBindingFlags flags, StackCrawlMark& stackMark) at System.Reflection.RuntimeMethodInfo.CreateDelegateInternal(Type delegateType, Object firstArgument, DelegateBindingFlags bindingFlags, StackCrawlMark& stackMark) at System.Reflection.RuntimeMethodInfo.CreateDelegate(Type delegateType) at Microsoft.AspNet.Mvc.PropertyHelper.MakeFastPropertyGetter(PropertyInfo propertyInfo) at Microsoft.AspNet.Mvc.PropertyHelper..ctor(PropertyInfo property) at Microsoft.AspNet.Mvc.PropertyHelper.CreateInstance(PropertyInfo property) at Microsoft.AspNet.Mvc.PropertyHelper.<>c__DisplayClass0.<GetProperties>b__3(PropertyInfo p) at System.Linq.Enumerable.WhereSelectArrayIterator2.MoveNext()
at System.Linq.Buffer1..ctor(IEnumerable1 source)
at System.Linq.Enumerable.ToArray[TSource](IEnumerable1 source) at Microsoft.AspNet.Mvc.PropertyHelper.GetProperties(Type type, Func2 createPropertyHelper, ConcurrentDictionary2 cache) at Microsoft.AspNet.Mvc.PropertyHelper.GetProperties(Type type) at Microsoft.AspNet.Mvc.ModelBinding.AssociatedMetadataProvider1.CreateTypeInformation(Type type, IEnumerable1 associatedAttributes) at Microsoft.AspNet.Mvc.ModelBinding.AssociatedMetadataProvider1.GetTypeInformation(Type type, IEnumerable1 associatedAttributes) at Microsoft.AspNet.Mvc.ModelBinding.AssociatedMetadataProvider1.GetMetadataForType(Func1 modelAccessor, Type modelType) at Microsoft.AspNet.Mvc.ViewDataDictionary.SetModel(Object value) at Microsoft.AspNet.Mvc.ViewDataDictionary1.SetModel(Object value)
at Microsoft.AspNet.Mvc.ViewDataDictionary`1.set_Model(TModel value)
at Microsoft.AspNet.Mvc.ViewComponent.View[TModel](String viewName, TModel model)
at Microsoft.AspNet.Mvc.ViewComponent.View[TModel](TModel model)
at Namespace.Component.MyCompComponent.d__1.MoveNext() in FileName\Components\MyComp.cs:line 80

@rynowak
Copy link
Member

rynowak commented Oct 14, 2014

@pranavkm @harshgMSFT

Do you know how model metadata is supposed to behave in this case?

@danroth27 danroth27 added this to the 6.0.0-rc1 milestone Oct 15, 2014
@danroth27 danroth27 modified the milestones: 6.0.0-beta2, 6.0.0-rc1 Oct 30, 2014
@danroth27
Copy link
Member

This seems to be less related to view components and more related to passing an IEnumerable to a View.
@BrennanConroy Can you provide us with the view for this issue. Or even better push a functional test that reproduces this issue?

@BrennanConroy
Copy link
Member Author

It doesn't matter what the view is. You can just have an empty one.

@sornaks
Copy link

sornaks commented Nov 19, 2014

@BrennanConroy - I am not able to repro this scenario.
This is my ViewComponent:

[ViewComponent(Name = "Test")]
    public class TestViewComponent : ViewComponent
    {
        public IViewComponentResult Invoke()
        {
            var kk = new List<Person>()
            {
                new Person() { Name = "Hello" },
                new Person() { Name = "World" }
            };

            return View(kk as IEnumerable<Person>);
        }
    }

My View calls this like:

@await Component.InvokeAsync("Test")

The build I am using is - KRE-CoreCLR-x86.1.0.0.0-beta2-10709

@BrennanConroy
Copy link
Member Author

Change the kk as IEnumerable<Person> to kk.Select(e => e)

@sornaks
Copy link

sornaks commented Nov 21, 2014

So, the scenario which was pointed out does not work only for Anonymous objects. And we are not currently planning to support binding Anonymous objects. Please refer this issue - #1484 - for more details.

@BrennanConroy
Copy link
Member Author

Could you please explain your comment about Anonymous objects? The scenario I am pointing out doesn't involve anonymous objects that I can see and it is an issue of something that works in Desktop CLR but not Core CLR

@sornaks
Copy link

sornaks commented Nov 21, 2014

So, when you do a kk.Select(e => e) it returns an objects of Anonymous type and not IEnumerable. Hence the issue..

@sornaks
Copy link

sornaks commented Nov 21, 2014

Actually, I am wrong. Select returns System.Linq.Enumerable+WhereSelectListIterator which is an Enumerable. Let me investigate further. Reopening this.

@sornaks
Copy link

sornaks commented Dec 12, 2014

This seems to be a bug in CoreCLR. I have contacted the CoreCLR team with this repro:

    public class Program
    {
        public void Main(string[] args)
        {
            var range = Enumerable.Range(0, 10).Select(x => x);
            var prop = range.GetType().GetProperty("Current");
            var propertyGetterAsFunc = prop.GetMethod.CreateDelegate(typeof(Func<,>).MakeGenericType(range.GetType(), typeof(int)));

            Console.WriteLine(propertyGetterAsFunc);
        }
    }

Will follow up.

sornaks pushed a commit that referenced this issue Dec 13, 2014
…passed in.

Fix - When the model is passed in to a View, ViewDataDictionary sets it. During this process, we recurse through all the properties and create FastPropertyGetters for each of them. In this case, since it is an enumerable, the properties which we recurse through are not the elements of the collection but the properties of the Enumerable instead. i.e - Enumerable.Current. Creating getters for these properties are not necessary. The fix moves the property iteration step to a place where the properties are actually requested.
sornaks pushed a commit that referenced this issue Dec 15, 2014
…passed in.

Fix - When the model is passed in to a View, ViewDataDictionary sets it. During this process, we recurse through all the properties and create FastPropertyGetters for each of them. In this case, since it is an enumerable, the properties which we recurse through are not the elements of the collection but the properties of the Enumerable instead. i.e - Enumerable.Current. Creating getters for these properties are not necessary. The fix moves the property iteration step to a place where the properties are actually requested.
sornaks pushed a commit that referenced this issue Dec 16, 2014
…passed in.

Fix - When the model is passed in to a View, ViewDataDictionary sets it. During this process, we recurse through all the properties and create FastPropertyGetters for each of them. In this case, since it is an enumerable, the properties which we recurse through are not the elements of the collection but the properties of the Enumerable instead. i.e - Enumerable.Current. Creating getters for these properties are not necessary. The fix moves the property iteration step to a place where the properties are actually requested.
- Splitting TypeInformation class into two and separating their caches appropriately.
@sornaks
Copy link

sornaks commented Dec 17, 2014

This is checked in - 07043ce

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants