【问题标题】:Is there any attribute to avoid validating the model?是否有任何属性可以避免验证模型?
【发布时间】:2012-07-06 18:37:23
【问题描述】:

我的控制器中有以下操作:

[HttpGet]
public ActionResult Office(GestionOffice model)
{
    ModelState.Clear();
    model.Initialize();
    return View(model);
}

我不需要通过 GET 执行操作,已进行验证。这将有助于我执行 GET 调用。

这将是我的理想情况:

[HttpGet]
[NotValidateModel]
public ActionResult Office(GestionOffice model)
{
    model.Initialize();
    return View(model);
}

谢谢。

编辑

NotValidateModel 澄清不存在,将归因案例以避免验证。

移动模型的原因是MOCK模型

编辑 II

我有我的 POST 动作,我需要通过 GET 在我的动作中接收,没有验证的模型,以成功完成控制器中动作的测试

[HttpGet]
[NotValidateModel]
public ActionResult Office(GestionOffice model)
{
    model.Initialize();
    return View(model);
}

[HttpPost]
[ActionName("Office")]
[NotValidateModel]
public ActionResult OfficePost(GestionOffice model)
{
    if(ModelState.IsValid)
    {
        model.Save();
        return RedirectToAction("List");
    }

    model.Initialize();
    return View(model);
}

@Mark的解决方案版

在我看来,我有几个动作调用,我必须使用动作和控制器创建一个键。

自定义模型元数据

public class CustomModelMetaData : ModelMetadata
{
    public CustomModelMetaData(ModelMetadataProvider provider, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
        : base(provider, containerType, modelAccessor, modelType, propertyName)
    {
    }

    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("NoValidation_{0}_{1}", controller, action);
    }
}

过滤器

public class NoValidationAttribute : FilterAttribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationContext filterContext)
    {
        var itemKey = this.CreateKey(filterContext.ActionDescriptor);
        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("NoValidation_{0}_{1}", controller, action);
    }
}

编辑过滤器

可能存在在主视图中有一个 foreach 以调用属性为NoValidation 的多个局部视图的情况。在这种情况下,包括一个检查密钥的控件。因为它在key中包含了控制器的名字和action,所以这个key几乎是唯一的,只能在描述的情况下重复

public class NoValidationAttribute : FilterAttribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationContext filterContext)
    {
        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("NoValidation_{0}_{1}", controller, action);
    }
}

【问题讨论】:

  • 一个仅供参考:使用模型获取 GET 是错误的。您应该使用 id 传递 GET,然后在您的方法中检索模型,如下所示 MyModel model = MyModel.Initialize(id)
  • @amb 好的,但我需要测试控制器,并制作模型的MOCK
  • @amb:在 this 实例中使用带有 GET 的模型是错误的想法,但在其他领域完全没问题。您的 GET 可能需要一些需要验证的参数。
  • @rossisdead 我同意,但是从“可能有”到“让我们插入另一个参数”,最后“很多参数”是很短的距离......更不用说 GET 有一个非常限制长度。在 RESTful 服务领域考虑 GET 并遵循指南很有用。

标签: c# .net asp.net-mvc validation attributes


【解决方案1】:

[查看下面的更新以及@ANDRES 在问题中提到的编辑]

您尝试做的事情很难实现,我不确定您为什么要这样做。我尝试通过自定义ModelMetaData 和过滤器来完成(未完全测试)。

我们无法从模型绑定器或元数据提供程序中读取通过操作修饰的属性,因此我们需要一个过滤器。过滤器在HttpContext.Items 中添加了一些值,我们可以从自定义元数据提供程序中检索它(http://stackoverflow.com/questions/6198155/asp-net-mvc-modelbinder-getting-action-method)。

过滤器

public class NoValidationAttribute : FilterAttribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationContext filterContext)
    {
      // please see the edits in question to see the key generation
      filterContext.HttpContext.Items.Add("NoValidation", true);
    }
}

自定义模型元数据

public class CustomModelMetaData : ModelMetadata
{
    public CustomModelMetaData(ModelMetadataProvider provider, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName) :
      base(provider, containerType, modelAccessor, modelType, propertyName)
    {
    }

    public override System.Collections.Generic.IEnumerable<ModelValidator> GetValidators(ControllerContext context)
    {
      if (context.HttpContext.Items["NoValidation"] != null && bool.Parse(context.HttpContext.Items["NoValidation"].ToString()) == true)
        return Enumerable.Empty<ModelValidator>();

      return base.GetValidators(context);
    }
}

自定义 ModelMetaDataProvider

public class CustomModelMetaDataProvider : DataAnnotationsModelMetadataProvider
{
    protected override ModelMetadata CreateMetadata(System.Collections.Generic.IEnumerable<Attribute> attributes,
      Type containerType, Func<object> modelAccessor,
      Type modelType,
      string propertyName)
    {
      return new CustomModelMetaData(this, containerType, modelAccessor, modelType, 
         propertyName); 
    }
}

Global.asax.cs

ModelMetadataProviders.Current = new CustomModelMetaDataProvider();

用法

[HttpGet]
[NoValidation]
public ActionResult Office(GestionOffice model)
{
   ...
}

==================================更新 ====== ================================

与其通过继承ModelMetadata 创建CustomModelMetaData,不如从DataAnnotationsModelMetadata 继承。

public class CustomModelMetaData : DataAnnotationsModelMetadata
{
    public CustomModelMetaData(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("NoValidation_{0}_{1}", controller, action);
    }
}

CustomModelMetaDataProvider 中你必须设置一些属性。

public class CustomModelMetaDataProvider : 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 CustomModelMetaData(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
      };
    }
}

【讨论】:

  • 哇,这就是我想要的,谢谢。我测试它,然后确认你
  • 我在我的观点中做了一些修改,因为我有很多“@Html.Action (..)”并且都有属性“novalidation”
  • DataAnnotationsModelMetadataProvider 的方法CreateMetadata 中创建对象ModelMetadata,所有属性作为描述或名称。但现在 CustomModelMetaDataProvider 没有创建所有这些属性。我必须复制代码DataAnnotationsModelMetadataProvider.CreateMetadata 才能获得相同的功能。
  • 我认为另一个问题是关于同一问题的另一个问题stackoverflow.com/questions/11595826/…
  • 我必须复制代码 DataAnnotationsModelMetadataProvider.CreateMetadata 才能获得相同的功能我会看看这个并更新你
【解决方案2】:

是的,您可以像这样使用[ValidateInput(false)] 属性:

[ValidateInput(false)]
[HttpGet]
public ActionResult Office(GestionOffice model)
{
    model.Initialize();
    return View(model);
}

【讨论】:

  • 我尝试使用ValidateInput,但属性同样有效,并且在 ModelState 中包含错误。作为所需的属性
  • 那么,自从您在帖子中验证后,您到底想做什么?还可以在帖子上使用[ValidateInput(false)] 来禁用自动验证,但不要使用 ModelState.IsValid,因为这样您就可以手动调用验证。验证过程发生在 POST 而不是 GET
【解决方案3】:

验证发生在 POST 中,因此您必须删除 Model.IsValid 并添加 [ValidateInput(false)]

[HttpPost]
[ValidateInput(false)]
[ActionName("Office")]
public ActionResult OfficePost(GestionOffice model)
{        
    model.Save();
    return RedirectToAction("List");
}

现在post会成功,但是如果你插入到数据库中,你必须小心。

【讨论】:

    【解决方案4】:

    如果您想在生产代码中使用而不进行验证,则需要禁用客户端验证,因为在服务器端它将被禁用。

    将 web.config 修改为 fallows:

    <appSettings>
        <add key="ClientValidationEnabled" value="false" />
    </appSettings>
    

    【讨论】:

    • 这只避免了客户端验证
    • 好吧,如果您想在生产代码中使用而不进行验证,则需要禁用客户端验证,因为在服务器端,它将被禁用。所以是的,你需要这个。
    • 1 - 你应该只回答一个问题,所以我可以评论一个回答。 2 - 我需要控制POST中的数据,我不需要的是控制GET中的模型,只有那个
    • 1.从现在开始我会的。 2.如果您需要控制POST中的数据,请按照我的最后一个答案,即修改您的POST方法的那个。 ASP.NET mvc 中的验证在 POST 中进行。
    猜你喜欢
    • 1970-01-01
    • 2012-06-15
    • 2013-01-27
    • 1970-01-01
    • 2021-07-28
    • 1970-01-01
    • 2021-01-23
    • 2014-08-06
    • 1970-01-01
    相关资源
    最近更新 更多