4

У меня есть форма mvc с несколько submit buttons - «Сохранить черновик» и «Опубликовать». Цель состоит в том, чтобы пропустить проверку на стороне клиента (javascript/unobstructive) и проверку на стороне сервера при нажатии кнопки «Сохранить черновик» и отправке формы. Но мне нужно активировать проверку, если нажата кнопка «Опубликовать».Включить/отключить проверку на стороне сервера mvc динамически

Мое исследование привело меня к нескольким решениям.

Client Side -К написание JQuery плагин

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

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

и ссылающегося на него, как Side

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

сервера - Но на стороне сервера, единственное решение, которое я мог бы найти заключается в удалении ошибок из ModelState. Я сделал это в Action Attribute, чтобы он был многоразовым и простым в использовании.

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

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

Но это не полностью служит моей цели. Почему мы должны запускать проверку и устранять ошибки, если мы можем предотвратить это? Это возможно?

Есть ли способы предотвратить валидацию сервера на первом месте, а не очищать полученные ошибки проверки?

ответ

1

Перелив и Билал, спасибо за ответ на мой вопрос.

@Bilal: Я использую ту же модель для сохранения и отправки и не хочу никаких атрибутов на модели, а нуждаюсь в чем-то на уровне контроллера/действия.

В поиске, чтобы найти лучший ответ, я придумал что-то вроде этого. Я прочитал это из другой статьи, но потерял ссылку. Как только я получу его, я обновлю то же самое.

Добавить новый атрибут действия фильтра

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] 
public class IgnoreValidationAttribute : FilterAttribute, IAuthorizationFilter 
{ 
    // TODO: Try to put it on another more appropriate method such as OnActionExcecuting. 
    // Looks like - This is the earliest method we can interpret before an action. I really dont like this! 
    public void OnAuthorization(AuthorizationContext filterContext) 
    { 
     //TODO: filterContext != null && filterContext.httpContext != null 
     var itemKey = this.CreateKey(filterContext.ActionDescriptor); 
     if (!filterContext.HttpContext.Items.Contains(itemKey)) 
     { 
      filterContext.HttpContext.Items.Add(itemKey, true); 
     } 
    } 

    private string CreateKey(ActionDescriptor actionDescriptor) 
    { 
     var action = actionDescriptor.ActionName.ToLower(); 
     var controller = actionDescriptor.ControllerDescriptor.ControllerName.ToLower(); 
     return string.Format("IgnoreValidation_{0}_{1}", controller, action); 
    } 
} 

Override DataAnnotationModelMetadata

public class IgnoreValidationModelMetaData : DataAnnotationsModelMetadata 
{ 
    public IgnoreValidationModelMetaData(DataAnnotationsModelMetadataProvider provider, Type containerType, 
      Func<object> modelAccessor, Type modelType, string propertyName, 
      DisplayColumnAttribute displayColumnAttribute) : 
     base(provider, containerType, modelAccessor, modelType, propertyName, displayColumnAttribute) 
    { 
    } 

    public override IEnumerable<ModelValidator> GetValidators(ControllerContext context) 
    { 
     var itemKey = this.CreateKey(context.RouteData); 

     if (context.HttpContext.Items[itemKey] != null && bool.Parse(context.HttpContext.Items[itemKey].ToString()) == true) 
     { 
      return Enumerable.Empty<ModelValidator>(); 
     } 

     return base.GetValidators(context); 
    } 

    private string CreateKey(RouteData routeData) 
    { 
     var action = (routeData.Values["action"] ?? null).ToString().ToLower(); 
     var controller = (routeData.Values["controller"] ?? null).ToString().ToLower(); 
     return string.Format("IgnoreValidation_{0}_{1}", controller, action); 
    } 
} 

Теперь скажите поставщику использовать наши метаданные аннотаций пользовательских данных и опустошить проверки, если IgnoreValidationAttribute является присутствующих в методе действия

public class IgnoreValidationModelMetaDataProvider : DataAnnotationsModelMetadataProvider 
{ 
    protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, 
     Type containerType, Func<object> modelAccessor, Type modelType, string propertyName) 
    { 
     var displayColumnAttribute = new List<Attribute>(attributes).OfType<DisplayColumnAttribute>().FirstOrDefault(); 

     var baseMetaData = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName); 

     // is there any other good strategy to copy the properties? 
     return new IgnoreValidationModelMetaData(this, containerType, modelAccessor, modelType, propertyName, displayColumnAttribute) 
     { 
      TemplateHint = baseMetaData.TemplateHint, 
      HideSurroundingHtml = baseMetaData.HideSurroundingHtml, 
      DataTypeName = baseMetaData.DataTypeName, 
      IsReadOnly = baseMetaData.IsReadOnly, 
      NullDisplayText = baseMetaData.NullDisplayText, 
      DisplayFormatString = baseMetaData.DisplayFormatString, 
      ConvertEmptyStringToNull = baseMetaData.ConvertEmptyStringToNull, 
      EditFormatString = baseMetaData.EditFormatString, 
      ShowForDisplay = baseMetaData.ShowForDisplay, 
      ShowForEdit = baseMetaData.ShowForEdit, 
      Description = baseMetaData.Description, 
      ShortDisplayName = baseMetaData.ShortDisplayName, 
      Watermark = baseMetaData.Watermark, 
      Order = baseMetaData.Order, 
      DisplayName = baseMetaData.DisplayName, 
      IsRequired = baseMetaData.IsRequired 
     }; 
    } 
} 

Использование

[HttpPost] 
    [IgnoreValidation] 
    public ActionResult SaveDraft(MyModel myModel) 
    { 
     if (ModelState.IsValid) 
     { 
      // Should always reach here 
     } 

     ....... 
    } 

    [HttpPost] 
    public ActionResult Submit(MyModel myModel) 
    { 
     if (ModelState.IsValid) 
     { 
     } 
    } 

Пожалуйста, не забудьте назвать это в вашей Application_Start для wireup «ModelMetadataProviders.Current = новый IgnoreValidationModelMetaDataProvider();

Есть несколько проблем, хотя.

  1. Есть ли раннее место, где мы могли бы манипулировать HttpContext, чем OnAuthorization()?. Мне не нравится идея переопределить это, чтобы сделать что-то, не связанное с авторизацией. Обратите внимание, что OnActionExecuting() будет слишком поздно в конвейере MVC для этого (я пробовал это и не работал).

  2. Есть ли лучший способ сделать это, чем добавить ключ к HttpContext и использовать его позже?

+0

Пожалуйста, не забудьте называть это в своем приложении Application_Start для проводника 'ModelMetadataProviders.Current = new IgnoreValidationModelMetaDataProvider();' –

1

Вы можете ввести переменную в вашем представленииModel под названием IsDraft.

Затем вывести свой ViewModel из IValidatableObject

Тогда реализовать свой метод, как это: (просто пример проверки пользовательской стороны сервера)

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) 
    { 
     if (!IsDraft && StartDate > EndDate) 
     { 
      yield return new ValidationResult("Start date should be less than end date", new[] { "StartDate" }); 
     } 
    } 

Таким образом, вы будете иметь ваши проверки на стороне сервера срабатывают только тогда, когда это не проект.

Теперь для клиента использования проверки на стороне реализации IClientValidatable

Это метод:

public IEnumerable<modelclientvalidationrule> GetClientValidationRules 
(ModelMetadata metadata, ControllerContext context) 
{ 

} 

Я считаю, что это лучший подход, чем позволяет отключить проверку.

относится к этой ссылке, если вам нужна помощь в реализации пользовательской стороны клиента валидаций:

Надежда, что помогает

1

Один из вариантов доступных для переопределения ModelBinder, see here.

В частности, переопределение функции OnPropertyValidating и return false предотвращает запуск функции проверки, как вам хотелось бы.

MVC все еще выполняет небольшую работу, поскольку он считывает метаданные (атрибуты проверки) и выполняет итерацию через них.

В любом случае, ModelBinder - это точка расширяемости, на которую вы должны смотреть, поскольку это то, что вызывает логику проверки.

эта ссылка ASP.MVC Extensibility Points