ASP.NET वेब एपीआई में ModelState सत्यापन संभालें


106

मैं सोच रहा था कि मैं ASP.NET वेब एपीआई के साथ मॉडल सत्यापन कैसे प्राप्त कर सकता हूं। मेरे पास मेरा मॉडल ऐसा है:

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

मेरे पास मेरे एपीआई नियंत्रक में एक पोस्ट एक्शन है:

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

मैं कैसे जोड़ूं if(ModelState.IsValid)और फिर उपयोगकर्ता को नीचे पारित करने के लिए त्रुटि संदेश को संभालूं?

जवाबों:


186

चिंता को अलग करने के लिए, मैं आपको मॉडल सत्यापन के लिए एक्शन फ़िल्टर का उपयोग करने का सुझाव दूंगा, इसलिए आपको अपने एपीआई नियंत्रक में सत्यापन करने की अधिक देखभाल करने की आवश्यकता नहीं है:

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

27
नामस्थान इस के लिए आवश्यक हैं System.Net.Http, System.Net System.Web.Http.Controllersऔर System.Web.Http.Filters
क्रिस्टोफर स्टीवेन्सन

11
आधिकारिक ASP.NET वेब एपी पेज पर भी ऐसा ही कार्यान्वयन है: asp.net/web-api/overview/formats-and-model-binding/…
Erik Schierboom

1
भले ही आप वेब एपीआई के ऊपर [ValidationActionFilter] नहीं डालते हैं, फिर भी यह कोड को कॉल करता है और मुझे खराब अनुरोध देता है।
माइक्रोनिक्स

1
यह इंगित करने के लायक है कि त्रुटि प्रतिक्रिया वापस आ गई है शामिल है द्वारा शामिल करेंईट्रेडरडेलपैलिसी । डिफ़ॉल्ट रूप से दूरस्थ अनुरोध की प्रतिक्रिया में केवल एक सामान्य "एक त्रुटि हुई है" संदेश शामिल है, लेकिन इसे सेट करने के IncludeErrorDetailPolicy.Alwaysलिए विवरण शामिल होगा (अपने उपयोगकर्ताओं के लिए विस्तार को उजागर करने के जोखिम पर)
रॉब

क्या एक विशिष्ट कारण है कि आपने इसके बजाय IAsyncActionFilter का उपयोग करने का सुझाव क्यों नहीं दिया?
रविवर

30

शायद वह नहीं जो आप ढूंढ रहे थे, लेकिन शायद किसी को पता चले:

यदि आप .net Web Api 2 का उपयोग कर रहे हैं तो आप निम्नलिखित कार्य कर सकते हैं:

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

मॉडल त्रुटियों के आधार पर, आपको यह परिणाम मिलता है:

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

1
ध्यान में रखते हुए जब मैंने यह सवाल पूछा था कि वेब एपीआई 1 को अभी जारी किया गया था, तब से शायद यह बहुत आगे बढ़ गया है :)
CallumVass

गुणों को वैकल्पिक के रूप में चिह्नित करना सुनिश्चित करें, अन्यथा आपको एक गैर-सहायक जेनेरिक मिलेगा "एक त्रुटि हुई है।" त्रुटि संदेश।
बूके

1
क्या संदेश बदलने का कोई तरीका है?
साकिब आदिल

29

इस तरह, उदाहरण के लिए:

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

यह इस तरह से प्रतिक्रिया देगा (JSON मानकर, लेकिन 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."]

आप निश्चित रूप से अपनी त्रुटि वस्तु का निर्माण कर सकते हैं / किसी भी तरह से सूची बना सकते हैं, उदाहरण के लिए फ़ील्ड नाम, फ़ील्ड आईडी आदि जोड़ना।

यहां तक ​​कि अगर यह एक "एक ही रास्ता" है अजाक्स एक नई इकाई के POST की तरह है, तो आपको अभी भी कॉलर को कुछ वापस करना चाहिए - ऐसा कुछ जो इंगित करता है कि अनुरोध सफल था या नहीं। एक साइट की कल्पना करें जहां आपका उपयोगकर्ता AJAX POST अनुरोध के माध्यम से अपने बारे में कुछ जानकारी जोड़ेगा। क्या होगा यदि उन्होंने जो जानकारी दर्ज करने की कोशिश की है वह वैध नहीं है - उन्हें कैसे पता चलेगा कि उनकी सेव एक्शन सफल थी या नहीं?

ऐसा करने का सबसे अच्छा तरीका अच्छा पुराने HTTP स्थिति कोड का उपयोग करना है जैसे कि 200 OKऔर इतने पर। इस तरह आपका जावास्क्रिप्ट सही कॉलबैक (त्रुटि, सफलता आदि) का उपयोग करके विफलताओं को ठीक से संभाल सकता है।

एक्शनफ़िल्टर और jQuery का उपयोग करके इस पद्धति के अधिक उन्नत संस्करण पर एक अच्छा ट्यूटोरियल दिया गया है: http://asp.net/web-api/videos/getting-started/custom-validation


यह सिर्फ मेरी enquiryवस्तु लौटाता है , यह नहीं कहता कि कौन से गुण हालांकि अमान्य हैं? इसलिए यदि मैंने CustomerAccountNumberखाली छोड़ दिया , तो यह कहना चाहिए कि डिफ़ॉल्ट सत्यापन संदेश (CusomterAccountNumber फ़ील्ड की आवश्यकता है ..)
CallumVass

मैं देख रहा हूँ, तो यह मॉडल मान्यता को संभालने का "सही" तरीका है? मुझे थोड़ा गड़बड़ लगता है ..
CallumVass

इसे करने के अन्य तरीके भी हैं, जैसे कि jQuery सत्यापन के साथ हुक अप करना। यहाँ एक अच्छा Microsoft उदाहरण है: asp.net/web-api/videos/getting-started/custom-validation
एंडर्स अरपी

यह विधि और उत्तर के रूप में चुनी गई विधि "कार्यात्मक रूप से समान" होनी चाहिए, इसलिए इस उत्तर में आपको दिखाने का अतिरिक्त मूल्य है कि आप इसे बिना किसी एक्शन फ़िल्टर के कैसे कर सकते हैं।
शॉन विल्सन

मैं लाइन बदलना पड़ा errors.Add(error.ErrorMessage);करने के लिए errors.Add(error.Exception.Message);मेरे लिए यह काम कर पाने के लिए।
कलस्टर

9

System.ComponentModel.DataAnnotationsसत्यापन नियम सेट करने के लिए आप नाम स्थान की विशेषताओं का उपयोग कर सकते हैं । मॉडल सत्यापन का संदर्भ लें - विवरण के लिए माइक वासन द्वारा

वीडियो ASP.NET वेब एपीआई, भाग 5 भी देखें : कस्टम सत्यापन - जॉन गैलोवे

अन्य संदर्भ

  1. WebAPI और WebForms के साथ क्लाइंट साइड पर वॉक करें
  2. कैसे ASP.NET वेब एपीआई HTTP संदेश डोमेन मॉडल के लिए बांधता है, और कैसे वेब एपीआई में मीडिया प्रारूपों के साथ काम करने के लिए।
  3. डोमिनिक बैयर - ASP.NET वेब एपीआई सुरक्षित करना
  4. हुकिंग AngularJS सत्यापन ASP.NET वेब एपीआई सत्यापन के लिए
  5. ASP.NET MVC में AngularJS के साथ मॉडलस्टेट त्रुटियों को प्रदर्शित करना
  6. क्लाइंट को त्रुटियों को कैसे प्रस्तुत करना है? AngularJS / WebApi ModelState
  7. निर्भरता-इंजेक्शन वेब एपीआई में मान्यता

8

या, यदि आप अपने ऐप्स के लिए त्रुटियों के सरल संग्रह की तलाश कर रहे हैं .. तो यहां मेरा यह कार्यान्वयन है:

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

त्रुटि संदेश प्रतिक्रिया जैसा दिखेगा:

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

5

नीचे दिए गए कोड को startup.cs फ़ाइल में जोड़ें

services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2).ConfigureApiBehaviorOptions(options =>
            {
                options.InvalidModelStateResponseFactory = (context) =>
                {
                    var errors = context.ModelState.Values.SelectMany(x => x.Errors.Select(p => new ErrorModel()
                   {
                       ErrorCode = ((int)HttpStatusCode.BadRequest).ToString(CultureInfo.CurrentCulture),
                        ErrorMessage = p.ErrorMessage,
                        ServerErrorMessage = string.Empty
                    })).ToList();
                    var result = new BaseResponse
                    {
                        Error = errors,
                        ResponseCode = (int)HttpStatusCode.BadRequest,
                        ResponseMessage = ResponseMessageConstants.VALIDATIONFAIL,

                    };
                    return new BadRequestObjectResult(result);
                };
           });

3

यहां आप एक-एक करके मॉडल की स्थिति को दिखाने के लिए जाँच कर सकते हैं

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

}


3

सी#

    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)
    {

जावास्क्रिप्ट

$.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

मेरे पास स्वीकार किए गए समाधान पैटर्न को लागू करने का एक मुद्दा था जहां कुछ मॉडल वस्तुओं के लिए मेरा ModelStateFilterहमेशा false(और बाद में एक 400) वापसी होगी actionContext.ModelState.IsValid:

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

मैं केवल JSON स्वीकार करता हूं, इसलिए मैंने एक कस्टम मॉडल बाइंडर वर्ग लागू किया:

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

जिसे मैं अपने मॉडल के माध्यम से सीधे रजिस्टर करता हूं

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.