Merge branch 'release' into dev
This commit is contained in:
commit
07043ce1a9
|
|
@ -12,8 +12,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
public abstract class AssociatedMetadataProvider<TModelMetadata> : IModelMetadataProvider
|
public abstract class AssociatedMetadataProvider<TModelMetadata> : IModelMetadataProvider
|
||||||
where TModelMetadata : ModelMetadata
|
where TModelMetadata : ModelMetadata
|
||||||
{
|
{
|
||||||
private readonly ConcurrentDictionary<Type, TypeInformation> _typeInfoCache =
|
private readonly ConcurrentDictionary<Type, TModelMetadata> _typeInfoCache =
|
||||||
new ConcurrentDictionary<Type, TypeInformation>();
|
new ConcurrentDictionary<Type, TModelMetadata>();
|
||||||
|
|
||||||
|
private readonly ConcurrentDictionary<Type, Dictionary<string, PropertyInformation>> _typePropertyInfoCache =
|
||||||
|
new ConcurrentDictionary<Type, Dictionary<string, PropertyInformation>>();
|
||||||
|
|
||||||
public IEnumerable<ModelMetadata> GetMetadataForProperties(object container, [NotNull] Type containerType)
|
public IEnumerable<ModelMetadata> GetMetadataForProperties(object container, [NotNull] Type containerType)
|
||||||
{
|
{
|
||||||
|
|
@ -26,15 +29,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(propertyName))
|
if (string.IsNullOrEmpty(propertyName))
|
||||||
{
|
{
|
||||||
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, "propertyName");
|
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(propertyName));
|
||||||
}
|
}
|
||||||
|
|
||||||
var typeInfo = GetTypeInformation(containerType);
|
var typePropertyInfo = GetTypePropertyInformation(containerType);
|
||||||
|
|
||||||
PropertyInformation propertyInfo;
|
PropertyInformation propertyInfo;
|
||||||
if (!typeInfo.Properties.TryGetValue(propertyName, out propertyInfo))
|
if (!typePropertyInfo.TryGetValue(propertyName, out propertyInfo))
|
||||||
{
|
{
|
||||||
var message = Resources.FormatCommon_PropertyNotFound(containerType, propertyName);
|
var message = Resources.FormatCommon_PropertyNotFound(containerType, propertyName);
|
||||||
throw new ArgumentException(message, "propertyName");
|
throw new ArgumentException(message, nameof(propertyName));
|
||||||
}
|
}
|
||||||
|
|
||||||
return CreatePropertyMetadata(modelAccessor, propertyInfo);
|
return CreatePropertyMetadata(modelAccessor, propertyInfo);
|
||||||
|
|
@ -42,7 +46,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
|
||||||
public ModelMetadata GetMetadataForType(Func<object> modelAccessor, [NotNull] Type modelType)
|
public ModelMetadata GetMetadataForType(Func<object> modelAccessor, [NotNull] Type modelType)
|
||||||
{
|
{
|
||||||
var prototype = GetTypeInformation(modelType).Prototype;
|
var prototype = GetTypeInformation(modelType);
|
||||||
return CreateMetadataFromPrototype(prototype, modelAccessor);
|
return CreateMetadataFromPrototype(prototype, modelAccessor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -53,7 +57,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(parameterName))
|
if (string.IsNullOrEmpty(parameterName))
|
||||||
{
|
{
|
||||||
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, "parameterName");
|
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(parameterName));
|
||||||
}
|
}
|
||||||
|
|
||||||
var parameter = methodInfo.GetParameters().FirstOrDefault(
|
var parameter = methodInfo.GetParameters().FirstOrDefault(
|
||||||
|
|
@ -92,8 +96,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
|
||||||
private IEnumerable<ModelMetadata> GetMetadataForPropertiesCore(object container, Type containerType)
|
private IEnumerable<ModelMetadata> GetMetadataForPropertiesCore(object container, Type containerType)
|
||||||
{
|
{
|
||||||
var typeInfo = GetTypeInformation(containerType);
|
var typePropertyInfo = GetTypePropertyInformation(containerType);
|
||||||
foreach (var kvp in typeInfo.Properties)
|
|
||||||
|
foreach (var kvp in typePropertyInfo)
|
||||||
{
|
{
|
||||||
var propertyInfo = kvp.Value;
|
var propertyInfo = kvp.Value;
|
||||||
Func<object> modelAccessor = null;
|
Func<object> modelAccessor = null;
|
||||||
|
|
@ -122,47 +127,43 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TypeInformation GetTypeInformation(Type type, IEnumerable<Attribute> associatedAttributes = null)
|
private TModelMetadata GetTypeInformation(Type type, IEnumerable<Attribute> associatedAttributes = null)
|
||||||
{
|
{
|
||||||
// This retrieval is implemented as a TryGetValue/TryAdd instead of a GetOrAdd
|
// This retrieval is implemented as a TryGetValue/TryAdd instead of a GetOrAdd
|
||||||
// to avoid the performance cost of creating instance delegates
|
// to avoid the performance cost of creating instance delegates
|
||||||
TypeInformation typeInfo;
|
TModelMetadata typeInfo;
|
||||||
if (!_typeInfoCache.TryGetValue(type, out typeInfo))
|
if (!_typeInfoCache.TryGetValue(type, out typeInfo))
|
||||||
{
|
{
|
||||||
typeInfo = CreateTypeInformation(type, associatedAttributes);
|
typeInfo = CreateTypeInformation(type, associatedAttributes);
|
||||||
_typeInfoCache.TryAdd(type, typeInfo);
|
_typeInfoCache.TryAdd(type, typeInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
return typeInfo;
|
return typeInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TypeInformation CreateTypeInformation(Type type, IEnumerable<Attribute> associatedAttributes)
|
private Dictionary<string, PropertyInformation> GetTypePropertyInformation(Type type)
|
||||||
{
|
{
|
||||||
var typeInfo = type.GetTypeInfo();
|
// This retrieval is implemented as a TryGetValue/TryAdd instead of a GetOrAdd
|
||||||
var attributes = typeInfo.GetCustomAttributes();
|
// to avoid the performance cost of creating instance delegates
|
||||||
|
Dictionary<string, PropertyInformation> typePropertyInfo;
|
||||||
|
if (!_typePropertyInfoCache.TryGetValue(type, out typePropertyInfo))
|
||||||
|
{
|
||||||
|
typePropertyInfo = GetPropertiesLookup(type);
|
||||||
|
_typePropertyInfoCache.TryAdd(type, typePropertyInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return typePropertyInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TModelMetadata CreateTypeInformation(Type type, IEnumerable<Attribute> associatedAttributes)
|
||||||
|
{
|
||||||
|
var attributes = type.GetTypeInfo().GetCustomAttributes();
|
||||||
if (associatedAttributes != null)
|
if (associatedAttributes != null)
|
||||||
{
|
{
|
||||||
attributes = attributes.Concat(associatedAttributes);
|
attributes = attributes.Concat(associatedAttributes);
|
||||||
}
|
}
|
||||||
var info = new TypeInformation
|
|
||||||
{
|
|
||||||
Prototype = CreateMetadataPrototype(attributes,
|
|
||||||
containerType: null,
|
|
||||||
modelType: type,
|
|
||||||
propertyName: null)
|
|
||||||
};
|
|
||||||
|
|
||||||
var properties = new Dictionary<string, PropertyInformation>(StringComparer.Ordinal);
|
return CreateMetadataPrototype(attributes, containerType: null, modelType: type, propertyName: null);
|
||||||
foreach (var propertyHelper in PropertyHelper.GetProperties(type))
|
|
||||||
{
|
|
||||||
// Avoid re-generating a property descriptor if one has already been generated for the property name
|
|
||||||
if (!properties.ContainsKey(propertyHelper.Name))
|
|
||||||
{
|
|
||||||
properties.Add(propertyHelper.Name, CreatePropertyInformation(type, propertyHelper));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
info.Properties = properties;
|
|
||||||
return info;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private PropertyInformation CreatePropertyInformation(Type containerType, PropertyHelper helper)
|
private PropertyInformation CreatePropertyInformation(Type containerType, PropertyHelper helper)
|
||||||
|
|
@ -179,6 +180,21 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Dictionary<string, PropertyInformation> GetPropertiesLookup(Type containerType)
|
||||||
|
{
|
||||||
|
var properties = new Dictionary<string, PropertyInformation>(StringComparer.Ordinal);
|
||||||
|
foreach (var propertyHelper in PropertyHelper.GetProperties(containerType))
|
||||||
|
{
|
||||||
|
// Avoid re-generating a property descriptor if one has already been generated for the property name
|
||||||
|
if (!properties.ContainsKey(propertyHelper.Name))
|
||||||
|
{
|
||||||
|
properties.Add(propertyHelper.Name, CreatePropertyInformation(containerType, propertyHelper));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
private ParameterInformation CreateParameterInfo(
|
private ParameterInformation CreateParameterInfo(
|
||||||
Type parameterType,
|
Type parameterType,
|
||||||
IEnumerable<object> attributes,
|
IEnumerable<object> attributes,
|
||||||
|
|
@ -200,12 +216,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
public TModelMetadata Prototype { get; set; }
|
public TModelMetadata Prototype { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class TypeInformation
|
|
||||||
{
|
|
||||||
public TModelMetadata Prototype { get; set; }
|
|
||||||
public Dictionary<string, PropertyInformation> Properties { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
private sealed class PropertyInformation
|
private sealed class PropertyInformation
|
||||||
{
|
{
|
||||||
public PropertyHelper PropertyHelper { get; set; }
|
public PropertyHelper PropertyHelper { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNet.Testing;
|
using Microsoft.AspNet.Testing;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
|
@ -73,6 +74,73 @@ namespace Microsoft.AspNet.Mvc.Core
|
||||||
metadataProvider.Verify();
|
metadataProvider.Verify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When SetModel is called, only GetMetadataForType from MetadataProvider is expected to be called.
|
||||||
|
[Fact]
|
||||||
|
public void SetModelCallsGetMetadataForTypeExactlyOnce()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var metadataProvider = new Mock<IModelMetadataProvider>(MockBehavior.Strict);
|
||||||
|
metadataProvider
|
||||||
|
.Setup(m => m.GetMetadataForType(It.IsAny<Func<object>>(), typeof(object)))
|
||||||
|
.Returns(new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(object)))
|
||||||
|
.Verifiable();
|
||||||
|
metadataProvider
|
||||||
|
.Setup(m => m.GetMetadataForType(It.IsAny<Func<object>>(), typeof(TestModel)))
|
||||||
|
.Returns(new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(TestModel)))
|
||||||
|
.Verifiable();
|
||||||
|
var modelState = new ModelStateDictionary();
|
||||||
|
var viewData = new TestViewDataDictionary(metadataProvider.Object, modelState);
|
||||||
|
var model = new TestModel();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
viewData.SetModelPublic(model);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotNull(viewData.ModelMetadata);
|
||||||
|
// Verifies if the GetMetadataForType is called only once.
|
||||||
|
metadataProvider.Verify(
|
||||||
|
m => m.GetMetadataForType(It.IsAny<Func<object>>(), typeof(object)), Times.Once());
|
||||||
|
// Verifies if GetMetadataForProperties and GetMetadataForProperty is not called.
|
||||||
|
metadataProvider.Verify(
|
||||||
|
m => m.GetMetadataForProperties(It.IsAny<Func<object>>(), typeof(object)), Times.Never());
|
||||||
|
metadataProvider.Verify(
|
||||||
|
m => m.GetMetadataForProperty(
|
||||||
|
It.IsAny<Func<object>>(), typeof(object), It.IsAny<string>()), Times.Never());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TheoryData<object> SetModelData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var model = new List<TestModel>()
|
||||||
|
{
|
||||||
|
new TestModel(),
|
||||||
|
new TestModel()
|
||||||
|
};
|
||||||
|
|
||||||
|
return new TheoryData<object>
|
||||||
|
{
|
||||||
|
{ model.Select(t => t) },
|
||||||
|
{ model.Where(t => t != null) },
|
||||||
|
{ model.SelectMany(t => t.ToString()) },
|
||||||
|
{ model.Take(2) },
|
||||||
|
{ model.TakeWhile(t => t != null) },
|
||||||
|
{ model.Union(model) }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(SetModelData))]
|
||||||
|
public void SetModelDoesNotThrowOnEnumerableModel(object model)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var vdd = new ViewDataDictionary(new EmptyModelMetadataProvider());
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
Assert.DoesNotThrow(() => { vdd.Model = model; });
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void CopyConstructorInitalizesModelAndModelMetadataBasedOnSource()
|
public void CopyConstructorInitalizesModelAndModelMetadataBasedOnSource()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,29 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
Assert.Equal("10", body.Trim());
|
Assert.Equal("10", body.Trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("http://localhost/Home/ViewComponentWithEnumerableModelUsingWhere", "Where")]
|
||||||
|
[InlineData("http://localhost/Home/ViewComponentWithEnumerableModelUsingSelect", "Select")]
|
||||||
|
[InlineData("http://localhost/Home/ViewComponentWithEnumerableModelUsingSelectMany", "SelectMany")]
|
||||||
|
[InlineData("http://localhost/Home/ViewComponentWithEnumerableModelUsingTake", "Take")]
|
||||||
|
[InlineData("http://localhost/Home/ViewComponentWithEnumerableModelUsingTakeWhile", "TakeWhile")]
|
||||||
|
[InlineData("http://localhost/Home/ViewComponentWithEnumerableModelUsingUnion", "Union")]
|
||||||
|
public async Task ViewComponents_SupportsEnumerableModel(string url, string linqQueryType)
|
||||||
|
{
|
||||||
|
var server = TestServer.Create(_provider, _app);
|
||||||
|
var client = server.CreateClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
// https://github.com/aspnet/Mvc/issues/1354
|
||||||
|
// The invoked ViewComponent/View has a model which is an internal type implementing Enumerable.
|
||||||
|
// For ex - TestEnumerableObject.Select(t => t) returns WhereSelectListIterator
|
||||||
|
var body = await client.GetStringAsync(url);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("<p>Hello</p><p>World</p><p>Sample</p><p>Test</p>"
|
||||||
|
+ "<p>Hello</p><p>World</p><p>" + linqQueryType + "</p><p>Test</p>", body.Trim());
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("ViewComponentWebSite.Namespace1.SameName")]
|
[InlineData("ViewComponentWebSite.Namespace1.SameName")]
|
||||||
[InlineData("ViewComponentWebSite.Namespace2.SameName")]
|
[InlineData("ViewComponentWebSite.Namespace2.SameName")]
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,22 @@ ViewWithNestedLayout-Content
|
||||||
Assert.Equal(expected, body.Trim());
|
Assert.Equal(expected, body.Trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task RazorView_DoesNotThrow_PartialViewWithEnumerableModel()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expected = "HelloWorld";
|
||||||
|
var server = TestServer.Create(_provider, _app);
|
||||||
|
var client = server.CreateClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var body = await client.GetStringAsync(
|
||||||
|
"http://localhost/ViewEngine/ViewWithPartialTakingModelFromIEnumerable");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expected, body.Trim());
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task RazorView_PassesViewContextBetweenViewAndLayout()
|
public async Task RazorView_PassesViewContextBetweenViewAndLayout()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNet.Mvc;
|
using Microsoft.AspNet.Mvc;
|
||||||
|
|
||||||
namespace RazorWebSite.Controllers
|
namespace RazorWebSite.Controllers
|
||||||
|
|
@ -37,6 +38,17 @@ namespace RazorWebSite.Controllers
|
||||||
return View(model);
|
return View(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IActionResult ViewWithPartialTakingModelFromIEnumerable()
|
||||||
|
{
|
||||||
|
var model = new List<Person>()
|
||||||
|
{
|
||||||
|
new Person() { Name = "Hello" },
|
||||||
|
new Person() { Name = "World" }
|
||||||
|
};
|
||||||
|
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
|
||||||
public ViewResult ViewPassesViewDataToLayout()
|
public ViewResult ViewPassesViewDataToLayout()
|
||||||
{
|
{
|
||||||
ViewData["Title"] = "Controller title";
|
ViewData["Title"] = "Controller title";
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
@model Person
|
||||||
|
@Html.DisplayFor(m => m.Name)
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
@using RazorWebSite
|
||||||
|
@model IEnumerable<Person>
|
||||||
|
@foreach (var item in Model)
|
||||||
|
{@await Html.PartialAsync("_PartialWithModelFromEnumerable", item)}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.AspNet.Mvc;
|
||||||
|
|
||||||
|
namespace ViewComponentWebSite
|
||||||
|
{
|
||||||
|
public class EnumerableViewComponent : ViewComponent
|
||||||
|
{
|
||||||
|
public IViewComponentResult Invoke(string linqQueryType)
|
||||||
|
{
|
||||||
|
var modelList = new List<SampleModel>()
|
||||||
|
{
|
||||||
|
new SampleModel { Prop1 = "Hello", Prop2 = "World" },
|
||||||
|
new SampleModel { Prop1 = linqQueryType, Prop2 = "Test" },
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (linqQueryType) {
|
||||||
|
case "Where":
|
||||||
|
return View(modelList.Where(e => e != null));
|
||||||
|
|
||||||
|
case "Take":
|
||||||
|
return View(modelList.Take(2));
|
||||||
|
|
||||||
|
case "TakeWhile":
|
||||||
|
return View(modelList.TakeWhile(a => a != null));
|
||||||
|
|
||||||
|
case "Union":
|
||||||
|
return View(modelList.Union(modelList));
|
||||||
|
|
||||||
|
case "SelectMany":
|
||||||
|
var selectManySampleModelList = new List<SelectManySampleModel>
|
||||||
|
{
|
||||||
|
new SelectManySampleModel {
|
||||||
|
TestModel =
|
||||||
|
new List<SampleModel> { new SampleModel { Prop1 = "Hello", Prop2 = "World" } } },
|
||||||
|
new SelectManySampleModel {
|
||||||
|
TestModel =
|
||||||
|
new List<SampleModel> { new SampleModel{ Prop1 = linqQueryType, Prop2 = "Test" } } }
|
||||||
|
};
|
||||||
|
|
||||||
|
return View(selectManySampleModelList.SelectMany(a => a.TestModel));
|
||||||
|
};
|
||||||
|
|
||||||
|
return View(modelList.Select(e => e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,12 +1,25 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using Microsoft.AspNet.Mvc;
|
using Microsoft.AspNet.Mvc;
|
||||||
|
|
||||||
namespace ViewComponentWebSite
|
namespace ViewComponentWebSite
|
||||||
{
|
{
|
||||||
public class HomeController
|
public class HomeController : Controller
|
||||||
{
|
{
|
||||||
|
private IEnumerable<SampleModel> ModelList { get; set; }
|
||||||
|
|
||||||
|
public HomeController()
|
||||||
|
{
|
||||||
|
ModelList = new List<SampleModel>()
|
||||||
|
{
|
||||||
|
new SampleModel { Prop1 = "Hello", Prop2 = "World" },
|
||||||
|
new SampleModel { Prop1 = "Sample", Prop2 = "Test" },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public ViewResult ViewWithAsyncComponents()
|
public ViewResult ViewWithAsyncComponents()
|
||||||
{
|
{
|
||||||
return new ViewResult();
|
return new ViewResult();
|
||||||
|
|
@ -21,5 +34,51 @@ namespace ViewComponentWebSite
|
||||||
{
|
{
|
||||||
return new ViewResult();
|
return new ViewResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ViewResult ViewComponentWithEnumerableModelUsingWhere()
|
||||||
|
{
|
||||||
|
ViewBag.LinqQueryType = "Where";
|
||||||
|
return View("ViewComponentWithEnumerableModel", ModelList.Where(a => a != null));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ViewResult ViewComponentWithEnumerableModelUsingSelect()
|
||||||
|
{
|
||||||
|
ViewBag.LinqQueryType = "Select";
|
||||||
|
return View("ViewComponentWithEnumerableModel", ModelList.Select(a => a));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ViewResult ViewComponentWithEnumerableModelUsingTake()
|
||||||
|
{
|
||||||
|
ViewBag.LinqQueryType = "Take";
|
||||||
|
return View("ViewComponentWithEnumerableModel", ModelList.Take(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ViewResult ViewComponentWithEnumerableModelUsingTakeWhile()
|
||||||
|
{
|
||||||
|
ViewBag.LinqQueryType = "TakeWhile";
|
||||||
|
return View("ViewComponentWithEnumerableModel", ModelList.TakeWhile(a => a != null));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ViewResult ViewComponentWithEnumerableModelUsingUnion()
|
||||||
|
{
|
||||||
|
ViewBag.LinqQueryType = "Union";
|
||||||
|
return View("ViewComponentWithEnumerableModel", ModelList.Union(ModelList));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ViewResult ViewComponentWithEnumerableModelUsingSelectMany()
|
||||||
|
{
|
||||||
|
var selectManySampleModelList = new List<SelectManySampleModel>
|
||||||
|
{
|
||||||
|
new SelectManySampleModel {
|
||||||
|
TestModel =
|
||||||
|
new List<SampleModel> { ModelList.ElementAt(0) } },
|
||||||
|
new SelectManySampleModel {
|
||||||
|
TestModel =
|
||||||
|
new List<SampleModel> { ModelList.ElementAt(1) } }
|
||||||
|
};
|
||||||
|
|
||||||
|
ViewBag.LinqQueryType = "SelectMany";
|
||||||
|
return View("ViewComponentWithEnumerableModel", selectManySampleModelList.SelectMany(s => s.TestModel));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace ViewComponentWebSite
|
||||||
|
{
|
||||||
|
public class SelectManySampleModel
|
||||||
|
{
|
||||||
|
public List<SampleModel> TestModel { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
@model IEnumerable<SampleModel>
|
||||||
|
@foreach (var m in Model)
|
||||||
|
{<p>@m.Prop1</p><p>@m.Prop2</p>}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
@model IEnumerable<SampleModel>
|
||||||
|
@foreach (var m in Model)
|
||||||
|
{<p>@m.Prop1</p><p>@m.Prop2</p>}
|
||||||
|
@Component.Invoke("Enumerable", ViewBag.LinqQueryType)
|
||||||
Loading…
Reference in New Issue