diff --git a/Build.ps1 b/Build.ps1 index bfbd989415..8ff62d6578 100644 --- a/Build.ps1 +++ b/Build.ps1 @@ -46,18 +46,18 @@ If($env:APPVEYOR_REPO_TAG -eq $true) { IF ([string]::IsNullOrWhitespace($revision)){ Write-Output "RUNNING dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts" - dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts + dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts --include-symbols CheckLastExitCode } Else { Write-Output "RUNNING dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts --version-suffix=$revision" - dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts --version-suffix=$revision + dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts --version-suffix=$revision --include-symbols CheckLastExitCode } } Else { Write-Output "VERSION-SUFFIX: alpha1-$revision" Write-Output "RUNNING dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts --version-suffix=alpha1-$revision" - dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts --version-suffix=alpha1-$revision + dotnet pack .\src\JsonApiDotNetCore -c Release -o .\artifacts --version-suffix=alpha1-$revision --include-symbols CheckLastExitCode } diff --git a/src/JsonApiDotNetCore/Models/AttrAttribute.cs b/src/JsonApiDotNetCore/Models/AttrAttribute.cs index 017cf72118..d5a30221bb 100644 --- a/src/JsonApiDotNetCore/Models/AttrAttribute.cs +++ b/src/JsonApiDotNetCore/Models/AttrAttribute.cs @@ -80,15 +80,54 @@ public AttrAttribute(string publicName, string internalName, bool isImmutable = /// Returns null if the attribute does not belong to the /// provided object. /// - public object GetValue(object entity) => PropertyInfo.GetValue(entity); + public object GetValue(object entity) + { + if (entity == null) + throw new InvalidOperationException("Cannot GetValue from null object."); + + var prop = GetResourceProperty(entity); + return prop?.GetValue(entity); + } /// /// Sets the value of the attribute on the given object. /// public void SetValue(object entity, object newValue) { - var convertedValue = TypeHelper.ConvertType(newValue, PropertyInfo.PropertyType); - PropertyInfo.SetValue(entity, convertedValue); + if (entity == null) + throw new InvalidOperationException("Cannot SetValue on null object."); + + var prop = GetResourceProperty(entity); + if(prop != null) + { + var convertedValue = TypeHelper.ConvertType(newValue, prop.PropertyType); + prop.SetValue(entity, convertedValue); + } + } + + private PropertyInfo GetResourceProperty(object resource) + { + // There are some scenarios, especially ones where users are using a different + // data model than view model, where they may use a repository implmentation + // that does not match the deserialized type. For now, we will continue to support + // this use case. + var targetType = resource.GetType(); + if (targetType != PropertyInfo.DeclaringType) + { + var propertyInfo = resource + .GetType() + .GetProperty(InternalAttributeName); + + return propertyInfo; + + // TODO: this should throw but will be a breaking change in some cases + //if (propertyInfo == null) + // throw new InvalidOperationException( + // $"'{targetType}' does not contain a member named '{InternalAttributeName}'." + + // $"There is also a mismatch in target types. Expected '{PropertyInfo.DeclaringType}' but instead received '{targetType}'."); + } + + return PropertyInfo; } /// diff --git a/src/JsonApiDotNetCore/Models/ResourceDefinition.cs b/src/JsonApiDotNetCore/Models/ResourceDefinition.cs index 03ac62390b..64ff918116 100644 --- a/src/JsonApiDotNetCore/Models/ResourceDefinition.cs +++ b/src/JsonApiDotNetCore/Models/ResourceDefinition.cs @@ -55,7 +55,7 @@ protected List Remove(Expression> filter, List model.Attribute if (filter.Body is MemberExpression memberExpression) return _contextEntity.Attributes - .Where(a => a.PropertyInfo.Name != memberExpression.Member.Name) + .Where(a => a.InternalAttributeName != memberExpression.Member.Name) .ToList(); // model => new { model.Attribute1, model.Attribute2 } @@ -63,7 +63,7 @@ protected List Remove(Expression> filter, List(); foreach (var attr in _contextEntity.Attributes) - if (newExpression.Members.Any(m => m.Name == attr.PropertyInfo.Name) == false) + if (newExpression.Members.Any(m => m.Name == attr.InternalAttributeName) == false) attributes.Add(attr); return attributes; diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index 0c3b7217fe..8b5a94f201 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -147,7 +147,7 @@ private object SetEntityAttributes( if (attributeValues.TryGetValue(attr.PublicAttributeName, out object newValue)) { var convertedValue = ConvertAttrValue(newValue, attr.PropertyInfo.PropertyType); - attr.PropertyInfo.SetValue(entity, convertedValue); + attr.SetValue(entity, convertedValue); if (attr.IsImmutable == false) _jsonApiContext.AttributesToUpdate[attr] = convertedValue;