Impelemented validation filter for asp.net core mvc.

pull/112/head
Halil İbrahim Kalkan 8 years ago
parent 24ae92fcee
commit e68dabf59b

@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Mvc.ExceptionHandling;
using Volo.Abp.AspNetCore.Mvc.Validation;
namespace Volo.Abp.AspNetCore.Mvc
{
@ -22,7 +23,7 @@ namespace Volo.Abp.AspNetCore.Mvc
{
//options.Filters.AddService(typeof(AbpAuthorizationFilter));
//options.Filters.AddService(typeof(AbpAuditActionFilter));
//options.Filters.AddService(typeof(AbpValidationActionFilter));
options.Filters.AddService(typeof(AbpValidationActionFilter));
//options.Filters.AddService(typeof(AbpUowActionFilter));
options.Filters.AddService(typeof(AbpExceptionFilter));
//options.Filters.AddService(typeof(AbpResultFilter));

@ -43,7 +43,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling
private void HandleAndWrapException(ExceptionContext context)
{
if (!ActionResultHelper.IsObjectResult(context.ActionDescriptor.GetMethodInfo().ReturnType))
if (!context.ActionDescriptor.IsControllerAction() || !ActionResultHelper.IsObjectResult(context.ActionDescriptor.GetMethodInfo().ReturnType))
{
return;
}

@ -0,0 +1,42 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Aspects;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.Mvc.Validation
{
public class AbpValidationActionFilter : IAsyncActionFilter, ITransientDependency
{
private readonly IServiceProvider _serviceProvider;
public AbpValidationActionFilter(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
//TODO: Configuration to disable validation for controllers..?
if (!context.ActionDescriptor.IsControllerAction() ||
!ActionResultHelper.IsObjectResult(context.ActionDescriptor.GetMethodInfo().ReturnType))
{
await next();
return;
}
using (AbpCrossCuttingConcerns.Applying(context.Controller, AbpCrossCuttingConcerns.Validation))
{
using (var scope = _serviceProvider.CreateScope())
{
var validator = scope.ServiceProvider.GetRequiredService<MvcActionInvocationValidator>();
validator.Initialize(context);
validator.Validate();
}
await next();
}
}
}
}

@ -0,0 +1,71 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Options;
using Volo.Abp.Validation;
namespace Volo.Abp.AspNetCore.Mvc.Validation
{
public class MvcActionInvocationValidator : MethodInvocationValidator
{
protected ActionExecutingContext ActionContext { get; private set; }
private bool _isValidatedBefore;
public MvcActionInvocationValidator(IOptions<AbpValidationOptions> options)
: base(options)
{
}
public void Initialize(ActionExecutingContext actionContext)
{
ActionContext = actionContext;
SetDataAnnotationAttributeErrors();
base.Initialize(
actionContext.ActionDescriptor.GetMethodInfo(),
GetParameterValues(actionContext)
);
}
protected override void SetDataAnnotationAttributeErrors(object validatingObject)
{
SetDataAnnotationAttributeErrors();
}
protected virtual void SetDataAnnotationAttributeErrors()
{
if (_isValidatedBefore || ActionContext.ModelState.IsValid)
{
return;
}
foreach (var state in ActionContext.ModelState)
{
foreach (var error in state.Value.Errors)
{
ValidationErrors.Add(new ValidationResult(error.ErrorMessage, new[] { state.Key }));
}
}
_isValidatedBefore = true;
}
protected virtual object[] GetParameterValues(ActionExecutingContext actionContext)
{
var methodInfo = actionContext.ActionDescriptor.GetMethodInfo();
var parameters = methodInfo.GetParameters();
var parameterValues = new object[parameters.Length];
for (var i = 0; i < parameters.Length; i++)
{
parameterValues[i] = actionContext.ActionArguments.GetOrDefault(parameters[i].Name);
}
return parameterValues;
}
}
}

@ -0,0 +1,34 @@
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Shouldly;
using Volo.Abp.AspNetCore.Mvc;
namespace Volo.Abp.AspNetCore.App
{
[Route("api/validation-test")]
public class ValidationTestController : AbpController
{
[HttpGet]
[Route("object-result-action")]
public Task<string> ObjectResultAction(ValidationTest1Model model)
{
ModelState.IsValid.ShouldBeTrue(); //AbpValidationFilter throws exception otherwise
return Task.FromResult(model.Value1);
}
[HttpGet]
[Route("action-result-action")]
public IActionResult ActionResultAction(ValidationTest1Model model)
{
return Content("ModelState.IsValid: " + ModelState.IsValid.ToString().ToLowerInvariant());
}
public class ValidationTest1Model
{
[Required]
[MinLength(2)]
public string Value1 { get; set; }
}
}
}

@ -5,7 +5,7 @@ using Volo.Abp.Http;
using Volo.Abp.Ui;
using Xunit;
namespace Volo.Abp.AspNetCore.Mvc
namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling
{
public class ExceptionTestController_Tests : AspNetCoreMvcTestBase
{

@ -0,0 +1,39 @@
using System.Net;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Http;
using Xunit;
namespace Volo.Abp.AspNetCore.Mvc.Validation
{
public class ValidationTestController_Tests : AspNetCoreMvcTestBase
{
[Fact]
public async Task Should_Validate_Object_Result_Success()
{
var result = await GetResponseAsStringAsync("/api/validation-test/object-result-action?value1=hello");
result.ShouldBe("hello");
}
[Fact]
public async Task Should_Validate_Object_Result_Failing()
{
var result = await GetResponseAsObjectAsync<RemoteServiceErrorResponse>("/api/validation-test/object-result-action?value1=a", HttpStatusCode.BadRequest); //value1 has min length of 2 chars.
result.Error.ValidationErrors.Length.ShouldBeGreaterThan(0);
}
[Fact]
public async Task Should_Not_Validate_Action_Result_Success()
{
var result = await GetResponseAsStringAsync("/api/validation-test/action-result-action?value1=hello");
result.ShouldBe("ModelState.IsValid: true");
}
[Fact]
public async Task Should_Not_Validate_Action_Result_Failing()
{
var result = await GetResponseAsStringAsync("/api/validation-test/action-result-action"); //Missed the value1
result.ShouldBe("ModelState.IsValid: false");
}
}
}
Loading…
Cancel
Save