From 9323342cd05dc69de4c6fb9f900bf8ced7fc0bad Mon Sep 17 00:00:00 2001 From: Alvaro Nicoli Date: Sun, 26 Jul 2020 00:23:53 -0300 Subject: [PATCH 1/4] fix: support for lazy loading proxies --- .../Internal/ResourceGraph.cs | 2 +- .../Internal/ResourceGraphBuilder_Tests.cs | 38 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/JsonApiDotNetCore/Internal/ResourceGraph.cs b/src/JsonApiDotNetCore/Internal/ResourceGraph.cs index ee056ad4c2..7c589442b0 100644 --- a/src/JsonApiDotNetCore/Internal/ResourceGraph.cs +++ b/src/JsonApiDotNetCore/Internal/ResourceGraph.cs @@ -26,7 +26,7 @@ public ResourceContext GetResourceContext(string resourceName) => Resources.SingleOrDefault(e => e.ResourceName == resourceName); /// public ResourceContext GetResourceContext(Type resourceType) - => Resources.SingleOrDefault(e => e.ResourceType == resourceType); + => Resources.SingleOrDefault(e => e.ResourceType == resourceType) ?? Resources.SingleOrDefault(e => e.ResourceType.IsAssignableFrom(resourceType)); /// public ResourceContext GetResourceContext() where TResource : class, IIdentifiable => GetResourceContext(typeof(TResource)); diff --git a/test/UnitTests/Internal/ResourceGraphBuilder_Tests.cs b/test/UnitTests/Internal/ResourceGraphBuilder_Tests.cs index 1ceb41f2aa..9348602cc8 100644 --- a/test/UnitTests/Internal/ResourceGraphBuilder_Tests.cs +++ b/test/UnitTests/Internal/ResourceGraphBuilder_Tests.cs @@ -1,6 +1,8 @@ +using System; using JsonApiDotNetCore.Builders; using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.Internal; +using JsonApiDotNetCore.Models; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; @@ -41,12 +43,48 @@ public void Adding_DbContext_Members_That_Do_Not_Implement_IIdentifiable_Logs_Wa Assert.Equal("Entity 'UnitTests.Internal.ResourceGraphBuilder_Tests+TestContext' does not implement 'IIdentifiable'.", loggerFactory.Logger.Messages[0].Text); } + [Fact] + public void GetResourceContext_Yields_Right_Type_For_Proxy() + { + // Arrange + var resourceGraphBuilder = new ResourceGraphBuilder(new JsonApiOptions(), NullLoggerFactory.Instance); + resourceGraphBuilder.AddResource(); + var resourceGraph = (ResourceGraph)resourceGraphBuilder.Build(); + + // Act + var result = resourceGraph.GetResourceContext(typeof(DummyProxy)); + + // Assert + Assert.Equal(typeof(Bar), result.ResourceType); + } + + [Fact] + public void GetResourceContext_Yields_Right_Type_For_IIdentifiable() + { + // Arrange + var resourceGraphBuilder = new ResourceGraphBuilder(new JsonApiOptions(), NullLoggerFactory.Instance); + resourceGraphBuilder.AddResource(); + var resourceGraph = (ResourceGraph)resourceGraphBuilder.Build(); + + // Act + var result = resourceGraph.GetResourceContext(typeof(Bar)); + + // Assert + Assert.Equal(typeof(Bar), result.ResourceType); + } + private class Foo { } private class TestContext : DbContext { public DbSet Foos { get; set; } } + + private class Bar : Identifiable { } + + // Used to simulate a lazy loading proxy + private class DummyProxy : Bar { } + } } From 5954d85ff6c23612f2a3d31676058aadbf00f94d Mon Sep 17 00:00:00 2001 From: Alvaro Nicoli Date: Sun, 26 Jul 2020 12:38:45 -0300 Subject: [PATCH 2/4] fix: discriminate proxies in GetResourceContext --- src/JsonApiDotNetCore/Internal/ResourceGraph.cs | 10 +++++++++- src/JsonApiDotNetCore/JsonApiDotNetCore.csproj | 1 + .../Internal/ResourceGraphBuilder_Tests.cs | 13 ++++++------- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/JsonApiDotNetCore/Internal/ResourceGraph.cs b/src/JsonApiDotNetCore/Internal/ResourceGraph.cs index 7c589442b0..a7a99b08fa 100644 --- a/src/JsonApiDotNetCore/Internal/ResourceGraph.cs +++ b/src/JsonApiDotNetCore/Internal/ResourceGraph.cs @@ -4,6 +4,7 @@ using System.Linq.Expressions; using JsonApiDotNetCore.Internal.Contracts; using JsonApiDotNetCore.Models; +using Castle.DynamicProxy; namespace JsonApiDotNetCore.Internal { @@ -26,7 +27,9 @@ public ResourceContext GetResourceContext(string resourceName) => Resources.SingleOrDefault(e => e.ResourceName == resourceName); /// public ResourceContext GetResourceContext(Type resourceType) - => Resources.SingleOrDefault(e => e.ResourceType == resourceType) ?? Resources.SingleOrDefault(e => e.ResourceType.IsAssignableFrom(resourceType)); + => IsDynamicProxy(resourceType) ? + Resources.SingleOrDefault(e => e.ResourceType == resourceType.BaseType) : + Resources.SingleOrDefault(e => e.ResourceType == resourceType); /// public ResourceContext GetResourceContext() where TResource : class, IIdentifiable => GetResourceContext(typeof(TResource)); @@ -125,6 +128,11 @@ private IEnumerable Getter(Expression> selec $"For example: 'article => article.Title' or 'article => new {{ article.Title, article.PageCount }}'."); } + private bool IsDynamicProxy(Type resourceType) + { + return typeof(IProxyTargetAccessor).IsAssignableFrom(resourceType); + } + private static Expression RemoveConvert(Expression expression) => expression is UnaryExpression unaryExpression && unaryExpression.NodeType == ExpressionType.Convert diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj index e2808125b5..9f27f70638 100644 --- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj +++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj @@ -22,6 +22,7 @@ + diff --git a/test/UnitTests/Internal/ResourceGraphBuilder_Tests.cs b/test/UnitTests/Internal/ResourceGraphBuilder_Tests.cs index 9348602cc8..87af07dfc7 100644 --- a/test/UnitTests/Internal/ResourceGraphBuilder_Tests.cs +++ b/test/UnitTests/Internal/ResourceGraphBuilder_Tests.cs @@ -1,4 +1,3 @@ -using System; using JsonApiDotNetCore.Builders; using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.Internal; @@ -6,6 +5,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using Castle.DynamicProxy; using Xunit; namespace UnitTests.Internal @@ -50,16 +50,18 @@ public void GetResourceContext_Yields_Right_Type_For_Proxy() var resourceGraphBuilder = new ResourceGraphBuilder(new JsonApiOptions(), NullLoggerFactory.Instance); resourceGraphBuilder.AddResource(); var resourceGraph = (ResourceGraph)resourceGraphBuilder.Build(); + var proxyGenerator = new ProxyGenerator(); // Act - var result = resourceGraph.GetResourceContext(typeof(DummyProxy)); + var proxy = proxyGenerator.CreateClassProxy(); + var result = resourceGraph.GetResourceContext(proxy.GetType()); // Assert Assert.Equal(typeof(Bar), result.ResourceType); } [Fact] - public void GetResourceContext_Yields_Right_Type_For_IIdentifiable() + public void GetResourceContext_Yields_Right_Type_For_Identifiable() { // Arrange var resourceGraphBuilder = new ResourceGraphBuilder(new JsonApiOptions(), NullLoggerFactory.Instance); @@ -80,10 +82,7 @@ private class TestContext : DbContext public DbSet Foos { get; set; } } - private class Bar : Identifiable { } - - // Used to simulate a lazy loading proxy - private class DummyProxy : Bar { } + public class Bar : Identifiable { } } From 0175043161d35a905f294e39d7c3621cc212befd Mon Sep 17 00:00:00 2001 From: Alvaro Nicoli Date: Mon, 27 Jul 2020 19:39:53 -0300 Subject: [PATCH 3/4] fix: remove dependency --- src/JsonApiDotNetCore/Internal/ResourceGraph.cs | 8 +++----- src/JsonApiDotNetCore/JsonApiDotNetCore.csproj | 1 - test/UnitTests/UnitTests.csproj | 1 + 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/JsonApiDotNetCore/Internal/ResourceGraph.cs b/src/JsonApiDotNetCore/Internal/ResourceGraph.cs index a7a99b08fa..5fcc7cef6c 100644 --- a/src/JsonApiDotNetCore/Internal/ResourceGraph.cs +++ b/src/JsonApiDotNetCore/Internal/ResourceGraph.cs @@ -4,7 +4,6 @@ using System.Linq.Expressions; using JsonApiDotNetCore.Internal.Contracts; using JsonApiDotNetCore.Models; -using Castle.DynamicProxy; namespace JsonApiDotNetCore.Internal { @@ -14,10 +13,12 @@ namespace JsonApiDotNetCore.Internal public class ResourceGraph : IResourceGraph { private List Resources { get; } + private Type ProxyInterface { get; } public ResourceGraph(List resources) { Resources = resources; + ProxyInterface = Type.GetType("Castle.DynamicProxy.IProxyTargetAccessor, Castle.Core"); } /// @@ -128,10 +129,7 @@ private IEnumerable Getter(Expression> selec $"For example: 'article => article.Title' or 'article => new {{ article.Title, article.PageCount }}'."); } - private bool IsDynamicProxy(Type resourceType) - { - return typeof(IProxyTargetAccessor).IsAssignableFrom(resourceType); - } + private bool IsDynamicProxy(Type resourceType) => ProxyInterface?.IsAssignableFrom(resourceType) ?? false; private static Expression RemoveConvert(Expression expression) => expression is UnaryExpression unaryExpression diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj index 9f27f70638..e2808125b5 100644 --- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj +++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj @@ -22,7 +22,6 @@ - diff --git a/test/UnitTests/UnitTests.csproj b/test/UnitTests/UnitTests.csproj index f9c5e4b14a..b934bfee70 100644 --- a/test/UnitTests/UnitTests.csproj +++ b/test/UnitTests/UnitTests.csproj @@ -16,6 +16,7 @@ + From 0c93d8a6952cc17a9a19d800cff79c22dd012b40 Mon Sep 17 00:00:00 2001 From: Alvaro Nicoli Date: Tue, 28 Jul 2020 12:33:02 -0300 Subject: [PATCH 4/4] fix: corrections --- src/JsonApiDotNetCore/Internal/ResourceGraph.cs | 10 +++++----- test/UnitTests/Internal/ResourceGraphBuilder_Tests.cs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/JsonApiDotNetCore/Internal/ResourceGraph.cs b/src/JsonApiDotNetCore/Internal/ResourceGraph.cs index 5fcc7cef6c..a39980a6ea 100644 --- a/src/JsonApiDotNetCore/Internal/ResourceGraph.cs +++ b/src/JsonApiDotNetCore/Internal/ResourceGraph.cs @@ -13,12 +13,11 @@ namespace JsonApiDotNetCore.Internal public class ResourceGraph : IResourceGraph { private List Resources { get; } - private Type ProxyInterface { get; } + private static readonly Type proxyTargetAccessorType = Type.GetType("Castle.DynamicProxy.IProxyTargetAccessor, Castle.Core"); public ResourceGraph(List resources) { Resources = resources; - ProxyInterface = Type.GetType("Castle.DynamicProxy.IProxyTargetAccessor, Castle.Core"); } /// @@ -28,7 +27,7 @@ public ResourceContext GetResourceContext(string resourceName) => Resources.SingleOrDefault(e => e.ResourceName == resourceName); /// public ResourceContext GetResourceContext(Type resourceType) - => IsDynamicProxy(resourceType) ? + => IsLazyLoadingProxyForResourceType(resourceType) ? Resources.SingleOrDefault(e => e.ResourceType == resourceType.BaseType) : Resources.SingleOrDefault(e => e.ResourceType == resourceType); /// @@ -125,11 +124,12 @@ private IEnumerable Getter(Expression> selec } throw new ArgumentException( - $"The expression '{selector}' should select a single property or select multiple properties into an anonymous type. " + + $"The expression '{selector}' should select a single property or select multiple properties into an anonymous type. " + $"For example: 'article => article.Title' or 'article => new {{ article.Title, article.PageCount }}'."); } - private bool IsDynamicProxy(Type resourceType) => ProxyInterface?.IsAssignableFrom(resourceType) ?? false; + private bool IsLazyLoadingProxyForResourceType(Type resourceType) => + proxyTargetAccessorType?.IsAssignableFrom(resourceType) ?? false; private static Expression RemoveConvert(Expression expression) => expression is UnaryExpression unaryExpression diff --git a/test/UnitTests/Internal/ResourceGraphBuilder_Tests.cs b/test/UnitTests/Internal/ResourceGraphBuilder_Tests.cs index 87af07dfc7..52186dedb9 100644 --- a/test/UnitTests/Internal/ResourceGraphBuilder_Tests.cs +++ b/test/UnitTests/Internal/ResourceGraphBuilder_Tests.cs @@ -44,7 +44,7 @@ public void Adding_DbContext_Members_That_Do_Not_Implement_IIdentifiable_Logs_Wa } [Fact] - public void GetResourceContext_Yields_Right_Type_For_Proxy() + public void GetResourceContext_Yields_Right_Type_For_LazyLoadingProxy() { // Arrange var resourceGraphBuilder = new ResourceGraphBuilder(new JsonApiOptions(), NullLoggerFactory.Instance);