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.