May 27, 2018

RePost: ASP.NET Core debugging in production environment Windows Server

When you test on staging server errors are suppressed.
On you dev machine you can see error through Visual Studio.

Bottom line use DOTNET.EXE web.dll from command prompt as explained here to see errors.
Quite frustrating after you've spent decade seeing this very same error in your browser in custom errors mode.

https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/troubleshoot?view=aspnetcore-2.0

You should also consider understanding new environment modes in ASP.NET Core.
Again bottom line should be (not been able to make it work :( ) to add good old system environment variable:
ASPNETCORE_ENVIRONMENT

as explained here:

https://andrewlock.net/how-to-set-the-hosting-environment-in-asp-net-core/

Note!
If you require two environment modes to work on same server you'll have to use web.config and defined it inside for each web app separately.

May 25, 2018

Razor tips & tricks (ASP.NET Core 2.0)

Some quick tips besides what you can quickly find on net...

@(xxxxxxxxxxx)

Anything you place in brackets will be printed:

So:

@(ViewBag.IsActive = true)

; will print True and assign value:


This saved my day many time:
@{Html.PartailView("xxxxxx");}

For some reason when mixing html and Razor PartialView method is not recognized so this solves problem.

For JS use :

<text>
$(document).ready();
</text>

Don't forget also:

@Html.Raw("class='mycssclass'")

And semicolon:

@:

May 8, 2018

JQuery how to prevent event handling (clicking etc.) more than once

You created  some delegated event handler for DOM event:

$( "#dataTable tbody tr" ).on( "click", function() {


Problem is that when you click on control Click event occurs more than once.
Check your code. Probably inside page life on client side you perform above event click registration multiple times. Thus every click triggers Click events based on how much registrations has happened.

To avoid this use Off method.
Place it right before On tho cleary any previous event registration on SAME function like this:

 $( "body" )
    .off( "click", "#theone", flash )

$( "body" )
    .on( "click", "#theone", flash )


http://api.jquery.com/off/

May 7, 2018

RePost: Asp.Net Core 2.0 how to localize generic validation attribute messages

I want to localize client side validation messages that show as part of data annotations applied to model (Required, Compare etc) They are injected by MVC to JQuery validation engine.

Watch for this. Inspect DOM for your input control:

<input class="form-control input-validation-error" type="text" data-val="true" data-val-required id="Name" name="Name" value="" aria-required="true" aria-describedby="Name-error" aria-invalid="true">
If your data-val-required attr is empty like in above then your server side MVC validation messages configuration failed. It didn't provide any message. Hence JQuery validation will default to it's own hardcoded message "This field is required"

Bellow example works. Look for CustomValidationMetadataProvider.

What was frustrating is to distinct between:

 - Validation Attribute Error Messages Localization
Model Binding Error Messages Localization. 

In example Model binding error messages are server side validation messages you'll get if you disable client side validation.

There is one more scenario to consider in this example. When you create data annotation without explicit error message like this:

[Required]
public string Name

I didn't care about that scenario.
https://blogs.msdn.microsoft.com/mvpawardprogram/2017/05/09/aspnetcore-mvc-error-message/


Watch for this !
Remove AddDataAnnotationsLocalization from ConfigureService. This will silently override your CustomValidationMetadataProvider and try to obtain localization from Shared folder.

Here is modification from above link of metaprovider for few standard Data annotations.

 public class CustomValidationMetadataProvider : IValidationMetadataProvider
    {
        private ResourceManager resourceManager; private Type resourceType;
        public CustomValidationMetadataProvider(string baseName, Type type)
        {
            resourceType = type;
            resourceManager = new ResourceManager(typeof(SiteResources));
        }
        public void CreateValidationMetadata(
            ValidationMetadataProviderContext context)
        {
            AddRequiredForValueTypeIfMissing(context);
            foreach (var attribute in context.ValidationMetadata.ValidatorMetadata)
            {
                ValidationAttribute tAttr = attribute as ValidationAttribute;
                if (tAttr != null)
                {
                    if (tAttr is RequiredAttribute ||
                        tAttr is EmailAddressAttribute ||
                        tAttr is StringLengthAttribute)

                    {
                        var name = tAttr.GetType().Name;
                        if (resourceManager.GetString(name) != null)
                        {
                            tAttr.ErrorMessageResourceType = resourceType;
                            tAttr.ErrorMessageResourceName = name;
                            tAttr.ErrorMessage = null;
                        }
                    }
                }
            }
        }
        private void AddRequiredForValueTypeIfMissing(ValidationMetadataProviderContext context)
        {
            if (context.Key.ModelType.GetTypeInfo().IsValueType &&
                            context.ValidationMetadata.ValidatorMetadata
                                .Where(m => m.GetType() == typeof(RequiredAttribute)).Count() == 0)
                context.ValidationMetadata.ValidatorMetadata.
                    Add(new RequiredAttribute());
        }
    }


Here is quick snippet of standard referencing of JQuery Validation:

<environment include="Development">
    <script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
    <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
</environment>
<environment exclude="Development">
    <script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.14.0/jquery.validate.min.js"
            asp-fallback-src="~/lib/jquery-validation/dist/jquery.validate.min.js"
            asp-fallback-test="window.jQuery && window.jQuery.validator"
            crossorigin="anonymous"
            integrity="sha384-Fnqn3nxp3506LP/7Y3j/25BlWeA3PXTyT1l78LjECcPaKCV12TsZP7yyMxOe/G/k">
    </script>
    <script src="https://ajax.aspnetcdn.com/ajax/jquery.validation.unobtrusive/3.2.6/jquery.validate.unobtrusive.min.js"
            asp-fallback-src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"
            asp-fallback-test="window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive"
            crossorigin="anonymous"
            integrity="sha384-JrXK+k53HACyavUKOsL+NkmSesD2P+73eDMrbTtTk0h4RmOF8hF8apPlkp26JlyH">
    </script>
</environment>

In View :
@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}