try net httpresponseexception handling exceptions exceptionfilterattribute errors error catch asp c# asp.net-web-api

c# - net - web api exceptionfilterattribute



Maneje la validaciĆ³n de ModelState en ASP.NET Web API (9)

Así, por ejemplo:

public HttpResponseMessage Post(Person person) { if (ModelState.IsValid) { PersonDB.Add(person); return Request.CreateResponse(HttpStatusCode.Created, person); } else { // the code below should probably be refactored into a GetModelErrors // method on your BaseApiController or something like that var errors = new List<string>(); foreach (var state in ModelState) { foreach (var error in state.Value.Errors) { errors.Add(error.ErrorMessage); } } return Request.CreateResponse(HttpStatusCode.Forbidden, errors); } }

Esto devolverá una respuesta como esta (asumiendo JSON, pero el mismo principio básico para XML):

HTTP/1.1 400 Bad Request Content-Type: application/json; charset=utf-8 (some headers removed here) ["A value is required.","The field First is required.","Some custom errorm essage."]

Por supuesto, puede construir su lista / objeto de error de la forma que desee, por ejemplo, agregando nombres de campo, identificaciones de campo, etc.

Incluso si se trata de una llamada Ajax "de una sola vía" como una POST de una entidad nueva, aún debe devolver algo a la persona que llama, algo que indica si la solicitud fue exitosa o no. Imagine un sitio donde su usuario agregará información acerca de sí mismo a través de una solicitud AJAX POST. ¿Qué ocurre si la información que intentaron ingresar no es válida? ¿Cómo sabrán si su acción de Guardar fue exitosa o no?

La mejor forma de hacerlo es usar Buenos códigos de estado de HTTP como 200 OK y así sucesivamente. De esta forma, su JavaScript puede manejar fallas de forma adecuada utilizando las devoluciones de llamada correctas (error, éxito, etc.).

Aquí hay un buen tutorial sobre una versión más avanzada de este método, usando ActionFilter y jQuery: http://asp.net/web-api/videos/getting-started/custom-validation

Me preguntaba cómo puedo lograr la validación del modelo con ASP.NET Web API. Tengo mi modelo así:

public class Enquiry { [Key] public int EnquiryId { get; set; } [Required] public DateTime EnquiryDate { get; set; } [Required] public string CustomerAccountNumber { get; set; } [Required] public string ContactName { get; set; } }

Luego tengo una acción de publicación en mi controlador de API:

public void Post(Enquiry enquiry) { enquiry.EnquiryDate = DateTime.Now; context.DaybookEnquiries.Add(enquiry); context.SaveChanges(); }

¿Cómo agrego if(ModelState.IsValid) y luego manejo el mensaje de error para pasarlo al usuario?


DO#

public class ValidateModelAttribute : ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext actionContext) { if (actionContext.ModelState.IsValid == false) { actionContext.Response = actionContext.Request.CreateErrorResponse( HttpStatusCode.BadRequest, actionContext.ModelState); } } }

...

[ValidateModel] public HttpResponseMessage Post([FromBody]AnyModel model) {

Javascript

$.ajax({ type: "POST", url: "/api/xxxxx", async: ''false'', contentType: "application/json; charset=utf-8", data: JSON.stringify(data), error: function (xhr, status, err) { if (xhr.status == 400) { DisplayModelStateErrors(xhr.responseJSON.ModelState); } }, .... function DisplayModelStateErrors(modelState) { var message = ""; var propStrings = Object.keys(modelState); $.each(propStrings, function (i, propString) { var propErrors = modelState[propString]; $.each(propErrors, function (j, propError) { message += propError; }); message += "/n"; }); alert(message); };


O bien, si está buscando una colección simple de errores para sus aplicaciones, aquí está mi implementación de esto:

public override void OnActionExecuting(HttpActionContext actionContext) { var modelState = actionContext.ModelState; if (!modelState.IsValid) { var errors = new List<string>(); foreach (var state in modelState) { foreach (var error in state.Value.Errors) { errors.Add(error.ErrorMessage); } } var response = new { errors = errors }; actionContext.Response = actionContext.Request .CreateResponse(HttpStatusCode.BadRequest, response, JsonMediaTypeFormatter.DefaultMediaType); } }

La respuesta del mensaje de error se verá así:

{ "errors": [ "Please enter a valid phone number (7+ more digits)", "Please enter a valid e-mail address" ] }


Para la separación de la preocupación, le sugiero que use el filtro de acción para la validación del modelo, por lo que no necesita preocuparse demasiado sobre cómo hacer la validación en su controlador de API:

using System.Net; using System.Net.Http; using System.Web.Http.Controllers; using System.Web.Http.Filters; namespace System.Web.Http.Filters { public class ValidationActionFilter : ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext actionContext) { var modelState = actionContext.ModelState; if (!modelState.IsValid) actionContext.Response = actionContext.Request .CreateErrorResponse(HttpStatusCode.BadRequest, modelState); } } }



Tal vez no sea lo que estabas buscando, pero tal vez sea bueno que alguien lo sepa:

Si está utilizando .net Web Api 2, puede hacer lo siguiente:

if (!ModelState.IsValid) return BadRequest(ModelState);

Dependiendo de los errores del modelo, obtienes este resultado:

{ Message: "The request is invalid." ModelState: { model.PropertyA: [ "The PropertyA field is required." ], model.PropertyB: [ "The PropertyB field is required." ] } }



Tuve un problema al implementar el patrón de solución aceptado donde mi ModelStateFilter siempre devolvería false (y subsecuentemente un 400) para actionContext.ModelState.IsValid para ciertos objetos del modelo:

public class ModelStateFilter : ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext actionContext) { if (!actionContext.ModelState.IsValid) { actionContext.Response = new HttpResponseMessage { StatusCode = HttpStatusCode.BadRequest}; } } }

Solo acepto JSON, así que implementé una clase de cuaderno de modelo personalizado:

public class AddressModelBinder : System.Web.Http.ModelBinding.IModelBinder { public bool BindModel(HttpActionContext actionContext, System.Web.Http.ModelBinding.ModelBindingContext bindingContext) { var posted = actionContext.Request.Content.ReadAsStringAsync().Result; AddressDTO address = JsonConvert.DeserializeObject<AddressDTO>(posted); if (address != null) { // moar val here bindingContext.Model = address; return true; } return false; } }

Que me registro directamente después de mi modelo a través de

config.BindParameter(typeof(AddressDTO), new AddressModelBinder());


Aquí puede verificar para mostrar el error de estado del modelo uno por uno

public HttpResponseMessage CertificateUpload(employeeModel emp) { if (!ModelState.IsValid) { string errordetails = ""; var errors = new List<string>(); foreach (var state in ModelState) { foreach (var error in state.Value.Errors) { string p = error.ErrorMessage; errordetails = errordetails + error.ErrorMessage; } } Dictionary<string, object> dict = new Dictionary<string, object>(); dict.Add("error", errordetails); return Request.CreateResponse(HttpStatusCode.BadRequest, dict); } else { //do something } }

}