Dec 20, 2018

RePost - Chrome inspector - network - inspect traffic - Ajax - MISC

chrome://net-internals/#events

https://stackoverflow.com/questions/17208268/how-to-find-out-which-javascript-causes-a-jquery-ajax-request/17210212


Dec 17, 2018

Javascript OOP - Example of inheritance with closure (module pattern)

//This is just wrapper function! Not a constructor! It's sole purpose is to provide
//closure for hiding private members. Module?
function Vehicle(type, registration){
//Private members
var defaultType = 'car';
var calcRegistration = function (registration){
return registration ? 'REG-'+registration : 'REG-UNKNOWN';
}
//(Public) Constructor
function Vehicle(type, registration){
this.Type = type || defaultType;
this.Registration = calcRegistration(registration);
}
//Public method
Vehicle.prototype.DumpData = function(){
console.log(this.Type,' ',this.Registration);
}
//object instantiation using constructor and provided params
return new Vehicle(type, registration);
}
function Bus(type, registration, passengers){
function Bus(type, registration, passengers){
//Call base constructor with params
Vehicle.call(this,type,registration);
this.Passengers = passengers;
this.Driver = "";
}
//Inherit methods from prototype of Parent
Bus.prototype = new Vehicle(type, registration, passengers);
//Revert to child constructor
Bus.prototype.constructor = Bus;
//Create new method on child prototype
//Note! Parent method DumpData is inheried/exists on child->prototype->prototoype
Bus.prototype.AssignDriver = function(){
if (this.Passengers>30)
{
this.Driver= "Jack";
}
else
{
this.Driver = "Jenny";
}
}
return new Bus(type, registration, passengers);
}

//new is not needed since Bus function is used to create instance.
var cityBus = new Bus('bus','ZZX23-1',10);
cityBus.AssignDriver();
console.log(cityBus);
var fordTransit = Vehicle('van','');
console.log(fordTransit);
fordTransit.DumpData();

Nov 6, 2018

JavaScript - How to get request url parts (segments)

 Extracting url parts:

var urlParts = window.location.pathname.split('/');
var lastSegment = urlParts.pop() || urlParts.pop();

window.location.href = window.location.pathname.replace(lastSegment, myQueryPath);

Oct 26, 2018

RePost: .NET Architecture guides - DDD, CQRS, Clean, Onion etc.



Set of really good (and free) e-books related to modern and distributed architectures:

Here is a interesting component to investigate (by the author of Automapper):



Here is a list of recommended code samples to look and digest:

Metrics:
https://www.app-metrics.io/






Oct 19, 2018

ASP.NET Core 2.1 - NuGet - Blocked by project issue - AspnetCore.App

Some NuGet packages are added by default as part of framework.

https://docs.microsoft.com/en-us/nuget/tools/package-manager-ui#updating-a-package

For example : Microsoft.ASPNetCore.App.

If you get error that you can not update them to newest version with something like:
"Blocked by project. Update SDK"
; this could help.

Opet CSPROJ file and manually add this line under <PropertyGroup>:

<RuntimeFrameworkVersion>2.1.4</RuntimeFrameworkVersion>



Oct 15, 2018

IoC - Dependecy injection - StructureMap - ASP.NET Core 2.1 - Using factory to inject all type implementations


There are different implementations of IApplicationContext:
- MyContext1
- MyContext2
Also in future we may add new implementations.
We want to use this context in generic class repository like this:

class MyRepository<T, C> : IRepository<T, C> where T : Entity<T> where C : IApplicationContext

So far everything is straightforward. Repository will know two dependencies - entity and repository.
Consumer classes will reference repository like this:

private IRepository<MyEntity, MyContext1> myRepo1;

But how to obtain instance of MyContext1 inside our MyRepository ?

We could write something like:

var context = new C();

It would work but we could not write unit tests for such class since we create explicit instance inside our method which breaks dependecy injection effort.

Alternative is quite elegant and supported by StructureMap IoC container.

First step is to explicitly scan for all instances of our context like this:

Scan(scan =>
{
scan.AssembliesFromApplicationBaseDirectory();
scan.WithDefaultConventions();
scan.AddAllTypesOf<IApplicationContext>();
});

Then comes the magic touch :)
We create new Factory class. 

Array of contexts is populated with all known implementations of IApplicationContext.

And lastly the requested one is selected from that list through simple generic method:

public class ApplicationContextFactory : IApplicationContextFactory

{

private readonly IApplicationContext[] _applicationContexts;

public ApplicationContextFactory(IApplicationContext[] applicationContexts)
{
_applicationContexts = applicationContexts ?? throw new ArgumentNullException(nameof(applicationContexts));

}

public IApplicationContext GetContext<T>() where T : IApplicationContext
{

return _applicationContexts.SingleOrDefault(c => c is T);

}
}

Factory is then used in our repository generic class to resolve in simple way our instance required by type that called repository:

_applicationContext = _applicationContextFactory.GetContext<C>();

Oct 5, 2018

JQuery Validation on dynamic form (ASP.NET MVC unobtrusive)

Update

Just add this line in your injected form or in success callback:

              $.validator.unobtrusive.parse("form");              

Bellow code is not needed but it may be useful for its context...

For some reason I've could only make it work on explicit input event binding.

    $(document).off('change', 'input', onInputChange);
        $(document).on('change', 'input', onInputChange);
 function onInputChange() {   
        //Manually initiate unobtrusive validation so error messages are shown
        $(this).closest("form").valid();     
    }

If you are saving using Ajax then prevent saving something like this:

    function SaveItemCallback(e) {
        e.preventDefault();
        if ($(this).closest('form').valid() === false) {
            return;
        }
 var postBody = $(this).closest('form').serialize();
        $.post(options.urlSave, postBody, function (id) {
            loadDetails(id);
        })
            .fail(function () {
                toastr.error(myErrorText);
            });

Sep 25, 2018

RePost: Naming convention - How to avoid calling everything with suffix "Manager"

https://stackoverflow.com/questions/1866794/naming-classes-how-to-avoid-calling-everything-a-whatevermanager?rq=1

Visul Studio Snippets - JavaScript revealing modul template

Here is snippet for revealing modul template explained among other here:

https://addyosmani.com/resources/essentialjsdesignpatterns/book/#revealingmodulepatternjavascript

For some reason only way to register is to create custom folder and use "Add" instead of "Import".
Bad part is that it doesn't get copied but just keeps reference to your folder.


<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
    <CodeSnippet Format="1.0.0">
        <Header>
            <Title>JS revealing module pattern</Title>
              <Shortcut>jsmodule</Shortcut>
        </Header>
        <Snippet>
            <Declarations>           
            <Object>
                <ID>Namespace</ID>
                <Type>object</Type>
                <ToolTip>Namespace</ToolTip>
                <Default>Namespace</Default>
            </Object>
            </Declarations>
            <Code Language="CSharp">
                <![CDATA[
                    "use strict";
                    var Snt = Snt || {};
                    Snt.$Namespace$ = Snt.$Namespace$ || {};
                    Snt.$Namespace$.ViewManager = (function () {
                        var options = null;
                       
                        function init(optionsParam) {
                            if (optionsParam) {
                                $$.extend(options, optionsParam);
                            }
                        }
                        return {
                            Init : init                       
                        };
                    })();
                ]]>
            </Code>
        </Snippet>
    </CodeSnippet>
</CodeSnippets>

Sep 24, 2018

Azure Cosmos Db tips (SQL)

https://docs.microsoft.com/en-us/azure/cosmos-db/sql-api-sql-query
Clause FROM refers to Collection of something.
If you deal with only one collection you can replace it with special keyword:

Root

; like this:

SELECT
Root.id,
Root.description,
Root.tags,
Root.foodGroup,
Root.manufacturerName,
Root.version
FROM Root
WHERE (Root.manufacturerName = "The Coca-Cola Company" AND Root.version > 0)


Here is good practical explanation in approaching the document design vs relational design.

https://docs.microsoft.com/en-us/azure/cosmos-db/modeling-data

When to embed and when not, or when to normalize and when keep stuff denormalized.

Sep 20, 2018

ASP.NET Core 2.1 - Download file (push)



[HttpGet]
        public async Task<IActionResult> DownloadAsync(int id)
        {
            var model = _baseRepository.Get<Literature>(id);
            var vModel = _mapper.Map<LiteratureViewModel>(model);
            if (model == null)
            {
                return Content(Resources.SharedResource.ErrorDownloadFileFileNotFound);
            }
            var memory = new MemoryStream();
            var fullName = _literatureService.GetFullPath(vModel);
            using (var stream = new FileStream(fullName, FileMode.Open))
            {
                await stream.CopyToAsync(memory);
            }
            memory.Position = 0;
            return File(memory, _literatureService.GetContentType(vModel), vModel.FileName);
        }


public string GetContentType(LiteratureViewModel model)
        {
            var types = GetMimeTypes();
            var ext = Path.GetExtension(model.FileName).ToLowerInvariant();
            return types[ext];
        }
        private Dictionary<string, string> GetMimeTypes()
        {
            return new Dictionary<string, string>
            {
                {".txt", "text/plain"},
                {".pdf", "application/pdf"},
                {".doc", "application/vnd.ms-word"},
                {".docx", "application/vnd.ms-word"},
                {".xls", "application/vnd.ms-excel"},
                {".xlsx", "application/vnd.openxmlformatsofficedocument.spreadsheetml.sheet"},
                {".png", "image/png"},
                {".jpg", "image/jpeg"},
                {".jpeg", "image/jpeg"},
                {".gif", "image/gif"},
                {".csv", "text/csv"}
            };
        } 

Sep 18, 2018

Visual Studio Snippet - IoC service reference

Standard pattern for IOC is to register you service interface through private field and constructor.
Here is Visual Studio snippet to help with that.
It's not fully auto but helps a lot to me.

<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
    <CodeSnippet Format="1.0.0">
        <Header>
            <Title>IoCserviceReference</Title>
              <Shortcut>iocsrv</Shortcut>
        </Header>
        <Snippet>
            <Declarations>
            <Object>
                <ID>IService</ID>
                <Type>Interface</Type>
                <ToolTip>Service interface.</ToolTip>
                <Default>IService</Default>
            </Object>
            <Object>
                <ID>ServiceVar</ID>
                <Type>object</Type>
                <ToolTip>Service variable.</ToolTip>
                <Default>serviceVar</Default>
            </Object>
            </Declarations>
            <Code Language="CSharp">
                <![CDATA[
                    private readonly I$IService$ _$IService$ = null;
                    I$IService$ $IService$
                    _$IService$ = $IService$ ?? throw new ArgumentNullException(nameof($IService$));
                ]]>
            </Code>
        </Snippet>
    </CodeSnippet>
</CodeSnippets>

Sep 14, 2018

ASP.NET Core 2.1 - custom tag helper - render all hidden fields from model marked with Hidden attribute


Creating custom tag helper to inspect provided model
 public class StudentExamViewModel : ExamBaseViewModel
    {
        [HiddenInput]
        public int StudentId { get; set; }       
    }

 [HtmlTargetElement("hidden-fields")]
    public class HiddenFieldsTagHelper : TagHelper
    {
        [HtmlAttributeName("for-model")]
        public ModelExpression Model { get; set; }
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            output.TagName = "div";
            output.TagMode = TagMode.StartTagAndEndTag;
            var sb = new StringBuilder();         
            Model.ModelExplorer.ModelType.GetProperties()
                                 .Where(prop => Attribute.IsDefined(prop, typeof(HiddenInputAttribute)))
                                 .ToList()
                                 .ForEach(hp =>
                                 {
                                    var propVal = Model.Model.GetType().GetProperty(hp.Name).GetValue(Model.Model, null);
                                    sb.AppendFormat($"<input type='hidden' name='{hp.Name}' value='{propVal}' />");
                                 });
            output.PreContent.SetHtmlContent(sb.ToString());
        }
    }

Use in View:

 <hidden-fields for-model="@Model" />

Register in ViewImports.cshtml:

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Web
Note that you need to reference root namespace!

Sep 12, 2018

ASP.NET Core 2.1 - Extending buildin taghelpers - select

Extend existing select tag helper:

namespace Web.Infrastructure.TagHelpers
{
    [HtmlTargetElement("examcategories", Attributes = ForAttributeName)]
    public class ExamCategorySelectTagHelper : SelectTagHelper
    {
        private const string ForAttributeName = "asp-for";
        private readonly IBaseRepository _baseRepository = null;
        public ExamCategorySelectTagHelper(
            IHtmlGenerator generator,
            IBaseRepository baseRepository
            ) : base(generator)
        {
            _baseRepository = baseRepository ?? throw new ArgumentNullException(nameof(baseRepository));
        }
       
        public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
        {
            Items = new List<SelectListItem>()
            {
                new SelectListItem() { Text = "dummy", Value="dummy"  }
            };
            output.TagName = "select";
            await base.ProcessAsync(context, output);
        }
    }
}
Don't forget to fix your tagname to generate proper HTML select (bold above).

Register assembly with your taghelpers in _ViewImports.cshtml

Watch it! For some reason you MUST register complete assembly namespace. In my case it was:

@addTagHelper *, Web

This WON'T work:

@addTagHelper *, Web.Infrastructure.TagHelpers

Don't know why :(

Rebuild and you should have proper reference in Visual Studio autocomplete.

                <examcategories asp-for="ExamCategoryId" asp-items="ViewBag.Dummy" class="form-control"></examcategories>
Cool thing is that you can peek into production tag helper source code on GitHub:





Sep 10, 2018

ASP.NET Core 2.1 - Identity - Multiple authentication policies or customizing default policy

In previous article http://developmentfootprints.blogspot.com/2018/09/aspnet-core-21-identity-using-hardcoded.html is demonstrated basic simplest approach in using hardcoded roles.
Here I'm addressing two further levels of customizing authorization which can include roles also.

You can use this approach for customizing default authentication/authorization or for implementing multiple authorization schemes in your app.

In a nutshell Identity authorization  implements collection of authorization policies and each of these can implement number of authentication schemes. As stated in previous article by default you have one authorization policy named:

Identity.Application

You can easily add new policies in your ConfigureServices like this:

services.AddAuthorization(options =>
                {
                    options.AddPolicy(nameof(RoleAuthorization.HasAdminRole), policyBuilder =>
                        {
                            policyBuilder.RequireRole(RoleAuthorization.AdminRole);
                            policyBuilder.AddAuthenticationSchemes(nameof(RoleAuthorization.HasAdminRole));

                        });

In above example we build new Policy with only one rule and we map it to appropriate auth scheme. This scheme must be registered like this:

     services.AddAuthentication()
                    .AddCookie(nameof(RoleAuthorization.HasAdminRole), options => ConfigureHasAdminRole(options));


It configures identity how to configure authentication for your new Policy using cookie.

Read previous article: 
http://developmentfootprints.blogspot.com/2018/09/aspnet-core-21-identity-using-hardcoded.html

; on small intro to policy and auth scheme and a way you can work with provided defaults without need of creating new policies or authentication schemes (cookies). It's not just cookies :)



Make sure to explore policyBuilder members. They provide with elegant approach to define most common rules you may have about Claims, Roles etc.

If you still can't express your rules use fully custom AuthorizeHandler. Add new extension:

public class LoyaltyUserLoggedIn : AuthorizationHandler<LoyaltyUserLoggedIn>, IAuthorizationRequirement

    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, LoyaltyUserLoggedIn requirement)
    {
        if (//check someting ... )
        {
            context.Succeed(requirement);
        }
        else
        {
            context.Fail();
        }

        return Task.CompletedTask;
    }
}

Register your new AuthorizationHandler as new requirement in your new Policy :

options.AddPolicy("LoyaltyLoggedIn", policyBuilder =>
{
policyBuilder.Requirements.Add(new LoyaltyUserLoggedIn(container.GetInstance<ILoyaltySecurityService>()));
policyBuilder.AddAuthenticationSchemes("LoyaltyCookie");
});

Authentication cookie configuration mapping is same as before.



Let's recap. There are policies which consist of number of requirements (claims, roles, custom) and related authentication schemes.

This is just a top of the iceberg of your options to customize Identity. There is also concept of permissions associated with Claims. Still haven't used that.


Sep 7, 2018

ASP.NET Core 2.1 Identity- Very simple role management using hardcoded roles in code with command IsInRole & Roles attribute

Update
Make sure to read this first:
https://techbrij.com/asp-net-core-identity-role-policy-authorization
; and this:
https://docs.microsoft.com/en-us/aspnet/core/security/authorization/roles?view=aspnetcore-2.1


After spending hours in searching very simple thing and passing few iterations of reducing too complex approach with simpler here are my tips.

Requirement is basic. Application has fixed, hard coded roles like this:



    public class RoleAuthorization

    {

        public const string IdentityApplication = "Identity.Application";



        public const string StudentRole = "STUDENT";

        public const string AdminRole = "ADMIN";

    }



When user is successfully authenticated with standard forms authentication we check in which roles he belongs.

Roles info is persisted in authentication cookie.

Appropriate controllers are protected with standard Authorize attribute like this:



  [Authorize(Roles =RoleAuthorization.StudentRole)]



Further more when needed we can check using User.IsInRole("ADMIN") does authenticated user belongs to given role.

Later I've discovered that this auth scheme name is part of IdentityConstants type:

IdentityConstants.ApplicationScheme

Also it seems that my requirement could be described as "Use cookie authentication without ASP.NET Core Identity" as explained here:

https://docs.microsoft.com/en-us/aspnet/core/security/authentication/cookie?view=aspnetcore-2.1&tabs=aspnetcore2x



Let's first look at big picture. There is default Policy. It consist of one or more authentication schemes. These can be different mechanisms apart from standard Cookie. Default authentication scheme name is registered in type CookieAuthenticationDefaults as:

CookieAuthenticationDefaults.AuthenticationScheme

This is key concept. Make sure that all referencing in Authorize attribute, SingIn etc. is done through this constant.
In simpliest form you (optionally) configure only default cookie auth mechanism. This is optional since default policy and its default cookie authentication scheme are already predefined.
I think that default policy name is defined in IdentityConstants type as :

IdentityConstants.ApplicationScheme

But to my knowledge there is no need to reference explicitly anywhere.

To achieve simple cookie configuration with default policy and default authentication scheme put this in your Startup inside ConfigureServices:

 services.AddAuthentication()
                    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>ConfigureCookie(options));
; and optionally configure your authentication rules like this:

   private void ConfigureCookie(CookieAuthenticationOptions options)
        {
            PathString loginUrl = new PathString($"/{nameof(AccountController).DropController()}/{nameof(AccountController.Login)}");
            options.LoginPath = loginUrl;
            options.AccessDeniedPath = loginUrl;         
            options.LogoutPath = loginUrl;
            options.ReturnUrlParameter ="ReturnUrl";
            options.ExpireTimeSpan = TimeSpan.FromMinutes(10);
        }

To achieve registering your authenticated user role(s) inside cookie you need to build claims with appropriate role name and perform singin with this mentioned default auth policy name CookieAuthenticationDefaults.AuthenticationScheme.

Here is excerpt from my working login action:

 [HttpGet]
        public IActionResult Login(string returnUrl = null)
        {
            //If you omit this IF you'll endup with error ERR_TOO_MANY_REDIRECTS
           //since each logout calls again this action
            if (User.Identity.IsAuthenticated)
            {             
                HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
            }

            ViewData[CookieAuthenticationDefaults.ReturnUrlParameter] = returnUrl;
            return View();
        }
      [HttpPost]
        public IActionResult Login(LoginViewModel model, string returnUrl = null)
        {         
            ViewData[CookieAuthenticationDefaults.ReturnUrlParameter] = returnUrl;
            if (ModelState.IsValid)
            {
                ApplicationUser user;
                if (!IsAuthenticated(model, out user))
                {
                    return View(model);
                }
                var rolesForUser = _userManager.GetRolesAsync(user).Result;             
                LoginType loginType = LoginType.Undefined;
                string roleName = string.Empty;
                if (rolesForUser.Contains(RoleAuthorization.AdminRole))
                {
                    loginType = LoginType.Admin;
                    roleName = RoleAuthorization.AdminRole;
                }
                else if (rolesForUser.Contains(RoleAuthorization.StudentRole))
                {
                    loginType = LoginType.Student;
                    roleName = RoleAuthorization.StudentRole;
                    var student = _baseRepository.GetByForeignKey<Student>(nameof(Student.ApplicationUserId), user.Id).FirstOrDefault();
                }
                else
                {
                    ModelState.AddModelError("", Resources.SharedResource.ErrorUnauthorized);
                    return View(model);
                }
                CreatePrincipalWithClaimsAndSignIn(model.UserName, roleName, IdentityConstants.ApplicationScheme);
                return RedirectToLocal(returnUrl, loginType);
            }

; and crucial part, creating claims and performing user sign in with default auth policy.



   private void CreatePrincipalWithClaimsAndSignIn(string userName, string role)
        {
            var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);         
            identity.AddClaim(new Claim(ClaimTypes.Name, userName));
            identity.AddClaim(new Claim(ClaimTypes.Role, role));
            var principal = new ClaimsPrincipal(identity);
            HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);
        }


You must specify explicitly default auth scheme although one would expect to be used by default since it is only default auth mechanism and method SingInAsync has overload without specifying auth scheme.

//Doesn't work!
          HttpContext.SignInAsync(principal);

All examples I could find pointed to SignInManager class which doesn't support building claims.



Most frustrating is that you can call above SignInAsync without auth policy :



            await HttpContext.SignInAsync( principal);



; and it won't raise exceptions nor perform expected authentication.


Lastly Authorize attribute must be properly decorated.

[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme, Roles =RoleAuthorization.StudentRole)]


This threw me off path. Note that you DON'T specify POLICY but SCHEME. You must do it even if it is default and only auth scheme in your system. Now you could define one policy with more than one scheme and even more than one policy with its own schemes. It looks that scheme name must be unique.


Here are some helpfull links on subject:

https://stackoverflow.com/questions/45695382/how-do-i-setup-multiple-auth-schemes-in-asp-net-core-2-0

https://docs.microsoft.com/en-us/aspnet/core/security/authorization/limitingidentitybyscheme?view=aspnetcore-2.1&tabs=aspnetcore2x


https://dzone.com/articles/how-to-add-policy-based-authorization-to-an-aspnet

Sep 5, 2018

C# passing class member name as argument using lambda expression


I want to pass name of one of my class member as argument to method. Goal is to avoid sending plain string and forcing strongly type parameter. Here is the solution how to send and extract member name.
Watch it. We assume this lambda c => c.Id format. Any other will generate error in runtime.

if (expression.Body.NodeType == ExpressionType.Convert)
            {
                return ((expression.Body as UnaryExpression).Operand as MemberExpression).Member.Name;
            }
            else
            {
                return (expression.Body as MemberExpression).Member.Name;
            }

...
class MyClass
{
       public int Id;
}
var d = new MyClass();
Build( c=>d.Id);
This was inspired with AutoMapper.

Aug 29, 2018

ASP.NET Core localization - Shared resources - simplest scenario RePost

I need one simple shared resource file for placing my label and error text in one place. There is no need for localization but resource file is best choice.

I've picked only bare minimum from this post:

https://damienbod.com/2017/11/01/shared-localization-in-asp-net-core-mvc/

Currently I'm working on ASP.NET Core 2.1

1. Create Resources folder in your Web project and inside create SharedResources.resx. Select from access modifier of resource file designer "Public".

2. Create override of localization factory as explained in above post:

public class CustomLocalizationService
    {
        private readonly IStringLocalizer _localizer;
        public CustomLocalizationService(IStringLocalizerFactory factory)
        {
            var type = typeof(SharedResource);
            var assemblyName = new AssemblyName(type.GetTypeInfo().Assembly.FullName);
            _localizer = factory.Create(nameof(SharedResource), assemblyName.Name);
        }
        public LocalizedString Get(string key)
        {
            return _localizer[key];
        }
    }
3. Register your new service in Startup:

     public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<CustomLocalizationService>();
            services.AddLocalization(options => options.ResourcesPath = "Resources");

4. Fix MVC options to support view localization and support for Data annotations error messages:

services.AddMvc()
                .AddViewLocalization()
                .AddDataAnnotationsLocalization(options =>
                  {
                      options.DataAnnotationLocalizerProvider = (type, factory) =>
                      {
                          var assemblyName = new AssemblyName(typeof(SharedResource).GetTypeInfo().Assembly.FullName);
                          return factory.Create(nameof(SharedResource), assemblyName.Name);
                      };
                  }); 
5. Finally when using in View you must use your new localization wrapper:

@inject CustomLocalizationService SharedLocalizer

Data annotations should look like this:

[StringLength(200, ErrorMessageResourceName = "ValidationErrorTooLongText", ErrorMessageResourceType =typeof(SharedResource))]

For some reason I couldn't use dot in my resource key naming so instead of:

Validation.Error.TooLongText

; I had to write:

ValidationErrorTooLongText

Jul 10, 2018

ASP.NET Core custom validation for required on file upload or radio - dirty way

In some cases like radio group or file upload buttons standard Required validation with JQuery don't work.
There is legit way of registering custom validation attributes for both serves side Model and for client side.
This is dirty way ...

Just create in doom so small that is not visible (NOT HIDDEN! ) input with same dom name.

   <span asp-validation-for="ImageRaw" style="padding-left:15px" class="text-danger"></span>
                        <input style="width:0px;border:0px!important;padding:0px;" type="text" asp-for="ImageRaw" />

If you hide it JQuery validation will ignore it. Through JQ apply changes to real input on the hidden one.

  $(document).on('change', 'input[name="PersonImage"]', function () {
            $('input#ImageRaw').val($(this).val());
        });




Jun 14, 2018

.NET C# Operations with flagged Enumerations

[Flags]
public enum Category
{
Undefined = 0,
AdultsOnly = 1,
Family = 2,
AllInclusive = 4,
City = 8
}
void Main()
{
Category c = Category.AdultsOnly | Category.City; Category[] categories = new Category[2] { Category.AllInclusive, Category.Family};
Category category = categories.Aggregate((i, t) => i | t);
var isThereAtLeastOneMatch = (c & category) != Category.Undefined;
var hasExact = (c & Category.AdultsOnly )== Category.AdultsOnly;
}

Jun 11, 2018

asp.net core 2.0 DataFormatString DisplayFor

Propert display formatting that worked in ASP.NET Core 2.0 :

                        <span class="room-price">@(Html.DisplayFor(m => rate.Price))&euro;</span>

[DisplayFormat(DataFormatString = "{0:#,###.00}", ApplyFormatInEditMode =false, NullDisplayText ="")]
public decimal Price { get; set; }       

Important!  Don't use DisplayTextFor!

Jun 7, 2018

asp.net mvc core 2.0 validating checkbox

Explains how to force required on checkbox.

    <input type="checkbox" id="TermsOfUseFake">
                        <label for="TermsOfUseFake"><a href='@navLinks.GetSitePageLink(languageGroupId: "TermsOfUse")' target="_blank">@Localizer["Loyalty.RegisterForm.TermsOfUse"]</a></label><br>
                        <input style="width:0px;border:0px!important;padding:0px;" type="text" asp-for="TermsOfUse" />
                        <span asp-validation-for="TermsOfUse" class="text-danger"></span>                        


 $(document).on('change', '#TermsOfUseFake', function () {
                debugger;               
                if ($('#TermsOfUseFake:checked')[0]) {
                    $('#TermsOfUse').val("true");
                }
                else {
                    $('#TermsOfUse').val("");
                }
                $("form#registerForm").validate().element("#TermsOfUse");
            });

ASP.NET MVC Core 2.0 - Resource Key is not compiled from RESX file

Open RESX and change Access Modifier to Public.

Make sure that project builds without error. You can be misled that RESX cant be built while you have compile error.

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");}
}

Apr 20, 2018

Javascript / Jquery working with arrays

When accessing jquery selector that returns list of elements you can't access elements using standard array methods:
- find
- map
- filter
Use only JQuery each.

var getCheckedInputIdList = function () {
        var checked = $('#map input.mapFilterControl[type="checkbox"]:checked');
        var checkedIdList = [];
        checked.each(function () {
            var filterItemValue = $(this)[0].id;
            checkedIdList.push(filterItemValue);
        });
        return checkedIdList;
    }


    var doesExistForId = function (arr, findThis) {
        return arr.find(function (element) {
            return element && element.Id === findThis.Id;
        })
    }


Short-hand or Arrow functions ( C# lambda like)

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

Warning! Arrow functions don't support "this" or constructors ?

Reduce, Slice & Join in Action

"You are given an array strarr of strings and an integer k. Your task is to return the first longest string consisting of k consecutive strings taken in the array.

#Example: longest_consec(["zone", "abigail", "theta", "form", "libe", "zas", "theta", "abigail"], 2) --> "abigailtheta"

n being the length of the string array, if n = 0 or k > n or k <= 0 return ""."
function longestConsec(strarr, k) {   
    return strarr.length > 0 && strarr.length >= k && k > 0
      ? strarr.reduce((longest, item, i) => {
        var curr = strarr.slice(i, i + k).join('');
          return curr.length > longest.length ? curr : longest;
           }, strarr.slice(0,k).join(''))
      : "";   
}
console.log( longestConsec(["wlwsasphmxx","owiaxujylentrklctozmymu","wpgozvxxiu"], 2) ); 

Reduce must produce single result. Watch for initial value for acumulator! In above sample we had to explicitly calculate it by joining k elements. By default it will take myArray[0] for acumulator value. 
Use it to iterate and calculate single result. Note how you don't have to care for "index out of range". Example shows how you iterate using reduce and again using slice inside on same array.

Slice DOESN'T take second index so for ...slice(0,1) you'll get only element[0] !

Join without params like this Join() will use ',' as delimiter. Use explicit Join('') for empty delimiter.

Mar 27, 2018

ASP.NET Entity Framework 6 Code First Migrations - basics (.NET 4.6.2 standard)

Create empty Web application with MVC (.NET 4.6.2)
Add Entity Framework as NuGet package.
Create first model:

public class Person
    {
        [Key]
        public int Id { get; set; }
        [Required]
        [StringLength(24)]
        public string FirstName { get; set; }
        [Required]
        public string LastName { get; set; }
    }
Run in Package Manager Console:

PM> enable-migrations
This will create Migrations folder with Configuration class. Enable auto migrations by changing this:

AutomaticMigrationsEnabled = true;

Create Context class. Here you must register all your models for database:

    public class AdresarContext : DbContext
    {
        public AdresarContext() : base("Adresar")
        {
        }
        public DbSet<Person> Persons { get; set; }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Conventions.Remove<System.Data.Entity.ModelConfiguration.Conventions.PluralizingTableNameConvention>();
        }
    }
Run in PM console:

PM> update-database -verbose
This should generate Database with table(s).

Let's add extra table with master detail relationship.

New class:

public class City
    {
        [Key]
        public int Id { get; set; }
        [StringLength(25)]
        public string Name { get; set; }
        public ICollection<Person> Persons { get; set; }
    }
Reference it in Person:

 [Required]
        public City City { get; set; }

Register it in Context:

        public DbSet<City> Cities { get; set; }

Run update again:

PM> update-database -verbose



Mar 19, 2018

Simple Javascript class with closure example for form with panels activated using buttons

This JS design is described as revealing modul template.
Here are more patterns:

https://addyosmani.com/resources/essentialjsdesignpatterns/book/#revealingmodulepatternjavascript


"use strict";
var Acme = Acme || {};
Acme.TravelAgency = Acme.TravelAgency || {};
Acme.TravelAgency.RegisterForm = (function () {
    const btnActiveCSS = "btn-danger";
    var options = null;

    var init = function (optionsParam) {
        options = {
            conjuctionWord: ' in '
        };
        if (optionsParam !== undefined) {
            $.extend(options, optionsParam);
        }
    }
    var dom = {
        btnYourInfoId: "#btnYourInfo",
        btnAccountSetup: "#btnAccountSetup",
        panelAccountSetupId: "#panelAccountSetup",
        panelYourInfoId: "#panelYourInfo"
};
function bindCallBacks() {
$(document).on('click', dom.btnAccountSetup, show);
        $(document).on('click', dom.btnYourInfoId, show);
}
function show(senderBtnId) {
$(dom.panelAccountSetupId).hide();
$(dom.panelYourInfoId).hide();
senderBtnId = resolveSender(senderBtnId);
switch (senderBtnId) {
    case dom.btnYourInfoId:
        activateStepIcon(senderBtnId);
$(dom.panelYourInfoId).show();
                break;
            case dom.btnAccountSetup:
                activateStepIcon(senderBtnId);
                $(dom.panelAccountSetupId).show();
break;
default:
break;
}
}
function activateStepIcon(btnId)
{   
        $(dom.btnYourInfoId).removeClass(btnActiveCSS);
        $(dom.btnAccountSetup).removeClass(btnActiveCSS);
    $(btnId).addClass(btnActiveCSS);
}
function resolveSender(senderId) {
var result = senderId;
if (senderId.currentTarget && senderId.currentTarget.id)
result = senderId.currentTarget.id;
if (senderId[0] !== "#") {
result = "#" + result;
}
return result;
}
var init = function () {
bindCallBacks();
show(dom.btnYourInfoId); }
return new Object({
Init : init
});
})();

Feb 28, 2018

.NET Core 2.0 SOAP platform not supported error

For developing SOAP / WCF services use:

System.ServiceModel.Http  NUPackage

Use SVCUTIL to generate proxy from WSDL file or url.

If you get error :

PlatformNotSupportedException: Compiling JScript/CSharp scripts is not supported

read this:

https://github.com/dotnet/wcf/issues/2219

Put this before Client method call:

    MethodInfo method = typeof(XmlSerializer).GetMethod("set_Mode", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
    method.Invoke(null, new object[] { 1 });

Feb 15, 2018

Bootstrap Custom Controls

Feb. 2018

Bootstrap Date picker with localization

Only one package required for example Bower or npm:

bootstrap-datepicker 

Reference package and css with appropriate Locale file. Dist folder is here only due to Bower :

    <link rel="stylesheet" href="~/lib/bootstrap-datepicker/dist/css/bootstrap-datepicker.standalone.min.css" />
...

<script src="~/lib/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js"></script>
 <script src="~/lib/bootstrap-datepicker/dist/locales/bootstrap-datepicker.hr.min.js"></script>

Set language param during init and it should work:

            $('input[name="Birthday2"]').datepicker({
                isRTL: false,
                format: 'dd.mm.yyyy',
                autoclose: true,
                language: 'hr'
            });


Bootstrap Multiselect Checkpoint

https://github.com/davidstutz/bootstrap-multiselect.git

http://davidstutz.de/bootstrap-multiselect/

Apply on existing <select> DOM element.

<script src="~/lib/bootstrap-multiselect/dist/js/bootstrap-multiselect.js"></script>
<link rel="stylesheet" href="~/lib/bootstrap-multiselect/dist/css/bootstrap-multiselect.css"/>


$(dom.multiselectCss).multiselect();

Feb 6, 2018

ASP.NET MVC - Injecting C# data into Java script

Inside Razor view use Newtonsoft JSON serialization from C# to JSON:

@Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(ViewBag.CityList,  Newtonsoft.Json.Formatting.None));

Jan 31, 2018

ASP.NET MVC custom culture client validation

Further info here: http://www.c-sharpcorner.com/article/internationalization-in-asp-net-core-mvc/

Watch for @inject ... for Localization property

Install NuGet packages:
- jquery-globalize.0.1.3
- jquery.validation
- Microsoft.jQuery.Unobtrusive.Validation

Choose your culture and properly initialize globalize library:

    <script src="~/Scripts/globalize.0.1.3/globalize.js"></script>

    <script src="~/Scripts/globalize.0.1.3/cultures/globalize.culture.hr.js"></script>
    <script>

        $(document).ready(function () {

            Globalize.culture("hr");

            $.validator.methods.number = function (value, element) {

                return this.optional(element) || !isNaN(Globalize.parseFloat(value));

            }

            $.validator.methods.range = function (value, element, param) {

                return this.optional(element) || (Globalize.parseFloat(value) >= param[0] && Globalize.parseFloat(value) <= param[1]);

            }

            $.validator.methods.date = function (value, element) {

                return this.optional(element) || Globalize.parseDate(value);

            };

        });

    </script>

This handles check on client side on input values.

I haven't tried but for input validation there is DataFormatString param validation:


[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime? BirthDate { get; set; }

https://stackoverflow.com/questions/13916991/mvc-datatype-errormessage