Thursday, September 27, 2018

ASP.NET Core and Angular Ignore TimeZone – Part 1 of 2


Date and Time is always hard, especially when it spans across time zones. Once your application becomes global, the time zone related issues become inevitable. This becomes harder with Single Page Application Technology, now we need to sync date between the javascript running on browser and with that of server.

Have you faced issue where you are losing a day or getting a day more than what user entered in your Angular application? Chances are that your server is in one time zone and your user is in a different time zone. Your user enters the date or picks the date using a calendar control (example Expiration Date). Due to time zone difference, the date may change when it reaches server. For example, user in India picked date at 27-09-2018 at 9:00 AM, the server in California receives this date as 26-09-2018 8:30 PM. If you are considering only date part then your date will be one day less (26th instead of 27th) due to this time zone conversion.

Below are the two solutions for this problem:
  1. Ignore time zone globally when sending data between browser and server
  2. A more elegant solution is to ignore time zone only for specific date controls or properties

In this blog, I will cover the first solution and in my next blog I will go over the second solution.

Ignore time zone globally
In most applications, we do not need to consider time. In these applications, ignoring time zone is the best approach. As you know, Angular and ASP.NET by default convert the date from one time zone to another time zone. This is true even if you are sending just date.

The best way for this problem, is to remove time zones while exchanging data between ASP.NET and Angular. Unfortunately, there is no out of box solution to remove time zones. However, the solution is very easy. When the data is exchanged between ASP.NET and Angular, the data is serialized to JSON and is transferred. We can tap into this serialization process and can force date conversion to ignore time zone.

ASP.NET Core by default uses Json.NET to serialize the data. In Json serialization configuration, we can specify the date serialization to remove time zone. For this, we need to pass the Date format as shown below:

.AddJsonOptions(options =>
{
      options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
      options.SerializerSettings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
      options.SerializerSettings.DateFormatString = "yyyy-MM-ddTHH:mm:ss";
});
In Angular we also need to override the Json serialization. Angular internally uses Json.stringy to serialize the object. Under hood, this json serializer uses toISOString. We can override this and provide the same format we used in the ASP.NET.


  Date.prototype.toISOString = function() {
      return this.getFullYear() + "-" + this.getMonth().toString().padStart(2, "0")
          + "-" + this.getDate().toString().padStart(2, "0") + "T"
          + this.getHours().toString().padStart(2, "0") + ":"
          + this.getMinutes().toString().padStart(2, 0) + ":"
          + this.getSeconds().toString().padStart(2, 0);
  };
By providing DateFormats without time zone on both ASP.NET and Angular we can ignore time zone. With this approach our application does not lose a day while sending data to and fro.

Sunday, December 10, 2017

Global CSS Styles in Angular

Angular recommends component based styling as the component should encapsulate every UI functionality. Here is a typical example using stylesheet for a component:

import { Component } from "@angular/core";

@Component({
    selector: "top-bar",
    templateUrl: "./TopBarComponent.html",
    styleUrls: ["./TopBarComponent.css"]
})
export class TopBarComponent {
}

In some situations we may need to have styles that we want to apply to multiple components or globally across the entire application. In this case we can define a css file and use it in the index.html page.

<link rel="stylesheet" href="~/styles.css" />

With the above approach we may lose the building and bundling provided by Angular and have to extend or implement a separate webpack or gulp task.
I recommend creating a separate component which contains all the global styles and expose these component’s style using encapsulation as shown below:

import { Component, ViewEncapsulation } from "@angular/core";

@Component({
    selector: "app-styles",
    template: "",
    styleUrls: ["./AppStyles.css"],
    encapsulation: ViewEncapsulation.None
})
export class AppStyles {
}

ViewEncapsulation.None exposes all the styles defined in AppStyles.css globally and these styles can be across the application. As a final step we need to include this AppStyles Component (which does not have any visible elments) inside our AppComponent


<app-styles></app-styles>

Friday, November 24, 2017

ASP.NET MVC style layout and section in Angular

As you know ASP.NET MVC provides a great feature for consistent look and feel with Layout engine. This layout engine consists of two main components, RenderBody and RenderSection which helps in defining hot areas in the page where we can substitute content from the current/active page. Almost everyone who worked/working in ASP.NET MVC have used this feature. In this blog I will go over how to recreate the same feature in Angular.

RenderBody

Similar to ASP.NET MVC we need to fill the content of the View at this location in HTML. In Angular this is similar to the router-outlet. So I will wrap the router-outlet with our own component called render-body. Here is the code for this:

import { Component } from '@angular/core';

@Component({
    selector: 'render-body',
    template: '<router-outlet></router-outlet>'
})
export class RenderBodyComponent {
}

RenderBody is straight forward. Whenever there is a route transition, Angular routing automatically inject the content of the view at this location. Here is how RenderBody can be used in the layout page

<render-body></render-body>

RenderSection

In MVC RenderSection allows a part of the layout page be replaced by the content defined in the current page. RenderSection allows us to define multiple named sections in the layout for which the content be defined in each page. It also allows to define a default content if the page does not specify the content.

I implemented the similar functionality in my RenderSection component. In addition I extended the RenderSection with an ability to hide from the content page. I also added the capability to have nested levels of RenderSection.

Similar to MVC, first you would define a named section and then in the content page specify the target where you would like the content to be displayed. Here is how you can use the RenderSection in the layout page with a default content (showing a menu)

<render-section name="menu" fxFlex="25">
    <b>Menu</b> <br />
    <a routerLink="/home">Home</a> <br />
    <a routerLink="/counter">Counter</a> <br />
    <a routerLink="/fetch-data">Fetch Data</a> <br />
</render-section>

In the content page this menu section can be replaced with page specific menu or content.

<render-section target="menu">
    Custom Menu from content page
</render-section>

Let’s delve into the code on how to implement the RenderSection component in Angular.
As we are showing content dynamically when a user navigates from page to page, we have to use ngTemplateOutlet. Angular transclusion (ng-content) is used for displaying the content. Here is the template code for RenderSection component for dynamic content:

<ng-container *ngTemplateOutlet="getTemplate()"></ng-container>
<ng-template #sectionRef>
    <ng-content></ng-content>
</ng-template>`

In the above code I am getting the current page’s template using the getTemplate function call and showing its content.
For each section I am capturing the following data (as defined in the SectionModel):

export class SectionModel {
    name: string;
    hidden: boolean;
    changeDetectorRef: ChangeDetectorRef;
    template: TemplateRef<any>;
    currentTemplate: TemplateRef<any>;
    targets: SectionTargetModel[];
}

Here are the details for each of the properties in the SectioModel
  • name – This holds the name of the section. This is used to display the content when the target is equal to the name of the template
  • hidden – This is the initial setting whether the section be hidden or not
  • changeDetectorRef – This is used to force a change detection when we set the target’s content to the section’s content. If a page has specified the content for a section (using target attribute), this page’s content is set to the section defined with name and the change detection is manually invoked for this section component
  • template – This is the default content for the section. If no target is defined in the content page, then this template is displayed as the section’s content
  • currentTemplate – This the template of the content which is currently shown. The currentTemplate is bound to the section template. This currentTemplate would contain either the default template or the template defined in the current page. A change detection is called whenever there is a change in this variable
  • targets – This is the stack of all the contents defined for a section. As my design support hierarchical replacement of the content, I am using stack. During the page load (ngAfterContentInit) if the page has a render-section, then the section’s template is pushed into this array. When this page is destroyed(ngOnDestroy), then the page’s template is poped. The targets are of type SectionTargetModel array whose definition is below:

export class SectionTargetModel {
    target: string;
    hidden: boolean;
    template: TemplateRef<any>;
}

Now let’s delve into the code. Surprisingly the code is very simple. We need three functions, push, pop and update. Here is important code for each of these functions.

push

As the name indicates it pushes the section defined either in the layout or in the page. This is also needed to support the default section content or the nested sections. During the page load (ngAfterContentInit), the section is pushed into the array.

public push(
            name: string,
            target: string,
            hidden: boolean,
            template: TemplateRef<any>,
            changeDetectorRef: ChangeDetectorRef
            ): void {

    if (name !== undefined) {
        this.sections[name] = <SectionModel>{
            name: name,
            hidden: hidden,
            changeDetectorRef: changeDetectorRef,
            targets: [<SectionTargetModel>{
                target: name,
                hidden: hidden,
                template: template
            }],
            template: template,
            currentTemplate: template
       };
       this.update(section);
    }
    else if(target !== undefined) {
        section.targets.push(<SectionTargetModel>{
            target: name,
            hidden: hidden,
            template: template
        });
        this.update(section);
    }
}

As you see above the code checks if the section with the name already exists or not, if not exists creates and pushes the section. If it exists it just pushes the section into the array. After pushing the section into the array, update is called to refresh the section in the layout and show the relevant section content from the page.

pop

Again as the name indicates, pop removes the page’s section content from the array. During page  destroyed(ngOnDestroy) the section is poped from the array. It also changes the section content from the array.

private popTemplate(name: string): void {
    let section: SectionModel = this.sections[name];
    section.targets.pop();
    this.update(section);
}

Similar to push the upgrade function is called in pop to refresh the section and to show the active content.

update

This sets the current template to a section and calls the change detection to refresh the section. This always shows the last section content in the array. It also has the logic to show or hide the section.

private update(section: SectionModel) {

    let targetSection = section.targets[section.targets.length - 1];
    section.currentTemplate = targetSection.template;
    if (targetSection.hidden) {
        section.template.elementRef.nativeElement.parentElement.style.display = "none";
    }
    if (!targetSection.hidden) {
        section.template.elementRef.nativeElement.parentElement.style.display = "block";
    }

    if (!(section.changeDetectorRef as ViewRef).destroyed) {
        section.changeDetectorRef.detectChanges();
    }
}

With these simple three functions, push, pop and update we can get the behaviour similar to that of ASP.NET MVC sections.
Finally here is the MVC type layout, which is a regular component in Angular. AppComponent can also be used for this.

<div fxLayout="row">
    <render-section name="menu" fxFlex="25">
        <b>Menu</b> <br />
        <a routerLink="/home">Home</a> <br />
        <a routerLink="/counter">Counter</a> <br />
        <a routerLink="/fetch-data">Fetch Data</a> <br />
    </render-section>
    <div fxFlex>
        <render-body></render-body>
    </div>
</div>

Finally I created an Angular module to wrap the RenderBody, RenderSection and supporting providers. You can review this code from my GitHub site


Sunday, April 2, 2017

Storing Identity Claims in Session or Redis


ASP.NET Core Identity by default uses cookies to store claims. If your authorization is very granular then you will end up using many claims. With all these claims stored in cookie, the cookie size gets bigger and you can exceed the cookie limit.

We can achieve the authorization granularity without exceeding the cookie limit and impacting the way ASP.NET Identity authorizes users by storing the claims in session, Redis or any other memory storage.

Below are the steps I implemented to store the claims in session.

First let’s store the claims in session (assuming that the ASP.NET Core Session is already configured). During authentication, Identity system uses SignInManager for creating principal object of the logged in user. While creating the principal object, Identity populates the claims. We can override this SignInManager and store the claims as shown below:

public class ApplicationSignInManager : SignInManager<ApplicationUser>
{
    private IHttpContextAccessor contextAccessor;

    public ApplicationSignInManager(UserManager<ApplicationUser> userManager, IHttpContextAccessor contextAccessor, IUserClaimsPrincipalFactory<ApplicationUser> claimsFactory, IOptions<IdentityOptions> optionsAccessor, ILogger<SignInManager<ApplicationUser>> logger)
        : base(userManager, contextAccessor, claimsFactory, optionsAccessor, logger)
    {
        this.contextAccessor = contextAccessor;
    }

    public override async Task<ClaimsPrincipal> CreateUserPrincipalAsync(ApplicationUser user)
    {
        var principal = await base.CreateUserPrincipalAsync(user);
        ClaimsIdentity identity = (ClaimsIdentity)principal.Identity;

        // storing claims in session and removing them. These claims will be added by Transformer
        List<ClaimModel> sessionClaims = new List<ClaimModel>();
        List<Claim> identityClaims = identity.Claims.ToList();
        foreach (var claim in identityClaims)
        {
            sessionClaims.Add(new ClaimModel() { ClaimType = claim.Type, ClaimValue = claim.Value });
            identity.RemoveClaim(claim);
        }

        this.contextAccessor.HttpContext.Session.SetString("IdentityClaims", JsonConvert.SerializeObject(sessionClaims));

        return principal;
    }
}

The Identity system should be configured to use our ApplicationSignInManager instead of the default one. For this we need to define the dependency injection in the Startup under ConfigureServices

services.AddScoped<SignInManager<ApplicationUser>, ApplicationSignInManager>();

As you see with above code claims are removed from the principal identity and stored in the session. These claims should to be added back to the principal identity for every request. This done through the claims transformer as shown below:

public class ClaimsTransformer : IClaimsTransformer
{
    public Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context)
    {
        ClaimsPrincipal principal = context.Principal;
        ClaimsIdentity identity = (ClaimsIdentity)principal.Identity;
        string claimString = NTContext.HttpContext.Session.GetString("IdentityClaims");
        if (claimString != null)
        {
            List<ClaimModel> sessionClaims = JsonConvert.DeserializeObject<List<ClaimModel>>(claimString);
            identity.AddClaims(sessionClaims.Select(sc => new Claim(sc.ClaimType, sc.ClaimValue)));
        }

        return Task.FromResult(principal);
    }
}

This ClaimsTransformer class is configured in the Startup under Configure section as shown below:

app.UseClaimsTransformation(new ClaimsTransformationOptions()
{
    Transformer = new ClaimsTransformer(),
});

app.UseIdentity();


With the above setup now the claims are stored in session when the user logs in. At every request from the user these claims will be copied from session to the identity object. Now we have overridden the default approach of using cookies with session J