التحقق من صحة الكائن بناء على العوامل الخارجية (أي تخزين البيانات)

StackOverflow https://stackoverflow.com/questions/1721327

سؤال

وصف

الحل الخاص بي لديه هذه المشاريع:

  • دال = إطار الكيانات المعدلة
  • في = كائنات نقل البيانات التي يمكن التحقق من صحة أنفسهم
  • بات = خدمات طبقة العمل
  • ويب = عرض تطبيق ASP.NET MVC

DAL، BL و WEB جميع مرجع DTO وهو رائع.
عادة ما تنفذ العملية بهذه الطريقة:

  1. يتم تقديم طلب الويب على الويب
  2. ويب يحصل على dtos نشر
    • تحصل DTOS على التحقق من صحة تلقائيا عبر ActionFilter
    • أخطاء التحقق من الصحة يتم جمعها تلقائيا
  3. (التحقق من الصحة على ما يرام) مكالمات الويب في BL توفير DTOS
  4. BL يدعو DAL باستخدام DTOS (يمكن إما تجاوزها أو مجرد استخدامها)

مشكلة التحقق من صحة DTO ثم ...

تتمكن DTOs My DTOS من صحة نفسها على أساس حالتها الخاصة (قيم الخصائص "). ولكن الآن أنا عرضت مع مشكلة عندما لا يكون هذا هو الحال. أحتاج إليها للتحقق من الصحة باستخدام BL (وبالتالي DAL).

مثالي الحقيقي: سجلات المستخدم والشبكة تحصل على مستخدم DTO الذي يحصل التحقق من صحته. الجزء الإشكالي هو username تصديق. يجب التحقق من تفردها ضد مخزن البيانات.
كيف من المفترض أن أفعل هذا؟

هناك معلومات إضافية تقوم بها جميع DTOS واجهة (أي. User DTO ينفذ IUser) لأغراض IOC و TDD. كلاهما جزء من مشروع DTO..

يحاول المستحيل

  1. لا يمكنني الرجوع إلى BL في DTO لأنني سأحصل على مرجع دائري.
    Compilation error
  2. لا يمكنني إنشاء مشروع إضافي DTO.VAL من شأنه أن يشير إلى فئات DTO الجزئية وتنفيذ التحقق من الصحة هناك (مرجع BL + DTO).
    Partial classes can't span assemblies.

محتملة المحاولة

  1. إنشاء خاص ActionFilter من شأنها التحقق من صحة الكائنات ضد الظروف الخارجية. سيتم إنشاء هذا واحد في الداخل مشروع الويب وبالتالي رؤية DTO و BL التي سيتم استخدامها هنا.
  2. ضع DTOS in BL ويحافظ على واجهات DTTO ك DTOS الفعلي المشاريع الأخرى والمشاريع الأخرى وإعادة تكوين جميع التعليمات البرمجية لاستخدام الواجهات بدلا من فئات الخرسانة.
  3. لا تتعامل مع التحقق من الصحة التابعة خارجية واترك التبعيات الخارجية رمي استثناء - ربما الأسوأ حل لهذه المشكلة

ما اقتراحك؟

هل كانت مفيدة؟

المحلول 4

حل الناتج

انتهى بك المطاف باستخدام عامل تصفية Action Controller كان قادرا على التحقق من صحة الكائنات ضد العوامل الخارجية التي لا يمكن الحصول عليها من الكائن نفسه.

قمت بإنشاء عامل التصفية الذي يأخذ اسم المعلمة الإجراء للتحقق من النوع والمصادقة التي ستحصل على التحقق من صحة هذه المعلمة الخاصة. بالطبع يتعين على هذا المصدق تنفيذ واجهة معينة لجعل كل شيء قابلة لإعادة الاستخدام.

[ValidateExternalFactors("user", typeof(UserExternalValidator))]
public ActionResult Create(User user)

يحتاج Validator إلى تطبيق هذه الواجهة البسيطة

public interface IExternalValidator<T>
{
    bool IsValid(T instance);
}

إنه حل بسيط وفعال لمشكلة معقدة على ما يبدو.

نصائح أخرى

أود أن أقترح تجربة أنني قد تم التعامل معها فقط في الأسبوع الماضي أو نحو ذلك.

مرتكز على هذا الإلهام أنا أخلق DTOS التي تتحقق بشكل مختلف قليلا مع ذلك DataAnnotations نهج. عينة DTO:

public class Contact : DomainBase, IModelObject
{
    public int ID { get; set; }
    public string Name { get; set; }
    public LazyList<ContactDetail> Details { get; set; }
    public DateTime Updated { get; set; }


    protected override void ConfigureRules()
    {
        base.AddRule(new ValidationRule()
        {
            Properties = new string[] { "name" },
            Description = "A Name is required but must not exceed 300 characters in length and some special characters are not allowed",
            validator = () => this.Name.IsRequired300LenNoSpecial()
        });

        base.AddRule(new ValidationRule()
        {
            Properties = new string[] { "updated" },
            Description = "required",
            validator = () => this.Updated.IsRequired()
        });
    }
}

قد يبدو هذا أكثر عمل من DataAnnotations وبصحة جيدة، هذا هو coz هو، لكنه ليس ضخما. أعتقد أنه أكثر عرضة في الفصل (لدي بعض فئات DTO القبيحة حقا مع DataAnnotations السمات - لا يمكنك حتى رؤية الخصائص بعد الآن). وقوة المندوبين المجهولين في هذا التطبيق هو تقريبا يستحق الكتاب (لذلك أنا اكتشف).

الطبقة الأساسية:

public partial class DomainBase : IDataErrorInfo
{
    private IList<ValidationRule> _rules = new List<ValidationRule>();

    public DomainBase()
    {
        // populate the _rules collection
        this.ConfigureRules();
    }

    protected virtual void ConfigureRules()
    {
        // no rules if not overridden
    }

    protected void AddRule(ValidationRule rule)
    {
        this._rules.Add(rule);
    }





    #region IDataErrorInfo Members

    public string Error
    {
        get { return String.Empty; }    // Validation should call the indexer so return "" here
    }                                   // ..we dont need to support this property.

    public string this[string columnName]
    {
        get
        {
            // get all the rules that apply to the property being validated
            var rulesThatApply = this._rules
                .Where(r => r.Properties.Contains(columnName));

            // get a list of error messages from the rules
            StringBuilder errorMessages = new StringBuilder();
            foreach (ValidationRule rule in rulesThatApply)
                if (!rule.validator.Invoke())   // if validator returns false then the rule is broken
                    if (errorMessages.ToString() == String.Empty)
                        errorMessages.Append(rule.Description);
                    else
                        errorMessages.AppendFormat("\r\n{0}", rule.Description);

            return errorMessages.ToString();
        }
    }

    #endregion
}

ValidationRule ووظائف التحقق من الصحة:

public class ValidationRule
{
    public string[] Properties { get; set; }
    public string Description { get; set; }
    public Func<bool> validator { get; set; }
}


/// <summary>
/// These extention methods return true if the validation condition is met.
/// </summary>
public static class ValidationFunctions
{
    #region IsRequired

    public static bool IsRequired(this String str)
    {
        return !str.IsNullOrTrimEmpty();
    }

    public static bool IsRequired(this int num)
    {
        return num != 0;
    }

    public static bool IsRequired(this long num)
    {
        return num != 0;
    }

    public static bool IsRequired(this double num)
    {
        return num != 0;
    }

    public static bool IsRequired(this Decimal num)
    {
        return num != 0;
    }

    public static bool IsRequired(this DateTime date)
    {
        return date != DateTime.MinValue;
    }

    #endregion


    #region String Lengths

    public static bool IsLengthLessThanOrEqual(this String str, int length)
    {
        return str.Length <= length;
    }

    public static bool IsRequiredWithLengthLessThanOrEqual(this String str, int length)
    {
        return !str.IsNullOrTrimEmpty() && (str.Length <= length);
    }

    public static bool IsRequired300LenNoSpecial(this String str)
    {
        return !str.IsNullOrTrimEmpty() &&
            str.RegexMatch(@"^[- \r\n\\\.!:*,@$%&""?\(\)\w']{1,300}$",
                RegexOptions.Multiline) == str;
    }

    #endregion

}

إذا يبدو رمزي فوضوي جيدا، فهذا لأنني كنت أعمل فقط في نهج التحقق من الصحة لهذا الأيام القليلة الماضية. أحتاج إلى هذه الفكرة لتلبية بعض المتطلبات:

  • أحتاج إلى دعم IDataErrorInfo واجهة حتى تصرف طبقة MVC الخاصة بي تلقائيا
  • أحتاج إلى أن أكون قادرا على دعم سيناريوهات التحقق المعقدة (النقطة بأكملها من سؤالك الذي أظن): أريد أن أكون قادرا على التحقق من صحة الخصائص المتعددة على نفس الكائن (أي Startdate و QuickDate)؛ خصائص من كائنات مختلفة / متعددة مرتبطة كما أود في رسم بياني كائن؛ وحتى أشياء أخرى لم أفكر بها بعد.
  • أحتاج إلى دعم فكرة وجود خطأ في التقدم إلى أكثر من خاصية واحدة
  • كجزء من رحلة TDD و DDD الخاصة بي أريد كائنات المجال الخاصة بي لوصف المزيد من "مجال" من أساليب طبقة الخدمة الخاصة بي، لذلك يبدو أن وضع هذه الظروف المعقدة في الكائنات النموذجية (وليس DTOS) لتحقيق ذلك

هذا النهج أعتقد أنه سيحصل على ما أريد، وربما أنت كذلك.

أود أن أتصور إذا قفزت على متن الطائرة معي في هذا أننا سنكون جميلة "لأنفسنا" ولكن قد يستحق كل هذا العناء. كنت أقرأ عن قدرات التحقق من الصحة الجديدة في MVC 2 ولكن لا يزال لا تفي بقائمة الأمنيات المذكورة أعلاه دون تعديل مخصص.

أتمنى أن يساعدك هذا.

يحتوي S # ARP Architecture على معرف الأسلوب [DomainSignature] الذي يستخدم مع Valide Level Validator [Hasuniquedomainsignature] سيفعل العمل. انظر نموذج التعليمات البرمجية أدناه:

[HasUniqueDomainSignature]
public class User : Entity
{
    public User()
    {
    }

    public User(string login, string email) : this()
    {
        Login = login;
        Email = email;
    }

    [DomainSignature]
    [NotNullNotEmpty]
    public virtual string Login { get; set; }

    [DomainSignature]
    public virtual string Email { get; set; }

}

نلقي نظرة فاحصة http://www.sharparchitecture.net/

كان لدي هذه المشكلة نفسها بالضبط وبعد محاولة العثور على عمل حول أيام وأيام وأيام، انتهى بي الأمر دمج بلدي DTO و DAL و BL في مكتبة واحدة. حافظت على طبقة العرض التقديمي منفصلة. لست متأكدا مما إذا كان هذا خيارا لك أم لا. بالنسبة لي، احسب أن فرصي في تغيير متجر البيانات كانت طفيفة للغاية، وبالتالي لم تكن هناك حاجة إلى الطبقة المنفصلة حقا.

لقد قمت أيضا بتنفيذ كتلة تطبيق التحقق من صحة Microsoft لجميع صحة DTO الخاصة بي. لديهم طريقة "التحقق من الصحة" التي تتيح لك إجراء التحقق من صحة معقدة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top