How to use FluentValidation to display UI error for either or fields - fluentvalidation

I have an MVC 3 app which uses FluentValidation to express validation logic on some ViewModel objects.
One of the objects has two properties as follows:
[DisplayNameAttribute(UiConstants.Telephone)]
public string Telephone { get; set; }
[DisplayNameAttribute(UiConstants.Email)]
public string Email { get; set; }
The rule is that EITHER of these properties must be entered at the UI and I want the UI to display a validation message for at least one of the fields (Email) when the user hits Submit but without doing a PostBack.
I can get the validation to work with the following code in the validator
RuleFor(contact => contact.Email)
.Must((contact, email) => string.IsNullOrWhiteSpace(email) != string.IsNullOrWhiteSpace(contact.Telephone))
.WithMessage(ValidationConstants.EmailOrTelephone);
and this will display my validation error message at the UI, but only after a PostBack.
I have also used a Custom Validator as follows
Custom(contactUs =>
{
return string.IsNullOrWhiteSpace(contactUs.Telephone) && string.IsNullOrWhiteSpace(contactUs.Email)
? new ValidationFailure("Email", ValidationConstants.EmailOrTelephone)
: null;
});
but this behaves in the same way.
Will this not work the way I am hoping?
Is there another way to do the validator to get the error message to display in the UI without doing a PostBack?
I know that I could also use DataAnnotations but I specifically want to do this with FluentValidation.
Many thanks
Brian

You're looking for client-side validation - this isn't specific to FluentValidation or DataAnnotations. Both mechanisms will work server-side automatically (you have to wire FluentValidation up to do this automatically after model binding, or run it manually).
If you want client-side validation with ASP.NET MVC, you'll also have to wire that bit up. This blog entry may help.
One note though - your Custom validator won't work by default (you'd have to replicate that validation in jQuery on the client). Check out this article on FluentValidation; here's an excerpt that shows what validators should "just work" client-side without rewriting your own:
Note that FluentValidation will also work with ASP.NET MVC's
client-side validation, but not all rules are supported. For example,
any rules defined using a condition (with When/Unless), custom
validators, or calls to Must will not run on the client side. The
following validators are supported on the client:
*NotNull/NotEmpty
*Matches (regex)
*InclusiveBetween (range)
*CreditCard
*Email
*EqualTo (cross-property equality comparison)
*Length

Related

IAuthenticationFilter equivalent in MVC6

I'm moving a Web Api 2 project to MVC 6, since Microsoft is merging the two APIs in ASP.NET 5. In my WebApi project I had a custom Attribute Filter class that would authenticate, authorize and prevent transaction replays using a combination of public key, private key and HMAC authentication (basically, doing this with some tweaks to fit into my project).
Now in MVC6, as far as I understand I must stop using anything in the Microsoft.Web.Http namespace and instead use Microsoft.AspNet.Mvc. So I have done that, but the Microsoft.AspNet.Mvc.Filters doesn't seem to have any equivalent of Web Api 2's IAuthenticationFilter.
This is a problem for me because my customer AuthenticationFilter implemented all of IAuthenticationFilter, with all the logic in there. More importantly, it was using the Context to temporarily store the public key of the account, so my controller could access it to load up the account in turn.
So my question is, what is the proper way to filter requests in MVC6, using an Authentication Filter-like class to intercept the requests and return the appropriate status codes? I can't find any article that goes specifically in these details (they all tend to cover MVC5).
I know it's an older question, but hopefully someone (maybe even yourself) might find value in the answer.
MVC6 does in fact have an alternative. You have an
public abstract class AuthorizationFilterAttribute :
Attribute, IAsyncAuthorizationFilter, IAuthorizationFilter, IOrderedFilter
which basically tells you, that you can create your custom class, derive it from this (namespace of all of these interfaces, btw, is Microsoft.AspNet.Mvc.Filters and that should be it. You can either decorate the action with it, or you can do this in Startup.cs, to apply to all actions:
public void ConfigureServices(IServiceCollection services)
{
// Add MVC services to the services container.
services.AddMvc(options =>
{
// add an instance of the filter, like we used to do it
options.Filters.Add(new MySpecialFilter());
});
services.AddTransient<LogFilter>();
}
If you want to use a bit more logic in the filter (e.g. my LogFilter above) which is instantiated through DI, you need to use either Service Filters or Type Filters.
You can now decorate the actions with [ServiceFilter(typeof(LogFilter))] or use o.Filters.Add(new ServiceFilterAttribute(typeof(LogFilter))); in the Startup.cs file. But keep in mind, to do this you need to register the type with the DI container, like I did above with the .AddTransient<>() call.
IAuthenticationFilter is no more and IAuthorizationFilter simply does not replace it in MVC 6
Reason: authentication is NOT EQUAL to authorization.
Therefore IMO the authentication filter should stay available!

Searching with WebAPI

I have made a web API class for my Customer model. I have the standard methods (GET, POST, PUT, DELETE). The problem is, I want to implement another GET method which is a search. Something like this:
[HttpGet]
public IEnumerable<Customer> Search(string id)
{
var customers = customerRepository.Search(id);
return customers;
}
The search method performs a search based on the account number of my customers, using the .Contains() method.
The problem is, when I navigate to: mySite.com/api/Customers/Search/123 I get a 404. What am I doing wrong here?
While Darin's answers are always of top quality this question would actually benefit from an answer that explains how searching, paging and filtering should actually be done in any API and how it should be done using the most current version of Web API (v2).
This is a post which I consider a good resource on the matter (technology indenpendent):
http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api
The answer should also reflect what's new in ASP.NET Web API v2 because Darin's answer is quite old.
Since this question comes up at the top when doing Google search for "asp.net web api searching" I will try to explain few things here.
To get as close as possible to REST principles with the latest version of ASP.NET Web API (v2) one should take a serious look at attribute routing that was introduced in the latest version. It is very hard to achieve RESTful routing with the old, classic, convention based routing (in global.asax.cs or RouteConfig.cs).
You should read more about that here
http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2
Now, to go into details how to implement the specifics you ask about.
The most common practice is to expose these types of functionality through query string parameters.
Per REST principles, you should have one endpoint for your Customers resource, for instance
/api/customers
To achieve this you would decorate your GetCustomers() action in your Web API controller like this
[HttpGet]
[Route("/api/customers")]
public HttpResponseMessage GetCustomers(string q="", string sortBy="", string sortDirection="", bool active=true, ...)
{
// q = being optional search query
// sortBy = optional sort by column/property
// sortDirection = optional sort direction
// active = filter on 'active' column/property
// ... other filters may be applicable
}
You would implement this action closely to what you did in classic MVC if you wanted to provide filtered Views.
I would only introduce new controllers and custom actions if really needed, for some custom edge cases.
with regards to a comment about SearchFilter strongly typed object, let's explain that this won't work out of the box because the default model binder will not bind to this class when using GET requests.
So I'd either take those properties out of SearchFilter class and put them on the action itself so they'd bind via query string binder or use the [FromBody] binder if you wanted to bind from the request body. As per http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api
HTH
As per the default route setup only the standard controller action names are allowed (the RESTful ones and the dispatching is done based on the HTTP verb). If you want to violate the RESTful conventions and use some custom action names then you will have to modify your route setup in order to include the action name in the url: api/{controller}/{action}/{id}. Now you can send a request to /api/Customers/Search/123 which will invoke the Search action on the Customers API controller.

ModelState.AddModelError

Am I missing something? I am trying to return model validation errors from my web api update method like this
public void Update public void UpdateModel(Models.Model entity) {
ModelState.AddModelError("name","error");
return;
However the JSON returned has no validation errors
For example in this article enter link description here
When I try to use a validation filter as in the previous article on this link I get the error Action xxxxx has one or more filters applied that do not derive from AuthorizationFilterAttribute. Only authorization filters are supported on DataController Insert/Update/Delete actions.
ModelState isnt accessible from your JSON, unless you specifically serialize it as such. It's more used from the HtmlHelper extensions behind the scenes. If you're attempting to update the UI as if the model state was marked as such, you're going about it all wrong. You can either:
Do a full post to the server and let it render the appropriate response
Take the json you get back and then style the fields as appropriate for that response.

WCF RIA Services v1 sp1, Composition, validate child entities

I'm using composition attribute. Recently I came into the following blog:
http://brettsam.com/2011/03/25/ria-services-composition-with-entity-framework/
So, I used the approach described in the above blog post to correct entity state of my child entities like the following:
foreach (Child c in this.ChangeSet
.GetAssociatedChanges(currentParent, p => p.Children))
{
ChangeOperation change = this.ChangeSet.GetChangeOperation(c);
switch (change)
{
case ChangeOperation.Delete:
...
case ChangeOperation.Insert:
// This is already done for us.
break;
case ChangeOperation.None:
...
case ChangeOperation.Update:
this.ObjectContext.Children
.AttachAsModified(c, this.ChangeSet.GetOriginal(c));
break;
default:
break;
}
}
I also removed UpdateChild(Child currentChild) method which was generated by default.
Now, the code works and child entities are saved to database as expected. However,
I noticed one problem. My child entity's some properties had custom validation attribute
(inherited from ValidationAttribute class). They were not called at all. This custom
validation attribute is not generated at the silverlight client side, because it uses
some classes which are only available in .NET. but not in silverlight. So, at the
client validation passes, and server-side doesn't validate either. However, if
I add UpdateChild method back to the DomainService, the validation attribute's code runs.
What's wrong here? Can someone explain this?
You should take a look at the EntityGraph
It's more powerful than composition and from my experience it works well - including the kind of validation scenario you have described. In fact you can do way more complicated cross entity validations with the graph.

Passing Validation exceptions via WCF REST

I am using WCF and REST, and I have complex types, which are working fine. Now I need to check for validation, I am thinking of using DataAnnotations e.g.
public class Customer
{
[Required]
public string FirstName {get;set;}
}
Now where the issue is how do I pass this validation down to the REST service?
ALso I need to validate the object when it comes back, and throw an exception, if I am to throw an exception then what is the best way of doing this using REST?
I would use the Validation Application Block included in the Microsoft Enterprise Library to validate the data transfer objects being used in the service interface. You can use attributes to decorate the objects' properties with validation rules, much in the same way as with the ASP.NET Data Annotations.
In case validation fails you should return an appropriate HTTP Error Code and include the details of what went wrong in the HTTP response.
Here is an example:
public void PostCustomer(Customer instance)
{
ValidationResults results = Validation.Validate(instance);
if (!results.IsValid)
{
string[] errors = results
.Select(r => r.Message)
.ToArray();
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.BadRequest;
WebOperationContext.Current.OutgoingResponse.StatusDescription = String.Concat(errors);
}
// Proceed with custom logic
}
If you are using the WCF REST Starter Kit, you should instead throw a WebProtocolException, as described in this article.
I would look into writing a custom IDispatchMessageInspector implementation where, in the AfterReceiveRequest method, you manually invoke the validation architecture.
I won't go into the details of how to call the Data Annotations validation architecture as I'm sure you can find that somewhere online if you don't already know how to do it. That said, once you have your validation results you can enumerate them and then, if there are any failed validations, you can throw a generic validation fault filled with the details from the AfterReceiveRequest implementation.