web-gelistirme-sc.com

ASP.NET Web API'sinde ModelState Doğrulaması'nı kullanma

ASP.NET Web API ile model doğrulamasını nasıl başarabileceğimi merak ediyordum. Bende böyle bir model var:

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; }
}

Daha sonra API Denetleyicimde bir Gönderi işlemi yapıyorum:

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

if(ModelState.IsValid) öğesini nasıl eklerim ve sonra kullanıcıya iletmek için hata iletisini nasıl kullanırım?

97
CallumVass

Endişenin ayrılması için, model doğrulaması için eylem filtresi kullanmanızı öneririm, bu yüzden api kontrol cihazınızda doğrulamayı nasıl yapacağınıza çok fazla dikkat etmeniz gerekmez:

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);
        }
    }
}
176
cuongle

Bunun gibi, örneğin:

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);
    }
}

Bu, bunun gibi bir yanıt döndürür (JSON, ancak XML için aynı temel prensibi varsayarsak):

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."]

Elbette hata nesnesini/listenizi istediğiniz şekilde, örneğin alan adlarını, alan kimliklerini vb. Oluşturabilirsiniz.

Yeni bir varlığın POST gibi bir "tek yönlü" Ajax çağrısı olsa bile, hala aramaya bir şey döndürmelisiniz - isteğin başarılı olup olmadığını gösteren bir şey. Kullanıcınızın, AJAX POST isteği aracılığıyla kendileriyle ilgili bazı bilgiler ekleyeceği bir site hayal edin. Ya girmeye çalıştıkları bilgiler geçerli değilse - Kaydet işlemlerinin başarılı olup olmadığını nasıl anlayacaklar?

Bunu yapmanın en iyi yolu, 200 OK ve benzeri gibi Eski Eski HTTP Durum Kodlarını kullanmaktır. Bu şekilde, JavaScript'iniz doğru geri çağrıları (hata, başarı vb.) Kullanarak hataları doğru bir şekilde yapabilir.

Bir ActionFilter ve jQuery kullanarak, bu yöntemin daha gelişmiş bir sürümü hakkında Güzel bir öğretici: http://asp.net/web-api/videos/getting-started/custom-validation

28
Anders Arpi

Belki aradığınızı değil, belki de birisinin bilmesi için güzel:

.Net Web Api 2 kullanıyorsanız, aşağıdakileri yapabilirsiniz:

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

Model hatalarına bağlı olarak, bu sonucu alırsınız:

{
   Message: "The request is invalid."
   ModelState: {
       model.PropertyA: [
            "The PropertyA field is required."
       ],
       model.PropertyB: [
             "The PropertyB field is required."
       ]
   }
}
24
Are Almaas
9
Lijo

Veya, uygulamalarınız için basit bir hata koleksiyonu arıyorsanız, bu benim uygulamam:

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);
        }
    }

Hata Mesajı Yanıt gibi görünecek:

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

C #

    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);
};
2
Nick Hermans

Burada model durumu hatasını tek tek gösterip göstermediğinizi kontrol edebilirsiniz

 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
        }
        }

}

2
Debendra Dash

kabul edilen çözüm kalıbını uygulayan bir sorunum vardı; burada ModelStateFilter, belirli model nesneleri için actionContext.ModelState.IsValid için her zaman false (ve ardından 400) döndürür:

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

Sadece JSON'u kabul ediyorum, bu yüzden özel bir model ciltleme sınıfı uyguladım:

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;
    }
}

Hangi modelden sonra doğrudan kayıt yaptırırım

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

Ayrıca burada belirtildiği şekilde istisnalar da atabilirsiniz: http://blogs.msdn.com/b/youssefm/archive/2012/06/28/error-handling-in-asp-net-webapi.aspx =

Not, bu makalenin önerdiği şeyi yapmak için, System.Net.Http'yi eklemeyi unutmayın

1