Merge pull request #10534 from umbraco/v9/task/cleanup-validation-results
Streamlines response handling in controllers
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
using System.Net;
|
||||
using System.Net;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Umbraco.Cms.Web.Common.ActionsResults
|
||||
{
|
||||
// TODO: What is the purpose of this? Doesn't seem to add any benefit
|
||||
public class UmbracoProblemResult : ObjectResult
|
||||
{
|
||||
public UmbracoProblemResult(string message, HttpStatusCode httpStatusCode = HttpStatusCode.InternalServerError) : base(new {Message = message})
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Web.Common.ActionsResults
|
||||
{
|
||||
// TODO: This should probably follow the same conventions as in aspnet core and use ProblemDetails
|
||||
// and ProblemDetails factory. See https://github.com/dotnet/aspnetcore/blob/main/src/Mvc/Mvc.Core/src/ControllerBase.cs#L1977
|
||||
// ProblemDetails is explicitly checked for in the application model.
|
||||
// In our base class UmbracoAuthorizedApiController the logic is there to create a ProblemDetails.
|
||||
// However, to do this will require changing how angular deals with errors since the response will
|
||||
// probably be different. Would just be better to follow the aspnet patterns.
|
||||
|
||||
/// <summary>
|
||||
/// Custom result to return a validation error message with required headers
|
||||
/// </summary>
|
||||
@@ -13,6 +22,11 @@ namespace Umbraco.Cms.Web.Common.ActionsResults
|
||||
/// </remarks>
|
||||
public class ValidationErrorResult : ObjectResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Typically this should not be used and just use the ValidationProblem method on the base controller class.
|
||||
/// </summary>
|
||||
/// <param name="errorMessage"></param>
|
||||
/// <returns></returns>
|
||||
public static ValidationErrorResult CreateNotificationValidationErrorResult(string errorMessage)
|
||||
{
|
||||
var notificationModel = new SimpleNotificationModel
|
||||
@@ -23,6 +37,9 @@ namespace Umbraco.Cms.Web.Common.ActionsResults
|
||||
return new ValidationErrorResult(notificationModel);
|
||||
}
|
||||
|
||||
public ValidationErrorResult(ModelStateDictionary modelState)
|
||||
: this(new SimpleValidationModel(modelState.ToErrorDictionary())) { }
|
||||
|
||||
public ValidationErrorResult(object value, int statusCode) : base(value)
|
||||
{
|
||||
StatusCode = statusCode;
|
||||
@@ -32,6 +49,7 @@ namespace Umbraco.Cms.Web.Common.ActionsResults
|
||||
{
|
||||
}
|
||||
|
||||
// TODO: Like here, shouldn't we use ProblemDetails?
|
||||
public ValidationErrorResult(string errorMessage, int statusCode) : base(new { Message = errorMessage })
|
||||
{
|
||||
StatusCode = statusCode;
|
||||
|
||||
55
src/Umbraco.Web.Common/Extensions/ModelStateExtensions.cs
Normal file
55
src/Umbraco.Web.Common/Extensions/ModelStateExtensions.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
||||
namespace Umbraco.Extensions
|
||||
{
|
||||
public static class ModelStateExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks if there are any model errors on any fields containing the prefix
|
||||
/// </summary>
|
||||
/// <param name="state"></param>
|
||||
/// <param name="prefix"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsValid(this ModelStateDictionary state, string prefix) =>
|
||||
state.Where(v => v.Key.StartsWith(prefix + ".")).All(v => !v.Value.Errors.Any());
|
||||
|
||||
public static IDictionary<string, object> ToErrorDictionary(this ModelStateDictionary modelState)
|
||||
{
|
||||
var modelStateError = new Dictionary<string, object>();
|
||||
foreach (KeyValuePair<string, ModelStateEntry> keyModelStatePair in modelState)
|
||||
{
|
||||
var key = keyModelStatePair.Key;
|
||||
ModelErrorCollection errors = keyModelStatePair.Value.Errors;
|
||||
if (errors != null && errors.Count > 0)
|
||||
{
|
||||
modelStateError.Add(key, errors.Select(error => error.ErrorMessage));
|
||||
}
|
||||
}
|
||||
return modelStateError;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the ModelState to JSON for JavaScript to interrogate the errors
|
||||
/// </summary>
|
||||
/// <param name="state"></param>
|
||||
/// <returns></returns>
|
||||
public static JsonResult ToJsonErrors(this ModelStateDictionary state) =>
|
||||
new JsonResult(new
|
||||
{
|
||||
success = state.IsValid.ToString().ToLower(),
|
||||
failureType = "ValidationError",
|
||||
validationErrors = from e in state
|
||||
where e.Value.Errors.Count > 0
|
||||
select new
|
||||
{
|
||||
name = e.Key,
|
||||
errors = e.Value.Errors.Select(x => x.ErrorMessage)
|
||||
.Concat(
|
||||
e.Value.Errors.Where(x => x.Exception != null).Select(x => x.Exception.Message))
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user