การตรวจสอบความถูกต้องในแอปพลิเคชันแบบเลเยอร์

ฉันสงสัยว่าอะไรคือวิธีที่ดีที่สุดในการตรวจสอบข้อ จำกัด ของฐานข้อมูล (เช่น UNIQUE) ในแอปพลิเคชัน ASP.NET MVC สร้างโดยคำนึงถึง DDD โดยที่เลเยอร์พื้นฐานคือ Application Layer (บริการแอปพลิเคชัน), Domain Layer (โมเดลโดเมน) และเลเยอร์โครงสร้างพื้นฐาน (ตรรกะการคงอยู่ การบันทึก ฯลฯ)

ฉันได้ดูตัวอย่าง DDD มากมาย แต่สิ่งที่หลายตัวอย่างไม่ได้กล่าวถึงคือวิธีการตรวจสอบความถูกต้องในพื้นที่เก็บข้อมูล (ฉันคิดว่านี่คือจุดที่การตรวจสอบความถูกต้องประเภทนี้เหมาะสม) หากคุณทราบตัวอย่างใด ๆ ที่ทำสิ่งนี้ กรุณาแบ่งปัน มันจะเป็นพระคุณมาก

เฉพาะเจาะจงมากขึ้น ฉันมีคำถามสองข้อ คุณจะดำเนินการตรวจสอบจริงอย่างไร คุณจะตรวจสอบอย่างชัดเจนว่ามีชื่อลูกค้าอยู่แล้วโดยการสอบถามฐานข้อมูลหรือไม่ หรือคุณจะลองแทรกชื่อนั้นลงในฐานข้อมูลโดยตรงและตรวจพบข้อผิดพลาดหากมี (ดูยุ่งเหยิง) ? ฉันชอบอันแรกมากกว่า และหากเลือกสิ่งนี้ ควรทำใน Repository หรือควรเป็นงานของ Application Service?

เมื่อตรวจพบข้อผิดพลาด คุณจะส่งต่อข้อผิดพลาดดังกล่าวไปยัง ASP.NET MVC อย่างไร เพื่อให้ผู้ใช้ได้รับแจ้งอย่างดีเกี่ยวกับข้อผิดพลาด ควรใช้ ModelStateDictionary เพื่อให้สามารถเน้นข้อผิดพลาดบนแบบฟอร์มได้อย่างง่ายดาย

ในแอป N-Lyered โดย Microsoft Spain พวกเขาใช้อินเทอร์เฟซ IValidatableObject และการตรวจสอบคุณสมบัติที่ง่ายที่สุดจะถูกวางไว้บนเอนทิตีเอง เช่น:

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
    var validationResults = new List<ValidationResult>();

    if (String.IsNullOrWhiteSpace(this.FirstName))
        validationResults.Add(new ValidationResult(Messages.validation_CustomerFirstNameCannotBeNull, new string[] { "FirstName" }));

    return validationResults;
}

ก่อนที่เอนทิตีจะยังคงอยู่ ข้อความตรวจสอบความถูกต้องจะถูกเรียกเพื่อให้แน่ใจว่าคุณสมบัตินั้นถูกต้อง:

void SaveCustomer(Customer customer)
{
    var validator = EntityValidatorFactory.CreateValidator();

    if (validator.IsValid(customer)) //if customer is valid
    {
        _customerRepository.Add(customer);
        _customerRepository.UnitOfWork.Commit();
    }
    else
        throw new ApplicationValidationErrorsException(validator.GetInvalidMessages<Customer>(customer));
}

จากนั้นสามารถจับ ApplicationValidationErrorsException ในแอปพลิเคชัน MVC และข้อความแสดงข้อผิดพลาดในการตรวจสอบความถูกต้องสามารถแยกวิเคราะห์และแทรกลงใน ModelStateDictionary ได้

ฉันสามารถเพิ่มตรรกะการตรวจสอบทั้งหมดลงในเมธอด SaveCustomer ได้ เช่น การสืบค้นฐานข้อมูลตรวจสอบว่ามีลูกค้าอยู่แล้วโดยใช้คอลัมน์ที่กำหนด (อันที่ไม่ซ้ำ) อาจจะไม่เป็นไร แต่ฉันอยากให้ validator.IsValid (หรืออะไรที่คล้ายกัน) ทำสิ่งนี้ให้ฉัน หรือการตรวจสอบความถูกต้องจะดำเนินการอีกครั้งในเลเยอร์โครงสร้างพื้นฐาน (หากเป็นของที่นี่ ฉันไม่แน่ใจ)

คุณคิดอย่างไร? คุณจะทำอย่างไรมันได้หรือไม่? ฉันสนใจที่จะรับข้อมูลเชิงลึกเพิ่มเติมเกี่ยวกับเทคนิคการตรวจสอบความถูกต้องต่างๆ ในแอปพลิเคชันแบบเลเยอร์


วิธีแก้ปัญหาที่เป็นไปได้ #1

ในกรณีที่ตรรกะการตรวจสอบความถูกต้องไม่สามารถทำได้ในเลเยอร์การนำเสนอ (เช่นที่ Iulian Margarintescu แนะนำ) และจำเป็นต้องดำเนินการในเลเยอร์บริการ คุณจะส่งผ่านข้อผิดพลาดในการตรวจสอบความถูกต้องไปยังเลเยอร์การนำเสนอได้อย่างไร

Microsoft มีข้อเสนอแนะ ที่นี่ (ดูรายการ 5) คุณคิดอย่างไรเกี่ยวกับแนวทางดังกล่าว?


person Tommy Jakobsen    schedule 01.05.2012    source แหล่งที่มา
comment
ฉันขอแนะนำให้คุณอ่านบทวิจารณ์ของ Ayende เกี่ยวกับแอปตัวอย่าง ซึ่งประกอบด้วยหลายโพสต์ เริ่มต้น ที่นี่ ซึ่งผู้เขียนแอปตัวอย่างตอบกลับ ที่นี่ ข้อสรุปของฉันคือไม่ใช้เวลามากเกินไปกับแอปตัวอย่างนี้   -  person Marijn    schedule 02.05.2012
comment
ทิ้งปัญหาทางเทคนิคของ MS ออกไปนอกหน้าต่าง เริ่มต้นจากศูนย์ด้วย c# ล้วนๆ สร้างโปรเจ็กต์ไลบรารีคลาสแบบง่ายๆ และลองสร้างโมเดลโดเมนของคุณราวกับว่าไม่จำเป็นต้องคงอยู่ในฐานข้อมูล จากนั้นคุณจึงจะสามารถเข้าใจได้อย่างแท้จริงว่าเฟรมเวิร์กประเภทใดที่คุณต้องเพิ่มเพื่อให้รัน/ดูดี และผลกระทบที่ไม่ดีที่เฟรมเวิร์กเหล่านั้นบังคับใช้กับโค้ดเบสของคุณ เมื่อคุณเริ่มต้นด้วยสถาปัตยกรรมขนาดใหญ่โดยไม่ต้องคำนึงถึงโดเมน การจมลงไปในเขาวงกตของปริศนาที่ไร้ความหมายเป็นสิ่งที่หลีกเลี่ยงไม่ได้   -  person Arnis Lapsa    schedule 02.05.2012
comment
ฉันรู้เรื่องนั้น และใช่ ฉันใช้คำแบบนั้น ซึ่งจริงๆ แล้วไม่เป็นเช่นนั้น การใช้งานบางอย่าง เช่น หน่วยงานและพื้นที่เก็บข้อมูลได้รับแรงบันดาลใจจากตัวอย่างของพวกเขา แต่ฉันยังห่างไกลจากการใช้ส่วนประกอบทั้งหมดของพวกเขา แอปพลิเคชันของฉันเป็น C# ธรรมดามาก ยกเว้นจาก Unity, Entity Framework (DbContext) และ AutoMapper   -  person Tommy Jakobsen    schedule 02.05.2012
comment
ฉันได้ลบการกล่าวถึงแอปตัวอย่าง MS เนื่องจากไม่เกี่ยวข้องกับคำถาม   -  person Tommy Jakobsen    schedule 02.05.2012


คำตอบ (2)


คุณพูดถึง DDD แต่ DDD ยังมีอะไรมากกว่าเอนทิตีและที่เก็บข้อมูลอีกด้วย ฉันคิดว่าคุณคุ้นเคยกับหนังสือ Domain Driven Design ของ Mr Eric Evans และฉันขอแนะนำให้คุณอ่านบทเกี่ยวกับการออกแบบเชิงกลยุทธ์และบริบทที่มีขอบเขตอีกครั้ง นอกจากนี้ Mr Evans ยังมีการพูดคุยดีๆ ที่เรียกว่า "สิ่งที่ฉันได้เรียนรู้เกี่ยวกับ DDD ตั้งแต่หนังสือเล่มนี้" ซึ่งคุณสามารถพบได้ที่นี่< /ก>. การพูดคุยเกี่ยวกับ SOA, CQRS และการจัดหากิจกรรมจาก Greg Young หรือ Udi Dahan ยังมีข้อมูลมากมายเกี่ยวกับ DDD และการประยุกต์ใช้ DDD ฉันต้องเตือนคุณว่าคุณอาจค้นพบสิ่งที่จะเปลี่ยนวิธีคิดเกี่ยวกับการสมัคร DDD

ตอนนี้สำหรับคำถามของคุณเกี่ยวกับการตรวจสอบ - วิธีหนึ่งอาจเป็นการสืบค้น db (โดยใช้การโทร Ajax ที่ตรงไปยังบริการแอพ) ทันทีที่ผู้ใช้พิมพ์บางอย่างในฟิลด์ "ชื่อ" และพยายามแนะนำชื่ออื่นหาก อันที่เขาเข้าไปมีอยู่แล้ว เมื่อผู้ใช้ส่งแบบฟอร์ม ให้ลองแทรกบันทึกใน db และจัดการข้อยกเว้นคีย์ที่ซ้ำกัน (ที่ระดับพื้นที่เก็บข้อมูลหรือบริการแอป) เนื่องจากคุณได้ตรวจสอบรายการซ้ำล่วงหน้าแล้ว กรณีที่คุณได้รับข้อยกเว้นน่าจะค่อนข้างหายาก ดังนั้นข้อความ "ขออภัย โปรดลองอีกครั้ง" ที่เหมาะสมควรดำเนินการตั้งแต่นั้นมา เว้นแต่คุณจะมีผู้ใช้จำนวนมาก พวกเขาอาจจะไม่เคยเห็นเลย .

โพสต์นี้จาก Udi Dahan ยังมีข้อมูลบางอย่างเกี่ยวกับการตรวจสอบความถูกต้องที่ใกล้เข้ามาอีกด้วย โปรดจำไว้ว่านี่อาจเป็นข้อจำกัดที่คุณกำหนดให้กับธุรกิจ แทนที่จะเป็นข้อจำกัดที่ธุรกิจกำหนดกับคุณ - บางทีมันอาจจะให้คุณค่ามากขึ้นสำหรับธุรกิจในการอนุญาตให้ลูกค้าที่มีชื่อเดียวกันสามารถลงทะเบียน แทนที่จะปฏิเสธพวกเขา

โปรดจำไว้ว่า DDD ให้ความสำคัญกับธุรกิจมากกว่าเทคโนโลยี คุณสามารถทำ DDD และปรับใช้แอปของคุณเป็นชุดประกอบเดียวได้ เลเยอร์ของโค้ดไคลเอ็นต์ที่อยู่ด้านบนของบริการที่อยู่ด้านบนของเอนทิตีที่อยู่ด้านบนของพื้นที่เก็บข้อมูลที่อยู่ด้านบนของฐานข้อมูลได้ถูกนำไปใช้ในทางที่ผิดหลายครั้งในนามของการออกแบบที่ "ดี" โดยไม่มีเหตุผลว่าทำไมจึงเป็นการออกแบบที่ดี

ฉันไม่แน่ใจว่าสิ่งนี้จะตอบคำถามของคุณได้ แต่ฉันหวังว่าสิ่งนี้จะช่วยให้คุณค้นหาคำตอบได้ด้วยตัวเอง

person Iulian Margarintescu    schedule 02.05.2012
comment
ขอบคุณสำหรับคำตอบของคุณลูเลียน ฉันตระหนักดีว่า DDD เป็นมากกว่าสิ่งที่ฉันได้พูดถึงไปมาก และฉันได้อ่านหนังสือของ Evans มาหลายครั้งและเห็นคำพูดของเขาที่คุณเชื่อมโยงอยู่ คำถามของฉันเกี่ยวกับการตรวจสอบความถูกต้องมากกว่าและจะต้องดำเนินการที่ไหน . ฉันไม่ควรพูดถึง DDD เลย เพราะผู้คนมักจะออกอาการประหลาดใจ (ไม่ได้บอกว่าคุณพูด) :-) แต่ฉันยังคงเรียนรู้อยู่ และตอนนี้มันเกี่ยวกับตรรกะในการตรวจสอบความถูกต้องและตำแหน่งที่จะใส่ไว้ คุณมีคำแนะนำที่ดีให้ฉัน และฉันจะดูโพสต์ที่คุณพูดถึง ขอบคุณ! - person Tommy Jakobsen; 02.05.2012
comment
ชื่อลูกค้าเป็นตัวอย่างง่ายๆ ที่ลูกค้าสามารถจัดการได้โดยการให้บริการตามที่คุณกล่าวถึง แต่เมื่อการตรวจสอบมีความซับซ้อนมากขึ้นและในกรณีที่ไม่สามารถทำได้ในชั้นการนำเสนอ คุณจะส่งผ่านผลการตรวจสอบจากชั้นบริการไปยังชั้นการนำเสนอได้อย่างไร MS มีข้อเสนอแนะที่นี่: asp.net/mvc/tutorials/older-versions/models-(data)/ (ดูรายการ 5) คุณคิดอย่างไรเกี่ยวกับแนวทางดังกล่าว? - person Tommy Jakobsen; 02.05.2012
comment
โดยส่วนตัวแล้วฉันไม่ชอบแนวทางนั้น เพราะมันบอกเป็นนัยว่าคุณสามารถสร้างผลิตภัณฑ์ที่ไม่ถูกต้องและพึ่งพาบริการเพื่อเพิ่มตรรกะเพิ่มเติมได้ นอกจากนี้ยังบอกเป็นนัยว่าแบบจำลองนั้นเป็นจริงและแบบจำลองโดเมนโลหิตจางซึ่งหากคุณพยายามทำ DDD จะเป็นการป้องกันรูปแบบ คุณสามารถให้เลเยอร์การนำเสนอเรียกใช้บริการกับ DTO โดยเร็วที่สุด (แต่ก่อนการสร้าง AR จริง) โดยมีวัตถุประสงค์เดียวในการใช้ตรรกะการตรวจสอบ บริการสามารถส่งคืนผลการตรวจสอบได้โดยตรงและเลเยอร์การนำเสนอก็สามารถแสดงผลได้ - person Iulian Margarintescu; 03.05.2012
comment
ในขณะที่สร้าง AR หากตรวจพบสถานะที่ไม่ถูกต้อง ให้ส่งข้อยกเว้น ตรรกะการตรวจสอบจริงสามารถอยู่ในแอสเซมบลีที่ใช้ร่วมกันได้ ถ้าการทำสำเนาโค้ดเป็นปัญหา นอกจากนี้ ยังมีการตรวจสอบความถูกต้องสองประเภท ได้แก่ การตรวจสอบค่าคงที่ของ Aggregate Roos และการตรวจสอบ UI ขั้นพื้นฐาน คุณไม่สามารถและไม่ควรทำการตรวจสอบความถูกต้องคงที่ภายนอกรูทรวม เนื่องจากมีความเกี่ยวข้องอย่างแน่นหนากับขอบเขต AR การตรวจสอบ UI ขั้นพื้นฐานที่คุณควรทำโดยเร็วที่สุดเพื่อป้องกันสถานะที่ไม่ถูกต้อง หวังว่ามันจะสมเหตุสมผล - person Iulian Margarintescu; 03.05.2012

ฉันสงสัยว่าอะไรคือวิธีที่ดีที่สุดในการตรวจสอบข้อ จำกัด ของฐานข้อมูล (เช่น UNIQUE)

และถ้าเลือกแบบนี้ควรทำใน Repository หรือควรเป็นงานของ Application Service ครับ?

ขึ้นอยู่กับสิ่งที่คุณกำลังตรวจสอบ

หากเป็นการสร้างรูทรวมที่คุณพยายามตรวจสอบ - ไม่มีอะไรที่เป็นสากลมากไปกว่าแอปที่เก็บไว้ ในกรณีนี้ ฉันจะใช้การตรวจสอบความถูกต้องในพื้นที่เก็บข้อมูลโดยตรง

หากเป็นเอนทิตี ก็จะอยู่ในบริบทรูทแบบรวม ในกรณีนี้ ฉันกำลังตรวจสอบความเป็นเอกลักษณ์ของเอนทิตีในรูทรวมเองกับเอนทิตีอื่น ๆ ทั้งหมดในรูทรวมนี้โดยเฉพาะ เช่นเดียวกับวัตถุค่าในเอนทิตี/รูท

ปล. พื้นที่เก็บข้อมูลเป็นบริการ อย่ามองว่าบริการเป็นร้านค้าสากลสำหรับความจำเป็นแต่ยากที่จะตั้งชื่อรหัสให้ถูกต้อง การตั้งชื่อมีความสำคัญ เช่นเดียวกับชื่อต่างๆ เช่น Helpers, Managers, Common, Utilities ฯลฯ - สิ่งเหล่านี้ค่อนข้างไม่มีความหมาย

นอกจากนี้ คุณไม่จำเป็นต้องทำให้โค้ดของคุณเสียหายด้วยชื่อรูปแบบ: AllProducts › ProductRepository; ผู้ลงทะเบียนคำสั่งซื้อ › บริการสั่งซื้อ; order.isCompleted › IsOrderCompletedSpecification.IsSatisfiedBy.

เฉพาะเจาะจงมากขึ้น ฉันมีคำถามสองข้อ คุณจะดำเนินการตรวจสอบจริงอย่างไร? คุณจะตรวจสอบอย่างชัดเจนว่ามีชื่อลูกค้าอยู่แล้วหรือไม่โดยการสืบค้นฐานข้อมูล หรือคุณจะลองแทรกชื่อนั้นลงในฐานข้อมูลโดยตรงและตรวจพบข้อผิดพลาดหากมี (ดูยุ่งเหยิง)

ฉันจะสอบถามฐานข้อมูล แม้ว่าหากประสิทธิภาพที่สูงเป็นปัญหาและความพร้อมใช้งานของชื่อลูกค้าเป็นเพียงสิ่งเดียวที่ฐานข้อมูลควรบังคับใช้ - ฉันจะเลือกใช้ฐานข้อมูล (เดินทางไปกลับน้อยกว่า 1 ครั้ง)

เมื่อตรวจพบข้อผิดพลาด คุณจะส่งต่อไปยัง ASP.NET MVC อย่างไร เพื่อให้ผู้ใช้ได้รับแจ้งเกี่ยวกับข้อผิดพลาดอย่างดี ควรใช้ ModelStateDictionary เพื่อให้เน้นข้อผิดพลาดบนแบบฟอร์มได้อย่างง่ายดาย

โดยปกติแล้ว ไม่ใช่ความคิดที่ดีที่จะใช้ข้อยกเว้นในการควบคุมโฟลว์ของแอปพลิเคชัน แต่เนื่องจากฉันต้องการบังคับให้ UI แสดงเฉพาะสิ่งที่พร้อมใช้งานที่สามารถทำได้ ฉันแค่ส่งข้อยกเว้นในกรณีที่การตรวจสอบล้มเหลว ในเลเยอร์ UI มีตัวจัดการที่หยิบมันขึ้นมาอย่างเรียบร้อยและแยกออกมาเป็น html

นอกจากนี้ สิ่งสำคัญคือต้องเข้าใจว่าขอบเขตของคำสั่งคืออะไร (เช่น คำสั่งสั่งสินค้าอาจตรวจสอบ 2 สิ่ง - ลูกค้าไม่ใช่ลูกหนี้ และสินค้าอยู่ในร้านหรือไม่) หากคำสั่งมีการตรวจสอบความถูกต้องที่เกี่ยวข้องกันหลายรายการ ควรเชื่อมโยงสิ่งเหล่านั้นเข้าด้วยกันเพื่อให้ UI ได้รับพร้อมกัน มิฉะนั้นจะนำไปสู่ประสบการณ์ผู้ใช้ที่น่ารำคาญ (เกิดข้อผิดพลาดหลายครั้งในขณะที่พยายามสั่งซื้อผลิตภัณฑ์เวรนั้นซ้ำแล้วซ้ำอีก)

person Arnis Lapsa    schedule 03.05.2012