Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: Morcatko/Morcatko.AspNetCore.JsonMergePatch
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 91e33911378c0e110ae28e9709307b87a8a11cac
Choose a base ref
..
head repository: Morcatko/Morcatko.AspNetCore.JsonMergePatch
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: bf6cbf29669b516f1d0980db899dc8f0849dfdc0
Choose a head ref
Original file line number Diff line number Diff line change
@@ -1,134 +1,134 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
using Morcatko.AspNetCore.JsonMergePatch.Internal;
using Morcatko.AspNetCore.JsonMergePatch.SystemText.Builders;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text.Json;
using System.Threading.Tasks;

namespace Morcatko.AspNetCore.JsonMergePatch.SystemText
{
internal class SystemTextJsonMergePatchInputFormatter : SystemTextJsonInputFormatter
{
private static readonly MediaTypeHeaderValue JsonMergePatchMediaType = MediaTypeHeaderValue.Parse(JsonMergePatchDocument.ContentType).CopyAsReadOnly();

private readonly Lazy<ModelMetadata> _modelMetadata;
private readonly JsonMergePatchOptions _jsonMergePatchOptions;

public SystemTextJsonMergePatchInputFormatter(
JsonOptions options,
ILogger<SystemTextJsonInputFormatter> logger,
Lazy<IModelMetadataProvider> lazyModelMetadataProvider,
JsonMergePatchOptions jsonMergePatchOptions)
: base(options, logger)
{
SupportedMediaTypes.Clear();
SupportedMediaTypes.Add(JsonMergePatchMediaType);
_modelMetadata = new Lazy<ModelMetadata>(() => lazyModelMetadataProvider.Value.GetMetadataForType(typeof(JsonElement)));
_jsonMergePatchOptions = jsonMergePatchOptions;
}

private static bool ContainerIsIEnumerable(InputFormatterContext context)
=> GetEnumerableElementType(context.ModelType) != null;
private static Type GetEnumerableElementType(Type type)
{
if (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
return type.GetGenericArguments()[0];
return null;
}
private static Type GetMergePatchDocumentModelType(Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(JsonMergePatchDocument<>))
return type.GetGenericArguments()[0];
return null;
}

private IInternalJsonMergePatchDocument CreatePatchDocument(Type jsonMergePatchType, Type modelType, JsonElement jsonElement)
{
var jsonMergePatchDocument = PatchBuilder.CreatePatchDocument(modelType, jsonElement, base.SerializerOptions, this._jsonMergePatchOptions);
return jsonMergePatchDocument;
}

private object ConvertToPatch(object o, IList container, Type jsonMergePatchType, Type modelType)
{
var e = (JsonElement)o;
switch (e.ValueKind)
{
case JsonValueKind.Object:
if (container != null)
throw new ArgumentException("Received object when array was expected"); //This could be handled by returning list with single item

return CreatePatchDocument(jsonMergePatchType, modelType, e);
case JsonValueKind.Array:
if (container == null)
throw new ArgumentException("Received array when object was expected");

var enumerator = e.EnumerateArray();
while (enumerator.MoveNext())
{
container.Add(CreatePatchDocument(jsonMergePatchType, modelType, enumerator.Current));
}
return container;
default:
throw new NotSupportedException($"Unsupported ValueKing '{e.ValueKind}'");
}
}

public override IReadOnlyList<string> GetSupportedContentTypes(string contentType, Type objectType)
{
if (GetMergePatchDocumentModelType(objectType) != null ||
(GetEnumerableElementType(objectType) is Type elementType && GetMergePatchDocumentModelType(elementType) != null))
{
return base.GetSupportedContentTypes(contentType, objectType);
}
return Array.Empty<string>();
}

public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
var patchContext = new InputFormatterContext(
context.HttpContext,
context.ModelName,
context.ModelState,
_modelMetadata.Value,
context.ReaderFactory,
context.TreatEmptyInputAsDefaultValue);

var jsonResult = await base.ReadRequestBodyAsync(patchContext);

if (jsonResult.HasError)
return jsonResult;

try
{
var jsonMergePatchType = context.ModelType;
var container = (IList)null;

if (ContainerIsIEnumerable(context))
{
jsonMergePatchType = context.ModelType.GenericTypeArguments[0];
var listType = typeof(List<>);
var constructedListType = listType.MakeGenericType(jsonMergePatchType);
container = (IList)Activator.CreateInstance(constructedListType);
}
var modelType = jsonMergePatchType.GenericTypeArguments[0];

var x = jsonResult.Model;

var result = ConvertToPatch(jsonResult.Model, container, jsonMergePatchType, modelType);
return InputFormatterResult.Success(result);
}
catch (Exception ex)
{
context.ModelState.TryAddModelError(context.ModelName, ex.Message);
return InputFormatterResult.Failure();
}
}

}
}
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
using Morcatko.AspNetCore.JsonMergePatch.Internal;
using Morcatko.AspNetCore.JsonMergePatch.SystemText.Builders;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text.Json;
using System.Threading.Tasks;

namespace Morcatko.AspNetCore.JsonMergePatch.SystemText
{
internal class SystemTextJsonMergePatchInputFormatter : SystemTextJsonInputFormatter
{
private static readonly MediaTypeHeaderValue JsonMergePatchMediaType = MediaTypeHeaderValue.Parse(JsonMergePatchDocument.ContentType).CopyAsReadOnly();

private readonly Lazy<ModelMetadata> _modelMetadata;
private readonly JsonMergePatchOptions _jsonMergePatchOptions;

public SystemTextJsonMergePatchInputFormatter(
JsonOptions options,
ILogger<SystemTextJsonInputFormatter> logger,
Lazy<IModelMetadataProvider> lazyModelMetadataProvider,
JsonMergePatchOptions jsonMergePatchOptions)
: base(options, logger)
{
SupportedMediaTypes.Clear();
SupportedMediaTypes.Add(JsonMergePatchMediaType);
_modelMetadata = new Lazy<ModelMetadata>(() => lazyModelMetadataProvider.Value.GetMetadataForType(typeof(JsonElement)));
_jsonMergePatchOptions = jsonMergePatchOptions;
}

private static bool ContainerIsIEnumerable(InputFormatterContext context)
=> GetEnumerableElementType(context.ModelType) != null;
private static Type GetEnumerableElementType(Type type)
{
if (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
return type.GetGenericArguments()[0];
return null;
}
private static Type GetMergePatchDocumentModelType(Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(JsonMergePatchDocument<>))
return type.GetGenericArguments()[0];
return null;
}

private IInternalJsonMergePatchDocument CreatePatchDocument(Type jsonMergePatchType, Type modelType, JsonElement jsonElement)
{
var jsonMergePatchDocument = PatchBuilder.CreatePatchDocument(modelType, jsonElement, base.SerializerOptions, this._jsonMergePatchOptions);
return jsonMergePatchDocument;
}

private object ConvertToPatch(object o, IList container, Type jsonMergePatchType, Type modelType)
{
var e = (JsonElement)o;
switch (e.ValueKind)
{
case JsonValueKind.Object:
if (container != null)
throw new ArgumentException("Received object when array was expected"); //This could be handled by returning list with single item

return CreatePatchDocument(jsonMergePatchType, modelType, e);
case JsonValueKind.Array:
if (container == null)
throw new ArgumentException("Received array when object was expected");

var enumerator = e.EnumerateArray();
while (enumerator.MoveNext())
{
container.Add(CreatePatchDocument(jsonMergePatchType, modelType, enumerator.Current));
}
return container;
default:
throw new NotSupportedException($"Unsupported ValueKing '{e.ValueKind}'");
}
}

public override IReadOnlyList<string> GetSupportedContentTypes(string contentType, Type objectType)
{
if (GetMergePatchDocumentModelType(objectType) != null ||
(GetEnumerableElementType(objectType) is Type elementType && GetMergePatchDocumentModelType(elementType) != null))
{
return base.GetSupportedContentTypes(contentType, objectType);
}
return Array.Empty<string>();
}

public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
var patchContext = new InputFormatterContext(
context.HttpContext,
context.ModelName,
context.ModelState,
_modelMetadata.Value,
context.ReaderFactory,
context.TreatEmptyInputAsDefaultValue);

var jsonResult = await base.ReadRequestBodyAsync(patchContext);

if (jsonResult.HasError)
return jsonResult;

try
{
var jsonMergePatchType = context.ModelType;
var container = (IList)null;

if (ContainerIsIEnumerable(context))
{
jsonMergePatchType = context.ModelType.GenericTypeArguments[0];
var listType = typeof(List<>);
var constructedListType = listType.MakeGenericType(jsonMergePatchType);
container = (IList)Activator.CreateInstance(constructedListType);
}
var modelType = jsonMergePatchType.GenericTypeArguments[0];

var x = jsonResult.Model;

var result = ConvertToPatch(jsonResult.Model, container, jsonMergePatchType, modelType);
return InputFormatterResult.Success(result);
}
catch (Exception ex)
{
context.ModelState.TryAddModelError(context.ModelName, ex.Message);
return InputFormatterResult.Failure();
}
}

}
}
Loading