Skip to content

Commit d8d3cea

Browse files
NthembaJune Ngeicorranrogue9gathogojr
authored
Fix/issue 551 (#2652)
* Added error to model state if ILogger is registered * Added ILogger Service to IServiceCollection * added tests to validate model state errors are added * Update test/UnitTest/Microsoft.AspNetCore.OData.Test/Abstraction/ServerFactory.cs Co-authored-by: Garrett DeBruin <corranrogue9@gmail.com> * Added flag to throw Model State exception if Ilogger is defined * Checks if flog allows throwing modelstate exception if ILogger is defined * Test ILogger flag when Ilogger is defined or not * Apply suggestions from code review Co-authored-by: John Gathogo <john.gathogo@gmail.com> * Changed flag name * Changed flag name in tests * Moved logger injection from the shared test ServerFactory * updated publicApi baseline with the new enum * Updates PublicApi.bsl file * removed extra spaces * Updated .bsl file with new compatibility option Co-authored-by: June Ngei <junengei@microsoft.com> Co-authored-by: Garrett DeBruin <corranrogue9@gmail.com> Co-authored-by: John Gathogo <john.gathogo@gmail.com>
1 parent eb66b3b commit d8d3cea

7 files changed

Lines changed: 189 additions & 2 deletions

File tree

src/Microsoft.AspNet.OData.Shared/CompatibilityOptions.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ public enum CompatibilityOptions
2828
/// <summary>
2929
/// Disable case-insensitive request property binding.
3030
/// </summary>
31-
DisableCaseInsensitiveRequestPropertyBinding = 0x2
31+
DisableCaseInsensitiveRequestPropertyBinding = 0x2,
32+
33+
/// <summary>
34+
/// Throw exception after logging ModelState error.
35+
/// </summary>
36+
ThrowExceptionAfterLoggingModelStateError = 0x4
3237
}
3338
}

src/Microsoft.AspNetCore.OData/Formatter/ODataInputFormatter.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@ public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputForma
142142
}
143143

144144
logger.LogError(ex, String.Empty);
145+
if (context.HttpContext.Request.GetCompatibilityOptions().HasFlag(CompatibilityOptions.ThrowExceptionAfterLoggingModelStateError))
146+
{
147+
throw ex;
148+
}
145149
};
146150

147151
List<IDisposable> toDispose = new List<IDisposable>();

test/UnitTest/Microsoft.AspNet.OData.Test/PublicApi/Microsoft.AspNet.OData.PublicApi.bsl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ public enum Microsoft.AspNet.OData.CompatibilityOptions : int {
55
AllowNextLinkWithNonPositiveTopValue = 1
66
DisableCaseInsensitiveRequestPropertyBinding = 2
77
None = 0
8+
ThrowExceptionAfterLoggingModelStateError = 4
89
}
910

1011
public enum Microsoft.AspNet.OData.EdmDeltaEntityKind : int {

test/UnitTest/Microsoft.AspNetCore.OData.Test/Abstraction/ServerFactory.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
using Microsoft.AspNetCore.Routing;
2525
using Microsoft.AspNetCore.TestHost;
2626
using Microsoft.Extensions.DependencyInjection;
27+
using Microsoft.Extensions.Logging;
2728

2829
namespace Microsoft.AspNet.OData.Test.Abstraction
2930
{
@@ -47,8 +48,9 @@ public static TestServer Create(Type[] controllers, Action<IRouteBuilder> config
4748
services.AddMvc();
4849
#else
4950
services.AddMvc(options => options.EnableEndpointRouting = false)
50-
.AddNewtonsoftJson();
51+
.AddNewtonsoftJson();
5152
#endif
53+
5254
services.AddOData();
5355
configureService?.Invoke(services);
5456
});
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
//-----------------------------------------------------------------------------
2+
// <copyright file="ODataInputFormatterTest.cs" company=".NET Foundation">
3+
// Copyright (c) .NET Foundation and Contributors. All rights reserved.
4+
// See License.txt in the project root for license information.
5+
// </copyright>
6+
//------------------------------------------------------------------------------
7+
#if NETCORE
8+
using System;
9+
using System.Collections.Generic;
10+
using System.Linq;
11+
using System.Net;
12+
using System.Net.Http;
13+
using System.Net.Http.Headers;
14+
using System.Threading.Tasks;
15+
using Microsoft.AspNet.OData.Batch;
16+
using Microsoft.AspNet.OData.Builder;
17+
using Microsoft.AspNet.OData.Extensions;
18+
using Microsoft.AspNet.OData.Test.Abstraction;
19+
using Microsoft.AspNet.OData.Test.Builder.TestModels;
20+
using Microsoft.AspNetCore.Mvc;
21+
using Microsoft.OData.Edm;
22+
using Microsoft.Extensions.DependencyInjection;
23+
using Xunit;
24+
using Microsoft.Extensions.Logging;
25+
#else
26+
using System;
27+
using System.Collections;
28+
using System.Collections.Generic;
29+
using System.Linq;
30+
using System.Net;
31+
using System.Net.Http;
32+
using System.Net.Http.Formatting;
33+
using System.Net.Http.Headers;
34+
using System.Text.RegularExpressions;
35+
using System.Threading.Tasks;
36+
using System.Web.Http;
37+
using Microsoft.AspNet.OData.Builder;
38+
using Microsoft.AspNet.OData.Extensions;
39+
using Microsoft.AspNet.OData.Formatter;
40+
using Microsoft.AspNet.OData.Formatter.Serialization;
41+
using Microsoft.AspNet.OData.Query;
42+
using Microsoft.AspNet.OData.Routing;
43+
using Microsoft.AspNet.OData.Routing.Conventions;
44+
using Microsoft.AspNet.OData.Test.Abstraction;
45+
using Microsoft.AspNet.OData.Test.Builder.TestModels;
46+
using Microsoft.AspNet.OData.Test.Common;
47+
using Microsoft.AspNet.OData.Test.Extensions;
48+
using Microsoft.OData;
49+
using Microsoft.OData.Edm;
50+
using Xunit;
51+
#endif
52+
53+
namespace Microsoft.AspNet.OData.Test.Formatter
54+
{
55+
public class ODataInputFormatterTest
56+
{
57+
58+
[Fact]
59+
public async Task ExceptionNotThrownWhenILoggerServiceIsDefinedAndFlagIsNotSet()
60+
{
61+
// Arrange
62+
const string requestbody = "{\"ID\":2,\"Name\":2}";
63+
64+
ODataConventionModelBuilder builder = ODataConventionModelBuilderFactory.Create();
65+
builder.EntitySet<Customer>("Customers");
66+
IEdmModel model = builder.GetEdmModel();
67+
var controllers = new[] { typeof(CustomersController) };
68+
var server = TestServerFactory.Create(controllers, (config) =>
69+
{
70+
config.MapODataServiceRoute("odata", null, model);
71+
}, (configureService) =>
72+
{
73+
configureService.AddSingleton<ILogger, TestLogger>();
74+
75+
});
76+
77+
using (HttpClient client = TestServerFactory.CreateClient(server))
78+
using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Customers"))
79+
{
80+
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json"));
81+
request.Content = new StringContent(requestbody);
82+
83+
// Act
84+
using (HttpResponseMessage response = await client.SendAsync(request))
85+
{
86+
// Assert
87+
Assert.NotNull(response);
88+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
89+
}
90+
}
91+
}
92+
93+
[Fact]
94+
public async Task ExceptionThrownWhenILoggerServiceIsDefinedAndFlagIsSet()
95+
{
96+
// Arrange
97+
const string requestbody = "{\"ID\":2,\"Name\":2}";
98+
99+
ODataConventionModelBuilder builder = ODataConventionModelBuilderFactory.Create();
100+
builder.EntitySet<Customer>("Customers");
101+
IEdmModel model = builder.GetEdmModel();
102+
var controllers = new[] { typeof(CustomersController) };
103+
var server = TestServerFactory.Create(controllers, (config) =>
104+
{
105+
config.MapODataServiceRoute("odata", null, model);
106+
config.SetCompatibilityOptions(CompatibilityOptions.ThrowExceptionAfterLoggingModelStateError);
107+
});
108+
109+
using (HttpClient client = TestServerFactory.CreateClient(server))
110+
using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Customers"))
111+
{
112+
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json"));
113+
request.Content = new StringContent(requestbody);
114+
115+
// Act
116+
using (HttpResponseMessage response = await client.SendAsync(request))
117+
{
118+
// Assert
119+
Assert.NotNull(response);
120+
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
121+
}
122+
}
123+
}
124+
125+
public class Customer
126+
{
127+
public int ID { get; set; }
128+
public string Name { get; set; }
129+
}
130+
131+
public class CustomersController : ODataController
132+
{
133+
private List<Customer> customers = new List<Customer>()
134+
{
135+
new Customer()
136+
{
137+
ID = 1,
138+
Name = "Jane",
139+
}
140+
};
141+
142+
[EnableQuery]
143+
public IActionResult Post([FromBody] Customer customer)
144+
{
145+
if (!ModelState.IsValid)
146+
{
147+
return BadRequest();
148+
}
149+
150+
customers.Add(customer);
151+
return Ok();
152+
153+
}
154+
}
155+
156+
private class TestLogger : ILogger
157+
{
158+
public IDisposable BeginScope<TState>(TState state)
159+
{
160+
return null;
161+
}
162+
163+
public bool IsEnabled(LogLevel logLevel)
164+
{
165+
return true;
166+
}
167+
168+
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
169+
{
170+
}
171+
}
172+
}
173+
}

test/UnitTest/Microsoft.AspNetCore.OData.Test/PublicApi/Microsoft.AspNetCore.OData.PublicApi.bsl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ public enum Microsoft.AspNet.OData.CompatibilityOptions : int {
55
AllowNextLinkWithNonPositiveTopValue = 1
66
DisableCaseInsensitiveRequestPropertyBinding = 2
77
None = 0
8+
ThrowExceptionAfterLoggingModelStateError = 4
89
}
910

1011
public enum Microsoft.AspNet.OData.EdmDeltaEntityKind : int {

test/UnitTest/Microsoft.AspNetCore.OData.Test/PublicApi/Microsoft.AspNetCore3x.OData.PublicApi.bsl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ public enum Microsoft.AspNet.OData.CompatibilityOptions : int {
55
AllowNextLinkWithNonPositiveTopValue = 1
66
DisableCaseInsensitiveRequestPropertyBinding = 2
77
None = 0
8+
ThrowExceptionAfterLoggingModelStateError = 4
89
}
910

1011
public enum Microsoft.AspNet.OData.EdmDeltaEntityKind : int {

0 commit comments

Comments
 (0)