ASP.NET Web API'sinde Model Doğrulama

Bu makalede modellerinize açıklama ekleme, veri doğrulama için ek açıklamaları kullanma ve web API'nizdeki doğrulama hatalarını işleme işlemleri gösterilir. bir istemci web API'nize veri gönderdiğinde, genellikle herhangi bir işlem yapmadan önce verileri doğrulamak istersiniz.

Veri Açıklamaları

ASP.NET Web API'sinde, modelinizdeki özellikler için doğrulama kuralları ayarlamak için System.ComponentModel.DataAnnotations ad alanından öznitelikleri kullanabilirsiniz. Aşağıdaki modeli göz önünde bulundurun:

using System.ComponentModel.DataAnnotations;

namespace MyApi.Models
{
    public class Product
    {
        public int Id { get; set; }
        [Required]
        public string Name { get; set; }
        public decimal Price { get; set; }
        [Range(0, 999)]
        public double Weight { get; set; }
    }
}

ASP.NET MVC'de model doğrulamayı kullandıysanız, bu tanıdık görünmelidir. Required özniteliği özelliğin Name null olmaması gerektiğini söylüyor. Range özniteliği bunun sıfır ile 999 arasında olması gerektiğini söylerWeight.

İstemcinin aşağıdaki JSON gösterimiyle bir POST isteği gönderdiğini varsayalım:

{ "Id":4, "Price":2.99, "Weight":5 }

İstemcinin gerekli olarak işaretlenmiş özelliğini içermediğini Name görebilirsiniz. Web API'si JSON'u bir Product örneğe dönüştürdüğünde Product doğrulama özniteliklerine göre öğesini doğrular. Denetleyici eyleminizde modelin geçerli olup olmadığını kontrol edebilirsiniz:

using MyApi.Models;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace MyApi.Controllers
{
    public class ProductsController : ApiController
    {
        public HttpResponseMessage Post(Product product)
        {
            if (ModelState.IsValid)
            {
                // Do something with the product (not shown).

                return new HttpResponseMessage(HttpStatusCode.OK);
            }
            else
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
            }
        }
    }
}

Model doğrulaması, istemci verilerinin güvenli olduğunu garanti etmez. Uygulamanın diğer katmanlarında ek doğrulama gerekebilir. (Örneğin, veri katmanı yabancı anahtar kısıtlamaları uygulayabilir.) Entity Framework ile Web API'sini kullanma öğreticisinde bu sorunlardan bazıları incelenmektedir.

"Az Deftere Nakil": İstemci bazı özellikleri bıraktığında az deftere nakil gerçekleşir. Örneğin, istemcinin aşağıdakileri gönderdiğini varsayalım:

{"Id":4, "Name":"Gizmo"}

Burada, istemci veya Weightiçin Price değer belirtmedi. JSON biçimlendiricisi eksik özelliklere varsayılan olarak sıfır değeri atar.

Ürün Mağazası noktalı Modeller noktalı Ürün açılan menü seçeneklerinin üzerinde olduğu kod parçacığının ekran görüntüsü.

Bu özellikler için sıfır geçerli bir değer olduğundan model durumu geçerlidir. Bunun bir sorun olup olmadığı senaryonuza bağlıdır. Örneğin, bir güncelleştirme işleminde "sıfır" ile "ayarlanmadı" arasında ayrım yapmak isteyebilirsiniz. İstemcileri bir değer ayarlamaya zorlamak için özelliğini null atanabilir hale getirin ve Gerekli özniteliğini ayarlayın:

[Required]
public decimal? Price { get; set; }

"Over-Posting": İstemci beklediğinizden daha fazla veri de gönderebilir. Örneğin:

{"Id":4, "Name":"Gizmo", "Color":"Blue"}

Burada, JSON modelde Product bulunmayan bir özellik ("Color") içerir. Bu durumda, JSON biçimlendiricisi yalnızca bu değeri yoksayar. (XML biçimlendiricisi de aynı işlemi yapar.) Modelinizde salt okunur olmasını amaçladığınız özellikler varsa, fazla gönderim sorunlara neden olur. Örneğin:

public class UserProfile
{
    public string Name { get; set; }
    public Uri Blog { get; set; }
    public bool IsAdmin { get; set; }  // uh-oh!
}

Kullanıcıların özelliği güncelleştirmesini IsAdmin ve kendilerini yöneticilere yükseltmesini istemezsiniz! En güvenli strateji, istemcinin göndermesine izin verilenle tam olarak eşleşen bir model sınıfı kullanmaktır:

public class UserProfileDTO
{
    public string Name { get; set; }
    public Uri Blog { get; set; }
    // Leave out "IsAdmin"
}

Not

Brad Wilson'ın "ASP.NET MVC'de Giriş Doğrulama ve Model Doğrulama" blog gönderisinde, yetersiz posta ve fazla gönderim hakkında iyi bir tartışma var. Gönderi ASP.NET MVC 2 hakkında olsa da, sorunlar Web API'sine yöneliktir.

Doğrulama Hatalarını İşleme

Doğrulama başarısız olduğunda Web API'sinin istemciye otomatik olarak hata döndürmemesi. Model durumunu denetlemek ve uygun şekilde yanıt vermek denetleyici eylemine göre değişir.

Denetleyici eylemi çağrılmadan önce model durumunu denetlemek için bir eylem filtresi de oluşturabilirsiniz. Aşağıdaki kodda bir örnek gösterilir:

using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using System.Web.Http.ModelBinding;

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

Model doğrulaması başarısız olursa, bu filtre doğrulama hatalarını içeren bir HTTP yanıtı döndürür. Bu durumda denetleyici eylemi çağrılmıyor.

HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
Date: Tue, 16 Jul 2013 21:02:29 GMT
Content-Length: 331

{
  "Message": "The request is invalid.",
  "ModelState": {
    "product": [
      "Required property 'Name' not found in JSON. Path '', line 1, position 17."
    ],
    "product.Name": [
      "The Name field is required."
    ],
    "product.Weight": [
      "The field Weight must be between 0 and 999."
    ]
  }
}

Bu filtreyi tüm Web API denetleyicilerine uygulamak için yapılandırma sırasında HttpConfiguration.Filters koleksiyonuna filtrenin bir örneğini ekleyin:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Filters.Add(new ValidateModelAttribute());

        // ...
    }
}

Bir diğer seçenek de filtreyi tek tek denetleyicilerde veya denetleyici eylemlerinde öznitelik olarak ayarlamaktır:

public class ProductsController : ApiController
{
    [ValidateModel]
    public HttpResponseMessage Post(Product product)
    {
        // ...
    }
}