Skip to content

Commit 0286487

Browse files
Paul Johnsonelit0451
andauthored
Fix optional id route param inferred as FromQuery (#11557)
* Fix optional id route param inferred as FromQuery Closes #11554 * Prevent breaking change, UmbracoJsonModelBinderConvention is public class * Set missing binding source for complex types * Update UmbracoApiBehaviorApplicationModelProvider.cs Co-authored-by: Elitsa Marinovska <[email protected]> Co-authored-by: Elitsa Marinovska <[email protected]>
1 parent 082e703 commit 0286487

File tree

2 files changed

+50
-16
lines changed

2 files changed

+50
-16
lines changed

src/Umbraco.Web.Common/ApplicationModels/UmbracoApiBehaviorApplicationModelProvider.cs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ namespace Umbraco.Cms.Web.Common.ApplicationModels
1818
/// <para>
1919
/// This is nearly a copy of aspnetcore's ApiBehaviorApplicationModelProvider which supplies a convention for the
2020
/// [ApiController] attribute, however that convention is too strict for our purposes so we will have our own.
21+
/// Uses UmbracoJsonModelBinder for complex parameters and those with BindingSource of Body, but leaves the rest alone see GH #11554
2122
/// </para>
2223
/// <para>
2324
/// See https://shazwazza.com/post/custom-body-model-binding-per-controller-in-asp-net-core/
@@ -41,14 +42,12 @@ public UmbracoApiBehaviorApplicationModelProvider(IModelMetadataProvider modelMe
4142
{
4243
new ClientErrorResultFilterConvention(), // Ensures the responses without any body is converted into a simple json object with info instead of a string like "Status Code: 404; Not Found"
4344
new ConsumesConstraintForFormFileParameterConvention(), // If an controller accepts files, it must accept multipart/form-data.
44-
new InferParameterBindingInfoConvention(modelMetadataProvider), // no need for [FromBody] everywhere, A complex type parameter is assigned to FromBody
4545

46-
// This ensures that all parameters of type BindingSource.Body (based on the above InferParameterBindingInfoConvention) are bound
46+
// This ensures that all parameters of type BindingSource.Body and those of complex type are bound
4747
// using our own UmbracoJsonModelBinder
48-
new UmbracoJsonModelBinderConvention()
48+
new UmbracoJsonModelBinderConvention(modelMetadataProvider)
4949
};
5050

51-
// TODO: Need to determine exactly how this affects errors
5251
var defaultErrorType = typeof(ProblemDetails);
5352
var defaultErrorTypeAttribute = new ProducesErrorResponseTypeAttribute(defaultErrorType);
5453
_actionModelConventions.Add(new ApiConventionApplicationModelConvention(defaultErrorTypeAttribute));
@@ -68,25 +67,24 @@ public void OnProvidersExecuted(ApplicationModelProviderContext context)
6867
/// <inheritdoc/>
6968
public void OnProvidersExecuting(ApplicationModelProviderContext context)
7069
{
71-
foreach (var controller in context.Result.Controllers)
70+
foreach (ControllerModel controller in context.Result.Controllers)
7271
{
7372
if (!IsUmbracoApiController(controller))
7473
{
7574
continue;
7675
}
7776

78-
foreach (var action in controller.Actions)
77+
foreach (ActionModel action in controller.Actions)
7978
{
80-
foreach (var convention in _actionModelConventions)
79+
foreach (IActionModelConvention convention in _actionModelConventions)
8180
{
8281
convention.Apply(action);
8382
}
8483
}
85-
8684
}
8785
}
8886

89-
private bool IsUmbracoApiController(ControllerModel controller)
87+
private static bool IsUmbracoApiController(ICommonModel controller)
9088
=> controller.Attributes.OfType<UmbracoApiControllerAttribute>().Any();
9189
}
9290
}
Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,61 @@
1-
using System.Linq;
21
using Microsoft.AspNetCore.Mvc.ApplicationModels;
32
using Microsoft.AspNetCore.Mvc.ModelBinding;
3+
using Microsoft.Extensions.DependencyInjection;
4+
using Umbraco.Cms.Web.Common.DependencyInjection;
45
using Umbraco.Cms.Web.Common.ModelBinders;
56

67
namespace Umbraco.Cms.Web.Common.ApplicationModels
78
{
89
/// <summary>
9-
/// Applies the <see cref="UmbracoJsonModelBinder"/> body model binder to any parameter binding source of type <see cref="BindingSource.Body"/>
10+
/// Applies the <see cref="UmbracoJsonModelBinder"/> body model binder to any complex parameter and those with a
11+
/// binding source of type <see cref="BindingSource.Body"/>
1012
/// </summary>
11-
/// <remarks>
12-
/// For this to work Microsoft's own <see cref="InferParameterBindingInfoConvention"/> convention must be executed before this one
13-
/// </remarks>
1413
public class UmbracoJsonModelBinderConvention : IActionModelConvention
1514
{
15+
private readonly IModelMetadataProvider _modelMetadataProvider;
16+
17+
public UmbracoJsonModelBinderConvention()
18+
: this(StaticServiceProvider.Instance.GetRequiredService<IModelMetadataProvider>())
19+
{
20+
}
21+
22+
public UmbracoJsonModelBinderConvention(IModelMetadataProvider modelMetadataProvider)
23+
{
24+
_modelMetadataProvider = modelMetadataProvider;
25+
}
26+
1627
/// <inheritdoc/>
1728
public void Apply(ActionModel action)
1829
{
19-
foreach (ParameterModel p in action.Parameters.Where(p => p.BindingInfo?.BindingSource == BindingSource.Body))
30+
foreach (ParameterModel p in action.Parameters)
2031
{
21-
p.BindingInfo.BinderType = typeof(UmbracoJsonModelBinder);
32+
if (p.BindingInfo == null)
33+
{
34+
if (IsComplexTypeParameter(p))
35+
{
36+
p.BindingInfo = new BindingInfo
37+
{
38+
BindingSource = BindingSource.Body,
39+
BinderType = typeof(UmbracoJsonModelBinder)
40+
};
41+
}
42+
43+
continue;
44+
}
45+
46+
if (p.BindingInfo.BindingSource == BindingSource.Body)
47+
{
48+
p.BindingInfo.BinderType = typeof(UmbracoJsonModelBinder);
49+
}
2250
}
2351
}
52+
53+
private bool IsComplexTypeParameter(ParameterModel parameter)
54+
{
55+
// No need for information from attributes on the parameter. Just use its type.
56+
ModelMetadata metadata = _modelMetadataProvider.GetMetadataForType(parameter.ParameterInfo.ParameterType);
57+
58+
return metadata.IsComplexType;
59+
}
2460
}
2561
}

0 commit comments

Comments
 (0)