2015-09-30 20 views
8

Tôi đã sao chép vấn đề tôi đang gặp trong một dự án API MVC Web API hoàn toàn mới.ModelState.IsValid là sai khi tôi có tham số nullable

Đây là mã mặc định có sửa đổi nhỏ.

public string Get(int? id, int? something = null) 
{ 
    var isValid = ModelState.IsValid; 
    return "value"; 
} 

Nếu bạn đi đến http://localhost/api/values/5?something=123 thì đây hoạt động tốt, và isValid là true.

Nếu bạn truy cập http://localhost/api/values/5?something= thì isValid là false.

Vấn đề tôi đang gặp là nếu bạn cung cấp một giá trị null hay bỏ qua cho một mục đó là nullable, cờ ModelState.IsValid một lỗi xác nhận nói "A value is required but was not present in the request."

Từ điển ModelState cũng trông như thế này:

enter image description here

với hai mục nhập cho something, một giá trị không thể xác định được, tôi không chắc liệu nó có quan trọng hay không.

Bất kỳ ý tưởng nào về cách tôi có thể sửa lỗi này để mô hình hợp lệ khi các tham số nullable bị bỏ qua hoặc được cung cấp dưới dạng null? Tôi đang sử dụng xác nhận mô hình trong api web của tôi và nó phá vỡ nó nếu mọi phương thức với tham số nullable tạo ra lỗi mô hình.

+0

thông tin có khả năng hữu ích ở đây: http://stackoverflow.com/a/11922978/3130094 - có lẽ bạn đang nhìn thấy tình huống này vì khá hơn là bỏ qua tham số 'something' hoàn toàn bạn đang thêm nó và gán không cái gì –

+0

Tôi đã cố gắng làm rối tung bộ nối tiếp json trong dự án ban đầu của mình, tôi không chắc chắn làm thế nào để đặt nó vào trong dự án này mặc dù tôi không làm json yêu cầu nhưng sử dụng trình duyệt (w hich tôi tin là khác nhau nhưng có thể sai?) – NibblyPig

+0

asp.net 4.5.2 nếu điều đó giúp. Tôi đã thêm 'config.Formatters.JsonFormatter.SerializerSettings = new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore};' để cho nó bỏ qua việc tuần tự hóa và deserialization các giá trị null nhưng điều này không làm việc. Tôi không biết nếu 'something =' được coi là 'null' hoặc' "" (chuỗi rỗng) 'mặc dù, hoặc nếu serializer này thậm chí còn được sử dụng cho các hoạt động thử nghiệm của tôi. – NibblyPig

Trả lời

3

Dường như mô hình ràng buộc mặc định không hiểu đầy đủ các loại không có giá trị. Như đã thấy trong câu hỏi, nó đưa ra ba lỗi tham số thay vì hai lỗi được mong đợi.

Bạn có thể làm được việc này với một mô hình chất kết dính tùy chỉnh nullable:

Mẫu Binder

public class NullableIntModelBinder : IModelBinder 
{ 
    public bool BindModel(System.Web.Http.Controllers.HttpActionContext actionContext, ModelBindingContext bindingContext) 
    { 
     if (bindingContext.ModelType != typeof(int?)) 
     { 
      return false; 
     } 

     ValueProviderResult val = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); 
     if (val == null) 
     { 
      return false; 
     } 

     string rawvalue = val.RawValue as string; 

     // Not supplied : /test/5 
     if (rawvalue == null) 
     { 
      bindingContext.Model = null; 
      return true; 
     } 

     // Provided but with no value : /test/5?something= 
     if (rawvalue == string.Empty) 
     { 
      bindingContext.Model = null; 
      return true; 
     } 

     // Provided with a value : /test/5?something=1 
     int result; 
     if (int.TryParse(rawvalue, out result)) 
     { 
      bindingContext.Model = result; 
      return true; 
     } 

     bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Cannot convert value to int"); 
     return false; 
    } 
} 

Cách sử dụng

public ModelStateDictionary Get(
    int? id, 
    [ModelBinder(typeof(NullableIntModelBinder))]int? something = null) 
{ 
    var isValid = ModelState.IsValid; 

    return ModelState; 
} 

Phỏng theo trang asp.net: http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api để đọc thêm và phương pháp thay thế để đặt nó ở lớp (kiểm soát ler) thay vì mỗi tham số.

này xử lý 3 kịch bản hợp lệ:

/test/5 
/test/5?something= 
/test/5?something=2 

đầu tiên cho "cái gì đó" này là null. Bất kỳ điều gì khác (ví dụ: ?something=x) sẽ báo lỗi.

Nếu bạn thay đổi chữ ký để

int? somthing 

(tức là loại bỏ = null) sau đó bạn phải cung cấp một cách rõ ràng thông số, tức là /test/5 sẽ không phải là một con đường có giá trị khi bạn tinh chỉnh các tuyến đường của bạn là tốt.

+0

Tuyệt vời, cảm ơn, trông gọn gàng hơn so với cách tiếp cận mà tôi sắp sửa. Tôi sẽ cho nó đi. – NibblyPig

+0

Đã làm việc điều trị. Nhiều đánh giá cao. Bất thường lý do tại sao họ không có hành vi này ra khỏi hộp, hoặc ít nhất là một thiết lập. – NibblyPig

0

Xóa giá trị null mặc định khỏi tham số thứ hai. Các mô hình chất kết dính sẽ thiết lập nó để null nếu nó là cái gì khác hơn là int.

+0

Điều này không ảnh hưởng đến nó, nó chỉ là một cái gì đó tôi đã cố gắng để xem nếu nó sẽ sửa chữa vấn đề mà tôi để lại trong – NibblyPig

+0

Điều gì sẽ xảy ra nếu bạn không chỉ định tham số trong GET? Như trong: GET/api/values ​​/ 5 – Maetis

+0

Rất thú vị, isValid là 'true' khi bỏ qua. Nếu tôi loại bỏ mặc định '= null', nó không khớp với tuyến đường. Điều này giải thích một chút công bằng. – NibblyPig

0

Bạn sẽ phải đăng ký một trình liên kết mô hình tùy chỉnh cho các loại có thể không có giá trị như trình kết nối mặc định đang gọi trình xác nhận hợp lệ cho các tham số nullable và sau này xem xét các giá trị rỗng đó là không hợp lệ.

Model Binder:

public class NullableModelBinder<T> : IModelBinder where T : struct 
{ 
    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) 
    { 
     var val = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); 

     if (val == null) 
      return false; 

     var rawVal = val.RawValue as string; 

     if (rawVal == null) 
      return false; 

     var converter = TypeDescriptor.GetConverter(typeof(T)); 

     if (converter.IsValid(rawVal)) 
     { 
      bindingContext.Model = converter.ConvertFromString(rawVal); 
      return true; 
     } 

     bindingContext.ValidationNode.SuppressValidation = true; 
     return false; 
    } 
} 

đăng ký:

public static class WebApiConfig 
{ 
    public static void Register(HttpConfiguration config) 
    { 
     // ... 

     var provider = new SimpleModelBinderProvider(typeof(int?), new NullableModelBinder<int>()); 
     config.Services.Insert(typeof(ModelBinderProvider), 0, provider); 

     // ... 
    } 
} 
Các vấn đề liên quan