ปิดใช้งานแอตทริบิวต์การตรวจสอบที่จำเป็นภายใต้สถานการณ์บางอย่าง


138

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

มีปัญหาเกี่ยวกับวิธีแก้ไขปัญหานี้หรือไม่?

แก้ไข:
และใช่การตรวจสอบลูกค้าเป็นปัญหาที่นี่เพราะมันจะไม่อนุญาตให้พวกเขาส่งแบบฟอร์มโดยไม่ต้องป้อนค่า


3
+1 ดี Q. น่าจะพูดถึงการตรวจสอบลูกค้าที่นี่ ทางเลือกหนึ่งคือการลบRequiredAttrทั้งหมดและทำการตรวจสอบฝั่งเซิร์ฟเวอร์เมื่อคุณต้องการ แต่สิ่งนี้จะยุ่งยากกับลูกค้า
gideon

4
คะแนนสำหรับทุกคนที่ครอบคลุมการปิดใช้งานบางฟิลด์จากการตรวจสอบลูกค้า (ไม่ลบการอ้างอิงถึงการตรวจสอบ jQuery)
gideon

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

เนื่องจากค่าเหล่านี้ได้ถูกแฮชแล้วเช่นรหัสผ่านและคำตอบเพื่อความปลอดภัยดังนั้นหากพวกเขาป้อนค่าใหม่ในแบบฟอร์มการแก้ไขฉันต้องการแฮชค่าใหม่อีกครั้งก่อนที่จะแทรก แต่ฉันยังต้องการให้ตัวเลือกว่างเปล่า เรียงลำดับของสิ่งต่าง ๆ
Alex Hope O'Connor

1
@gideon: ดูคำตอบของ Adrian Smith: stackoverflow.com/a/9781066/114029
Leniel Maccaferri

คำตอบ:


76

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

public UpdateViewView
{
    [Required]
    public string Id { get; set; }

    ... some other properties
}

public class InsertViewModel
{
    public string Id { get; set; }

    ... some other properties
}

ซึ่งจะใช้ในการดำเนินการควบคุมที่เกี่ยวข้อง:

[HttpPost]
public ActionResult Update(UpdateViewView model)
{
    ...
}

[HttpPost]
public ActionResult Insert(InsertViewModel model)
{
    ...
}

ไม่จริงเสมอไปถ้าคุณมีบูลีน / บิตที่ไม่สามารถใช้ได้ แต่จริงๆไม่ได้สร้างความแตกต่างเพราะมันจะจบลงจริงหรือเท็จ ฉันมี CSS เพื่อเน้นฟิลด์ที่จำเป็นและมันไฮไลต์เท็จรายการ CheckBoxFor โซลูชันของฉัน: $ ("# IsValueTrue") removeAttr ("จำเป็นต้องใช้ data-val");
Robert Koch

ในการอัปเดตโดยทั่วไปเรามี (คอลเลกชัน FormCollection) โปรดอธิบายว่าคุณใช้โมเดลเป็นพารามิเตอร์ได้อย่างไร
Raj Kumar

4
ไม่เรามักจะไม่มีUpdate(FormCollection collection)อย่างน้อยฉันก็ไม่เคยทำ ฉันมักจะกำหนดและใช้รูปแบบการดูเฉพาะUpdate(UpdateViewView model)เสมอ:
ดารินทร์ดิมิทรอฟ

ไม่อนุญาตให้ใช้วิธีการมากเกินไปกับการกระทำ HTTP เดียวกันดังนั้นสำหรับฉันดูเหมือนว่าจะไม่ทำงาน ฉันพลาดอะไรไปรึเปล่า?
e11s

@edgi ไม่คุณไม่พลาดอะไรเลย มันเป็นความผิดพลาดในโพสต์ของฉัน Insertวิธีการดำเนินการที่สองเห็นได้ชัดว่าควรจะเรียกว่า ขอบคุณที่ชี้นำสิ่งนี้
ดารินทร์ดิมิทรอฟ

55

หากคุณต้องการปิดใช้งานการตรวจสอบความถูกต้องสำหรับเขตข้อมูลเดียวในฝั่งไคลเอ็นต์คุณสามารถแทนที่แอตทริบิวต์การตรวจสอบความถูกต้องดังต่อไปนี้:

@Html.TexBoxFor(model => model.SomeValue, 
                new Dictionary<string, object> { { "data-val", false }})

20
สิ่งที่ทำงานสำหรับฉันผ่านทาง jQuery: $ ("# SomeValue") removeAttr ("data-val-required");
Robert Koch

6
ฉันชอบวิธีการนี้ แต่ฉันต้องการวิเคราะห์แอตทริบิวต์การตรวจสอบแบบฟอร์มอีกครั้งโดยใช้: $ ('ฟอร์ม') removeData ('unobtrusiveValidation'); $ ( 'รูปแบบ') removeData ( 'ตรวจสอบ'). $ .validator.unobtrusive.parse ('ตัวเลือกสำหรับแบบฟอร์มของคุณ');
Yannick Smits

15
@Html.TexBoxFor(model => model.SomeValue, new { data_val = false })- ง่ายต่อการอ่าน IMO
eth0

ฉันชอบวิธีการนี้ส่วนใหญ่เพื่อให้ฉันสามารถควบคุมแต่ละฟิลด์ได้ดี แต่คุณสามารถเพิ่มเพื่อยกเลิก ModelState.IsValid เมื่อส่งข้อมูลเพื่อบันทึกโดย POST อาจทำให้เกิดความเสี่ยง?
Felipe FMMobile

4
หากคุณต้องการปิดการใช้งานผ่าน jQuery:$(".search select").attr('data-val', false);
Leniel Maccaferri

40

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

นี่คือคำแนะนำของฉัน:

public class InsertModel
{
    [Display(...)]
    public virtual string ID { get; set; }

    ...Other properties
}

public class UpdateModel : InsertModel
{
    [Required]
    public override string ID
    {
        get { return base.ID; }
        set { base.ID = value; }
    }
}

ด้วยวิธีนี้คุณไม่ต้องกังวลกับการตรวจสอบฝั่งไคลเอ็นต์ / เซิร์ฟเวอร์กรอบงานจะทำงานตามที่ควรจะเป็น นอกจากนี้หากคุณกำหนด[Display]แอตทริบิวต์ในคลาสพื้นฐานคุณไม่จำเป็นต้องกำหนดใหม่ในUpdateModelแอตทริบิวต์บนชั้นฐานที่คุณไม่ได้ที่จะกำหนดไว้ในของคุณ

และคุณยังสามารถใช้คลาสเหล่านี้ได้ในลักษณะเดียวกัน:

[HttpPost]
public ActionResult Update(UpdateModel model)
{
    ...
}

[HttpPost]
public ActionResult Insert(InsertModel model)
{
    ...
}

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

ฉันคิดว่าบางสิ่งเช่นนี้เช่นกันแม้ว่าฉันจะมี viewModel ที่มีวัตถุ 'Project' ที่มีหลายคุณลักษณะและฉันต้องการเพียงหนึ่งในคุณสมบัติเหล่านี้ที่ได้รับการตรวจสอบภายใต้สถานการณ์บางอย่าง ฉันไม่คิดว่าฉันสามารถแทนที่คุณลักษณะของวัตถุได้ใช่ไหม คำแนะนำใด ๆ?
vincent de g

คุณไม่สามารถแทนที่แอตทริบิวต์ คลาสฐานควรมีแอตทริบิวต์ทั่วไปสำหรับคลาสย่อยทั้งหมดเท่านั้น จากนั้นคลาสย่อยของคุณควรกำหนดคุณลักษณะที่ต้องการ
PhilDulac

1
โซลูชันที่หรูหราที่สุดใช้ซ้ำได้และชัดเจน การจำลองแบบไม่ดี ความแตกต่างเป็นวิธี +1
T-moty

ในกรณีของฉันคลาสฐานมีคุณสมบัติที่ต้องการและฉันต้องการทำให้มันไม่จำเป็นในชั้นผู้ปกครองของฉัน เป็นไปได้หรือไม่หากไม่มีรุ่นสองชุด?
Alexey Strakh

27

คุณสามารถลบการตรวจสอบความถูกต้องทั้งหมดออกจากคุณสมบัติด้วยสิ่งต่อไปนี้ในการดำเนินการควบคุมของคุณ

ModelState.Remove<ViewModel>(x => x.SomeProperty);

@ความคิดเห็นของเอียนเกี่ยวกับ MVC5

ต่อไปนี้ยังคงเป็นไปได้

ModelState.Remove("PropertyNameInModel");

บิตที่น่ารำคาญที่คุณสูญเสียการพิมพ์คงที่ด้วย API ที่อัปเดต คุณสามารถบรรลุสิ่งที่คล้ายกับวิธีการแบบเก่าโดยการสร้างตัวอย่างของ HTML ผู้ช่วยและการใช้NameExtensions วิธี


ยกเว้น ... ไม่มีวิธีการModelStateที่ตรงกับลายเซ็นนั้น ไม่ได้อยู่ใน MVC 5 อย่างน้อย
Ian Kemp

คำถามไม่ได้เป็นวิธีการลบการตรวจสอบทั้งหมด มันเป็นวิธีการลบการตรวจสอบสนามที่จำเป็น คุณอาจต้องการทำสิ่งนี้ในขณะที่ออกจากกฎการตรวจสอบอื่น ๆ
Richard

15

ฝั่งไคลเอ็นต์ สำหรับปิดใช้งานการตรวจสอบความถูกต้องของฟอร์มตัวเลือกหลายตัวจากการวิจัยของฉันได้รับด้านล่าง หวังว่าหนึ่งในนั้นจะได้ผลสำหรับคุณ

ตัวเลือกที่ 1

ฉันชอบสิ่งนี้และมันใช้งานได้อย่างสมบูรณ์แบบสำหรับฉัน

(function ($) {
    $.fn.turnOffValidation = function (form) {
        var settings = form.validate().settings;

        for (var ruleIndex in settings.rules) {
            delete settings.rules[ruleIndex];
        }
    };
})(jQuery); 

และกล่าวอ้างเหมือน

$('#btn').click(function () {
    $(this).turnOffValidation(jQuery('#myForm'));
});

ตัวเลือก 2

$('your selector here').data('val', false);
$("form").removeData("validator");
$("form").removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse("form");

ตัวเลือก 3

var settings = $.data($('#myForm').get(0), 'validator').settings;
settings.ignore = ".input";

ตัวเลือก 4

 $("form").get(0).submit();
 jQuery('#createForm').unbind('submit').submit();

ตัวเลือก 5

$('input selector').each(function () {
    $(this).rules('remove');
});

ฝั่งเซิร์ฟเวอร์

สร้างแอตทริบิวต์และทำเครื่องหมายวิธีการกระทำของคุณด้วยแอตทริบิวต์นั้น ปรับแต่งสิ่งนี้เพื่อปรับให้เข้ากับความต้องการเฉพาะของคุณ

[AttributeUsage(AttributeTargets.All)]
public class IgnoreValidationAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var modelState = filterContext.Controller.ViewData.ModelState;

        foreach (var modelValue in modelState.Values)
        {
            modelValue.Errors.Clear();
        }
    }
}

มีการอธิบายวิธีการที่ดีกว่าที่นี่เปิดใช้งาน / ปิดใช้งานการตรวจสอบความถูกต้องฝั่งเซิร์ฟเวอร์ mvc แบบไดนามิก


$ ('input selector'). แต่ละอัน (function () {$ (this) .rules ('remove');}); ช่วยฉัน
Sachin Pakale

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

14

โดยส่วนตัวแล้วฉันมักจะใช้วิธีการที่ดารินดิมิทรอฟแสดงในโซลูชันของเขา สิ่งนี้จะช่วยให้คุณสามารถใช้วิธีการเพิ่มความคิดเห็นด้วยการตรวจสอบความถูกต้องและมีแอตทริบิวต์ข้อมูลแยกต่างหากในแต่ละ ViewModel ที่สอดคล้องกับภารกิจในมือ เพื่อลดปริมาณของการทำงานสำหรับการคัดลอกระหว่างรูปแบบและ Viewmodel คุณควรดูที่ AutoMapper หรือValueInjecter ทั้งคู่มีจุดแข็งของตนเองดังนั้นตรวจสอบทั้งคู่

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

ValidationResult ประกอบด้วยข้อความแสดงข้อผิดพลาดและรายการสตริงที่มีชื่อเขตข้อมูล ข้อความแสดงข้อผิดพลาดจะปรากฏที่ตำแหน่งใกล้กับช่องป้อนข้อความ

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
  if( NumberField < 0 )
  {
    yield return new ValidationResult( 
        "Don't input a negative number", 
        new[] { "NumberField" } );
  }

  if( NumberField > 100 )
  {
    yield return new ValidationResult( 
        "Don't input a number > 100", 
        new[] { "NumberField" } );
  }

  yield break;
}

เราขอสิ่งนี้ทางฝั่งลูกค้าได้ไหม
มูฮัมหมัด Adeel Zahid

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

7

วิธีที่สะอาดที่สุดที่นี่ฉันเชื่อว่ากำลังจะปิดการใช้งานการตรวจสอบฝั่งไคลเอ็นต์ของคุณและในฝั่งเซิร์ฟเวอร์คุณจะต้อง:

  1. ModelState ["SomeField"]. Errors.Clear (ในตัวควบคุมของคุณหรือสร้างตัวกรองการกระทำเพื่อลบข้อผิดพลาดก่อนที่จะเรียกใช้รหัสตัวควบคุม)
  2. เพิ่ม ModelState.AddModelError จากรหัสคอนโทรลเลอร์ของคุณเมื่อคุณตรวจพบการละเมิดปัญหาที่ตรวจพบของคุณ

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


1
นี่คือสิ่งที่ฉันต้องการ ฉันมีหนึ่งมุมมองและการกระทำที่แตกต่างกันเกิดขึ้นในมุมมองนี้ดังนั้นฉันจึงไม่สามารถใช้ ViewModels ที่แตกต่างกันได้ งานนี้เหมือนมีเสน่ห์
ggderas

6

นี่เป็นคำตอบของคนอื่นในความคิดเห็น ... แต่ควรเป็นคำตอบจริง:

$("#SomeValue").removeAttr("data-val-required")

ทดสอบใน MVC 6 ด้วยฟิลด์ที่มี[Required]แอตทริบิวต์

คำตอบถูกขโมยจากhttps://stackoverflow.com/users/73382/robด้านบน


1
แล้วการตรวจสอบฝั่งเซิร์ฟเวอร์ล่ะ
T-moty

ModelState.Remove ใช่ไหม? สำหรับฉันแล้วปัญหาก็คือฉันมีเอนทิตีที่สองที่รวมอยู่ในโมเดลของฉัน ... หลักที่ฉันต้องการตรวจสอบความถูกต้อง แต่ที่รองไม่ต้องการการตรวจสอบในหน้านั้น ... ดังนั้นภายใต้สถานการณ์นี้ จำเป็นต้องใช้ JQuery เท่านั้น
Mike_Matthews_II

ฉันคิดว่าลิงก์เสียดังนั้นโปรดแก้ไข นี่เป็นคำตอบบางส่วน
T-moty

มันแปลกที่คุณพูดว่ามันใช้งานได้ใน MVC6 (ฉันยังไม่มีตัวเลือกในการทดสอบกับ MVC6 ในปัจจุบัน) แต่ใช้ไม่ได้กับ MVC4 ที่ฉันใช้อยู่ในปัจจุบัน
eaglei22

คำถามสำหรับ MVC / C # - ไม่ใช่ JS คำตอบจะไม่ทำงานฝั่งเซิร์ฟเวอร์
mtbennett

2

ฉันมีปัญหานี้เมื่อฉันสร้างมุมมองแก้ไขสำหรับโมเดลของฉันและฉันต้องการอัพเดตเพียงหนึ่งฟิลด์

วิธีแก้ปัญหาของฉันสำหรับวิธีที่ง่ายที่สุดคือทำให้ทั้งสองฟิลด์ใช้:

 <%: Html.HiddenFor(model => model.ID) %>
 <%: Html.HiddenFor(model => model.Name)%>
 <%: Html.HiddenFor(model => model.Content)%>
 <%: Html.TextAreaFor(model => model.Comments)%>

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

ASP.NET MVC 3 Entity


1

AFAIK คุณไม่สามารถลบแอททริบิวตอนรันไทม์ แต่เปลี่ยนค่าของพวกเขา (เช่น: อ่านอย่างเดียวจริง / เท็จ) ดูสิ่งที่คล้ายกันที่นี่ เป็นอีกวิธีหนึ่งในการทำสิ่งที่คุณต้องการโดยไม่ต้องยุ่งกับคุณลักษณะฉันจะไปกับ ViewModel สำหรับการกระทำเฉพาะของคุณเพื่อให้คุณสามารถแทรกตรรกะทั้งหมดโดยไม่ทำลายตรรกะที่จำเป็นโดยตัวควบคุมอื่น ๆ หากคุณพยายามที่จะรับตัวช่วยสร้างบางอย่าง (ฟอร์มหลายขั้นตอน) คุณสามารถทำให้เป็นอันดับเขตข้อมูลที่คอมไพล์แล้วและ TempData นำพวกเขาไปตามขั้นตอนของคุณ (สำหรับความช่วยเหลือในการดีซีเรียลไลซ์ซีเรียลไลซ์คุณสามารถใช้ฟิวเจอร์ส MVC ได้ )


1

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

public UpdateViewView
{
    [Required]
    public Guid? Id { get; set; }
    [Required]
    public string Name { get; set; }
    [Required]
    public int? Age { get; set; }
    [Required]
    public bool? IsApproved { get; set; }
    //... some other properties
}

1

ในฐานะของ MVC 5 global.asaxนี้สามารถทำได้อย่างง่ายดายโดยการเพิ่มนี้ของคุณ

DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;

1

ฉันกำลังมองหาวิธีแก้ปัญหาที่ฉันสามารถใช้โมเดลเดียวกันสำหรับการแทรกและอัปเดตในเว็บ API ในสถานการณ์ของฉันนี่คือเนื้อหาของร่างกายเสมอ [Requiered]แอตทริบิวต์จะต้องข้ามถ้ามันเป็นวิธีการปรับปรุง ในโซลูชันของฉันคุณวางแอตทริบิวต์[IgnoreRequiredValidations]เหนือวิธี นี่คือดังนี้:

public class WebServiceController : ApiController
{
    [HttpPost]
    public IHttpActionResult Insert(SameModel model)
    {
        ...
    }

    [HttpPut]
    [IgnoreRequiredValidations]
    public IHttpActionResult Update(SameModel model)
    {
        ...
    }

    ...

ต้องทำอะไรอีก BodyModelValidator ของตัวเองจะต้องสร้างและเพิ่มเมื่อเริ่มต้น นี่คือ HttpConfiguration และมีลักษณะดังนี้:config.Services.Replace(typeof(IBodyModelValidator), new IgnoreRequiredOrDefaultBodyModelValidator());

using Owin;
using your_namespace.Web.Http.Validation;

[assembly: OwinStartup(typeof(your_namespace.Startup))]

namespace your_namespace
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            Configuration(app, new HttpConfiguration());
        }

        public void Configuration(IAppBuilder app, HttpConfiguration config)
        {
            config.Services.Replace(typeof(IBodyModelValidator), new IgnoreRequiredOrDefaultBodyModelValidator());
        }

        ...

BodyModelValidator ของฉันเองได้มาจาก DefaultBodyModelValidator และฉันคิดว่าฉันต้องแทนที่ 'ShallowValidate' methode ในการแทนที่นี้ฉันกรองตัวตรวจสอบรูปแบบ requierd และตอนนี้คลาส IgnoreRequiredOrDefaultBodyModelValidator และคลาส IgnoreRequiredValidations

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web.Http.Controllers;
using System.Web.Http.Metadata;
using System.Web.Http.Validation;

namespace your_namespace.Web.Http.Validation
{
    public class IgnoreRequiredOrDefaultBodyModelValidator : DefaultBodyModelValidator
    {
        private static ConcurrentDictionary<HttpActionBinding, bool> _ignoreRequiredValidationByActionBindingCache;

        static IgnoreRequiredOrDefaultBodyModelValidator()
        {
            _ignoreRequiredValidationByActionBindingCache = new ConcurrentDictionary<HttpActionBinding, bool>();
        }

        protected override bool ShallowValidate(ModelMetadata metadata, BodyModelValidatorContext validationContext, object container, IEnumerable<ModelValidator> validators)
        {
            var actionContext = validationContext.ActionContext;

            if (RequiredValidationsIsIgnored(actionContext.ActionDescriptor.ActionBinding))
                validators = validators.Where(v => !v.IsRequired);          

            return base.ShallowValidate(metadata, validationContext, container, validators);
        }

        #region RequiredValidationsIsIgnored
        private bool RequiredValidationsIsIgnored(HttpActionBinding actionBinding)
        {
            bool ignore;

            if (!_ignoreRequiredValidationByActionBindingCache.TryGetValue(actionBinding, out ignore))
                _ignoreRequiredValidationByActionBindingCache.TryAdd(actionBinding, ignore = RequiredValidationsIsIgnored(actionBinding.ActionDescriptor as ReflectedHttpActionDescriptor));

            return ignore;
        }

        private bool RequiredValidationsIsIgnored(ReflectedHttpActionDescriptor actionDescriptor)
        {
            if (actionDescriptor == null)
                return false;

            return actionDescriptor.MethodInfo.GetCustomAttribute<IgnoreRequiredValidationsAttribute>(false) != null;
        } 
        #endregion
    }

    [AttributeUsage(AttributeTargets.Method, Inherited = true)]
    public class IgnoreRequiredValidationsAttribute : Attribute
    {

    }
}

แหล่งที่มา:


0

หากคุณไม่ต้องการใช้ ViewModel อื่นคุณสามารถปิดใช้งานการตรวจสอบความถูกต้องของไคลเอ็นต์ในมุมมองและลบการตรวจสอบความถูกต้องบนเซิร์ฟเวอร์สำหรับคุณสมบัติเหล่านั้นที่คุณต้องการเพิกเฉย โปรดตรวจสอบคำตอบนี้เพื่อรับคำอธิบายเพิ่มเติมhttps://stackoverflow.com/a/15248790/1128216


0

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

public class ValidateAttribute : ActionFilterAttribute
{
    public string Exclude { get; set; }
    public string Base { get; set; }
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        if (!string.IsNullOrWhiteSpace(this.Exclude))
        {
            string[] excludes = this.Exclude.Split(',');
            foreach (var exclude in excludes)
            {
                actionContext.ModelState.Remove(Base + "." + exclude);
            }
        }
        if (actionContext.ModelState.IsValid == false)
        {
            var mediaType = new MediaTypeHeaderValue("application/json");
            var error = actionContext.ModelState;

            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.OK, error.Keys, mediaType);

        }
    }
}

และในตัวควบคุมของคุณ

[Validate(Base= "person",Exclude ="Age,Name")]
    public async Task<IHttpActionResult> Save(User person)
    {

            //do something           

    }

พูดแบบจำลองคือ

public class User
{
    public int Id { get; set; }
    [Required]
    public string Name { get; set; }
    [Range(18,99)]
    public string Age { get; set; }
    [MaxLength(250)]
    public string Address { get; set; }
}

-1

ใช่มันเป็นไปได้ที่จะปิดการใช้งานแอตทริบิวต์ที่จำเป็น สร้างแอตทริบิวต์คลาสที่กำหนดเองของคุณเอง (โค้ดตัวอย่างที่ชื่อว่า ChangeableRequired) เพื่อขยายขอบเขตจาก RequiredAtribute และเพิ่มคุณสมบัติที่ปิดใช้งานและแทนที่วิธี IsValid เพื่อตรวจสอบว่ามีการปรับสมดุลหรือไม่ ใช้การสะท้อนเพื่อตั้งค่า poperty ที่ปิดใช้งานเช่น:

แอตทริบิวต์ที่กำหนดเอง:

namespace System.ComponentModel.DataAnnotations
{
    public class ChangeableRequired : RequiredAttribute
    {
       public bool Disabled { get; set; }

       public override bool IsValid(object value)
       {
          if (Disabled)
          {
            return true;
          }

          return base.IsValid(value);
       }
    }
}

อัปเดตคุณสมบัติของคุณเพื่อใช้แอตทริบิวต์ที่กำหนดเองใหม่ของคุณ:

 class Forex
 {
 ....
    [ChangeableRequired]
    public decimal? ExchangeRate {get;set;}
 ....
 }

ที่คุณต้องการปิดการใช้งานคุณสมบัติการสะท้อนการตั้งค่า:

Forex forex = new Forex();
// Get Property Descriptor from instance with the Property name
PropertyDescriptor descriptor = TypeDescriptor.GetProperties(forex.GetType())["ExchangeRate"];
//Search for Attribute
ChangeableRequired attrib =  (ChangeableRequired)descriptor.Attributes[typeof(ChangeableRequired)];

// Set Attribute to true to Disable
attrib.Disabled = true;

รู้สึกดีและสะอาด?

หมายเหตุ: การตรวจสอบข้างต้นจะถูกปิดการใช้งานในขณะที่อินสแตนซ์วัตถุของคุณยังมีชีวิตอยู่ \ active ...


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

การเปลี่ยนค่าสแตติกเพื่อปิดใช้งานการตรวจสอบความถูกต้องทั้งหมดของเขตข้อมูลที่ดำเนินการภายในกระบวนการเดียวกันนั้นฟังดูเหมือนเป็นความคิดที่แย่มาก
Jeremy Lakeman
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.