7

使用 vanilla MVC,我可以使用 TryValidateModel 重新验证我的模型。TryValidateModel 方法似乎不适用于 WebAPI。使用 WebAPI 时如何重新验证我的模型?

4

4 回答 4

10

我知道这个问题已经有一段时间了,但问题仍然有效。因此,我认为我应该分享我对这个问题的解决方案。我决定自己实现 TryValidateModel(object model),基于 System.Web.Mvc.Controller.cs 中的实现

问题是 mvc 的 TryValidateModel 内部使用了自己的 HttpContext 和 ModelState。如果你去比较这两者,它们非常相似......

能够使用我们自己的 HttpContext 存在一个 HttpContextWrapper 可以用于此。
而且由于我们必须清除我们的模型状态,所以我们使用不同类型的 ModelState 并不重要,只要我们得到想要的结果,因此我从正确的类型创建一个新的 ModelState 对象......
我做到了将错误添加到控制器的 ModelState 而不是模型状态到新创建的 ModelState ,这对我来说似乎工作得很好:)
这是我的代码,我刚刚添加到控制器中......
不要忘记导入库...

using System.Web.ModelBinding;

    protected internal bool TryValidateModel(object model)
    {
        return TryValidateModel(model, null /* prefix */);
    }

    protected internal bool TryValidateModel(object model, string prefix)
    {
        if (model == null)
        {
            throw new ArgumentNullException("model");
        }

        ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType());
        var t = new ModelBindingExecutionContext(new HttpContextWrapper(HttpContext.Current), new System.Web.ModelBinding.ModelStateDictionary());

        foreach (ModelValidationResult validationResult in ModelValidator.GetModelValidator(metadata, t).Validate(null))
        {
            ModelState.AddModelError(validationResult.MemberName, validationResult.Message);
        }

        return ModelState.IsValid;
    }
于 2013-10-30T08:45:36.830 回答
5

我不知道它是什么时候添加的,但现在 api 控制器上有 Validate 方法。

ApiController.Validate 方法(TEntity) https://msdn.microsoft.com/en-us/library/dn573258%28v=vs.118%29.aspx

于 2015-06-11T21:36:17.063 回答
3

基于rik-vanmechelen 的原始答案,这是我的版本,它依赖于 Web API 公开的服务容器。

    /// <summary>
    /// Tries to validate the model.
    /// </summary>
    /// <param name="model">The model.</param>
    /// <returns>Whether the model is valid or not.</returns>
    protected internal bool TryValidateModel(object model)
    {
        if (model == null)
        {
            throw new ArgumentNullException("model");
        }

        var metadataProvider = Configuration.Services.GetService<System.Web.Http.Metadata.ModelMetadataProvider>();
        var validatorProviders = Configuration.Services.GetServices<System.Web.Http.Validation.ModelValidatorProvider>();
        var metadata = metadataProvider.GetMetadataForType(() => model, model.GetType());

        ModelState.Clear();
        var modelValidators = metadata.GetValidators(validatorProviders);
        foreach (var validationResult in modelValidators.SelectMany(v => v.Validate(metadata, null)))
        {
            ModelState.AddModelError(validationResult.MemberName, validationResult.Message);
        }

        return ModelState.IsValid;
    }

这使用以下简单的扩展方法来访问服务:

  /// <summary>
  /// Services container extension methods.
  /// </summary>
  public static class ServicesContainerExtensions
  {
    /// <summary>
    /// Gets the service.
    /// </summary>
    /// <typeparam name="TService">The type of the service.</typeparam>
    /// <param name="services">The services.</param>
    /// <returns>The service.</returns>
    /// <exception cref="System.ArgumentNullException">services</exception>
    public static TService GetService<TService>(this ServicesContainer services)
    {
        if (services == null)
        {
            throw new ArgumentNullException("services");
        }
        return (TService)((object)services.GetService(typeof(TService)));
    }

    /// <summary>
    /// Gets the services.
    /// </summary>
    /// <typeparam name="TService">The type of the service.</typeparam>
    /// <param name="services">The services.</param>
    /// <returns>The services.</returns>
    /// <exception cref="System.ArgumentNullException">services</exception>
    public static IEnumerable<TService> GetServices<TService>(this ServicesContainer services)
    {
        if (services == null)
        {
            throw new ArgumentNullException("services");
        }
        return services.GetServices(typeof(TService)).Cast<TService>();
    }
}

使用此方法的优点是它重用了您为 Web API 应用程序配置的 MetadataProvider 和 ValidatorProvider(s),而上一个答案是检索在 ASP.NET MVC 中配置的那个。ASP.NET MVC 和 WebAPI 通过不同的管道运行。

于 2013-11-05T04:13:50.583 回答
1

原来 WebAPI 不支持 TryValidateModel。CodePlex 上有一个功能请求。

于 2012-10-19T08:43:48.737 回答