আমি কীভাবে আইভিডিয়েটেটেবলঅবজেক্টটি ব্যবহার করব?


182

আমি বুঝতে পারি যে IValidatableObjectকোনও জিনিসকে এমনভাবে বৈধ করতে ব্যবহার করা হয় যা একে অপরের বিরুদ্ধে বৈশিষ্ট্যের তুলনা করতে দেয়।

আমি স্বতন্ত্র বৈশিষ্ট্য বৈধতা দেওয়ার জন্য বৈশিষ্ট্য থাকতে চাই, তবে আমি কিছু ক্ষেত্রে কিছু বৈশিষ্ট্যের ব্যর্থতা উপেক্ষা করতে চাই।

আমি কি নীচের ক্ষেত্রে এটি ভুলভাবে ব্যবহার করার চেষ্টা করছি? না হলে আমি কীভাবে এটি বাস্তবায়ন করব?

public class ValidateMe : IValidatableObject
{
    [Required]
    public bool Enable { get; set; }

    [Range(1, 5)]
    public int Prop1 { get; set; }

    [Range(1, 5)]
    public int Prop2 { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (!this.Enable)
        {
            /* Return valid result here.
             * I don't care if Prop1 and Prop2 are out of range
             * if the whole object is not "enabled"
             */
        }
        else
        {
            /* Check if Prop1 and Prop2 meet their range requirements here
             * and return accordingly.
             */ 
        }
    }
}

উত্তর:


168

প্রথমে, আমাকে সঠিক উত্সগুলিতে ইঙ্গিত করার জন্য @ পেপার 1337 কে ধন্যবাদ ... আমি নিবন্ধিত নই তাই আমি তাকে ভোট দিতে পারি না, দয়া করে অন্য কেউ যদি এটি পড়েন তবে তা করুন।

আমি যা করার চেষ্টা করেছিলাম তা কীভাবে সম্পাদন করতে হবে তা এখানে।

বৈধতাযোগ্য শ্রেণি:

public class ValidateMe : IValidatableObject
{
    [Required]
    public bool Enable { get; set; }

    [Range(1, 5)]
    public int Prop1 { get; set; }

    [Range(1, 5)]
    public int Prop2 { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        var results = new List<ValidationResult>();
        if (this.Enable)
        {
            Validator.TryValidateProperty(this.Prop1,
                new ValidationContext(this, null, null) { MemberName = "Prop1" },
                results);
            Validator.TryValidateProperty(this.Prop2,
                new ValidationContext(this, null, null) { MemberName = "Prop2" },
                results);

            // some other random test
            if (this.Prop1 > this.Prop2)
            {
                results.Add(new ValidationResult("Prop1 must be larger than Prop2"));
            }
        }
        return results;
    }
}

Validator.TryValidateProperty()যদি ব্যর্থতা বৈধতা থাকে ব্যবহার করে ফলাফল সংগ্রহে যুক্ত হবে। যদি কোনও ব্যর্থ বৈধতা না থাকে তবে ফলাফল সংগ্রহের সাথে কিছুই যুক্ত হবে না যা সাফল্যের ইঙ্গিত।

বৈধতা করছেন:

    public void DoValidation()
    {
        var toValidate = new ValidateMe()
        {
            Enable = true,
            Prop1 = 1,
            Prop2 = 2
        };

        bool validateAllProperties = false;

        var results = new List<ValidationResult>();

        bool isValid = Validator.TryValidateObject(
            toValidate,
            new ValidationContext(toValidate, null, null),
            results,
            validateAllProperties);
    }

validateAllPropertiesএই পদ্ধতিটি কাজ করার জন্য ভুয়াতে সেট করা গুরুত্বপূর্ণ । যখন validateAllPropertiesমিথ্যা হয় কেবল কোনও [Required]বৈশিষ্ট্যযুক্ত বৈশিষ্ট্যগুলি চেক করা হয়। এটি IValidatableObject.Validate()পদ্ধতিটি শর্তযুক্ত বৈধতাগুলি পরিচালনা করতে দেয় ।


আমি এমন দৃশ্যের কথা ভাবতে পারি না যেখানে আমি এটি ব্যবহার করব। আপনি কোথায় এটি ব্যবহার করবেন তার একটি উদাহরণ দিতে পারেন?
স্টিফান ভাসিলজেভিক

আপনার টেবিলে যদি ট্র্যাকিং কলামগুলি থাকে (যেমন এটি ব্যবহারকারী যিনি এটি তৈরি করেছেন)। এটি ডেটাবেজে প্রয়োজন তবে এটিকে পপুলেশন করার জন্য আপনি প্রসঙ্গে সংরক্ষণাগারগুলিতে পদক্ষেপ নিন (এটি নির্ধারণ করার জন্য বিকাশকারীদের মনে রাখার প্রয়োজনীয়তা দূর করে)। আপনি অবশ্যই সংরক্ষণের আগে বৈধতা প্রমাণ করবেন। সুতরাং আপনি প্রয়োজনীয় হিসাবে "স্রষ্টা" কলামটি চিহ্নিত করেন না তবে অন্যান্য সমস্ত কলাম / বৈশিষ্ট্যের বিরুদ্ধে বৈধতা দিন।
ধাতবফিনিক্স

এই সমাধানটির সমস্যাটি হ'ল এখন আপনি নিজের অবজেক্টটি সঠিকভাবে যাচাই করার জন্য কলারের উপর নির্ভরশীল।
কোকোগজা

এই উত্তরটি বাড়ানোর জন্য, বৈধতার বৈশিষ্ট্যযুক্ত সমস্ত বৈশিষ্ট্য সন্ধান করতে কেউ প্রতিবিম্ব ব্যবহার করতে পারে, তারপরে ট্রাইভালিডেটপ্রোপার্টি কল করুন।
পল চেরনোচ

78

ভ্যালিডেটরের সাথে বৈধকরণের বিষয়গুলি এবং সম্পত্তিগুলিতে জেফ হ্যান্ডলির ব্লগ পোস্টের উদ্ধৃতি :

কোনও বস্তুর বৈধতা দেওয়ার সময়, নিম্নলিখিত প্রক্রিয়াটি ভ্যালিডেটরে প্রয়োগ করা হয় Vভালিডেটঅবজেক্ট:

  1. সম্পত্তি-স্তরের বৈশিষ্ট্যগুলি বৈধ করুন
  2. যদি কোনও বৈধকারী অবৈধ হয় তবে ব্যর্থতা (গুলি) ফেরত বৈধতা বৈধতা
  3. অবজেক্ট-স্তরের বৈশিষ্ট্যগুলি বৈধ করুন
  4. যদি কোনও বৈধকারী অবৈধ হয় তবে ব্যর্থতা (গুলি) ফেরত বৈধতা বৈধতা
  5. যদি ডেস্কটপ ফ্রেমওয়ার্কে থাকে এবং অবজেক্টটি আইভিডিটিয়েটেবলবজেক্ট প্রয়োগ করে, তবে এর বৈধতা পদ্ধতিটি কল করুন এবং কোনও ব্যর্থতা (গুলি) ফিরিয়ে দিন

এটি ইঙ্গিত দেয় যে আপনি যা করার চেষ্টা করছেন তা বাক্সের বাইরে কাজ করবে না কারণ বৈধতাটি # 2 পদক্ষেপে বাতিল হয়ে যাবে। আপনি বিল্ট-ইনগুলি থেকে উত্তরাধিকারসূত্রে এমন বৈশিষ্ট্য তৈরি করার চেষ্টা করতে পারেন এবং তাদের সাধারণ বৈধতা কার্যকর করার আগে নির্দিষ্টভাবে কোনও সক্ষম সম্পত্তি (ইন্টারফেসের মাধ্যমে) উপস্থিতির জন্য পরীক্ষা করতে পারেন। বিকল্পভাবে, আপনি Validateপদ্ধতিটিতে সত্তাকে বৈধতা দেওয়ার জন্য সমস্ত যুক্তি যুক্ত করতে পারেন ।


36

কেবল কয়েকটি পয়েন্ট যোগ করতে:

কারণ Validate()পদ্ধতিটির স্বাক্ষরটি প্রত্যাবর্তন করে IEnumerable<>, যা yield returnঅলসভাবে ফলাফল উত্পন্ন করতে ব্যবহার করা যেতে পারে - বৈধতা যাচাইয়ের কিছু যদি আইও বা সিপিইউ নিবিড় হয় তবে এটি উপকারী।

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
    if (this.Enable)
    {
        // ...
        if (this.Prop1 > this.Prop2)
        {
            yield return new ValidationResult("Prop1 must be larger than Prop2");
        }

এছাড়াও, আপনি যদি ব্যবহার করছেন MVC ModelState, আপনি বৈধতা ফলাফল ব্যর্থতা ModelStateনিম্নলিখিত হিসাবে এন্ট্রি রূপান্তর করতে পারেন (আপনি যদি একটি কাস্টম মডেল বাইন্ডারে বৈধতা যাচ্ছেন এটি কার্যকর হতে পারে ):

var resultsGroupedByMembers = validationResults
    .SelectMany(vr => vr.MemberNames
                        .Select(mn => new { MemberName = mn ?? "", 
                                            Error = vr.ErrorMessage }))
    .GroupBy(x => x.MemberName);

foreach (var member in resultsGroupedByMembers)
{
    ModelState.AddModelError(
        member.Key,
        string.Join(". ", member.Select(m => m.Error)));
}

সুন্দর! বৈধতা পদ্ধতিতে গুণাবলী এবং প্রতিবিম্ব ব্যবহার করে কি সার্থক হয়?
শালচ

4

আমি বৈধতার জন্য একটি সাধারণ ব্যবহার বিমূর্ত শ্রেণি প্রয়োগ করেছি

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace App.Abstractions
{
    [Serializable]
    abstract public class AEntity
    {
        public int Id { get; set; }

        public IEnumerable<ValidationResult> Validate()
        {
            var vResults = new List<ValidationResult>();

            var vc = new ValidationContext(
                instance: this,
                serviceProvider: null,
                items: null);

            var isValid = Validator.TryValidateObject(
                instance: vc.ObjectInstance,
                validationContext: vc,
                validationResults: vResults,
                validateAllProperties: true);

            /*
            if (true)
            {
                yield return new ValidationResult("Custom Validation","A Property Name string (optional)");
            }
            */

            if (!isValid)
            {
                foreach (var validationResult in vResults)
                {
                    yield return validationResult;
                }
            }

            yield break;
        }


    }
}

1
আমি নামকরা প্যারামিটারগুলি ব্যবহার করার স্টাইলটি পছন্দ করি, কোড পড়তে আরও সহজ করে তোলে।
ড্রিজিন

0

গৃহীত উত্তরের সাথে সমস্যাটি হ'ল এটি এখন অবজেক্টের সঠিকভাবে যাচাই করার জন্য কলারের উপর নির্ভর করে। আমি হয় রেঞ্জএট্রিবিউটটি সরিয়ে ভ্যালিডেট পদ্ধতির অভ্যন্তরে পরিসীমা বৈধতা করব বা আমি একটি কাস্টম অ্যাট্রিবিউট সাবক্লাসিং রেঞ্জএট্রিবিউট তৈরি করব যা কনস্ট্রাক্টরের উপর যুক্তি হিসাবে প্রয়োজনীয় সম্পত্তির নাম নেয়।

উদাহরণ স্বরূপ:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
class RangeIfTrueAttribute : RangeAttribute
{
    private readonly string _NameOfBoolProp;

    public RangeIfTrueAttribute(string nameOfBoolProp, int min, int max) : base(min, max)
    {
        _NameOfBoolProp = nameOfBoolProp;
    }

    public RangeIfTrueAttribute(string nameOfBoolProp, double min, double max) : base(min, max)
    {
        _NameOfBoolProp = nameOfBoolProp;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var property = validationContext.ObjectType.GetProperty(_NameOfBoolProp);
        if (property == null)
            return new ValidationResult($"{_NameOfBoolProp} not found");

        var boolVal = property.GetValue(validationContext.ObjectInstance, null);

        if (boolVal == null || boolVal.GetType() != typeof(bool))
            return new ValidationResult($"{_NameOfBoolProp} not boolean");

        if ((bool)boolVal)
        {
            return base.IsValid(value, validationContext);
        }
        return null;
    }
}

0

আমি কোকজার উত্তরটি পছন্দ করেছিকলিং বেসটি ব্যতীত এইভিডির ফলে স্ট্যাক ওভারফ্লো ব্যতিক্রম ঘটল কারণ এটি ইসভিলাল পদ্ধতিতে পুনরায় প্রবেশ করবে। সুতরাং আমি এটিকে নির্দিষ্ট ধরণের বৈধতার জন্য হিসাবে সংশোধন করেছি, আমার ক্ষেত্রে এটি কোনও ইমেল ঠিকানার জন্য।

[AttributeUsage(AttributeTargets.Property)]
class ValidEmailAddressIfTrueAttribute : ValidationAttribute
{
    private readonly string _nameOfBoolProp;

    public ValidEmailAddressIfTrueAttribute(string nameOfBoolProp)
    {
        _nameOfBoolProp = nameOfBoolProp;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (validationContext == null)
        {
            return null;
        }

        var property = validationContext.ObjectType.GetProperty(_nameOfBoolProp);
        if (property == null)
        {
            return new ValidationResult($"{_nameOfBoolProp} not found");
        }

        var boolVal = property.GetValue(validationContext.ObjectInstance, null);

        if (boolVal == null || boolVal.GetType() != typeof(bool))
        {
            return new ValidationResult($"{_nameOfBoolProp} not boolean");
        }

        if ((bool)boolVal)
        {
            var attribute = new EmailAddressAttribute {ErrorMessage = $"{value} is not a valid e-mail address."};
            return attribute.GetValidationResult(value, validationContext);
        }
        return null;
    }
}

এটি আরও ভাল কাজ করে! এটি ক্রাশ হয় না এবং একটি দুর্দান্ত ত্রুটি বার্তা উত্পন্ন করে। আশা করি এটি কাউকে সাহায্য করবে!


0

আইভালিডেট সম্পর্কে আমি যে জিনিসটি পছন্দ করি না তা হ'ল এটি কেবল সমস্ত অন্যান্য বৈধতার পরে চলবে।
অতিরিক্তভাবে, কমপক্ষে আমাদের সাইটে এটি সংরক্ষণের চেষ্টা চলাকালীন আবার চলবে। আমি আপনাকে কেবল একটি ফাংশন তৈরি করতে এবং এতে আপনার সমস্ত বৈধকরণ কোডটি রাখার পরামর্শ দেব। বিকল্প হিসাবে ওয়েবসাইটগুলির জন্য, মডেলটি তৈরি হওয়ার পরে আপনার নিজের "বিশেষ" বৈধতা নিয়ন্ত্রণকারীর মধ্যে থাকতে পারে। উদাহরণ:

 public ActionResult Update([DataSourceRequest] DataSourceRequest request, [Bind(Exclude = "Terminal")] Driver driver)
    {

        if (db.Drivers.Where(m => m.IDNumber == driver.IDNumber && m.ID != driver.ID).Any())
        {
            ModelState.AddModelError("Update", string.Format("ID # '{0}' is already in use", driver.IDNumber));
        }
        if (db.Drivers.Where(d => d.CarrierID == driver.CarrierID
                                && d.FirstName.Equals(driver.FirstName, StringComparison.CurrentCultureIgnoreCase)
                                && d.LastName.Equals(driver.LastName, StringComparison.CurrentCultureIgnoreCase)
                                && (driver.ID == 0 || d.ID != driver.ID)).Any())
        {
            ModelState.AddModelError("Update", "Driver already exists for this carrier");
        }

        if (ModelState.IsValid)
        {
            try
            {
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.