0

I have a registration page, if the user types an email address that's already registered I need to output a link for them to login in the validation message.

However, validation tag helpers HTML encode error messages, so the link is displayed as HTML.

In the view:

@model Site.ViewModels.RegisterEmail
<h1>Register</h1>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Email">
            <div class="form-group">
                <label asp-for="Email" class="control-label"></label>
                <input asp-for="Email" class="form-control" />
                <span asp-validation-for="Email" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Continue" class="btn btn-default" />
            </div>
        </form>
    </div>
</div>

In the controller:

var LoginLink = $"<a href='{Request.Scheme}://{Request.Host}{Request.PathBase}/Login'>Login</a>";


if (CustomerRepo.CustomerEmailExists(RegisterEmail.Email))
    ModelState.AddModelError("Email", $"Email already registered. {LoginLink} with your email, or register below");

How can I prevent the validator HTML encoding, or otherwise properly display the HTML link in the validation message?

I can't find anything on Google about this.

Thanks.

3
  • Possible duplicate of How can I render html in validation message in ASP.NET MVC? Commented Oct 10, 2018 at 11:27
  • Similar - though this is ASP.net Core and refers to Tag Helpers - which don't exist in regular MVC Commented Oct 10, 2018 at 11:27
  • TagHelpers encode the content. You would need to write you own TagHelper (or HtmlHelper extension method) Commented Oct 10, 2018 at 11:28

1 Answer 1

3

Extend the validation message tag helper

The first step is to create the tag helper that extends the existing validation message tag helper. You need to set its attribute to be asp-validation-for so that it would get called.

You also need to declare a field to indicate whether you want to output raw HTML or not. I called it OutputHtml and denoted the attribute name as asp-validation-output-html.

using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;

namespace DL.SO.Framework.Mvc.TagHelpers
{
    [HtmlTargetElement("span", Attributes = ForAttributeName)]
    public class RawHtmlValidationMessageTagHelper : ValidationMessageHelper
    {
        private const string ForAttributeName = "asp-validation-for";

        [HtmlAttributeName("asp-validation-output-html")]
        public bool OutputHtml { get; set; }

        public RawHtmlValidationMessageTagHelper(IHtmlGenerator generator) : base(generator) {}

        public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
        {
            await base.ProcessAsync(context, output);

            if (this.OutputHtml)
            {
                using (var writer = new StringWriter())
                {
                    output.WriteTo(writer, NullHtmlEncoder.Default);

                    output.Content.SetHtmlContent(writer.ToString());
                }
            }
        }
    }
}

The trick here is to use NullHtmlEncoder to write tag helper's output, without encoding, to a writer first, and then write the writer's content back to tag helper's Html content.

On the view

<form asp-action="Email">
    <div class="form-group">
        <label asp-for="Email" class="control-label"></label>
        <input asp-for="Email" class="form-control" />
        <span 
            asp-validation-for="Email"
            asp-validation-output-html="true"
            class="text-danger">
        </span>
    </div>
    <div class="form-group">
        <input type="submit" value="Continue" class="btn btn-default" />
    </div>
</form>

Disclaimer: There might be better/smarter ways to do it but here is just my 0.02.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you. This fixed my issue. Couple of things I did change ValidationMessageHelper to ValidationMessageTagHelper and added taghelper to _ViewImports.cshtml.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.