locked
Client side custom validation using attributes is not accepting messages which have special characters like apostrophe RRS feed

  • Question

  • User-68514802 posted

    Code Back ground : custom-client-side-validation
    I am using this approach in my current code. I observed +,' etc. special characters are not getting accepted in regex patterns or even customized error message. My code works fine if i don't have them. I need to show customized messages which may come in any launguage. As of now the code is not showing error messages if i have other languages messages such as in french "L'identifiant du locataire n'est pas au format correct"

    Problem(Asp dot net core 2.2):
    Now, that i need to show my error messages in Different languages like french i saw my messages are resulting in empty string in the UI.

    <div>
    <input id="cf-tenantid" class="cf-input-box input-validation-error" type="text" data-val="true" data-val-regex="" 
    data-val-regex-pattern="^[a-zA-Z0-9-]{36}$" data-val-required="" name="TenantId"
     value="" aria-describedby="cf-tenantid-error" aria-invalid="true">
    <br>
    <span id="tenantIdErrorMsg" class="field-validation-error" data-valmsg-for="TenantId" data-valmsg-replace="true">
    <span id="cf-tenantid-error" class=""></span></span>
    </div>

    At back end :

    public override void AddValidation(ClientModelValidationContext context)
    {
                MergeAttribute(context.Attributes, "data-val", "true");
                MergeAttribute(context.Attributes, "data-val-regex", @"'Tenant Id not in correct format'");
                MergeAttribute(context.Attributes, "data-val-regex-pattern", @"^[a-zA-Z0-9-]{36}$");
                MergeAttribute(context.Attributes, "data-val-required", @"pas une chaîne valide");
    }

    I have built a form input element using tag helper. This form/ViewComponent loads when any user selects a radio button.

    If the form is opened at page load then even special characters come in attributes. But if the view component is loaded after radio button selection then it shows empty in all attributes having special character. 

    Friday, May 3, 2019 7:52 AM

All replies

  • User-854763662 posted

    Hi niveditatewari ,

    Do you mean that the customized error message is fine with the default language , but it is empty string in UI when you select the other langauges ?

    Could you share the demo that can reproduce the issue or the steps to reproduce with related code ?

    Best Regards ,

    Sherry

    Monday, May 6, 2019 9:59 AM
  • User-68514802 posted

    actually to be more specific my customized message get emptied if they are in some formats like given below: 

    Example of Values not getting accepted for data-val-regex:

    • "The 'Tenant Id' is not in correct format"  
    • "Le 'numéro de locataire' n'est pas au format correct"

    Example of Values getting accepted for data-val-regex:

    • The Tenant Id is not in correct format 

    Observation as of now is special characters like +,', are not getting accepted. 

    NOTE: on first time page load the form shows all types of messages.

    We loose the messages with special character when my form opens up on a radio button selection after page load. 

    On the radio button selection there is an API call .

    Below is my view component which opens on radio button selection

    namespace AutoPilot
    {
        public class AutoPilot : ViewComponent
        {
            [TenantId("^[a-zA-Z0-9-]{36}$")]
            public string TenantId { get; set; }
    
            [DomainId(@"^[a-zA-Z0-9-.]*[.][a-zA-Z0-9-.]*$", 1,40)]
            public string DomainId { get; set; }
    
            public IViewComponentResult Invoke()
            {
                
                return View(this.ViewPath(), this);
            }
        }
    }
    
    namespace CustomValidator
    {
        public class DomainIdAttributeAdapter : AttributeAdapterBase<DomainIdAttribute>
        {
            private const string Pattern = "[+\"'\\\\]";
            private readonly ILocalizer _localizer;
            public DomainIdAttributeAdapter(DomainIdAttribute attribute, IStringLocalizer stringLocalizer, ILocalizer localizer) : base(attribute, stringLocalizer)
            {
                _localizer = localizer;
            }
    
            public override string GetErrorMessage(ModelValidationContextBase validationContext)
            {
                return GetErrorMessage(validationContext.ModelMetadata, validationContext.ModelMetadata.GetDisplayName());
            }
    
            public override void AddValidation(ClientModelValidationContext context)
            {
                MergeAttribute(context.Attributes, "data-val", "true");
                MergeAttribute(context.Attributes, "data-val-regex", GetFormattedMessage(_localizer?.Resources.WindowsAutopilotDomainFormatErrorMessage));
                MergeAttribute(context.Attributes, "data-val-regex-pattern", Attribute.RegexPattern);
                MergeAttribute(context.Attributes, "data-val-required", GetFormattedMessage(_localizer?.Resources.WindowsAutopilotDomainEmptyErrorMessage));
                MergeAttribute(context.Attributes, "data-val-length-max", Attribute.Max);
                MergeAttribute(context.Attributes, "maxlength", Attribute.Max);
                MergeAttribute(context.Attributes, "data-val-length", GetFormattedMessage(_localizer?.Resources.WindowsAutopilotDomainFormatErrorMessage));
            }
    
    //Using this as of now to get the messages.
    //the regex maching to "[+\"'\\\\]" will get replaced to give messages without these //characters
    //If i remove this function i get empty value in message
            public string GetFormattedMessage(string message)
            {
                if (string.IsNullOrWhiteSpace(message)) return string.Empty;
                var updatedMessage = Regex.Replace(message, Pattern, string.Empty);
                return updatedMessage;
            }
        }
    }
    
    @model AutoPilot
    <form id="cf-autopilot-form">
    
        <div class="cf-grey-back">
            <div class="cf-consent-message">
                <img alt="Info" class="cf-info-icon" src="~/images/cf-icon-info.svg" width="20" height="20" cf-asset="true"/>
                <div has-content="@Localizer.Resources.WindowsAutopilotCustomerConsentMessage">
                    <p class="cf-consent-message-para">@Html.Raw(Localizer.Resources.WindowsAutopilotCustomerConsentMessage)</p>
                </div>
            </div>
    
            <div class="cf-autopilot-label" has-content="@Localizer.Resources.WindowsAutopilotLabel">
                <p>@Localizer.Resources.WindowsAutopilotLabel</p>
            </div>
    
            <div class="cf-autopilot-label" has-content="@Localizer.Resources.WindowsAutopilotTenantidLabel">
                <p class="cf-autopilot-icon">
                    @Localizer.Resources.WindowsAutopilotTenantidLabel
                    <div class="js-tooltip-trigger cf-autopilot-label cf-info-icon-border-bottom" js-tooltip="" js-is-clickable="" cf-title="@Localizer.Resources.WindowsAutopilotTenantidLabel"
                         has-content="@Localizer.Resources.WindowsAutopilotTenantIdMessage" cf-message='@Localizer.Resources.WindowsAutopilotTenantIdMessage'>
                        <img src="~/images/cf-icon-info.svg" width="16" height="16" alt="Info" cf-asset="true"/>
                    </div>
                </p>
                <div>
                    <input id="cf-tenantid" class="cf-input-box" asp-for="TenantId"  asp-validation-summary="@ValidationSummary.All"/>
                    <br/>
                    <span id="tenantIdErrorMsg" asp-validation-for="TenantId"  ></span>
                </div>
            </div>
    
            <div class="cf-autopilot-label cf-autopilot-domainid" has-content="@Localizer.Resources.WindowsAutopilotDomainLabel">
                <p class="cf-autopilot-icon">
                    @Localizer.Resources.WindowsAutopilotDomainLabel
                    <div class="js-tooltip-trigger cf-autopilot-label cf-info-icon-border-bottom" js-tooltip="" js-is-clickable="" cf-title="@Localizer.Resources.WindowsAutopilotDomainLabel"
                         has-content="@Localizer.Resources.WindowsAutopilotDomainIdMessage" cf-message='@Localizer.Resources.WindowsAutopilotDomainIdMessage'>
                        <img src="~/images/cf-icon-info.svg" width="16" height="16" alt="Info" cf-asset="true"/>
                    </div>
                </p>
                <div>
                    <input id="cf-domainid" class="cf-input-box" asp-for="DomainId"/>
                    <br/>
                    <span id="domainErroMsg" asp-validation-for="DomainId"></span>
                </div>
            </div>
        </div>
    </form>

    Tuesday, May 7, 2019 6:27 AM
  • User-854763662 posted

    Hi niveditatewari ,

    I am using this approach in my current code. I observed +,' etc. special characters are not getting accepted in regex patterns or even customized error message. 

    Your regex pattern  is for letters and numbers, no other special strings are allowed. Then the special characters in the message should be show correctly by default language .This is by design.

    As of now the code is not showing error messages if i have other languages messages such as in french "L'identifiant du locataire n'est pas au format correct"

    From the code you provided , the problem seems to be the return of GetFormattedMessage() . You could create the breakpoint at the GetFormattedMessage method to troubleshoot what is returned by it . If the return is the updatedMessage and it has the value , it may be the show error of the view . Otherwise , you could check if there is a corresponding key value in the Resource file .

    It would be better if you could share a reproducible demo , currently ,  we could not reproduce your problem because there are  a lot of special custom classes and methods .

    Best Regards ,

    Sherry

    Thursday, May 9, 2019 10:01 AM
  • User-68514802 posted

    The GetFormattedMessage  I have written is to replace special charaters such as ' , + so that i can see a message. 

    So, this function returns : window's => windows 

    this is just a work around for me as of now. 

    I can't give a reproducible demo as this happens only after an ajax call in which i parse jquery validate.

    If i use this without the ajax call i am able to get all languages well without any issues.

    Here is my ajax call:

       function makeConfigCall(configuration) {
            var intQty = parseInt(configuration.quantity, 10),
                requestData = {
                    configurationId: configurationId,
                    source: configuration.source,
                    moduleId: configuration.moduleId,
                    optionId: configuration.optionId,
                    isSelected: configuration.isSelected,
                    quantity: (intQty) ? intQty : 1,
                    selectedTerm: configuration.selectedTerm ? parseInt(configuration.selectedTerm, 10) : undefined
                },
                currentPosition = cfVars.body.hasClass('cf-is-mobile') ? $('#cfm_off_screen_pane').scrollTop() : $(window).scrollTop();
    
            if (configuration.parentModuleId && configuration.parentOptionId) {
                requestData.parentModuleId = configuration.parentModuleId;
                requestData.parentOptionId = configuration.parentOptionId;
            }
    
            cfLoading.start();
    
            var url = rzVars.optionSelectionApiUrl;
    
            perfMetrics("start", "ajax:" + url);
            return $.ajax({
                url: url,
                type: "POST",
                contentType: "application/json; charset=utf-8",
                data: JSON.stringify(requestData)
            })
                .done(function (data) {
    	            perfMetrics("end", "ajax:" + url);
    
    	            perfMetrics("start", "ajax-callback:" + url);
                    parseDeltaCall(data);
                    if ($("#cf-autopilot-form").length > 0)
                        $.validator.unobtrusive.parse($("#cf-autopilot-form"));
                    var scrollTarget = cfVars.body.hasClass('cf-is-mobile') ? '#cfm_off_screen_pane' : 'html, body';
                    $(scrollTarget).scrollTop(currentPosition);
                    perfMetrics("end", "ajax-callback:" + url);
                })
                .fail(function (jqXHR, textStatus, error) {
                    perfMetrics("end", "ajax:" + url);
    
                    try {
                        resetLastOption();
                    } catch (e) {
                        cfLog.log("resetLastOption failed: " + e);
                    }
    
                    cfLog.log("OptionSelection Api errored. jqXHR: " + jqXHR + ", textStatus : " + textStatus + ", error: " + error + ".");
                })
                .always(function () {
                    cfLoading.stop();
                });
        }

    Highlighting the line we need to call because without this full validation is not working.

    Friday, June 7, 2019 6:21 AM
  • User-68514802 posted

    Before the ajax call:

    <input id="cf-tenantid" class="cf-input-box" type="text" data-val="true" data-val-regex="租户ID格式不正确" data-val-regex-pattern="^[a-zA-Z0-9-]{36}$" data-val-required="Tenant ID should not be empty" name="TenantId" value="">

    After the ajax call:

    <input id="cf-tenantid" class="cf-input-box" type="text" data-val="true" data-val-regex="" data-val-regex-pattern="^[a-zA-Z0-9-]{36}$" data-val-required="Tenant ID should not be empty" name="TenantId" value="">

    Friday, June 7, 2019 7:05 AM