Включить / отключить проверку на стороне сервера MVC динамически

У меня есть форма MVC смножественный отправить кнопки - 'Сохранить черновик ' а также 'Публиковать', Цель состоит в том, чтобы пропустить проверку как на стороне клиента (javascript / unobructive), так и на стороне сервера, когда 'Сохранить черновик ' нажата кнопка и форма отправлена. Но мне нужно запустить обе проверки, еслиПубликовать' кнопка нажата.

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

Клиентская сторона - путем написания плагина jquery

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

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

и вызывая его как

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

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

[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();
        }
    }
}

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

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

Ответы на вопрос(3)

IsDraft

Затем выведите свою модель представления из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" });
        }
    }
</validationresult>

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

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

Это метод:

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

}
</modelclientvalidationrule>

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

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

Ссылка на сайтСсылка на сайт

надеюсь, это поможет

посмотреть здесь.

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

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

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

Смотрите эту ссылкуASP.MVC Точки расширения

Решение Вопроса

@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);
    }
}

Переопределить 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);
    }
}
<p><strong>Теперь попросите провайдера использовать наши собственные метаданные аннотации данных и очистить проверку, если IgnoreValidationAttribute присутствует в методе действия</strong></p><pre><code>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
        };
    }
}
<p><strong>использование</strong></p><pre><code>[HttpPost]
    [IgnoreValidation]
    public ActionResult SaveDraft(MyModel myModel)
    {
        if (ModelState.IsValid)
        {
            // Should always reach here
        }

        .......
    }

    [HttpPost]
    public ActionResult Submit(MyModel myModel)
    {
        if (ModelState.IsValid)
        {
        }
    }
</code></pre><p>Пожалуйста, не'не забудьте вызвать это в вашем Application_Start для подключенияModelMetadataProviders.Current = new IgnoreValidationModelMetaDataProvider ();</p><p>Есть несколько проблем, хотя.</p><ol><li><p>Есть ли раннее место, где мы могли бы манипулировать HttpContext, чем OnAuthorization ()? Мне не нравится идея переопределить это, чтобы сделать что-то, не связанное с авторизацией. Обратите внимание, что OnActionExecuting () будет слишком поздно в конвейере MVC, чтобы сделать это (я пробовал это и не работает).</p></li><li><p>Есть ли лучший способ сделать это, чем добавить ключ к HttpContext и использовать его позже?</p></li></ol></displaycolumnattribute></attribute></object></attribute></code></pre></modelvalidator></modelvalidator></object>
 int-i27 июн. 2013 г., 20:52
Пожалуйста, не забудьте вызвать это в вашем Application_Start для прослушиванияModelMetadataProviders.Current = new IgnoreValidationModelMetaDataProvider (); '

Ваш ответ на вопрос