Skip to content

Fixed validation of nested objects did not work #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 18 additions & 7 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ indent_size = 2

# C# files
[*.cs]
charset = utf-8-bom

# New line preferences
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
Expand All @@ -30,7 +32,7 @@ csharp_new_line_between_query_expression_clauses = true
csharp_indent_block_contents = true
csharp_indent_braces = false
csharp_indent_case_contents = true
csharp_indent_case_contents_when_block = true
csharp_indent_case_contents_when_block = false
csharp_indent_switch_labels = true
csharp_indent_labels = one_less_than_current

Expand All @@ -44,9 +46,9 @@ dotnet_style_qualification_for_method = false:suggestion
dotnet_style_qualification_for_event = false:suggestion

# Types: use keywords instead of BCL types, and permit var only when the type is clear
csharp_style_var_for_built_in_types = false:suggestion
csharp_style_var_when_type_is_apparent = false:none
csharp_style_var_elsewhere = false:suggestion
csharp_style_var_for_built_in_types = true:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
csharp_style_var_elsewhere = true:suggestion
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
dotnet_style_predefined_type_for_member_access = true:suggestion

Expand All @@ -66,7 +68,7 @@ dotnet_naming_symbols.static_fields.applicable_kinds = field
dotnet_naming_symbols.static_fields.required_modifiers = static
dotnet_naming_symbols.static_fields.applicable_accessibilities = private, internal, private_protected
dotnet_naming_style.static_prefix_style.required_prefix = s_
dotnet_naming_style.static_prefix_style.capitalization = camel_case
dotnet_naming_style.static_prefix_style.capitalization = camel_case

# internal and private fields should be _camelCase
dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion
Expand All @@ -75,11 +77,12 @@ dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_
dotnet_naming_symbols.private_internal_fields.applicable_kinds = field
dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal
dotnet_naming_style.camel_case_underscore_style.required_prefix = _
dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case
dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case

# Code style defaults
csharp_using_directive_placement = outside_namespace:suggestion
dotnet_sort_system_directives_first = true
dotnet_separate_import_directive_groups = true
csharp_prefer_braces = true:refactoring
csharp_preserve_single_line_blocks = true:none
csharp_preserve_single_line_statements = false:none
Expand Down Expand Up @@ -181,4 +184,12 @@ indent_size = 2
[*.sh]
end_of_line = lf
[*.{cmd, bat}]
end_of_line = crlf
end_of_line = crlf

# JavaScript files
[*.{js,json}]
indent_size= 2

# Html files
[*.html]
indent_size= 2
2 changes: 1 addition & 1 deletion samples/BasicSample/BasicSample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<AzureFunctionsVersion>v3</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.5" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.13" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Azure.WebJobs.Extensions.HttpApi\Azure.WebJobs.Extensions.HttpApi.csproj" />
Expand Down
17 changes: 2 additions & 15 deletions samples/BasicSample/Function1.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System.ComponentModel.DataAnnotations;

using Azure.WebJobs.Extensions.HttpApi;
using Azure.WebJobs.Extensions.HttpApi;

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
Expand All @@ -17,7 +15,7 @@ public Function1(IHttpContextAccessor httpContextAccessor)
{
}

[FunctionName("Function1")]
[FunctionName(nameof(Function1))]
public IActionResult Run(
[HttpTrigger(AuthorizationLevel.Function, "post")]
SampleModel model,
Expand All @@ -31,15 +29,4 @@ public IActionResult Run(
return Ok(model);
}
}

public class SampleModel
{
[Required]
public string Name { get; set; }

public string[] Array { get; set; }

[Range(100, 10000)]
public int Price { get; set; }
}
}
4 changes: 2 additions & 2 deletions samples/BasicSample/Function2.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;

using Azure.WebJobs.Extensions.HttpApi;

Expand All @@ -17,7 +17,7 @@ public Function2(IHttpContextAccessor httpContextAccessor)
{
}

[FunctionName("Function2")]
[FunctionName(nameof(Function2))]
public IActionResult Run(
[HttpTrigger(AuthorizationLevel.Function, "get")]
HttpRequest req,
Expand Down
4 changes: 2 additions & 2 deletions samples/BasicSample/Function3.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Azure.WebJobs.Extensions.HttpApi;
using Azure.WebJobs.Extensions.HttpApi;

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
Expand All @@ -15,7 +15,7 @@ public Function3(IHttpContextAccessor httpContextAccessor)
{
}

[FunctionName("Function3")]
[FunctionName(nameof(Function3))]
public IActionResult Run(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "route/{id}")]
HttpRequest req,
Expand Down
4 changes: 2 additions & 2 deletions samples/BasicSample/Function4.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Azure.WebJobs.Extensions.HttpApi;
using Azure.WebJobs.Extensions.HttpApi;

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
Expand All @@ -15,7 +15,7 @@ public Function4(IHttpContextAccessor httpContextAccessor)
{
}

[FunctionName("Function4")]
[FunctionName(nameof(Function4))]
public IActionResult Run(
[HttpTrigger(AuthorizationLevel.Function, "post")]
SampleModel model,
Expand Down
32 changes: 32 additions & 0 deletions samples/BasicSample/Function5.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using Azure.WebJobs.Extensions.HttpApi;

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;

namespace BasicSample
{
public class Function5 : HttpFunctionBase
{
public Function5(IHttpContextAccessor httpContextAccessor)
: base(httpContextAccessor)
{
}

[FunctionName(nameof(Function5))]
public IActionResult Run(
[HttpTrigger(AuthorizationLevel.Function, "post")]
SampleNestedModel model,
ILogger log)
{
if (!TryValidateModel(model))
{
return BadRequest(ModelState);
}

return Ok(model);
}
}
}
15 changes: 15 additions & 0 deletions samples/BasicSample/SampleModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.ComponentModel.DataAnnotations;

namespace BasicSample
{
public class SampleModel
{
[Required]
public string Name { get; set; }

public string[] Array { get; set; }

[Range(100, 10000)]
public int Price { get; set; }
}
}
19 changes: 19 additions & 0 deletions samples/BasicSample/SampleNestedModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System.ComponentModel.DataAnnotations;

namespace BasicSample
{
public class SampleNestedModel
{
[Required]
public string Name { get; set; }

[Required]
public SampleChildModel Child { get; set; }
}

public class SampleChildModel
{
[Required]
public string Name { get; set; }
}
}
4 changes: 2 additions & 2 deletions samples/VirtualPathSample/Function1.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using Azure.WebJobs.Extensions.HttpApi;
using Azure.WebJobs.Extensions.HttpApi;

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;

namespace VirtualPathSample
Expand Down
2 changes: 1 addition & 1 deletion samples/VirtualPathSample/VirtualPathSample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<AzureFunctionsVersion>v3</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.7" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.13" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Azure.WebJobs.Extensions.HttpApi\Azure.WebJobs.Extensions.HttpApi.csproj" />
Expand Down
22 changes: 9 additions & 13 deletions src/Azure.WebJobs.Extensions.HttpApi/HttpFunctionBase.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System;
using System.IO;
using System.Security.Claims;
using System.Text;
Expand All @@ -10,6 +8,7 @@
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.StaticFiles;
Expand All @@ -29,6 +28,7 @@ protected HttpFunctionBase(IHttpContextAccessor httpContextAccessor)
private readonly IHttpContextAccessor _httpContextAccessor;

private IUrlHelper _url;
private IObjectModelValidator _objectModelValidator;
private ProblemDetailsFactory _problemDetailsFactory;

private const string DefaultContentType = "application/octet-stream";
Expand Down Expand Up @@ -56,6 +56,10 @@ protected IUrlHelper Url
return _url;
}
}

public IObjectModelValidator ObjectValidator
=> _objectModelValidator ??= HttpContext?.RequestServices?.GetRequiredService<IObjectModelValidator>();

public ProblemDetailsFactory ProblemDetailsFactory
=> _problemDetailsFactory ??= HttpContext?.RequestServices?.GetRequiredService<ProblemDetailsFactory>();

Expand Down Expand Up @@ -209,17 +213,9 @@ protected AcceptedResult AcceptedAtFunction(string functionName, object routeVal

protected bool TryValidateModel(object model)
{
var validationResults = new List<ValidationResult>();
var actionContext = new ActionContext(HttpContext, HttpContext.GetRouteData(), new ActionDescriptor(), ModelState);

Validator.TryValidateObject(model, new ValidationContext(model), validationResults, true);

foreach (var validationResult in validationResults)
{
foreach (var memberName in validationResult.MemberNames)
{
ModelState.AddModelError(memberName, validationResult.ErrorMessage);
}
}
ObjectValidator.Validate(actionContext, null, string.Empty, model);

return ModelState.IsValid;
}
Expand Down