Skip to content

Commit f6686bd

Browse files
authored
Merge pull request #190 from ivaylokenov/view-component-testing
Separated ViewFeatures into smaller packages
2 parents 7045acd + 3bb35fb commit f6686bd

File tree

116 files changed

+59957
-481
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

116 files changed

+59957
-481
lines changed

MyTested.AspNetCore.Mvc.sln

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,18 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MyTested.AspNetCore.Mvc.Htt
9898
EndProject
9999
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MyTested.AspNetCore.Mvc.Routing.Test", "test\MyTested.AspNetCore.Mvc.Routing.Test\MyTested.AspNetCore.Mvc.Routing.Test.xproj", "{56348217-F55C-4C61-8779-B94C009DC4BE}"
100100
EndProject
101+
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MyTested.AspNetCore.Mvc.ViewActionResults", "src\MyTested.AspNetCore.Mvc.ViewActionResults\MyTested.AspNetCore.Mvc.ViewActionResults.xproj", "{9050F562-C77C-471E-8968-FAF2ED4E6F28}"
102+
EndProject
103+
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MyTested.AspNetCore.Mvc.ViewActionResults.Test", "test\MyTested.AspNetCore.Mvc.ViewActionResults.Test\MyTested.AspNetCore.Mvc.ViewActionResults.Test.xproj", "{0FE597F3-3495-440A-A16C-AC1F01CC7C89}"
104+
EndProject
105+
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MyTested.AspNetCore.Mvc.TempData", "src\MyTested.AspNetCore.Mvc.TempData\MyTested.AspNetCore.Mvc.TempData.xproj", "{64DB9A46-8DC1-4DE6-99EB-939A015DA2AD}"
106+
EndProject
107+
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MyTested.AspNetCore.Mvc.TempData.Test", "test\MyTested.AspNetCore.Mvc.TempData.Test\MyTested.AspNetCore.Mvc.TempData.Test.xproj", "{DE25BE38-9AF4-4BB4-A12A-B2FB1D5D8C75}"
108+
EndProject
109+
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MyTested.AspNetCore.Mvc.ViewData", "src\MyTested.AspNetCore.Mvc.ViewData\MyTested.AspNetCore.Mvc.ViewData.xproj", "{86D4B1F6-3ACA-415E-A3C5-1DF3648F1EDC}"
110+
EndProject
111+
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MyTested.AspNetCore.Mvc.ViewData.Test", "test\MyTested.AspNetCore.Mvc.ViewData.Test\MyTested.AspNetCore.Mvc.ViewData.Test.xproj", "{C5B868E3-3428-42CB-B628-DF11A5F1B882}"
112+
EndProject
101113
Global
102114
GlobalSection(SolutionConfigurationPlatforms) = preSolution
103115
Debug|Any CPU = Debug|Any CPU
@@ -264,6 +276,30 @@ Global
264276
{56348217-F55C-4C61-8779-B94C009DC4BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
265277
{56348217-F55C-4C61-8779-B94C009DC4BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
266278
{56348217-F55C-4C61-8779-B94C009DC4BE}.Release|Any CPU.Build.0 = Release|Any CPU
279+
{9050F562-C77C-471E-8968-FAF2ED4E6F28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
280+
{9050F562-C77C-471E-8968-FAF2ED4E6F28}.Debug|Any CPU.Build.0 = Debug|Any CPU
281+
{9050F562-C77C-471E-8968-FAF2ED4E6F28}.Release|Any CPU.ActiveCfg = Release|Any CPU
282+
{9050F562-C77C-471E-8968-FAF2ED4E6F28}.Release|Any CPU.Build.0 = Release|Any CPU
283+
{0FE597F3-3495-440A-A16C-AC1F01CC7C89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
284+
{0FE597F3-3495-440A-A16C-AC1F01CC7C89}.Debug|Any CPU.Build.0 = Debug|Any CPU
285+
{0FE597F3-3495-440A-A16C-AC1F01CC7C89}.Release|Any CPU.ActiveCfg = Release|Any CPU
286+
{0FE597F3-3495-440A-A16C-AC1F01CC7C89}.Release|Any CPU.Build.0 = Release|Any CPU
287+
{64DB9A46-8DC1-4DE6-99EB-939A015DA2AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
288+
{64DB9A46-8DC1-4DE6-99EB-939A015DA2AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
289+
{64DB9A46-8DC1-4DE6-99EB-939A015DA2AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
290+
{64DB9A46-8DC1-4DE6-99EB-939A015DA2AD}.Release|Any CPU.Build.0 = Release|Any CPU
291+
{DE25BE38-9AF4-4BB4-A12A-B2FB1D5D8C75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
292+
{DE25BE38-9AF4-4BB4-A12A-B2FB1D5D8C75}.Debug|Any CPU.Build.0 = Debug|Any CPU
293+
{DE25BE38-9AF4-4BB4-A12A-B2FB1D5D8C75}.Release|Any CPU.ActiveCfg = Release|Any CPU
294+
{DE25BE38-9AF4-4BB4-A12A-B2FB1D5D8C75}.Release|Any CPU.Build.0 = Release|Any CPU
295+
{86D4B1F6-3ACA-415E-A3C5-1DF3648F1EDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
296+
{86D4B1F6-3ACA-415E-A3C5-1DF3648F1EDC}.Debug|Any CPU.Build.0 = Debug|Any CPU
297+
{86D4B1F6-3ACA-415E-A3C5-1DF3648F1EDC}.Release|Any CPU.ActiveCfg = Release|Any CPU
298+
{86D4B1F6-3ACA-415E-A3C5-1DF3648F1EDC}.Release|Any CPU.Build.0 = Release|Any CPU
299+
{C5B868E3-3428-42CB-B628-DF11A5F1B882}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
300+
{C5B868E3-3428-42CB-B628-DF11A5F1B882}.Debug|Any CPU.Build.0 = Debug|Any CPU
301+
{C5B868E3-3428-42CB-B628-DF11A5F1B882}.Release|Any CPU.ActiveCfg = Release|Any CPU
302+
{C5B868E3-3428-42CB-B628-DF11A5F1B882}.Release|Any CPU.Build.0 = Release|Any CPU
267303
EndGlobalSection
268304
GlobalSection(SolutionProperties) = preSolution
269305
HideSolutionNode = FALSE
@@ -311,5 +347,11 @@ Global
311347
{41E51D79-AC4A-42A3-A55D-912DDB6F0FA9} = {D140FA14-A6C2-4279-8A41-35BC55279DA8}
312348
{D9F6A7BB-6E8E-4983-8007-3BC0D23016D0} = {D140FA14-A6C2-4279-8A41-35BC55279DA8}
313349
{56348217-F55C-4C61-8779-B94C009DC4BE} = {D140FA14-A6C2-4279-8A41-35BC55279DA8}
350+
{9050F562-C77C-471E-8968-FAF2ED4E6F28} = {09353A03-2B0C-496B-8EB1-2CB6A22D758B}
351+
{0FE597F3-3495-440A-A16C-AC1F01CC7C89} = {D140FA14-A6C2-4279-8A41-35BC55279DA8}
352+
{64DB9A46-8DC1-4DE6-99EB-939A015DA2AD} = {09353A03-2B0C-496B-8EB1-2CB6A22D758B}
353+
{DE25BE38-9AF4-4BB4-A12A-B2FB1D5D8C75} = {D140FA14-A6C2-4279-8A41-35BC55279DA8}
354+
{86D4B1F6-3ACA-415E-A3C5-1DF3648F1EDC} = {09353A03-2B0C-496B-8EB1-2CB6A22D758B}
355+
{C5B868E3-3428-42CB-B628-DF11A5F1B882} = {D140FA14-A6C2-4279-8A41-35BC55279DA8}
314356
EndGlobalSection
315357
EndGlobal

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@ This package will include all available assertion methods in your test project.
2020
- `MyTested.AspNetCore.Mvc.Controllers` - contains setup and assertion methods for controllers
2121
- `MyTested.AspNetCore.Mvc.Routing` - contains setup and assertion methods for routes
2222
- `MyTested.AspNetCore.Mvc.Core` - contains setup and assertion methods for MVC core features
23+
- `MyTested.AspNetCore.Mvc.TempData` - contains setup and assertion methods for `ITempDataDictionary`
24+
- `MyTested.AspNetCore.Mvc.ViewData` - contains assertion methods for `ViewDataDictionary` and dynamic `ViewBag`
25+
- `MyTested.AspNetCore.Mvc.ViewActionResults` - contains setup and assertion methods for view action results
2326
- `MyTested.AspNetCore.Mvc.ViewFeatures` - contains setup and assertion methods for MVC view features
2427
- `MyTested.AspNetCore.Mvc.Http` - contains setup and assertion methods for HTTP context, request and response
25-
- `MyTested.AspNetCore.Mvc.Authentication` - contains setup for `ClaimsPrincipal`
28+
- `MyTested.AspNetCore.Mvc.Authentication` - contains setup methods for `ClaimsPrincipal`
2629
- `MyTested.AspNetCore.Mvc.DataAnnotations` - contains setup and assertion methods for `ModelState` validations
2730
- `MyTested.AspNetCore.Mvc.EntityFrameworkCore` - contains setup and assertion methods for `DbContext`
2831
- `MyTested.AspNetCore.Mvc.DependencyInjection` - contains setup methods for dependency injection services

samples/MusicStore/MusicStore.Test/Controllers/CheckoutControllerTest.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public void PostAddressAndPaymentShouldRedirectToCompleteWhenSuccessful()
6767
.WithAuthenticatedUser()
6868
.WithRouteData()
6969
.WithDbContext(db => db
70-
.WithEntities<MusicStoreContext>(entities =>
70+
.WithEntities(entities =>
7171
{
7272
var cartItems = CreateTestCartItems(
7373
cartId,
@@ -121,7 +121,7 @@ public void CompleteShouldReturnViewWithCorrectIdWithCorrectOrder()
121121
.Controller<CheckoutController>()
122122
.WithAuthenticatedUser(user => user.WithUsername("TestUser"))
123123
.WithDbContext(dbContext =>
124-
dbContext.WithSet<MusicStoreContext, Order>(o => o.Add(new Order
124+
dbContext.WithSet<Order>(o => o.Add(new Order
125125
{
126126
OrderId = 1,
127127
Username = "TestUser"
@@ -138,7 +138,7 @@ public void CompleteShouldReturnViewWithErrorWithIncorrectOrder()
138138
.Controller<CheckoutController>()
139139
.WithAuthenticatedUser(user => user.WithUsername("TestUser"))
140140
.WithDbContext(dbContext =>
141-
dbContext.WithSet<MusicStoreContext, Order>(o => o.Add(new Order
141+
dbContext.WithSet<Order>(o => o.Add(new Order
142142
{
143143
OrderId = 1,
144144
Username = "AnotherUser"

samples/MusicStore/MusicStore.Test/Controllers/HomeControllerTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public void IndexShouldReturnTopSellingAlbumsAndSaveThenIntoCache()
1818
.WithOptions(options => options
1919
.For<AppSettings>(settings => settings.CacheDbResults = true))
2020
.WithDbContext(dbContext => dbContext
21-
.WithSet<MusicStoreContext, Album>(albums => albums
21+
.WithSet<Album>(albums => albums
2222
.AddRange(TestAlbumDataProvider.GetAlbums())))
2323
.Calling(c => c.Index(
2424
From.Services<MusicStoreContext>(),

samples/MusicStore/MusicStore.Test/Controllers/ShoppingCartControllerTest.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public void IndexShouldReturnCartItemsWhenItemsInCart()
5252
.Controller<ShoppingCartController>()
5353
.WithSession(session => session.WithEntry("Session", cartId))
5454
.WithDbContext(db => db
55-
.WithEntities<MusicStoreContext>(entities =>
55+
.WithEntities(entities =>
5656
{
5757
var cartItems = CreateTestCartItems(
5858
cartId,
@@ -82,7 +82,7 @@ public void AddToCartShouldAddItemsToCart()
8282
.Controller<ShoppingCartController>()
8383
.WithSession(session => session.WithEntry("Session", "CartId_A"))
8484
.WithDbContext(db => db
85-
.WithEntities<MusicStoreContext>(entities => entities
85+
.WithEntities(entities => entities
8686
.AddRange(CreateTestAlbums(itemPrice: 10))))
8787
.Calling(c => c.AddToCart(albumId))
8888
.ShouldReturn()
@@ -110,7 +110,7 @@ public void RemoveFromCartShouldRemoveItemFromCart()
110110
.Controller<ShoppingCartController>()
111111
.WithSession(session => session.WithEntry("Session", cartId))
112112
.WithDbContext(db => db
113-
.WithEntities<MusicStoreContext>(entities =>
113+
.WithEntities(entities =>
114114
{
115115
var cartItems = CreateTestCartItems(cartId, unitPrice, numberOfItem);
116116
entities.AddRange(cartItems.Select(n => n.Album).Distinct());

samples/MusicStore/MusicStore.Test/TestStartup.cs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,8 @@ public void ConfigureTestServices(IServiceCollection services)
3737
TestHelper.HttpFeatureRegistrationPlugins.Add(new SessionTestPlugin());
3838

3939
services
40-
.AddCoreTesting()
41-
.AddControllersTesting()
42-
.AddRoutingTesting()
43-
.ReplaceDbContext()
44-
.ReplaceMemoryCache()
45-
.ReplaceSession()
46-
.ReplaceOptions()
47-
.ReplaceTempDataProvider();
40+
.AddMvcTesting()
41+
.AddRoutingTesting();
4842
#endif
4943
}
5044
}

samples/MusicStore/MusicStore.Test/project.lock.json

Lines changed: 107 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4534,12 +4534,57 @@
45344534
"netstandard1.6/MyTested.AspNetCore.Mvc.Session.dll": {}
45354535
}
45364536
},
4537+
"MyTested.AspNetCore.Mvc.TempData/1.0.0-preview-final": {
4538+
"type": "project",
4539+
"framework": ".NETStandard,Version=v1.6",
4540+
"dependencies": {
4541+
"Microsoft.AspNetCore.Mvc.ViewFeatures": "1.0.0",
4542+
"MyTested.AspNetCore.Mvc.Controllers": "1.0.0"
4543+
},
4544+
"compile": {
4545+
"netstandard1.6/MyTested.AspNetCore.Mvc.TempData.dll": {}
4546+
},
4547+
"runtime": {
4548+
"netstandard1.6/MyTested.AspNetCore.Mvc.TempData.dll": {}
4549+
}
4550+
},
4551+
"MyTested.AspNetCore.Mvc.ViewActionResults/1.0.0-preview-final": {
4552+
"type": "project",
4553+
"framework": ".NETStandard,Version=v1.6",
4554+
"dependencies": {
4555+
"Microsoft.AspNetCore.Mvc.ViewFeatures": "1.0.0",
4556+
"MyTested.AspNetCore.Mvc.Controllers": "1.0.0"
4557+
},
4558+
"compile": {
4559+
"netstandard1.6/MyTested.AspNetCore.Mvc.ViewActionResults.dll": {}
4560+
},
4561+
"runtime": {
4562+
"netstandard1.6/MyTested.AspNetCore.Mvc.ViewActionResults.dll": {}
4563+
}
4564+
},
4565+
"MyTested.AspNetCore.Mvc.ViewData/1.0.0-preview-final": {
4566+
"type": "project",
4567+
"framework": ".NETStandard,Version=v1.6",
4568+
"dependencies": {
4569+
"Microsoft.AspNetCore.Mvc.ViewFeatures": "1.0.0",
4570+
"MyTested.AspNetCore.Mvc.Abstractions": "1.0.0"
4571+
},
4572+
"compile": {
4573+
"netstandard1.6/MyTested.AspNetCore.Mvc.ViewData.dll": {}
4574+
},
4575+
"runtime": {
4576+
"netstandard1.6/MyTested.AspNetCore.Mvc.ViewData.dll": {}
4577+
}
4578+
},
45374579
"MyTested.AspNetCore.Mvc.ViewFeatures/1.0.0-preview-final": {
45384580
"type": "project",
45394581
"framework": ".NETStandard,Version=v1.6",
45404582
"dependencies": {
45414583
"Microsoft.AspNetCore.Mvc.ViewFeatures": "1.0.0",
4542-
"MyTested.AspNetCore.Mvc.DataAnnotations": "1.0.0"
4584+
"MyTested.AspNetCore.Mvc.DataAnnotations": "1.0.0",
4585+
"MyTested.AspNetCore.Mvc.TempData": "1.0.0",
4586+
"MyTested.AspNetCore.Mvc.ViewActionResults": "1.0.0",
4587+
"MyTested.AspNetCore.Mvc.ViewData": "1.0.0"
45434588
},
45444589
"compile": {
45454590
"netstandard1.6/MyTested.AspNetCore.Mvc.ViewFeatures.dll": {}
@@ -6948,12 +6993,57 @@
69486993
"net451/MyTested.AspNetCore.Mvc.Session.dll": {}
69496994
}
69506995
},
6996+
"MyTested.AspNetCore.Mvc.TempData/1.0.0-preview-final": {
6997+
"type": "project",
6998+
"framework": ".NETFramework,Version=v4.5.1",
6999+
"dependencies": {
7000+
"Microsoft.AspNetCore.Mvc.ViewFeatures": "1.0.0",
7001+
"MyTested.AspNetCore.Mvc.Controllers": "1.0.0"
7002+
},
7003+
"compile": {
7004+
"net451/MyTested.AspNetCore.Mvc.TempData.dll": {}
7005+
},
7006+
"runtime": {
7007+
"net451/MyTested.AspNetCore.Mvc.TempData.dll": {}
7008+
}
7009+
},
7010+
"MyTested.AspNetCore.Mvc.ViewActionResults/1.0.0-preview-final": {
7011+
"type": "project",
7012+
"framework": ".NETFramework,Version=v4.5.1",
7013+
"dependencies": {
7014+
"Microsoft.AspNetCore.Mvc.ViewFeatures": "1.0.0",
7015+
"MyTested.AspNetCore.Mvc.Controllers": "1.0.0"
7016+
},
7017+
"compile": {
7018+
"net451/MyTested.AspNetCore.Mvc.ViewActionResults.dll": {}
7019+
},
7020+
"runtime": {
7021+
"net451/MyTested.AspNetCore.Mvc.ViewActionResults.dll": {}
7022+
}
7023+
},
7024+
"MyTested.AspNetCore.Mvc.ViewData/1.0.0-preview-final": {
7025+
"type": "project",
7026+
"framework": ".NETFramework,Version=v4.5.1",
7027+
"dependencies": {
7028+
"Microsoft.AspNetCore.Mvc.ViewFeatures": "1.0.0",
7029+
"MyTested.AspNetCore.Mvc.Abstractions": "1.0.0"
7030+
},
7031+
"compile": {
7032+
"net451/MyTested.AspNetCore.Mvc.ViewData.dll": {}
7033+
},
7034+
"runtime": {
7035+
"net451/MyTested.AspNetCore.Mvc.ViewData.dll": {}
7036+
}
7037+
},
69517038
"MyTested.AspNetCore.Mvc.ViewFeatures/1.0.0-preview-final": {
69527039
"type": "project",
69537040
"framework": ".NETFramework,Version=v4.5.1",
69547041
"dependencies": {
69557042
"Microsoft.AspNetCore.Mvc.ViewFeatures": "1.0.0",
6956-
"MyTested.AspNetCore.Mvc.DataAnnotations": "1.0.0"
7043+
"MyTested.AspNetCore.Mvc.DataAnnotations": "1.0.0",
7044+
"MyTested.AspNetCore.Mvc.TempData": "1.0.0",
7045+
"MyTested.AspNetCore.Mvc.ViewActionResults": "1.0.0",
7046+
"MyTested.AspNetCore.Mvc.ViewData": "1.0.0"
69577047
},
69587048
"compile": {
69597049
"net451/MyTested.AspNetCore.Mvc.ViewFeatures.dll": {}
@@ -13645,6 +13735,21 @@
1364513735
"path": "../../../src/MyTested.AspNetCore.Mvc.Session/project.json",
1364613736
"msbuildProject": "../../../src/MyTested.AspNetCore.Mvc.Session/MyTested.AspNetCore.Mvc.Session.xproj"
1364713737
},
13738+
"MyTested.AspNetCore.Mvc.TempData/1.0.0-preview-final": {
13739+
"type": "project",
13740+
"path": "../../../src/MyTested.AspNetCore.Mvc.TempData/project.json",
13741+
"msbuildProject": "../../../src/MyTested.AspNetCore.Mvc.TempData/MyTested.AspNetCore.Mvc.TempData.xproj"
13742+
},
13743+
"MyTested.AspNetCore.Mvc.ViewActionResults/1.0.0-preview-final": {
13744+
"type": "project",
13745+
"path": "../../../src/MyTested.AspNetCore.Mvc.ViewActionResults/project.json",
13746+
"msbuildProject": "../../../src/MyTested.AspNetCore.Mvc.ViewActionResults/MyTested.AspNetCore.Mvc.ViewActionResults.xproj"
13747+
},
13748+
"MyTested.AspNetCore.Mvc.ViewData/1.0.0-preview-final": {
13749+
"type": "project",
13750+
"path": "../../../src/MyTested.AspNetCore.Mvc.ViewData/project.json",
13751+
"msbuildProject": "../../../src/MyTested.AspNetCore.Mvc.ViewData/MyTested.AspNetCore.Mvc.ViewData.xproj"
13752+
},
1364813753
"MyTested.AspNetCore.Mvc.ViewFeatures/1.0.0-preview-final": {
1364913754
"type": "project",
1365013755
"path": "../../../src/MyTested.AspNetCore.Mvc.ViewFeatures/project.json",
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
namespace MyTested.AspNetCore.Mvc.Internal
2+
{
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using System.Reflection;
7+
using Utilities;
8+
9+
public abstract class BasePropertyHelper
10+
{
11+
private const string InvalidDelegateErrorMessage = "The {0} property cannot be activated for value of {1} type.";
12+
13+
private static readonly MethodInfo CallPropertyGetterOpenGenericMethod =
14+
typeof(BasePropertyHelper).GetTypeInfo().GetDeclaredMethod(nameof(CallPropertyGetter));
15+
16+
protected BasePropertyHelper(Type type)
17+
{
18+
this.Type = type;
19+
this.Properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
20+
}
21+
22+
protected Type Type { get; private set; }
23+
24+
protected IEnumerable<PropertyInfo> Properties { get; private set; }
25+
26+
protected static Func<object, TResult> MakeFastPropertyGetter<TResult>(PropertyInfo propertyInfo)
27+
{
28+
try
29+
{
30+
var propertyGetMethod = propertyInfo.GetMethod;
31+
32+
var typeInput = propertyGetMethod.DeclaringType;
33+
var typeOutput = propertyGetMethod.ReturnType;
34+
35+
var delegateType = typeof(Func<,>).MakeGenericType(typeInput, typeOutput);
36+
var propertyGetterDelegate = propertyGetMethod.CreateDelegate(delegateType);
37+
38+
var wrapperDelegateMethod = CallPropertyGetterOpenGenericMethod.MakeGenericMethod(typeInput, typeOutput);
39+
var accessorDelegate = wrapperDelegateMethod.CreateDelegate(
40+
typeof(Func<object, TResult>),
41+
propertyGetterDelegate);
42+
43+
return (Func<object, TResult>)accessorDelegate;
44+
}
45+
catch
46+
{
47+
throw new InvalidOperationException(string.Format(InvalidDelegateErrorMessage, propertyInfo.Name, typeof(TResult)));
48+
}
49+
}
50+
51+
protected PropertyInfo FindPropertyWithAttribute<TAttribute>()
52+
where TAttribute : Attribute
53+
{
54+
return this.Properties.FirstOrDefault(pr => pr.GetCustomAttribute(typeof(TAttribute), true) != null);
55+
}
56+
57+
protected void ThrowNewInvalidOperationExceptionIfNull(object value, string propertyName)
58+
{
59+
if (value == null)
60+
{
61+
throw new InvalidOperationException($"{propertyName} could not be found on the provided {this.Type.ToFriendlyTypeName()}. The property should be specified manually by providing controller instance or using the specified helper methods.");
62+
}
63+
}
64+
65+
// Called via reflection
66+
private static TValue CallPropertyGetter<TDeclaringType, TValue>(
67+
Func<TDeclaringType, TValue> getter,
68+
object target)
69+
{
70+
return getter((TDeclaringType)target);
71+
}
72+
}
73+
}

0 commit comments

Comments
 (0)