Saya bertanya-tanya apakah mungkin untuk menonaktifkan atribut validasi yang diperlukan dalam tindakan pengontrol tertentu. Saya bertanya-tanya ini karena pada salah satu formulir edit saya, saya tidak mengharuskan pengguna memasukkan nilai untuk bidang yang telah mereka tentukan sebelumnya. Namun saya kemudian mengimplementasikan logika yang ketika mereka memasukkan nilai itu menggunakan beberapa logika khusus untuk memperbarui model, seperti hashing nilai dll.
Adakah saran tentang cara mengatasi masalah ini?
EDIT:
Dan ya, validasi klien adalah masalah di sini, karena tidak memungkinkan mereka untuk mengirimkan formulir tanpa memasukkan nilai.
c#
asp.net-mvc
asp.net-mvc-3
data-annotations
Alex Hope O'Connor
sumber
sumber
RequiredAttr
seluruhnya dan melakukan pemeriksaan sisi server bila Anda perlu. Tetapi ini akan menjadi rumit pada klienJawaban:
Masalah ini dapat dengan mudah diselesaikan dengan menggunakan model tampilan. Model tampilan adalah kelas yang secara khusus disesuaikan dengan kebutuhan tampilan tertentu. Jadi misalnya dalam kasus Anda, Anda dapat memiliki model tampilan berikut:
public UpdateViewView { [Required] public string Id { get; set; } ... some other properties } public class InsertViewModel { public string Id { get; set; } ... some other properties }
yang akan digunakan dalam aksi pengontrol yang sesuai:
[HttpPost] public ActionResult Update(UpdateViewView model) { ... } [HttpPost] public ActionResult Insert(InsertViewModel model) { ... }
sumber
Update(FormCollection collection)
, setidaknya saya tidak pernah melakukannya. Saya selalu menentukan dan menggunakan tampilan model spesifik:Update(UpdateViewView model)
.Insert
. Terima kasih telah menunjukkan hal ini.Jika Anda hanya ingin menonaktifkan validasi untuk satu bidang di sisi klien, Anda dapat mengganti atribut validasi sebagai berikut:
@Html.TextBoxFor(model => model.SomeValue, new Dictionary<string, object> { { "data-val", false }})
sumber
@Html.TexBoxFor(model => model.SomeValue, new { data_val = false })
- lebih mudah membaca IMO.$(".search select").attr('data-val', false);
Saya tahu pertanyaan ini telah dijawab sejak lama dan jawaban yang diterima benar-benar akan berhasil. Tetapi ada satu hal yang mengganggu saya: harus menyalin 2 model hanya untuk menonaktifkan validasi.
Inilah saran saya:
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; } } }
Dengan cara ini, Anda tidak perlu repot dengan validasi sisi klien / server, kerangka kerja akan berperilaku sebagaimana mestinya. Selain itu, jika Anda mendefinisikan
[Display]
atribut di kelas dasar, Anda tidak perlu mendefinisikannya kembali diUpdateModel
.Dan Anda masih dapat menggunakan kelas-kelas ini dengan cara yang sama:
[HttpPost] public ActionResult Update(UpdateModel model) { ... } [HttpPost] public ActionResult Insert(InsertModel model) { ... }
sumber
Anda dapat menghapus semua validasi dari sebuah properti dengan mengikuti tindakan pengontrol Anda.
Komentar @ Ian tentang MVC5
Berikut ini masih memungkinkan
ModelState.Remove("PropertyNameInModel");
Agak mengganggu karena Anda kehilangan pengetikan statis dengan API yang diperbarui. Anda bisa mencapai sesuatu yang mirip dengan cara lama dengan membuat instance pembantu HTML dan menggunakan Metode NameExtensions .
sumber
ModelState
yang cocok dengan tanda tangan itu. Tidak di MVC 5, setidaknya.Sisi klien Untuk menonaktifkan validasi formulir, beberapa opsi berdasarkan penelitian saya diberikan di bawah ini. Salah satunya mudah-mudahan akan berhasil untuk Anda.
Pilihan 1
Saya lebih suka ini, dan ini bekerja dengan sempurna untuk saya.
(function ($) { $.fn.turnOffValidation = function (form) { var settings = form.validate().settings; for (var ruleIndex in settings.rules) { delete settings.rules[ruleIndex]; } }; })(jQuery);
dan memintanya seperti
$('#btn').click(function () { $(this).turnOffValidation(jQuery('#myForm')); });
pilihan 2
$('your selector here').data('val', false); $("form").removeData("validator"); $("form").removeData("unobtrusiveValidation"); $.validator.unobtrusive.parse("form");
Pilihan 3
var settings = $.data($('#myForm').get(0), 'validator').settings; settings.ignore = ".input";
Pilihan 4
$("form").get(0).submit(); jQuery('#createForm').unbind('submit').submit();
Pilihan 5
$('input selector').each(function () { $(this).rules('remove'); });
Sisi server
Buat atribut dan tandai metode tindakan Anda dengan atribut itu. Sesuaikan ini untuk menyesuaikan dengan kebutuhan spesifik Anda.
[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(); } } }
Pendekatan yang lebih baik telah dijelaskan di sini Mengaktifkan / Menonaktifkan validasi sisi server mvc secara dinamis
sumber
Secara pribadi saya akan cenderung menggunakan pendekatan yang ditunjukkan Darin Dimitrov dalam solusinya. Ini membebaskan Anda untuk dapat menggunakan pendekatan anotasi data dengan validasi DAN memiliki atribut data terpisah pada setiap ViewModel yang sesuai dengan tugas yang sedang ditangani. Untuk meminimalkan jumlah pekerjaan untuk menyalin antara model dan viewmodel, Anda harus melihat AutoMapper atau ValueInjecter . Keduanya memiliki kelebihan masing-masing, jadi periksalah keduanya.
Pendekatan lain yang mungkin untuk Anda adalah mendapatkan viewmodel atau model dari IValidatableObject. Ini memberi Anda opsi untuk mengimplementasikan fungsi Validasi. Dalam validasi, Anda dapat mengembalikan elemen List of ValidationResult atau mengeluarkan hasil untuk setiap masalah yang Anda deteksi dalam validasi.
ValidationResult terdiri dari pesan kesalahan dan daftar string dengan nama bidang. Pesan kesalahan akan ditampilkan di lokasi dekat kolom input.
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; }
sumber
Cara terbersih di sini saya percaya akan menonaktifkan validasi sisi klien Anda dan di sisi server Anda perlu:
Tampaknya model tampilan kustom di sini tidak akan menyelesaikan masalah karena jumlah kolom 'yang dijawab sebelumnya' dapat bervariasi. Jika tidak, maka model tampilan kustom mungkin memang cara termudah, tetapi menggunakan teknik di atas, Anda dapat mengatasi masalah validasi Anda.
sumber
ini adalah jawaban orang lain di komentar ... tetapi itu harus menjadi jawaban nyata:
$("#SomeValue").removeAttr("data-val-required")
diuji pada MVC 6 dengan bidang yang memiliki
[Required]
atributjawaban dicuri dari https://stackoverflow.com/users/73382/rob di atas
sumber
Saya mengalami masalah ini saat membuat Tampilan Edit untuk Model saya dan saya hanya ingin memperbarui satu bidang.
Solusi saya untuk cara paling sederhana adalah meletakkan dua bidang menggunakan:
Komentar adalah bidang yang hanya saya perbarui di Tampilan Edit, yang tidak memiliki Atribut Wajib.
Entitas ASP.NET MVC 3
sumber
AFAIK Anda tidak dapat menghapus atribut saat runtime, tetapi hanya mengubah nilainya (yaitu: readonly true / false) lihat di sini untuk sesuatu yang serupa . Sebagai cara lain untuk melakukan apa yang Anda inginkan tanpa mengotak-atik atribut, saya akan menggunakan ViewModel untuk tindakan spesifik Anda sehingga Anda dapat memasukkan semua logika tanpa merusak logika yang dibutuhkan oleh pengontrol lain. Jika Anda mencoba mendapatkan semacam wizard (bentuk multi langkah), Anda dapat membuat serialisasi bidang yang sudah dikompilasi dan dengan TempData membawanya mengikuti langkah Anda. (untuk bantuan dalam serialisasi deserialize Anda dapat menggunakan MVC futures )
sumber
Apa yang dikatakan @Darin adalah apa yang akan saya rekomendasikan juga. Namun saya akan menambahkannya (dan sebagai tanggapan atas salah satu komentar) bahwa Anda sebenarnya juga dapat menggunakan metode ini untuk tipe primitif seperti bit, bool, bahkan struktur seperti Guid dengan hanya membuatnya nullable. Setelah Anda melakukan ini,
Required
atribut berfungsi seperti yang diharapkan.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 }
sumber
Pada MVC 5 ini dapat dengan mudah dicapai dengan menambahkan ini di file
global.asax
.DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
sumber
Saya sedang mencari solusi di mana saya dapat menggunakan model yang sama untuk penyisipan dan pembaruan di api web. Dalam situasi saya, ini selalu merupakan konten tubuh. The
[Requiered]
atribut harus dilewati jika itu adalah metode update. Dalam solusi saya, Anda menempatkan atribut di[IgnoreRequiredValidations]
atas metode. Ini adalah sebagai berikut:public class WebServiceController : ApiController { [HttpPost] public IHttpActionResult Insert(SameModel model) { ... } [HttpPut] [IgnoreRequiredValidations] public IHttpActionResult Update(SameModel model) { ... } ...
Apa lagi yang perlu dilakukan? BodyModelValidator sendiri harus dibuat dan ditambahkan saat startup. Ini ada di HttpConfiguration dan terlihat seperti ini:
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 saya sendiri berasal dari DefaultBodyModelValidator. Dan saya menemukan bahwa saya harus mengganti metode 'ShallowValidate'. Dalam penggantian ini saya memfilter validator model yang diminta. Dan sekarang kelas IgnoreRequiredOrDefaultBodyModelValidator dan kelas atribut 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 { } }
Sumber:
string debug = new StackTrace().ToString()
untuk mengetahui siapa yang menangani validasi model.sumber
Jika Anda tidak ingin menggunakan ViewModel lain, Anda dapat menonaktifkan validasi klien pada tampilan dan juga menghapus validasi di server untuk properti yang ingin Anda abaikan. Silakan periksa jawaban ini untuk penjelasan lebih dalam https://stackoverflow.com/a/15248790/1128216
sumber
Dalam kasus saya Model yang sama digunakan di banyak halaman untuk tujuan kegunaan kembali. Jadi apa yang saya lakukan adalah saya telah membuat atribut khusus yang memeriksa pengecualian
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); } } }
dan di pengontrol Anda
[Validate(Base= "person",Exclude ="Age,Name")] public async Task<IHttpActionResult> Save(User person) { //do something }
Katakanlah Modelnya
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; } }
sumber
Ya itu mungkin untuk menonaktifkan Atribut yang Diperlukan. Buat atribut kelas khusus Anda sendiri (kode contoh disebut ChangeableRequired) sejauh dari RequiredAtribute dan tambahkan Properti Dinonaktifkan dan timpa metode IsValid untuk memeriksa apakah itu disbaled. Gunakan refleksi untuk mengatur poperty yang dinonaktifkan, seperti:
Atribut Khusus:
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); } } }
Perbarui properti Anda untuk menggunakan Atribut khusus baru Anda:
class Forex { .... [ChangeableRequired] public decimal? ExchangeRate {get;set;} .... }
di mana Anda perlu menonaktifkan refleksi penggunaan properti untuk mengaturnya:
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;
Ini terasa bagus dan bersih?
NB: Validasi di atas akan dinonaktifkan saat instance objek Anda hidup \ aktif ...
sumber