Skip to content

Commit ff7b27a

Browse files
committed
fb
1 parent 002cbd0 commit ff7b27a

File tree

2 files changed

+64
-3
lines changed

2 files changed

+64
-3
lines changed

src/Mvc/Mvc.Core/src/ModelBinding/Binders/BodyModelBinder.cs

+8-3
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,15 @@ public async Task BindModelAsync(ModelBindingContext bindingContext)
144144

145145
if (formatter == null)
146146
{
147-
if (AllowEmptyBody && httpContext.Features.Get<IHttpRequestBodyDetectionFeature>()?.CanHaveBody == false)
147+
if (AllowEmptyBody)
148148
{
149-
bindingContext.Result = ModelBindingResult.Success(model: null);
150-
return;
149+
var hasBody = httpContext.Features.Get<IHttpRequestBodyDetectionFeature>()?.CanHaveBody;
150+
hasBody ??= httpContext.Request.ContentLength is not null && httpContext.Request.ContentLength == 0;
151+
if (hasBody == false)
152+
{
153+
bindingContext.Result = ModelBindingResult.Success(model: null);
154+
return;
155+
}
151156
}
152157

153158
_logger.NoInputFormatterSelected(formatterContext);

src/Mvc/Mvc.Core/test/ModelBinding/Binders/BodyModelBinderTests.cs

+56
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,62 @@ public async Task BindModel_PassesAllowEmptyInputOptionViaContext(bool treatEmpt
195195
Times.Once);
196196
}
197197

198+
[Fact]
199+
public async Task BindModel_SetsModelIfAllowEmpty()
200+
{
201+
// Arrange
202+
var mockInputFormatter = new Mock<IInputFormatter>();
203+
mockInputFormatter.Setup(f => f.CanRead(It.IsAny<InputFormatterContext>()))
204+
.Returns(false);
205+
var inputFormatter = mockInputFormatter.Object;
206+
207+
var provider = new TestModelMetadataProvider();
208+
provider.ForType<Person>().BindingDetails(d => d.BindingSource = BindingSource.Body);
209+
210+
var bindingContext = GetBindingContext(
211+
typeof(Person),
212+
metadataProvider: provider);
213+
bindingContext.BinderModelName = "custom";
214+
215+
var binder = CreateBinder(new[] { inputFormatter }, treatEmptyInputAsDefaultValueOption : true);
216+
217+
// Act
218+
await binder.BindModelAsync(bindingContext);
219+
220+
// Assert
221+
Assert.True(bindingContext.Result.IsModelSet);
222+
Assert.Null(bindingContext.Result.Model);
223+
Assert.True(bindingContext.ModelState.IsValid);
224+
}
225+
226+
[Fact]
227+
public async Task BindModel_FailsIfNotAllowEmpty()
228+
{
229+
// Arrange
230+
var mockInputFormatter = new Mock<IInputFormatter>();
231+
mockInputFormatter.Setup(f => f.CanRead(It.IsAny<InputFormatterContext>()))
232+
.Returns(false);
233+
var inputFormatter = mockInputFormatter.Object;
234+
235+
var provider = new TestModelMetadataProvider();
236+
provider.ForType<Person>().BindingDetails(d => d.BindingSource = BindingSource.Body);
237+
238+
var bindingContext = GetBindingContext(
239+
typeof(Person),
240+
metadataProvider: provider);
241+
bindingContext.BinderModelName = "custom";
242+
243+
var binder = CreateBinder(new[] { inputFormatter }, treatEmptyInputAsDefaultValueOption: false);
244+
245+
// Act
246+
await binder.BindModelAsync(bindingContext);
247+
248+
// Assert
249+
Assert.False(bindingContext.ModelState.IsValid);
250+
Assert.Single(bindingContext.ModelState[bindingContext.BinderModelName].Errors);
251+
Assert.Equal("Unsupported content type ''.", bindingContext.ModelState[bindingContext.BinderModelName].Errors[0].Exception.Message);
252+
}
253+
198254
// Throwing InputFormatterException
199255
[Fact]
200256
public async Task BindModel_CustomFormatter_ThrowingInputFormatterException_AddsErrorToModelState()

0 commit comments

Comments
 (0)