Using vanilla MVC I can revalidate my model with TryValidateModel. The TryValidateModel method doesn't seem to be applicable to WebAPI. How can I revalidate my model when using WebAPI?
-
What do you mean by `How can I revalidate my model when using WebAPI?` ? – gdoron Oct 16 '12 at 01:33
-
I'm looking for the same functionality in WebAPI as TryValidateModel provides in MVC. If my model state, after initial databinding, is invalid I want to make some changes to it and then revalidate. How Can I rerun that validation process? In MVC this is easily accomplished with TryValidateModel. – Mark Oct 16 '12 at 01:37
4 Answers
I know it has been a while since this has been asked, but the problem is still valid. Thus i thought i should share my solution to this problem. I decided to implement the TryValidateModel(object model) myself, based on the implementation in the System.Web.Mvc.Controller.cs
The problem is that the mvc's TryValidateModel internally used their own HttpContext and ModelState. If you go and compaire the two, they are very similar....
The be able to use our own HttpContext there exists a HttpContextWrapper that can be used for that.
And Since we have to clear our model state, it doesn't really matter that we use a different type of ModelState , as long as we get the desired result, thus i create a new ModelState object from the correct type...
I did add the error to the ModelState of the controller and not to the model state to the newly created ModelState , This seems to work just fine for me :)
Here is my code, that i just added to the controller...
do not forget to import the library...
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;
}

- 1,904
- 17
- 24
-
1@bbodenmiller what do you mean? Although i haven't tried it, i think it should work for any nested resources, unless msft does something weird (which is still probable...) – rik.vanmechelen Nov 12 '13 at 08:21
-
TryValidateModel doesn't support nested validation as per http://stackoverflow.com/questions/4465432/asp-net-mvc-2-controllers-tryvalidate-doesnt-validate-the-list-items-within which I imagine is why this also does not support nested validation. :( – bbodenmiller Nov 13 '13 at 22:46
-
Ah, that would make sense. Thank you for mentioning it. following http://stackoverflow.com/questions/4384081/read-foreign-key-metadata-programatically-with-entity-framework-4 you could use the same method of validation for the navigational properties (nested resources) – rik.vanmechelen Nov 14 '13 at 08:39
I don't know when was it added but now there is Validate method on api controller.
ApiController.Validate Method (TEntity) https://msdn.microsoft.com/en-us/library/dn573258%28v=vs.118%29.aspx

- 713
- 1
- 11
- 17
Based from rik-vanmechelen original answer, here is my version that relies on the services container exposed by 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;
}
This uses the following simple extension methods to access the services :
/// <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>();
}
}
The advantage of using this method is that it reuses the MetadataProvider and ValidatorProvider(s) you have configured for your Web API application while the previous answer is retrieving the one configured in ASP.NET MVC. ASP.NET MVC and WebAPI run through different pipelines.
-
-
The second block goes anywhere. This defines extension methods for the ServicesContainer type used by the first block. – Onlyann Nov 26 '13 at 07:16
-
Interesting :) but if get it correctly, it is only necessary when you have created custom MetadataProviders etc.? – rik.vanmechelen Jan 10 '14 at 08:34
-
1If we have a different validation configuration between web API and MVC (or we don't have any validation provider hooked into MVC), then the operation will not behave as expected. – Onlyann Jan 13 '14 at 06:26
-
I tried this solution, but the `modelValidators` came out empty. I'm using WebAPI 1 (i think). What am I missing? – Tsahi Asher Dec 23 '15 at 15:17
Turns out TryValidateModel is not supported in WebAPI. There's a feature request over on CodePlex.

- 21,067
- 14
- 53
- 71
-
1Do you by any chance have a link to that issue, or remember what it was called? (I know it's been a year, but nothing ventured, right?) – Sixten Otto Oct 07 '13 at 22:45
-
@SixtenOtto I added an aswer with a possible workaround to the problem. I hope it might help you as well. – rik.vanmechelen Oct 30 '13 at 08:46
-
1I don't know when was it added but now there is Validate method on controller. ApiController.Validate
Method (TEntity) https://msdn.microsoft.com/en-us/library/dn573258%28v=vs.118%29.aspx – hex Jun 11 '15 at 21:35