Aufbauend auf Manish Jain
Antwort (die für Web API 2 gedacht ist, was die Sache vereinfacht):
1) Verwendung Validierungsstrukturen so viele Validierungsfehler wie möglich zu beantworten. Diese Strukturen können auch verwendet werden, um auf Anfragen aus Formularen zu reagieren.
public class FieldError
{
public String FieldName { get; set; }
public String FieldMessage { get; set; }
}
// a result will be able to inform API client about some general error/information and details information (related to invalid parameter values etc.)
public class ValidationResult<T>
{
public bool IsError { get; set; }
/// <summary>
/// validation message. It is used as a success message if IsError is false, otherwise it is an error message
/// </summary>
public string Message { get; set; } = string.Empty;
public List<FieldError> FieldErrors { get; set; } = new List<FieldError>();
public T Payload { get; set; }
public void AddFieldError(string fieldName, string fieldMessage)
{
if (string.IsNullOrWhiteSpace(fieldName))
throw new ArgumentException("Empty field name");
if (string.IsNullOrWhiteSpace(fieldMessage))
throw new ArgumentException("Empty field message");
// appending error to existing one, if field already contains a message
var existingFieldError = FieldErrors.FirstOrDefault(e => e.FieldName.Equals(fieldName));
if (existingFieldError == null)
FieldErrors.Add(new FieldError {FieldName = fieldName, FieldMessage = fieldMessage});
else
existingFieldError.FieldMessage = $"{existingFieldError.FieldMessage}. {fieldMessage}";
IsError = true;
}
public void AddEmptyFieldError(string fieldName, string contextInfo = null)
{
AddFieldError(fieldName, $"No value provided for field. Context info: {contextInfo}");
}
}
public class ValidationResult : ValidationResult<object>
{
}
2) Dienstebene が返ってきます。 ValidationResult
s, unabhängig davon, ob die Operation erfolgreich war oder nicht. z.B:
public ValidationResult DoSomeAction(RequestFilters filters)
{
var ret = new ValidationResult();
if (filters.SomeProp1 == null) ret.AddEmptyFieldError(nameof(filters.SomeProp1));
if (filters.SomeOtherProp2 == null) ret.AddFieldError(nameof(filters.SomeOtherProp2 ), $"Failed to parse {filters.SomeOtherProp2} into integer list");
if (filters.MinProp == null) ret.AddEmptyFieldError(nameof(filters.MinProp));
if (filters.MaxProp == null) ret.AddEmptyFieldError(nameof(filters.MaxProp));
// validation affecting multiple input parameters
if (filters.MinProp > filters.MaxProp)
{
ret.AddFieldError(nameof(filters.MinProp, "Min prop cannot be greater than max prop"));
ret.AddFieldError(nameof(filters.MaxProp, "Check"));
}
// also specify a global error message, if we have at least one error
if (ret.IsError)
{
ret.Message = "Failed to perform DoSomeAction";
return ret;
}
ret.Message = "Successfully performed DoSomeAction";
return ret;
}
3) API-Controller wird die Antwort auf der Grundlage des Ergebnisses der Servicefunktion konstruieren
Eine Möglichkeit besteht darin, praktisch alle Parameter als optional einzustufen und eine benutzerdefinierte Validierung durchzuführen, die eine aussagekräftigere Antwort liefert. Außerdem achte ich darauf, dass keine Ausnahme über die Dienstgrenze hinausgeht.
[Route("DoSomeAction")]
[HttpPost]
public HttpResponseMessage DoSomeAction(int? someProp1 = null, string someOtherProp2 = null, int? minProp = null, int? maxProp = null)
{
try
{
var filters = new RequestFilters
{
SomeProp1 = someProp1 ,
SomeOtherProp2 = someOtherProp2.TrySplitIntegerList() ,
MinProp = minProp,
MaxProp = maxProp
};
var result = theService.DoSomeAction(filters);
return !result.IsError ? Request.CreateResponse(HttpStatusCode.OK, result) : Request.CreateResponse(HttpStatusCode.BadRequest, result);
}
catch (Exception exc)
{
Logger.Log(LogLevel.Error, exc, "Failed to DoSomeAction");
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, new HttpError("Failed to DoSomeAction - internal error"));
}
}