Question

I just implemented FluentValidation, everything seems awesome except one awkward little detail.

@using (Html.BeginForm("Create", "Posts", FormMethod.Post, new { @class = "create-post" }))
{
    @Html.TextBoxFor(m => m.Text, new { @class = "post-input" })
    @Html.Validation(m => m.Text)
    <input type="submit" value="@Html.Resource("Publish")" />
}

    public static MvcHtmlString Validation<T>(this HtmlHelper<T> helper, Expression<Func<T, string>> expression)
    {
        return helper.ValidationMessageFor(expression, null, Resources.Constants.ModelValidationMessageCssClass);
    }

With the default implementation from ASP.NET MVC 3, this created an <span> that had whatever class the validator deemed appropriate AND input-validation (which is the one from my resource). FluentValidation seems to just ignore this setting. Any idea how I can add a CSS class selector to the span generated by FluentValidation?

On a similar note, take for example this output it produces:

<form method="post" class="create-post" action="/posts/create" novalidate="novalidate">
    <input type="text" value="" name="Text" id="Text" data-val-required="complete this!" data-val-regex-pattern="long-stuff" data-val-regex="wrong regex!" data-val="true" class="post-input input-validation-error">
    <span data-valmsg-replace="true" data-valmsg-for="Text" class="field-validation-error">
        <span for="Text" generated="true" class="">wrong regex!</span>
    </span>
    <input type="submit" value="Publicar!">
</form>

I feel I'm back in ASP.NET WebForms here :( .. , how can I remove stuff like novalidate="true" or the generated="true" attribute? I'm fine with data attributes, though.

Was it helpful?

Solution

So the first thing I think is causing trouble is your Validation extension method. It calls ValidationMessageFor, which is an MVC3 extension on the HTML helper, but with a signature that would match passing it the validation message instead:

public static MvcHtmlString ValidationMessageFor<TModel, TProperty>
    (this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string validationMessage)

Based on your code, I would actually expect the error message to be the CSS class name in your resource, based on this snippet from how the <span> is generated:

if (!String.IsNullOrEmpty(validationMessage)) {
        builder.SetInnerText(validationMessage);
    }
    else if (modelError != null) {
        builder.SetInnerText(GetUserErrorMessageOrDefault(htmlHelper.ViewContext.HttpContext, modelError, modelState));
    }

So you probably want to modify your extension to something like (if it doesn't get overruled):

public static MvcHtmlString Validation<T>(this HtmlHelper<T> helper, Expression<Func<T, string>> expression)
{
    return helper.ValidationMessageFor(expression, null, null, new { _class = Resources.Constants.ModelValidationMessageCssClass });
}

Bottom line though, I don't think FluentValidation has anything to do with the markup generated - it should only be feeding your validation errors to ModelState, and ASP.NET MVC is doing the rest. If you want to take even more control you could just write your own HTML tag builder; I grabbed most of this from the MVC3 source, so you could follow their patterns or go a different way. You can also reference the FluentValidation source for some more insights.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top