Initial commit providing the AdapterFactory directly to the ObjectAdapter to all for customization of the Adapter selection and the ability to override the built in adapters to leverage their ability as much as possible.

This commit is contained in:
DHumphreys 2018-05-11 15:08:09 -04:00 committed by Ryan Nowak
parent d7ac5c57ef
commit 4d92d76b64
12 changed files with 263 additions and 68 deletions

View File

@ -0,0 +1,39 @@
using Microsoft.AspNetCore.JsonPatch.Internal;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace Microsoft.AspNetCore.JsonPatch.Adapters
{
/// <summary>
/// The default AdapterFactory to be used for resolving <see cref="IAdapter"/>.
/// </summary>
public class AdapterFactory : IAdapterFactory
{
/// <inheritdoc />
public virtual IAdapter Create(object target, IContractResolver contractResolver)
{
var jsonContract = contractResolver.ResolveContract(target.GetType());
if (target is IList)
{
return new ListAdapter();
}
else if (jsonContract is JsonDictionaryContract jsonDictionaryContract)
{
var type = typeof(DictionaryAdapter<,>).MakeGenericType(jsonDictionaryContract.DictionaryKeyType, jsonDictionaryContract.DictionaryValueType);
return (IAdapter)Activator.CreateInstance(type);
}
else if (jsonContract is JsonDynamicContract)
{
return new DynamicObjectAdapter();
}
else
{
return new PocoAdapter();
}
}
}
}

View File

@ -0,0 +1,22 @@
using Microsoft.AspNetCore.JsonPatch.Internal;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Text;
namespace Microsoft.AspNetCore.JsonPatch.Adapters
{
/// <summary>
/// Defines the operations used for loading an <see cref="IAdapter"/> based on the current object and ContractResolver.
/// </summary>
public interface IAdapterFactory
{
/// <summary>
/// Creates an <see cref="IAdapter"/> for the current object
/// </summary>
/// <param name="target">The target object</param>
/// <param name="contractResolver">The current contract resolver</param>
/// <returns>The needed <see cref="IAdapter"/></returns>
IAdapter Create(object target, IContractResolver contractResolver);
}
}

View File

@ -18,17 +18,37 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters
/// <param name="logErrorAction">The <see cref="Action"/> for logging <see cref="JsonPatchError"/>.</param> /// <param name="logErrorAction">The <see cref="Action"/> for logging <see cref="JsonPatchError"/>.</param>
public ObjectAdapter( public ObjectAdapter(
IContractResolver contractResolver, IContractResolver contractResolver,
Action<JsonPatchError> logErrorAction) Action<JsonPatchError> logErrorAction):
this(contractResolver, logErrorAction, new AdapterFactory())
{ {
ContractResolver = contractResolver ?? throw new ArgumentNullException(nameof(contractResolver));
LogErrorAction = logErrorAction;
} }
/// <summary>
/// Initializes a new instance of <see cref="ObjectAdapter"/>.
/// </summary>
/// <param name="contractResolver">The <see cref="IContractResolver"/>.</param>
/// <param name="logErrorAction">The <see cref="Action"/> for logging <see cref="JsonPatchError"/>.</param>
/// <param name="adapterFactory">The <see cref="IAdapterFactory"/> to use when creating adaptors.</param>
public ObjectAdapter(
IContractResolver contractResolver,
Action<JsonPatchError> logErrorAction,
IAdapterFactory adapterFactory)
{
ContractResolver = contractResolver ?? throw new ArgumentNullException(nameof(contractResolver));
LogErrorAction = logErrorAction;
AdapterFactory = adapterFactory ?? throw new ArgumentNullException(nameof(adapterFactory));
}
/// <summary> /// <summary>
/// Gets or sets the <see cref="IContractResolver"/>. /// Gets or sets the <see cref="IContractResolver"/>.
/// </summary> /// </summary>
public IContractResolver ContractResolver { get; } public IContractResolver ContractResolver { get; }
/// <summary>
/// Gets or sets the <see cref="IAdapterFactory"/>
/// </summary>
public IAdapterFactory AdapterFactory { get; set; }
/// <summary> /// <summary>
/// Action for logging <see cref="JsonPatchError"/>. /// Action for logging <see cref="JsonPatchError"/>.
/// </summary> /// </summary>
@ -75,7 +95,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters
} }
var parsedPath = new ParsedPath(path); var parsedPath = new ParsedPath(path);
var visitor = new ObjectVisitor(parsedPath, ContractResolver); var visitor = new ObjectVisitor(parsedPath, ContractResolver, AdapterFactory);
var target = objectToApplyTo; var target = objectToApplyTo;
if (!visitor.TryVisit(ref target, out var adapter, out var errorMessage)) if (!visitor.TryVisit(ref target, out var adapter, out var errorMessage))
@ -144,7 +164,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters
private void Remove(string path, object objectToApplyTo, Operation operationToReport) private void Remove(string path, object objectToApplyTo, Operation operationToReport)
{ {
var parsedPath = new ParsedPath(path); var parsedPath = new ParsedPath(path);
var visitor = new ObjectVisitor(parsedPath, ContractResolver); var visitor = new ObjectVisitor(parsedPath, ContractResolver, AdapterFactory);
var target = objectToApplyTo; var target = objectToApplyTo;
if (!visitor.TryVisit(ref target, out var adapter, out var errorMessage)) if (!visitor.TryVisit(ref target, out var adapter, out var errorMessage))
@ -175,7 +195,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters
} }
var parsedPath = new ParsedPath(operation.path); var parsedPath = new ParsedPath(operation.path);
var visitor = new ObjectVisitor(parsedPath, ContractResolver); var visitor = new ObjectVisitor(parsedPath, ContractResolver, AdapterFactory);
var target = objectToApplyTo; var target = objectToApplyTo;
if (!visitor.TryVisit(ref target, out var adapter, out var errorMessage)) if (!visitor.TryVisit(ref target, out var adapter, out var errorMessage))
@ -239,7 +259,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters
} }
var parsedPath = new ParsedPath(operation.path); var parsedPath = new ParsedPath(operation.path);
var visitor = new ObjectVisitor(parsedPath, ContractResolver); var visitor = new ObjectVisitor(parsedPath, ContractResolver, AdapterFactory);
var target = objectToApplyTo; var target = objectToApplyTo;
if (!visitor.TryVisit(ref target, out var adapter, out var errorMessage)) if (!visitor.TryVisit(ref target, out var adapter, out var errorMessage))
@ -281,7 +301,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Adapters
propertyValue = null; propertyValue = null;
var parsedPath = new ParsedPath(fromLocation); var parsedPath = new ParsedPath(fromLocation);
var visitor = new ObjectVisitor(parsedPath, ContractResolver); var visitor = new ObjectVisitor(parsedPath, ContractResolver, AdapterFactory);
var target = objectToGetValueFrom; var target = objectToGetValueFrom;
if (!visitor.TryVisit(ref target, out var adapter, out var errorMessage)) if (!visitor.TryVisit(ref target, out var adapter, out var errorMessage))

View File

@ -10,7 +10,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
{ {
public class DictionaryAdapter<TKey, TValue> : IAdapter public class DictionaryAdapter<TKey, TValue> : IAdapter
{ {
public bool TryAdd( public virtual bool TryAdd(
object target, object target,
string segment, string segment,
IContractResolver contractResolver, IContractResolver contractResolver,
@ -37,7 +37,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
return true; return true;
} }
public bool TryGet( public virtual bool TryGet(
object target, object target,
string segment, string segment,
IContractResolver contractResolver, IContractResolver contractResolver,
@ -66,7 +66,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
return true; return true;
} }
public bool TryRemove( public virtual bool TryRemove(
object target, object target,
string segment, string segment,
IContractResolver contractResolver, IContractResolver contractResolver,
@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
return true; return true;
} }
public bool TryReplace( public virtual bool TryReplace(
object target, object target,
string segment, string segment,
IContractResolver contractResolver, IContractResolver contractResolver,
@ -128,7 +128,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
return true; return true;
} }
public bool TryTest( public virtual bool TryTest(
object target, object target,
string segment, string segment,
IContractResolver contractResolver, IContractResolver contractResolver,
@ -177,7 +177,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
} }
} }
public bool TryTraverse( public virtual bool TryTraverse(
object target, object target,
string segment, string segment,
IContractResolver contractResolver, IContractResolver contractResolver,
@ -208,7 +208,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
} }
} }
private bool TryConvertKey(string key, out TKey convertedKey, out string errorMessage) protected virtual bool TryConvertKey(string key, out TKey convertedKey, out string errorMessage)
{ {
var conversionResult = ConversionResultProvider.ConvertTo(key, typeof(TKey)); var conversionResult = ConversionResultProvider.ConvertTo(key, typeof(TKey));
if (conversionResult.CanBeConverted) if (conversionResult.CanBeConverted)
@ -225,7 +225,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
} }
} }
private bool TryConvertValue(object value, out TValue convertedValue, out string errorMessage) protected virtual bool TryConvertValue(object value, out TValue convertedValue, out string errorMessage)
{ {
var conversionResult = ConversionResultProvider.ConvertTo(value, typeof(TValue)); var conversionResult = ConversionResultProvider.ConvertTo(value, typeof(TValue));
if (conversionResult.CanBeConverted) if (conversionResult.CanBeConverted)

View File

@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
{ {
public class DynamicObjectAdapter : IAdapter public class DynamicObjectAdapter : IAdapter
{ {
public bool TryAdd( public virtual bool TryAdd(
object target, object target,
string segment, string segment,
IContractResolver contractResolver, IContractResolver contractResolver,
@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
return true; return true;
} }
public bool TryGet( public virtual bool TryGet(
object target, object target,
string segment, string segment,
IContractResolver contractResolver, IContractResolver contractResolver,
@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
return true; return true;
} }
public bool TryRemove( public virtual bool TryRemove(
object target, object target,
string segment, string segment,
IContractResolver contractResolver, IContractResolver contractResolver,
@ -78,7 +78,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
} }
public bool TryReplace( public virtual bool TryReplace(
object target, object target,
string segment, string segment,
IContractResolver contractResolver, IContractResolver contractResolver,
@ -105,7 +105,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
return true; return true;
} }
public bool TryTest( public virtual bool TryTest(
object target, object target,
string segment, string segment,
IContractResolver contractResolver, IContractResolver contractResolver,
@ -135,7 +135,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
} }
} }
public bool TryTraverse( public virtual bool TryTraverse(
object target, object target,
string segment, string segment,
IContractResolver contractResolver, IContractResolver contractResolver,
@ -155,7 +155,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
} }
} }
private bool TryGetDynamicObjectProperty( protected virtual bool TryGetDynamicObjectProperty(
object target, object target,
IContractResolver contractResolver, IContractResolver contractResolver,
string segment, string segment,
@ -191,7 +191,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
} }
} }
private bool TrySetDynamicObjectProperty( protected virtual bool TrySetDynamicObjectProperty(
object target, object target,
IContractResolver contractResolver, IContractResolver contractResolver,
string segment, string segment,
@ -227,7 +227,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
} }
} }
private bool TryConvertValue(object value, Type propertyType, out object convertedValue) protected virtual bool TryConvertValue(object value, Type propertyType, out object convertedValue)
{ {
var conversionResult = ConversionResultProvider.ConvertTo(value, propertyType); var conversionResult = ConversionResultProvider.ConvertTo(value, propertyType);
if (!conversionResult.CanBeConverted) if (!conversionResult.CanBeConverted)

View File

@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
{ {
public class ListAdapter : IAdapter public class ListAdapter : IAdapter
{ {
public bool TryAdd( public virtual bool TryAdd(
object target, object target,
string segment, string segment,
IContractResolver contractResolver, IContractResolver contractResolver,
@ -50,7 +50,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
return true; return true;
} }
public bool TryGet( public virtual bool TryGet(
object target, object target,
string segment, string segment,
IContractResolver contractResolver, IContractResolver contractResolver,
@ -84,7 +84,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
return true; return true;
} }
public bool TryRemove( public virtual bool TryRemove(
object target, object target,
string segment, string segment,
IContractResolver contractResolver, IContractResolver contractResolver,
@ -115,7 +115,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
return true; return true;
} }
public bool TryReplace( public virtual bool TryReplace(
object target, object target,
string segment, string segment,
IContractResolver contractResolver, IContractResolver contractResolver,
@ -152,7 +152,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
return true; return true;
} }
public bool TryTest( public virtual bool TryTest(
object target, object target,
string segment, string segment,
IContractResolver contractResolver, IContractResolver contractResolver,
@ -189,7 +189,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
} }
} }
public bool TryTraverse( public virtual bool TryTraverse(
object target, object target,
string segment, string segment,
IContractResolver contractResolver, IContractResolver contractResolver,
@ -224,7 +224,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
return true; return true;
} }
private bool TryConvertValue( protected virtual bool TryConvertValue(
object originalValue, object originalValue,
Type listTypeArgument, Type listTypeArgument,
string segment, string segment,
@ -244,7 +244,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
return true; return true;
} }
private bool TryGetListTypeArgument(IList list, out Type listTypeArgument, out string errorMessage) protected virtual bool TryGetListTypeArgument(IList list, out Type listTypeArgument, out string errorMessage)
{ {
// Arrays are not supported as they have fixed size and operations like Add, Insert do not make sense // Arrays are not supported as they have fixed size and operations like Add, Insert do not make sense
var listType = list.GetType(); var listType = list.GetType();
@ -272,7 +272,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
} }
} }
private bool TryGetPositionInfo( protected virtual bool TryGetPositionInfo(
IList list, IList list,
string segment, string segment,
OperationType operationType, OperationType operationType,
@ -318,7 +318,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
} }
} }
private struct PositionInfo protected struct PositionInfo
{ {
public PositionInfo(PositionType type, int index) public PositionInfo(PositionType type, int index)
{ {
@ -330,7 +330,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
public int Index { get; } public int Index { get; }
} }
private enum PositionType protected enum PositionType
{ {
Index, // valid index Index, // valid index
EndOfList, // '-' EndOfList, // '-'
@ -338,7 +338,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
OutOfBounds OutOfBounds
} }
private enum OperationType protected enum OperationType
{ {
Add, Add,
Remove, Remove,

View File

@ -3,19 +3,38 @@
using System; using System;
using System.Collections; using System.Collections;
using Microsoft.AspNetCore.JsonPatch.Adapters;
using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Serialization;
namespace Microsoft.AspNetCore.JsonPatch.Internal namespace Microsoft.AspNetCore.JsonPatch.Internal
{ {
public class ObjectVisitor public class ObjectVisitor
{ {
private readonly IAdapterFactory _adapterFactory;
private readonly IContractResolver _contractResolver; private readonly IContractResolver _contractResolver;
private readonly ParsedPath _path; private readonly ParsedPath _path;
/// <summary>
/// Initializes a new instance of <see cref="ObjectVisitor"/>.
/// </summary>
/// <param name="path">The path of the JsonPatch operation</param>
/// <param name="contractResolver">The <see cref="IContractResolver"/>.</param>
public ObjectVisitor(ParsedPath path, IContractResolver contractResolver) public ObjectVisitor(ParsedPath path, IContractResolver contractResolver)
:this(path, contractResolver, new AdapterFactory())
{
}
/// <summary>
/// Initializes a new instance of <see cref="ObjectVisitor"/>.
/// </summary>
/// <param name="path">The path of the JsonPatch operation</param>
/// <param name="contractResolver">The <see cref="IContractResolver"/>.</param>
/// <param name="adapterFactory">The <see cref="IAdapterFactory"/> to use when creating adaptors.</param>
public ObjectVisitor(ParsedPath path, IContractResolver contractResolver, IAdapterFactory adapterFactory)
{ {
_path = path; _path = path;
_contractResolver = contractResolver ?? throw new ArgumentNullException(nameof(contractResolver)); _contractResolver = contractResolver ?? throw new ArgumentNullException(nameof(contractResolver));
_adapterFactory = adapterFactory ?? throw new ArgumentNullException(nameof(adapterFactory));
} }
public bool TryVisit(ref object target, out IAdapter adapter, out string errorMessage) public bool TryVisit(ref object target, out IAdapter adapter, out string errorMessage)
@ -48,25 +67,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
private IAdapter SelectAdapter(object targetObject) private IAdapter SelectAdapter(object targetObject)
{ {
var jsonContract = _contractResolver.ResolveContract(targetObject.GetType()); return _adapterFactory.Create(targetObject, _contractResolver);
if (targetObject is IList)
{
return new ListAdapter();
}
else if (jsonContract is JsonDictionaryContract jsonDictionaryContract)
{
var type = typeof(DictionaryAdapter<,>).MakeGenericType(jsonDictionaryContract.DictionaryKeyType, jsonDictionaryContract.DictionaryValueType);
return (IAdapter)Activator.CreateInstance(type);
}
else if (jsonContract is JsonDynamicContract)
{
return new DynamicObjectAdapter();
}
else
{
return new PocoAdapter();
}
} }
} }
} }

View File

@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
{ {
public class PocoAdapter : IAdapter public class PocoAdapter : IAdapter
{ {
public bool TryAdd( public virtual bool TryAdd(
object target, object target,
string segment, string segment,
IContractResolver contractResolver, IContractResolver contractResolver,
@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
return true; return true;
} }
public bool TryGet( public virtual bool TryGet(
object target, object target,
string segment, string segment,
IContractResolver contractResolver, IContractResolver contractResolver,
@ -69,7 +69,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
return true; return true;
} }
public bool TryRemove( public virtual bool TryRemove(
object target, object target,
string segment, string segment,
IContractResolver contractResolver, IContractResolver contractResolver,
@ -102,7 +102,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
return true; return true;
} }
public bool TryReplace( public virtual bool TryReplace(
object target, object target,
string segment, string segment,
IContractResolver IContractResolver
@ -134,7 +134,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
return true; return true;
} }
public bool TryTest( public virtual bool TryTest(
object target, object target,
string segment, string segment,
IContractResolver IContractResolver
@ -171,7 +171,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
return true; return true;
} }
public bool TryTraverse( public virtual bool TryTraverse(
object target, object target,
string segment, string segment,
IContractResolver contractResolver, IContractResolver contractResolver,
@ -197,7 +197,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
return false; return false;
} }
private bool TryGetJsonProperty( protected virtual bool TryGetJsonProperty(
object target, object target,
IContractResolver contractResolver, IContractResolver contractResolver,
string segment, string segment,
@ -220,7 +220,7 @@ namespace Microsoft.AspNetCore.JsonPatch.Internal
return false; return false;
} }
private bool TryConvertValue(object value, Type propertyType, out object convertedValue) protected virtual bool TryConvertValue(object value, Type propertyType, out object convertedValue)
{ {
var conversionResult = ConversionResultProvider.ConvertTo(value, propertyType); var conversionResult = ConversionResultProvider.ConvertTo(value, propertyType);
if (!conversionResult.CanBeConverted) if (!conversionResult.CanBeConverted)

View File

@ -174,7 +174,7 @@ namespace Microsoft.AspNetCore.JsonPatch
throw new ArgumentNullException(nameof(objectToApplyTo)); throw new ArgumentNullException(nameof(objectToApplyTo));
} }
ApplyTo(objectToApplyTo, new ObjectAdapter(ContractResolver, logErrorAction: null)); ApplyTo(objectToApplyTo, new ObjectAdapter(ContractResolver, null, new AdapterFactory()));
} }
/// <summary> /// <summary>
@ -183,13 +183,28 @@ namespace Microsoft.AspNetCore.JsonPatch
/// <param name="objectToApplyTo">Object to apply the JsonPatchDocument to</param> /// <param name="objectToApplyTo">Object to apply the JsonPatchDocument to</param>
/// <param name="logErrorAction">Action to log errors</param> /// <param name="logErrorAction">Action to log errors</param>
public void ApplyTo(object objectToApplyTo, Action<JsonPatchError> logErrorAction) public void ApplyTo(object objectToApplyTo, Action<JsonPatchError> logErrorAction)
{
ApplyTo(objectToApplyTo, new ObjectAdapter(ContractResolver, logErrorAction, new AdapterFactory()), logErrorAction);
}
/// <summary>
/// Apply this JsonPatchDocument
/// </summary>
/// <param name="objectToApplyTo">Object to apply the JsonPatchDocument to</param>
/// <param name="adapter">IObjectAdapter instance to use when applying</param>
/// <param name="logErrorAction">Action to log errors</param>
public void ApplyTo(object objectToApplyTo, IObjectAdapter adapter, Action<JsonPatchError> logErrorAction)
{ {
if (objectToApplyTo == null) if (objectToApplyTo == null)
{ {
throw new ArgumentNullException(nameof(objectToApplyTo)); throw new ArgumentNullException(nameof(objectToApplyTo));
} }
var adapter = new ObjectAdapter(ContractResolver, logErrorAction); if (adapter == null)
{
throw new ArgumentNullException(nameof(adapter));
}
foreach (var op in Operations) foreach (var op in Operations)
{ {
try try

View File

@ -697,7 +697,7 @@ namespace Microsoft.AspNetCore.JsonPatch
throw new ArgumentNullException(nameof(objectToApplyTo)); throw new ArgumentNullException(nameof(objectToApplyTo));
} }
ApplyTo(objectToApplyTo, new ObjectAdapter(ContractResolver, logErrorAction: null)); ApplyTo(objectToApplyTo, new ObjectAdapter(ContractResolver, null, new AdapterFactory()));
} }
/// <summary> /// <summary>
@ -706,13 +706,28 @@ namespace Microsoft.AspNetCore.JsonPatch
/// <param name="objectToApplyTo">Object to apply the JsonPatchDocument to</param> /// <param name="objectToApplyTo">Object to apply the JsonPatchDocument to</param>
/// <param name="logErrorAction">Action to log errors</param> /// <param name="logErrorAction">Action to log errors</param>
public void ApplyTo(TModel objectToApplyTo, Action<JsonPatchError> logErrorAction) public void ApplyTo(TModel objectToApplyTo, Action<JsonPatchError> logErrorAction)
{
ApplyTo(objectToApplyTo, new ObjectAdapter(ContractResolver, logErrorAction, new AdapterFactory()), logErrorAction);
}
/// <summary>
/// Apply this JsonPatchDocument
/// </summary>
/// <param name="objectToApplyTo">Object to apply the JsonPatchDocument to</param>
/// <param name="adapter">IObjectAdapter instance to use when applying</param>
/// <param name="logErrorAction">Action to log errors</param>
public void ApplyTo(TModel objectToApplyTo, IObjectAdapter adapter, Action<JsonPatchError> logErrorAction)
{ {
if (objectToApplyTo == null) if (objectToApplyTo == null)
{ {
throw new ArgumentNullException(nameof(objectToApplyTo)); throw new ArgumentNullException(nameof(objectToApplyTo));
} }
var adapter = new ObjectAdapter(ContractResolver, logErrorAction); if (adapter == null)
{
throw new ArgumentNullException(nameof(adapter));
}
foreach (var op in Operations) foreach (var op in Operations)
{ {
try try

View File

@ -0,0 +1,73 @@
using Microsoft.AspNetCore.JsonPatch.Adapters;
using Microsoft.AspNetCore.JsonPatch.Internal;
using Moq;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Text;
using Xunit;
namespace Microsoft.AspNetCore.JsonPatch.Test.Adapters
{
public class AdapterFactoryTests
{
[Fact]
public void GetListAdapterForListTargets()
{
// Arrange
AdapterFactory factory = new AdapterFactory();
//Act:
IAdapter adapter = factory.Create(new List<string>(), new DefaultContractResolver());
// Assert
Assert.Equal(typeof(ListAdapter), adapter.GetType());
}
[Fact]
public void GetDictionaryAdapterForDictionaryObjects()
{
// Arrange
AdapterFactory factory = new AdapterFactory();
//Act:
IAdapter adapter = factory.Create(new Dictionary<string, string>(), new DefaultContractResolver());
// Assert
Assert.Equal(typeof(DictionaryAdapter<string, string>), adapter.GetType());
}
private class PocoModel
{}
[Fact]
public void GetPocoAdapterForGenericObjects()
{
// Arrange
AdapterFactory factory = new AdapterFactory();
//Act:
IAdapter adapter = factory.Create(new PocoModel(), new DefaultContractResolver());
// Assert
Assert.Equal(typeof(PocoAdapter), adapter.GetType());
}
[Fact]
public void GetDynamicAdapterForGenericObjects()
{
// Arrange
AdapterFactory factory = new AdapterFactory();
//Act:
IAdapter adapter = factory.Create(new TestDynamicObject(), new DefaultContractResolver());
// Assert
Assert.Equal(typeof(DynamicObjectAdapter), adapter.GetType());
}
}
}

View File

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Text;
namespace Microsoft.AspNetCore.JsonPatch.Test.Adapters
{
public class TestDynamicObject : DynamicObject
{ }
}