Adding errors in ModelState
This commit is contained in:
parent
9f97d25e02
commit
e48565dcd8
17
Mvc.sln
17
Mvc.sln
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.22726.0
|
||||
VisualStudioVersion = 14.0.22806.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}"
|
||||
EndProject
|
||||
|
|
@ -160,6 +160,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.JsonPatch.
|
|||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.JsonPatch", "src\Microsoft.AspNet.JsonPatch\Microsoft.AspNet.JsonPatch.xproj", "{4D55F4D8-633B-462F-A5B1-FEB84BD2D534}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "JsonPatchWebSite", "test\WebSites\JsonPatchWebSite\JsonPatchWebSite.xproj", "{DAB1252D-577C-4912-98BE-1A812BF83F86}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -950,6 +952,18 @@ Global
|
|||
{4D55F4D8-633B-462F-A5B1-FEB84BD2D534}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{4D55F4D8-633B-462F-A5B1-FEB84BD2D534}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{4D55F4D8-633B-462F-A5B1-FEB84BD2D534}.Release|x86.Build.0 = Release|Any CPU
|
||||
{DAB1252D-577C-4912-98BE-1A812BF83F86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DAB1252D-577C-4912-98BE-1A812BF83F86}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DAB1252D-577C-4912-98BE-1A812BF83F86}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{DAB1252D-577C-4912-98BE-1A812BF83F86}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{DAB1252D-577C-4912-98BE-1A812BF83F86}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{DAB1252D-577C-4912-98BE-1A812BF83F86}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{DAB1252D-577C-4912-98BE-1A812BF83F86}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DAB1252D-577C-4912-98BE-1A812BF83F86}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DAB1252D-577C-4912-98BE-1A812BF83F86}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{DAB1252D-577C-4912-98BE-1A812BF83F86}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{DAB1252D-577C-4912-98BE-1A812BF83F86}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{DAB1252D-577C-4912-98BE-1A812BF83F86}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -1028,5 +1042,6 @@ Global
|
|||
{B42D4844-FFF8-4EC2-88D1-3AE95234D9EB} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
{81C20848-E063-4E12-AC40-0B55A532C16C} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
|
||||
{4D55F4D8-633B-462F-A5B1-FEB84BD2D534} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||
{DAB1252D-577C-4912-98BE-1A812BF83F86} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNet.JsonPatch;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
|
||||
|
|
@ -34,7 +35,12 @@ namespace MvcSample.Web.Controllers
|
|||
}
|
||||
};
|
||||
|
||||
patchDoc.ApplyTo(customer);
|
||||
patchDoc.ApplyTo(customer, ModelState);
|
||||
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return HttpBadRequest(ModelState);
|
||||
}
|
||||
|
||||
return new ObjectResult(customer);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@
|
|||
"Orders": [{"OrderName": "Order1"},
|
||||
{"OrderName": "Order2"}]
|
||||
};
|
||||
$('#currentlabel').text(JSON.stringify(currentObj))
|
||||
$('#currentLabel').text(JSON.stringify(currentObj))
|
||||
|
||||
$('#addorder').on("click", function () {
|
||||
$('#addOrder').on("click", function () {
|
||||
var obj = [{
|
||||
"op": "Add",
|
||||
"path": "Customer/Orders/2",
|
||||
|
|
@ -22,12 +22,34 @@
|
|||
dataType: 'json',
|
||||
contentType: 'application/json-patch+json',
|
||||
success: function (data) {
|
||||
$('#addlabel').text(JSON.stringify(data))
|
||||
$('#addLabel').text(JSON.stringify(data))
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#removeorder').on("click", function () {
|
||||
$('#invalidAddOrder').on("click", function () {
|
||||
var obj = [{
|
||||
"op": "Add",
|
||||
"path": "Customer/Orders/5",
|
||||
"value": { "OrderName": "Name5" }
|
||||
}]
|
||||
$.ajax({
|
||||
url: 'jsonpatch',
|
||||
type: 'PATCH',
|
||||
data: JSON.stringify(obj),
|
||||
dataType: 'json',
|
||||
contentType: 'application/json-patch+json',
|
||||
success: function (data) {
|
||||
$('#invalidAddLabel').text(data)
|
||||
},
|
||||
error: function (request, status, error) {
|
||||
$('#invalidAddLabel').text(error)
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$('#removeOrder').on("click", function () {
|
||||
var obj = [{
|
||||
"op": "Remove",
|
||||
"path": "Customer/Name"
|
||||
|
|
@ -39,12 +61,12 @@
|
|||
dataType: 'json',
|
||||
contentType: 'application/json-patch+json',
|
||||
success: function (data) {
|
||||
$('#removelabel').text(JSON.stringify(data))
|
||||
$('#removeLabel').text(JSON.stringify(data))
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#moveorder').on("click", function () {
|
||||
$('#moveOrder').on("click", function () {
|
||||
var obj = [{
|
||||
"op": "Move",
|
||||
"from": "Customer/Orders/0",
|
||||
|
|
@ -57,12 +79,12 @@
|
|||
dataType: 'json',
|
||||
contentType: 'application/json-patch+json',
|
||||
success: function (data) {
|
||||
$('#movelabel').text(JSON.stringify(data))
|
||||
$('#moveLabel').text(JSON.stringify(data))
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#replaceorder').on("click", function () {
|
||||
$('#replaceOrder').on("click", function () {
|
||||
var obj = [{
|
||||
"op": "Replace",
|
||||
"path": "Customer/Name",
|
||||
|
|
@ -75,7 +97,7 @@
|
|||
dataType: 'json',
|
||||
contentType: 'application/json-patch+json',
|
||||
success: function (data) {
|
||||
$('#replacelabel').text(JSON.stringify(data))
|
||||
$('#replaceLabel').text(JSON.stringify(data))
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -86,29 +108,35 @@
|
|||
<div>
|
||||
<label>Current Customer</label>
|
||||
<br />
|
||||
<label id="currentlabel" name="currentlabel"></label>
|
||||
<label id="currentLabel" name="currentLabel"></label>
|
||||
<br />
|
||||
</div>
|
||||
<div>
|
||||
<button id="addorder" type="submit" class="btn btn-primary"> Add </button>
|
||||
<button id="addOrder" type="submit" class="btn btn-primary"> Add </button>
|
||||
<br />
|
||||
<label id="addlabel" name="addlabel"></label>
|
||||
<label id="addLabel" name="addLabel"></label>
|
||||
<br />
|
||||
</div>
|
||||
<div>
|
||||
<button id="removeorder" type="submit" class="btn btn-primary"> Remove </button>
|
||||
<button id="invalidAddOrder" type="submit" class="btn btn-primary"> Invalid Add </button>
|
||||
<br />
|
||||
<label id="removelabel" name="removelabel"></label>
|
||||
</div>
|
||||
<div>
|
||||
<button id="moveorder" type="submit" class="btn btn-primary"> Move </button>
|
||||
<br />
|
||||
<label id="movelabel" name="movelabel"></label>
|
||||
<label id="invalidAddLabel" name="invalidAddLabel"></label>
|
||||
<br />
|
||||
</div>
|
||||
<div>
|
||||
<button id="replaceorder" type="submit" class="btn btn-primary"> Replace </button>
|
||||
<button id="removeOrder" type="submit" class="btn btn-primary"> Remove </button>
|
||||
<br />
|
||||
<label id="replacelabel" name="replacelabel"></label>
|
||||
<label id="removeLabel" name="removeLabel"></label>
|
||||
</div>
|
||||
<div>
|
||||
<button id="moveOrder" type="submit" class="btn btn-primary"> Move </button>
|
||||
<br />
|
||||
<label id="moveLabel" name="moveLabel"></label>
|
||||
<br />
|
||||
</div>
|
||||
<div>
|
||||
<button id="replaceOrder" type="submit" class="btn btn-primary"> Replace </button>
|
||||
<br />
|
||||
<label id="replaceLabel" name="replaceLabel"></label>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -1,16 +1,21 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.JsonPatch.Operations;
|
||||
|
||||
namespace Microsoft.AspNet.JsonPatch.Adapters
|
||||
{
|
||||
public interface IObjectAdapter<T>
|
||||
where T : class
|
||||
/// <summary>
|
||||
/// Defines the operations that can be performed on a JSON patch document.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public interface IObjectAdapter<T> where T : class
|
||||
{
|
||||
void Add(Microsoft.AspNet.JsonPatch.Operations.Operation<T> operation, T objectToApplyTo);
|
||||
void Copy(Microsoft.AspNet.JsonPatch.Operations.Operation<T> operation, T objectToApplyTo);
|
||||
void Move(Microsoft.AspNet.JsonPatch.Operations.Operation<T> operation, T objectToApplyTo);
|
||||
void Remove(Microsoft.AspNet.JsonPatch.Operations.Operation<T> operation, T objectToApplyTo);
|
||||
void Replace(Microsoft.AspNet.JsonPatch.Operations.Operation<T> operation, T objectToApplyTo);
|
||||
void Test(Microsoft.AspNet.JsonPatch.Operations.Operation<T> operation, T objectToApplyTo);
|
||||
void Add(Operation<T> operation, T objectToApplyTo);
|
||||
void Copy(Operation<T> operation, T objectToApplyTo);
|
||||
void Move(Operation<T> operation, T objectToApplyTo);
|
||||
void Remove(Operation<T> operation, T objectToApplyTo);
|
||||
void Replace(Operation<T> operation, T objectToApplyTo);
|
||||
void Test(Operation<T> operation, T objectToApplyTo);
|
||||
}
|
||||
}
|
||||
|
|
@ -7,20 +7,34 @@ using System.Reflection;
|
|||
using Microsoft.AspNet.JsonPatch.Exceptions;
|
||||
using Microsoft.AspNet.JsonPatch.Helpers;
|
||||
using Microsoft.AspNet.JsonPatch.Operations;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace Microsoft.AspNet.JsonPatch.Adapters
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class ObjectAdapter<T> : IObjectAdapter<T> where T : class
|
||||
{
|
||||
public IContractResolver ContractResolver { get; set; }
|
||||
|
||||
public ObjectAdapter(IContractResolver contractResolver)
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="ObjectAdapter{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="contractResolver">The <see cref="IContractResolver"/>.</param>
|
||||
/// <param name="logErrorAction">The <see cref="Action"/> for logging <see cref="JsonPatchError{T}"/>.</param>
|
||||
public ObjectAdapter(IContractResolver contractResolver, Action<JsonPatchError<T>> logErrorAction)
|
||||
{
|
||||
ContractResolver = contractResolver;
|
||||
LogErrorAction = logErrorAction;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="IContractResolver"/>.
|
||||
/// </summary>
|
||||
public IContractResolver ContractResolver { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Action for logging <see cref="JsonPatchError{T}"/>.
|
||||
/// </summary>
|
||||
public Action<JsonPatchError<T>> LogErrorAction { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The "add" operation performs one of the following functions,
|
||||
/// depending upon what the target location references:
|
||||
|
|
@ -123,7 +137,10 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
|
|||
.FindPropertyAndParent(objectToApplyTo, actualPathToProperty, ContractResolver);
|
||||
|
||||
// does property at path exist?
|
||||
CheckIfPropertyExists(patchProperty, objectToApplyTo, operationToReport, path);
|
||||
if (!CheckIfPropertyExists(patchProperty, objectToApplyTo, operationToReport, path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// it exists. If it' an array, add to that array. If it's not, we replace.
|
||||
// is the path an array (but not a string (= char[]))? In this case,
|
||||
|
|
@ -139,7 +156,10 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
|
|||
|
||||
var conversionResult = PropertyHelpers.ConvertToActualType(genericTypeOfArray, value);
|
||||
|
||||
CheckIfPropertyCanBeSet(conversionResult, objectToApplyTo, operationToReport, path);
|
||||
if (!CheckIfPropertyCanBeSet(conversionResult, objectToApplyTo, operationToReport, path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// get value (it can be cast, we just checked that)
|
||||
var array = (IList)patchProperty.Property.ValueProvider.GetValue(patchProperty.Parent);
|
||||
|
|
@ -157,19 +177,23 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
|
|||
}
|
||||
else
|
||||
{
|
||||
throw new JsonPatchException<T>(
|
||||
LogError(new JsonPatchError<T>(
|
||||
objectToApplyTo,
|
||||
operationToReport,
|
||||
Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, path),
|
||||
objectToApplyTo);
|
||||
Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, path)));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new JsonPatchException<T>(
|
||||
LogError(new JsonPatchError<T>(
|
||||
objectToApplyTo,
|
||||
operationToReport,
|
||||
Resources.FormatInvalidPathForArrayProperty(operationToReport.op, path),
|
||||
objectToApplyTo);
|
||||
Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, path)));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -179,7 +203,10 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
|
|||
value);
|
||||
|
||||
// Is conversion successful
|
||||
CheckIfPropertyCanBeSet(conversionResultTuple, objectToApplyTo, operationToReport, path);
|
||||
if (!CheckIfPropertyCanBeSet(conversionResultTuple, objectToApplyTo, operationToReport, path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
patchProperty.Property.ValueProvider.SetValue(
|
||||
patchProperty.Parent,
|
||||
|
|
@ -229,7 +256,10 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
|
|||
.FindPropertyAndParent(objectToApplyTo, actualFromProperty, ContractResolver);
|
||||
|
||||
// does property at from exist?
|
||||
CheckIfPropertyExists(patchProperty, objectToApplyTo, operation, operation.from);
|
||||
if (!CheckIfPropertyExists(patchProperty, objectToApplyTo, operation, operation.from))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// is the path an array (but not a string (= char[]))? In this case,
|
||||
// the path must end with "/position" or "/-", which we already determined before.
|
||||
|
|
@ -245,20 +275,24 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
|
|||
|
||||
if (array.Count <= positionAsInteger)
|
||||
{
|
||||
throw new JsonPatchException<T>(
|
||||
LogError(new JsonPatchError<T>(
|
||||
objectToApplyTo,
|
||||
operation,
|
||||
Resources.FormatInvalidIndexForArrayProperty(operation.op, operation.from),
|
||||
objectToApplyTo);
|
||||
Resources.FormatInvalidIndexForArrayProperty(operation.op, operation.from)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
valueAtFromLocation = array[positionAsInteger];
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new JsonPatchException<T>(
|
||||
LogError(new JsonPatchError<T>(
|
||||
objectToApplyTo,
|
||||
operation,
|
||||
Resources.FormatInvalidPathForArrayProperty(operation.op, operation.from),
|
||||
objectToApplyTo);
|
||||
Resources.FormatInvalidPathForArrayProperty(operation.op, operation.from)));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -324,7 +358,10 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
|
|||
.FindPropertyAndParent(objectToApplyTo, actualPathToProperty, ContractResolver);
|
||||
|
||||
// does the target location exist?
|
||||
CheckIfPropertyExists(patchProperty, objectToApplyTo, operationToReport, path);
|
||||
if (!CheckIfPropertyExists(patchProperty, objectToApplyTo, operationToReport, path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// get the property, and remove it - in this case, for DTO's, that means setting
|
||||
// it to null or its default value; in case of an array, remove at provided index
|
||||
|
|
@ -352,19 +389,23 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
|
|||
}
|
||||
else
|
||||
{
|
||||
throw new JsonPatchException<T>(
|
||||
LogError(new JsonPatchError<T>(
|
||||
objectToApplyTo,
|
||||
operationToReport,
|
||||
Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, path),
|
||||
objectToApplyTo);
|
||||
Resources.FormatInvalidIndexForArrayProperty(operationToReport.op, path)));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new JsonPatchException<T>(
|
||||
LogError(new JsonPatchError<T>(
|
||||
objectToApplyTo,
|
||||
operationToReport,
|
||||
Resources.FormatInvalidPathForArrayProperty(operationToReport.op, path),
|
||||
objectToApplyTo);
|
||||
Resources.FormatInvalidPathForArrayProperty(operationToReport.op, path)));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -451,10 +492,13 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
|
|||
.FindPropertyAndParent(objectToApplyTo, actualPathProperty, ContractResolver);
|
||||
|
||||
// does property at path exist?
|
||||
CheckIfPropertyExists(patchProperty, objectToApplyTo, operation, operation.path);
|
||||
if (!CheckIfPropertyExists(patchProperty, objectToApplyTo, operation, operation.path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// get the property path
|
||||
Type typeOfFinalPropertyAtPathLocation;
|
||||
Type typeOfFinalPropertyAtPathLocation = null;
|
||||
|
||||
// is the path an array (but not a string (= char[]))? In this case,
|
||||
// the path must end with "/position" or "/-", which we already determined before.
|
||||
|
|
@ -471,20 +515,24 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
|
|||
|
||||
if (array.Count <= positionInPathAsInteger)
|
||||
{
|
||||
throw new JsonPatchException<T>(
|
||||
LogError(new JsonPatchError<T>(
|
||||
objectToApplyTo,
|
||||
operation,
|
||||
Resources.FormatInvalidIndexForArrayProperty(operation.op, operation.path),
|
||||
objectToApplyTo);
|
||||
Resources.FormatInvalidIndexForArrayProperty(operation.op, operation.path)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
valueAtPathLocation = array[positionInPathAsInteger];
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new JsonPatchException<T>(
|
||||
LogError(new JsonPatchError<T>(
|
||||
objectToApplyTo,
|
||||
operation,
|
||||
Resources.FormatInvalidPathForArrayProperty(operation.op, operation.path),
|
||||
objectToApplyTo);
|
||||
Resources.FormatInvalidPathForArrayProperty(operation.op, operation.path)));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -499,7 +547,10 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
|
|||
operation.value);
|
||||
|
||||
// Is conversion successful
|
||||
CheckIfPropertyCanBeSet(conversionResultTuple, objectToApplyTo, operation, operation.path);
|
||||
if (!CheckIfPropertyCanBeSet(conversionResultTuple, objectToApplyTo, operation, operation.path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//Compare
|
||||
}
|
||||
|
|
@ -571,7 +622,10 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
|
|||
.FindPropertyAndParent(objectToApplyTo, actualFromProperty, ContractResolver);
|
||||
|
||||
// does property at from exist?
|
||||
CheckIfPropertyExists(patchProperty, objectToApplyTo, operation, operation.from);
|
||||
if (!CheckIfPropertyExists(patchProperty, objectToApplyTo, operation, operation.from))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// get the property path
|
||||
// is the path an array (but not a string (= char[]))? In this case,
|
||||
|
|
@ -588,19 +642,24 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
|
|||
|
||||
if (array.Count <= positionAsInteger)
|
||||
{
|
||||
throw new JsonPatchException<T>(operation,
|
||||
Resources.FormatInvalidIndexForArrayProperty(operation.op, operation.from),
|
||||
objectToApplyTo);
|
||||
LogError(new JsonPatchError<T>(
|
||||
objectToApplyTo,
|
||||
operation,
|
||||
Resources.FormatInvalidIndexForArrayProperty(operation.op, operation.from)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
valueAtFromLocation = array[positionAsInteger];
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new JsonPatchException<T>(
|
||||
LogError(new JsonPatchError<T>(
|
||||
objectToApplyTo,
|
||||
operation,
|
||||
Resources.FormatInvalidPathForArrayProperty(operation.op, operation.from),
|
||||
objectToApplyTo);
|
||||
Resources.FormatInvalidPathForArrayProperty(operation.op, operation.from)));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -614,7 +673,7 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
|
|||
Add(operation.path, valueAtFromLocation, objectToApplyTo, operation);
|
||||
}
|
||||
|
||||
private void CheckIfPropertyExists(
|
||||
private bool CheckIfPropertyExists(
|
||||
JsonPatchProperty patchProperty,
|
||||
T objectToApplyTo,
|
||||
Operation<T> operation,
|
||||
|
|
@ -622,18 +681,25 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
|
|||
{
|
||||
if (patchProperty == null)
|
||||
{
|
||||
throw new JsonPatchException<T>(
|
||||
LogError(new JsonPatchError<T>(
|
||||
objectToApplyTo,
|
||||
operation,
|
||||
Resources.FormatPropertyDoesNotExist(propertyPath),
|
||||
objectToApplyTo);
|
||||
Resources.FormatPropertyDoesNotExist(propertyPath)));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (patchProperty.Property.Ignored)
|
||||
{
|
||||
throw new JsonPatchException<T>(
|
||||
LogError(new JsonPatchError<T>(
|
||||
objectToApplyTo,
|
||||
operation,
|
||||
Resources.FormatCannotUpdateProperty(propertyPath),
|
||||
objectToApplyTo);
|
||||
Resources.FormatCannotUpdateProperty(propertyPath)));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool IsNonStringArray(JsonPatchProperty patchProperty)
|
||||
|
|
@ -643,7 +709,7 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
|
|||
patchProperty.Property.PropertyType.GetTypeInfo());
|
||||
}
|
||||
|
||||
private void CheckIfPropertyCanBeSet(
|
||||
private bool CheckIfPropertyCanBeSet(
|
||||
ConversionResult result,
|
||||
T objectToApplyTo,
|
||||
Operation<T> operation,
|
||||
|
|
@ -651,10 +717,26 @@ namespace Microsoft.AspNet.JsonPatch.Adapters
|
|||
{
|
||||
if (!result.CanBeConverted)
|
||||
{
|
||||
throw new JsonPatchException<T>(
|
||||
LogError(new JsonPatchError<T>(
|
||||
objectToApplyTo,
|
||||
operation,
|
||||
Resources.FormatInvalidValueForProperty(result.ConvertedInstance, path),
|
||||
objectToApplyTo);
|
||||
Resources.FormatInvalidValueForProperty(result.ConvertedInstance, path)));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void LogError(JsonPatchError<T> jsonPatchError)
|
||||
{
|
||||
if (LogErrorAction != null)
|
||||
{
|
||||
LogErrorAction(jsonPatchError);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new JsonPatchException<T>(jsonPatchError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,15 +26,15 @@ namespace Microsoft.AspNet.JsonPatch.Exceptions
|
|||
|
||||
}
|
||||
|
||||
public JsonPatchException(Operation<T> operation, string message, T affectedObject)
|
||||
public JsonPatchException(JsonPatchError<T> jsonPatchError)
|
||||
{
|
||||
FailedOperation = operation;
|
||||
_message = message;
|
||||
AffectedObject = affectedObject;
|
||||
FailedOperation = jsonPatchError.Operation;
|
||||
_message = jsonPatchError.ErrorMessage;
|
||||
AffectedObject = jsonPatchError.AffectedObject;
|
||||
}
|
||||
|
||||
public JsonPatchException(Operation<T> operation, string message, T affectedObject, Exception innerException)
|
||||
: this(operation, message, affectedObject)
|
||||
public JsonPatchException(JsonPatchError<T> jsonPatchError, Exception innerException)
|
||||
: this(jsonPatchError)
|
||||
{
|
||||
InnerException = innerException;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.JsonPatch.Operations;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.JsonPatch
|
||||
{
|
||||
/// <summary>
|
||||
/// Captures error message and the related entity and the operation that caused it.
|
||||
/// </summary>
|
||||
public class JsonPatchError<T> where T : class
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="JsonPatchError{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="affectedObject">The object that is affected by the error.</param>
|
||||
/// <param name="operation">The <see cref="Operation{T}"/> that caused the error.</param>
|
||||
/// <param name="errorMessage">The error message.</param>
|
||||
public JsonPatchError(
|
||||
[NotNull] T affectedObject,
|
||||
[NotNull] Operation<T> operation,
|
||||
[NotNull] string errorMessage)
|
||||
{
|
||||
AffectedObject = affectedObject;
|
||||
Operation = operation;
|
||||
ErrorMessage = errorMessage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the object that is affected by the error.
|
||||
/// </summary>
|
||||
public T AffectedObject { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Operation{T}"/> that caused the error.
|
||||
/// </summary>
|
||||
public Operation<T> Operation { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the error message.
|
||||
/// </summary>
|
||||
public string ErrorMessage { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -354,12 +354,16 @@ namespace Microsoft.AspNet.JsonPatch
|
|||
|
||||
public void ApplyTo(T objectToApplyTo)
|
||||
{
|
||||
ApplyTo(objectToApplyTo, new ObjectAdapter<T>(ContractResolver));
|
||||
ApplyTo(objectToApplyTo, new ObjectAdapter<T>(ContractResolver, logErrorAction: null));
|
||||
}
|
||||
|
||||
public void ApplyTo(T objectToApplyTo, Action<JsonPatchError<T>> logErrorAction)
|
||||
{
|
||||
ApplyTo(objectToApplyTo, new ObjectAdapter<T>(ContractResolver, logErrorAction));
|
||||
}
|
||||
|
||||
public void ApplyTo(T objectToApplyTo, IObjectAdapter<T> adapter)
|
||||
{
|
||||
|
||||
// apply each operation in order
|
||||
foreach (var op in Operations)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.JsonPatch;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions for <see cref="JsonPatchDocument{T}"/>
|
||||
/// </summary>
|
||||
public static class JsonPatchExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Applies JSON patch operations on object and logs errors in <see cref="ModelStateDictionary"/>.
|
||||
/// </summary>
|
||||
/// <param name="patchDoc">The <see cref="JsonPatchDocument{T}"/>.</param>
|
||||
/// <param name="objectToApplyTo">The entity on which <see cref="JsonPatchDocument{T}"/> is applied.</param>
|
||||
/// <param name="modelState">The <see cref="ModelStateDictionary"/> to add errors.</param>
|
||||
public static void ApplyTo<T>(
|
||||
[NotNull] this JsonPatchDocument<T> patchDoc,
|
||||
[NotNull] T objectToApplyTo,
|
||||
[NotNull] ModelStateDictionary modelState) where T : class
|
||||
{
|
||||
patchDoc.ApplyTo(objectToApplyTo, modelState, prefix: string.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies JSON patch operations on object and logs errors in <see cref="ModelStateDictionary"/>.
|
||||
/// </summary>
|
||||
/// <param name="patchDoc">The <see cref="JsonPatchDocument{T}"/>.</param>
|
||||
/// <param name="objectToApplyTo">The entity on which <see cref="JsonPatchDocument{T}"/> is applied.</param>
|
||||
/// <param name="modelState">The <see cref="ModelStateDictionary"/> to add errors.</param>
|
||||
/// <param name="prefix">The prefix to use when looking up values in <see cref="ModelStateDictionary"/>.</param>
|
||||
public static void ApplyTo<T>(
|
||||
[NotNull] this JsonPatchDocument<T> patchDoc,
|
||||
[NotNull] T objectToApplyTo,
|
||||
[NotNull] ModelStateDictionary modelState,
|
||||
string prefix) where T : class
|
||||
{
|
||||
patchDoc.ApplyTo(objectToApplyTo, jsonPatchError =>
|
||||
{
|
||||
var affectedObjectName = jsonPatchError.AffectedObject.GetType().Name;
|
||||
var key = string.IsNullOrEmpty(prefix) ? affectedObjectName : prefix + "." + affectedObjectName;
|
||||
|
||||
modelState.TryAddModelError(key, jsonPatchError.ErrorMessage);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -282,8 +282,10 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<JsonPatchException<SimpleDTOWithNestedDTO>>(() => { patchDoc.ApplyTo(doc); });
|
||||
Assert.Equal("For operation 'add' on array property at path '/simpledto/integerlist/4', the index is " +
|
||||
"larger than the array size.", exception.Message);
|
||||
Assert.Equal(
|
||||
"For operation 'add' on array property at path '/simpledto/integerlist/4', the index is " +
|
||||
"larger than the array size.",
|
||||
exception.Message);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -311,8 +313,39 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal("For operation 'add' on array property at path '/simpledto/integerlist/4', the index is " +
|
||||
"larger than the array size.", exception.Message);
|
||||
Assert.Equal(
|
||||
"For operation 'add' on array property at path '/simpledto/integerlist/4', the index is " +
|
||||
"larger than the array size.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddToListInvalidPositionTooLarge_LogsError()
|
||||
{
|
||||
// Arrange
|
||||
var doc = new SimpleDTOWithNestedDTO()
|
||||
{
|
||||
SimpleDTO = new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
}
|
||||
};
|
||||
|
||||
// create patch
|
||||
var patchDoc = new JsonPatchDocument<SimpleDTOWithNestedDTO>();
|
||||
patchDoc.Add<int>(o => o.SimpleDTO.IntegerList, 4, 4);
|
||||
|
||||
var logger = new TestErrorLogger<SimpleDTOWithNestedDTO>();
|
||||
|
||||
// Act
|
||||
patchDoc.ApplyTo(doc, logger.LogErrorMessage);
|
||||
|
||||
//Assert
|
||||
Assert.Equal(
|
||||
"For operation 'add' on array property at path '/simpledto/integerlist/4', the index is larger than " +
|
||||
"the array size.",
|
||||
logger.ErrorMessage);
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -363,6 +396,31 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
Assert.Equal("Property does not exist at path '/simpledto/integerlist/-1'.", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddToListInvalidPositionTooSmall_LogsError()
|
||||
{
|
||||
// Arrange
|
||||
var doc = new SimpleDTOWithNestedDTO()
|
||||
{
|
||||
SimpleDTO = new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
}
|
||||
};
|
||||
|
||||
// create patch
|
||||
var patchDoc = new JsonPatchDocument<SimpleDTOWithNestedDTO>();
|
||||
patchDoc.Add<int>(o => o.SimpleDTO.IntegerList, 4, -1);
|
||||
|
||||
var logger = new TestErrorLogger<SimpleDTOWithNestedDTO>();
|
||||
|
||||
// Act
|
||||
patchDoc.ApplyTo(doc, logger.LogErrorMessage);
|
||||
|
||||
//Assert
|
||||
Assert.Equal("Property does not exist at path '/simpledto/integerlist/-1'.", logger.ErrorMessage);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddToListAppend()
|
||||
{
|
||||
|
|
@ -528,8 +586,10 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<JsonPatchException<SimpleDTOWithNestedDTO>>(() => { patchDoc.ApplyTo(doc); });
|
||||
Assert.Equal("For operation 'remove' on array property at path '/simpledto/integerlist/3', the index is " +
|
||||
"larger than the array size.", exception.Message);
|
||||
Assert.Equal(
|
||||
"For operation 'remove' on array property at path '/simpledto/integerlist/3', the index is " +
|
||||
"larger than the array size.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -556,8 +616,38 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal("For operation 'remove' on array property at path '/simpledto/integerlist/3', the index is " +
|
||||
"larger than the array size.", exception.Message);
|
||||
Assert.Equal(
|
||||
"For operation 'remove' on array property at path '/simpledto/integerlist/3', the index is " +
|
||||
"larger than the array size.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveFromListInvalidPositionTooLarge_LogsError()
|
||||
{
|
||||
// Arrange
|
||||
var doc = new SimpleDTOWithNestedDTO()
|
||||
{
|
||||
SimpleDTO = new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
}
|
||||
};
|
||||
|
||||
// create patch
|
||||
var patchDoc = new JsonPatchDocument<SimpleDTOWithNestedDTO>();
|
||||
patchDoc.Remove<int>(o => o.SimpleDTO.IntegerList, 3);
|
||||
|
||||
var logger = new TestErrorLogger<SimpleDTOWithNestedDTO>();
|
||||
|
||||
// Act
|
||||
patchDoc.ApplyTo(doc, logger.LogErrorMessage);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(
|
||||
"For operation 'remove' on array property at path '/simpledto/integerlist/3', the index is " +
|
||||
"larger than the array size.",
|
||||
logger.ErrorMessage);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -608,6 +698,31 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
Assert.Equal("Property does not exist at path '/simpledto/integerlist/-1'.", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveFromListInvalidPositionTooSmall_LogsError()
|
||||
{
|
||||
// Arrange
|
||||
var doc = new SimpleDTOWithNestedDTO()
|
||||
{
|
||||
SimpleDTO = new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
}
|
||||
};
|
||||
|
||||
// create patch
|
||||
var patchDoc = new JsonPatchDocument<SimpleDTOWithNestedDTO>();
|
||||
patchDoc.Remove<int>(o => o.SimpleDTO.IntegerList, -1);
|
||||
|
||||
var logger = new TestErrorLogger<SimpleDTOWithNestedDTO>();
|
||||
|
||||
// Act
|
||||
patchDoc.ApplyTo(doc, logger.LogErrorMessage);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Property does not exist at path '/simpledto/integerlist/-1'.", logger.ErrorMessage);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveFromEndOfList()
|
||||
{
|
||||
|
|
@ -1014,8 +1129,10 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<JsonPatchException<SimpleDTOWithNestedDTO>>(() => { patchDoc.ApplyTo(doc); });
|
||||
Assert.Equal("For operation 'replace' on array property at path '/simpledto/integerlist/3', the index is " +
|
||||
"larger than the array size.", exception.Message);
|
||||
Assert.Equal(
|
||||
"For operation 'replace' on array property at path '/simpledto/integerlist/3', the index is " +
|
||||
"larger than the array size.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1042,8 +1159,38 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal("For operation 'replace' on array property at path '/simpledto/integerlist/3', the index is " +
|
||||
"larger than the array size.", exception.Message);
|
||||
Assert.Equal(
|
||||
"For operation 'replace' on array property at path '/simpledto/integerlist/3', the index is " +
|
||||
"larger than the array size.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReplaceInListInvalid_PositionTooLarge_LogsError()
|
||||
{
|
||||
// Arrange
|
||||
var doc = new SimpleDTOWithNestedDTO()
|
||||
{
|
||||
SimpleDTO = new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
}
|
||||
};
|
||||
|
||||
// create patch
|
||||
var patchDoc = new JsonPatchDocument<SimpleDTOWithNestedDTO>();
|
||||
patchDoc.Replace<int>(o => o.SimpleDTO.IntegerList, 5, 3);
|
||||
|
||||
var logger = new TestErrorLogger<SimpleDTOWithNestedDTO>();
|
||||
|
||||
// Act
|
||||
patchDoc.ApplyTo(doc, logger.LogErrorMessage);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(
|
||||
"For operation 'replace' on array property at path '/simpledto/integerlist/3', the index is " +
|
||||
"larger than the array size.",
|
||||
logger.ErrorMessage);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1091,6 +1238,31 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
Assert.Equal("Property does not exist at path '/simpledto/integerlist/-1'.", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReplaceInListInvalidPositionTooSmall_LogsError()
|
||||
{
|
||||
// Arrange
|
||||
var doc = new SimpleDTOWithNestedDTO()
|
||||
{
|
||||
SimpleDTO = new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
}
|
||||
};
|
||||
|
||||
// create patch
|
||||
var patchDoc = new JsonPatchDocument<SimpleDTOWithNestedDTO>();
|
||||
patchDoc.Replace<int>(o => o.SimpleDTO.IntegerList, 5, -1);
|
||||
|
||||
var logger = new TestErrorLogger<SimpleDTOWithNestedDTO>();
|
||||
|
||||
// Act
|
||||
patchDoc.ApplyTo(doc, logger.LogErrorMessage);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Property does not exist at path '/simpledto/integerlist/-1'.", logger.ErrorMessage);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Copy()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -113,8 +113,10 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<JsonPatchException<SimpleDTO>>(() => { patchDoc.ApplyTo(doc); });
|
||||
Assert.Equal("For operation 'add' on array property at path '/integerlist/4', the index is " +
|
||||
"larger than the array size.", exception.Message);
|
||||
Assert.Equal(
|
||||
"For operation 'add' on array property at path '/integerlist/4', the index is " +
|
||||
"larger than the array size.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -135,8 +137,35 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<JsonPatchException<SimpleDTO>>(() => { deserialized.ApplyTo(doc); });
|
||||
Assert.Equal("For operation 'add' on array property at path '/integerlist/4', the index is " +
|
||||
"larger than the array size.", exception.Message);
|
||||
Assert.Equal(
|
||||
"For operation 'add' on array property at path '/integerlist/4', the index is " +
|
||||
"larger than the array size.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddToListInvalidPositionTooLarge_LogsError()
|
||||
{
|
||||
// Arrange
|
||||
var doc = new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
};
|
||||
|
||||
// create patch
|
||||
var patchDoc = new JsonPatchDocument<SimpleDTO>();
|
||||
patchDoc.Add<int>(o => o.IntegerList, 4, 4);
|
||||
|
||||
var logger = new TestErrorLogger<SimpleDTO>();
|
||||
|
||||
// Act
|
||||
patchDoc.ApplyTo(doc, logger.LogErrorMessage);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(
|
||||
"For operation 'add' on array property at path '/integerlist/4', the index is " +
|
||||
"larger than the array size.",
|
||||
logger.ErrorMessage);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -264,6 +293,28 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
Assert.Equal("Property does not exist at path '/integerlist/-1'.", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddToListInvalidPositionTooSmall_LogsError()
|
||||
{
|
||||
// Arrange
|
||||
var doc = new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
};
|
||||
|
||||
// create patch
|
||||
var patchDoc = new JsonPatchDocument<SimpleDTO>();
|
||||
patchDoc.Add<int>(o => o.IntegerList, 4, -1);
|
||||
|
||||
var logger = new TestErrorLogger<SimpleDTO>();
|
||||
|
||||
// Act
|
||||
patchDoc.ApplyTo(doc, logger.LogErrorMessage);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Property does not exist at path '/integerlist/-1'.", logger.ErrorMessage);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddToListAppend()
|
||||
{
|
||||
|
|
@ -408,8 +459,10 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<JsonPatchException<SimpleDTO>>(() => { patchDoc.ApplyTo(doc); });
|
||||
Assert.Equal("For operation 'remove' on array property at path '/integerlist/3', the index is " +
|
||||
"larger than the array size.", exception.Message);
|
||||
Assert.Equal(
|
||||
"For operation 'remove' on array property at path '/integerlist/3', the index is " +
|
||||
"larger than the array size.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -430,8 +483,35 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<JsonPatchException<SimpleDTO>>(() => { deserialized.ApplyTo(doc); });
|
||||
Assert.Equal("For operation 'remove' on array property at path '/integerlist/3', the index is " +
|
||||
"larger than the array size.", exception.Message);
|
||||
Assert.Equal(
|
||||
"For operation 'remove' on array property at path '/integerlist/3', the index is " +
|
||||
"larger than the array size.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveFromListInvalidPositionTooLarge_LogsError()
|
||||
{
|
||||
// Arrange
|
||||
var doc = new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
};
|
||||
|
||||
// create patch
|
||||
var patchDoc = new JsonPatchDocument<SimpleDTO>();
|
||||
patchDoc.Remove<int>(o => o.IntegerList, 3);
|
||||
|
||||
var logger = new TestErrorLogger<SimpleDTO>();
|
||||
|
||||
// Act
|
||||
patchDoc.ApplyTo(doc, logger.LogErrorMessage);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(
|
||||
"For operation 'remove' on array property at path '/integerlist/3', the index is " +
|
||||
"larger than the array size.",
|
||||
logger.ErrorMessage);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -473,6 +553,28 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
Assert.Equal("Property does not exist at path '/integerlist/-1'.", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveFromListInvalidPositionTooSmall_LogsError()
|
||||
{
|
||||
// Arrange
|
||||
var doc = new SimpleDTO()
|
||||
{
|
||||
IntegerList = new List<int>() { 1, 2, 3 }
|
||||
};
|
||||
|
||||
// create patch
|
||||
var patchDoc = new JsonPatchDocument<SimpleDTO>();
|
||||
patchDoc.Remove<int>(o => o.IntegerList, -1);
|
||||
|
||||
var logger = new TestErrorLogger<SimpleDTO>();
|
||||
|
||||
// Act
|
||||
patchDoc.ApplyTo(doc, logger.LogErrorMessage);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Property does not exist at path '/integerlist/-1'.", logger.ErrorMessage);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RemoveFromEndOfList()
|
||||
{
|
||||
|
|
@ -971,8 +1073,10 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
{
|
||||
patchDoc.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal("For operation 'replace' on array property at path '/integerlist/3', the index is " +
|
||||
"larger than the array size.", exception.Message);
|
||||
Assert.Equal(
|
||||
"For operation 'replace' on array property at path '/integerlist/3', the index is " +
|
||||
"larger than the array size.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -995,8 +1099,10 @@ namespace Microsoft.AspNet.JsonPatch.Test
|
|||
{
|
||||
deserialized.ApplyTo(doc);
|
||||
});
|
||||
Assert.Equal("For operation 'replace' on array property at path '/integerlist/3', the index is " +
|
||||
"larger than the array size.", exception.Message);
|
||||
Assert.Equal(
|
||||
"For operation 'replace' on array property at path '/integerlist/3', the index is " +
|
||||
"larger than the array size.",
|
||||
exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.AspNet.JsonPatch.Test
|
||||
{
|
||||
public class TestErrorLogger<T> where T: class
|
||||
{
|
||||
public string ErrorMessage { get; set; }
|
||||
|
||||
public void LogErrorMessage(JsonPatchError<T> patchError)
|
||||
{
|
||||
ErrorMessage = patchError.ErrorMessage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using JsonPatchWebSite;
|
||||
using JsonPatchWebSite.Models;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||
{
|
||||
public class JsonPatchTest
|
||||
{
|
||||
private const string SiteName = nameof(JsonPatchWebSite);
|
||||
private readonly Action<IApplicationBuilder> _app = new Startup().Configure;
|
||||
private readonly Action<IServiceCollection> _configureServices = new Startup().ConfigureServices;
|
||||
|
||||
[Theory]
|
||||
[InlineData("http://localhost/jsonpatch/JsonPatchWithModelState")]
|
||||
[InlineData("http://localhost/jsonpatch/JsonPatchWithModelStateAndPrefix?prefix=Patch")]
|
||||
public async Task JsonPatch_ValidAddOperation_List(string url)
|
||||
{
|
||||
// Arrange
|
||||
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
|
||||
var client = server.CreateClient();
|
||||
|
||||
var input = "[{ \"op\": \"add\", \"path\": \"Customer/Orders/2\", " +
|
||||
"\"value\": { \"OrderName\": \"Name2\" }}]";
|
||||
var request = new HttpRequestMessage
|
||||
{
|
||||
Content = new StringContent(input, Encoding.UTF8, "application/json-patch+json"),
|
||||
Method = new HttpMethod("PATCH"),
|
||||
RequestUri = new Uri(url)
|
||||
};
|
||||
|
||||
// Act
|
||||
var response = await client.SendAsync(request);
|
||||
|
||||
// Assert
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
var customer = JsonConvert.DeserializeObject<Customer>(body);
|
||||
Assert.Equal("Name2", customer.Orders[2].OrderName);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("http://localhost/jsonpatch/JsonPatchWithModelState")]
|
||||
[InlineData("http://localhost/jsonpatch/JsonPatchWithModelStateAndPrefix?prefix=Patch")]
|
||||
public async Task JsonPatch_MultipleValidOperations_Success(string url)
|
||||
{
|
||||
// Arrange
|
||||
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
|
||||
var client = server.CreateClient();
|
||||
|
||||
var input = "[{ \"op\": \"add\", \"path\": \"Customer/Orders/2\", " +
|
||||
"\"value\": { \"OrderName\": \"Name2\" }}, {\"op\": \"copy\", \"from\": \"Customer/Orders/2\", " +
|
||||
"\"path\": \"Customer/Orders/3\" }, {\"op\": \"replace\", \"path\": \"Customer/Orders/2/OrderName\", " +
|
||||
"\"value\": \"ReplacedName\" }]";
|
||||
var request = new HttpRequestMessage
|
||||
{
|
||||
Content = new StringContent(input, Encoding.UTF8, "application/json-patch+json"),
|
||||
Method = new HttpMethod("PATCH"),
|
||||
RequestUri = new Uri(url)
|
||||
};
|
||||
|
||||
// Act
|
||||
var response = await client.SendAsync(request);
|
||||
|
||||
// Assert
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
var customer = JsonConvert.DeserializeObject<Customer>(body);
|
||||
Assert.Equal("ReplacedName", customer.Orders[2].OrderName);
|
||||
Assert.Equal("Name2", customer.Orders[3].OrderName);
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> InvalidJsonPatchData
|
||||
{
|
||||
get
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new object[] {
|
||||
"http://localhost/jsonpatch/JsonPatchWithModelStateAndPrefix?prefix=Patch",
|
||||
"[{ \"op\": \"add\", \"path\": \"Customer/Orders/5\", " +
|
||||
"\"value\": { \"OrderName\": \"Name5\" }}]",
|
||||
"{\"Patch.Customer\":[\"For operation 'add' on array property at path " +
|
||||
"'Customer/Orders/5', the index is larger than the array size.\"]}"
|
||||
},
|
||||
new object[] {
|
||||
"http://localhost/jsonpatch/JsonPatchWithModelState",
|
||||
"[{ \"op\": \"add\", \"path\": \"Customer/Orders/5\", " +
|
||||
"\"value\": { \"OrderName\": \"Name5\" }}]",
|
||||
"{\"Customer\":[\"For operation 'add' on array property at path " +
|
||||
"'Customer/Orders/5', the index is larger than the array size.\"]}"
|
||||
},
|
||||
new object[] {
|
||||
"http://localhost/jsonpatch/JsonPatchWithModelStateAndPrefix?prefix=Patch",
|
||||
"[{ \"op\": \"add\", \"path\": \"Customer/Orders/2\", \"value\": " +
|
||||
"{ \"OrderName\": \"Name2\" }}, {\"op\": \"copy\", \"from\": \"Customer/Orders/4\", " +
|
||||
"\"path\": \"Customer/Orders/3\" }, {\"op\": \"replace\", \"path\": " +
|
||||
"\"Customer/Orders/2/OrderName\", \"value\": \"ReplacedName\" }]",
|
||||
"{\"Patch.Customer\":[\"For operation 'copy' on array property at path " +
|
||||
"'Customer/Orders/4', the index is larger than the array size.\"]}"
|
||||
},
|
||||
new object[] {
|
||||
"http://localhost/jsonpatch/JsonPatchWithModelState",
|
||||
"[{ \"op\": \"add\", \"path\": \"Customer/Orders/2\", \"value\": " +
|
||||
"{ \"OrderName\": \"Name2\" }}, {\"op\": \"copy\", \"from\": \"Customer/Orders/4\", " +
|
||||
"\"path\": \"Customer/Orders/3\" }, {\"op\": \"replace\", \"path\": " +
|
||||
"\"Customer/Orders/2/OrderName\", \"value\": \"ReplacedName\" }]",
|
||||
"{\"Customer\":[\"For operation 'copy' on array property at path " +
|
||||
"'Customer/Orders/4', the index is larger than the array size.\"]}"
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory, MemberData("InvalidJsonPatchData")]
|
||||
public async Task JsonPatch_InvalidOperations_failure(string url, string input, string errorMessage)
|
||||
{
|
||||
// Arrange
|
||||
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
|
||||
var client = server.CreateClient();
|
||||
|
||||
var request = new HttpRequestMessage
|
||||
{
|
||||
Content = new StringContent(input, Encoding.UTF8, "application/json-patch+json"),
|
||||
Method = new HttpMethod("PATCH"),
|
||||
RequestUri = new Uri(url)
|
||||
};
|
||||
|
||||
// Act
|
||||
var response = await client.SendAsync(request);
|
||||
|
||||
// Assert
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal(errorMessage, body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -28,6 +28,7 @@
|
|||
"FormatFilterWebSite": "1.0.0-*",
|
||||
"FormatterWebSite": "1.0.0",
|
||||
"InlineConstraintsWebSite": "1.0.0",
|
||||
"JsonPatchWebSite": "1.0.0",
|
||||
"LoggingWebSite": "1.0.0",
|
||||
"LowercaseUrlsWebSite": "1.0.0-*",
|
||||
"Microsoft.AspNet.Mvc": "6.0.0-*",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.JsonPatch;
|
||||
using Microsoft.AspNet.JsonPatch.Operations;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class JsonPatchExtensionsTest
|
||||
{
|
||||
[Fact]
|
||||
public void ApplyTo_JsonPatchDocument_ModelState()
|
||||
{
|
||||
// Arrange
|
||||
var operation = new Operation<Customer>("add", "Customer/CustomerId", from: null, value: "TestName");
|
||||
var patchDoc = new JsonPatchDocument<Customer>();
|
||||
patchDoc.Operations.Add(operation);
|
||||
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
// Act
|
||||
patchDoc.ApplyTo(new Customer(), modelState);
|
||||
|
||||
// Assert
|
||||
var error = Assert.Single(modelState["Customer"].Errors);
|
||||
Assert.Equal("Property does not exist at path 'Customer/CustomerId'.", error.ErrorMessage);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyTo_JsonPatchDocument_PrefixModelState()
|
||||
{
|
||||
// Arrange
|
||||
var operation = new Operation<Customer>("add", "Customer/CustomerId", from: null, value: "TestName");
|
||||
var patchDoc = new JsonPatchDocument<Customer>();
|
||||
patchDoc.Operations.Add(operation);
|
||||
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
// Act
|
||||
patchDoc.ApplyTo(new Customer(), modelState, "jsonpatch");
|
||||
|
||||
// Assert
|
||||
var error = Assert.Single(modelState["jsonpatch.Customer"].Errors);
|
||||
Assert.Equal("Property does not exist at path 'Customer/CustomerId'.", error.ErrorMessage);
|
||||
}
|
||||
|
||||
public class Customer
|
||||
{
|
||||
public string CustomerName { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using JsonPatchWebSite.Models;
|
||||
using Microsoft.AspNet.JsonPatch;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
|
||||
namespace JsonPatchWebSite.Controllers
|
||||
{
|
||||
[Route("jsonpatch/[action]")]
|
||||
public class JsonPatchController : Controller
|
||||
{
|
||||
[HttpPatch]
|
||||
public IActionResult JsonPatchWithModelState([FromBody] JsonPatchDocument<Customer> patchDoc)
|
||||
{
|
||||
var customer = CreateCustomer();
|
||||
|
||||
patchDoc.ApplyTo(customer, ModelState);
|
||||
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return HttpBadRequest(ModelState);
|
||||
}
|
||||
|
||||
return new ObjectResult(customer);
|
||||
}
|
||||
|
||||
[HttpPatch]
|
||||
public IActionResult JsonPatchWithModelStateAndPrefix(
|
||||
[FromBody] JsonPatchDocument<Customer> patchDoc,
|
||||
string prefix)
|
||||
{
|
||||
var customer = CreateCustomer();
|
||||
|
||||
patchDoc.ApplyTo(customer, ModelState, prefix);
|
||||
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return HttpBadRequest(ModelState);
|
||||
}
|
||||
|
||||
return new ObjectResult(customer);
|
||||
}
|
||||
|
||||
private Customer CreateCustomer()
|
||||
{
|
||||
return new Customer
|
||||
{
|
||||
CustomerName = "John",
|
||||
Orders = new List<Order>()
|
||||
{
|
||||
new Order
|
||||
{
|
||||
OrderName = "Order1"
|
||||
},
|
||||
new Order
|
||||
{
|
||||
OrderName = "Order2"
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>dab1252d-577c-4912-98be-1a812bf83f86</ProjectGuid>
|
||||
<RootNamespace>JsonPatchWebSite</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<DevelopmentServerPort>29149</DevelopmentServerPort>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace JsonPatchWebSite.Models
|
||||
{
|
||||
public class Customer
|
||||
{
|
||||
public string CustomerName { get; set; }
|
||||
|
||||
public List<Order> Orders { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace JsonPatchWebSite.Models
|
||||
{
|
||||
public class Order
|
||||
{
|
||||
public string OrderName { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
|
||||
namespace JsonPatchWebSite
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
// Set up application services
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
// Add MVC services to the services container
|
||||
services.AddMvc();
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
app.UseCultureReplacer();
|
||||
|
||||
// Add MVC to the request pipeline
|
||||
app.UseMvc();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"commands": {
|
||||
"web": "Microsoft.AspNet.Hosting server=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:5001",
|
||||
"kestrel": "Microsoft.AspNet.Hosting --server Kestrel --server.urls http://localhost:5000"
|
||||
},
|
||||
"dependencies": {
|
||||
"Kestrel": "1.0.0-*",
|
||||
"Microsoft.AspNet.Mvc": "6.0.0-*",
|
||||
"Microsoft.AspNet.Mvc.TestConfiguration": "1.0.0",
|
||||
"Microsoft.AspNet.Server.IIS": "1.0.0-*",
|
||||
"Microsoft.AspNet.Server.WebListener": "1.0.0-*",
|
||||
"Microsoft.AspNet.StaticFiles": "1.0.0-*"
|
||||
},
|
||||
"frameworks": {
|
||||
"dnx451": { },
|
||||
"dnxcore50": { }
|
||||
},
|
||||
"webroot": "wwwroot"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
JsonPatchWebSite
|
||||
===
|
||||
|
||||
This web site illustrates how to use JSON Patch operation on an object.
|
||||
|
|
@ -0,0 +1 @@
|
|||
HelloWorld
|
||||
Loading…
Reference in New Issue