Sunday, January 29, 2017

Angular 2 UI-Grid



As you know currently (Jan 2017) UI-Grid is not supported in Angular 2 and there is no other data table that provides the functionality of what UI-Grid is providing. PrimeNG does provide a decent grid, ag-grid became commercial and Material 2 data table is still in specs. Considering the current state of other grids I opted to use UI-Grid in my next application. Yes, I need to take the overhead of loading Angular 1, but felt it is worth it. Also some of my applications are running on Angular 1 and Angular 2 side by side, hence I can use UI Grid without too much performance overhead.

To support UI-Grid in Angular 2, we need to use the Upgrade Module which enables us to run Angular 1 and Angular 2 side by side. Once the project is setup to have Angular 1, we need to write a wrapper that wraps the UI-Grid and provides a way to invoke this from Angular 2. Here is such wrapper, I am calling this as NT-Grid (NT stands for Nootus, the company I own)

export const ntGrid: ng.IComponentOptions = {
    bindings: {
        gridOptions: "<"
    },
    template: `<div ui-grid="$ctrl.gridOptions"></div>`
}

angular.module("ng2uigrid").component("ntGrid", ntGrid);

import { Directive, ElementRef, Injector, Input, Output, EventEmitter } from "@angular/core";
import { UpgradeComponent } from "@angular/upgrade/static";

@Directive({
    selector: "nt-grid"
})
export class NtGridDirective extends UpgradeComponent {
    @Input() gridOptions: any;

    constructor(elementRef: ElementRef, injector: Injector) {
        super("ntGrid", elementRef, injector);
    }
}

Here is the screenshot of UI grid in my Angular 2 POC.

This POC is on GitHub


Monday, January 23, 2017

Startup- Multi-Tenant Claim Based Identity for ASP.NET Core - Part 6 of 10



This part 5 of 10 part series which outlines my implementation of Multi-Tenant Claim Based Identity. For more details please see my index post.


As you know Startup is used for configure the request pipeline that handles all requests made to the application. I am using this Startup to configure the following:
  •  Configure Identity Framework
  • Dependency Injection of Identity classes and my classes
  • Automapper configuration (optional)

Here are the different sections of Startup. I have included only relevant code.

Startup Constructor
This is standard code. In this I am saving the connection string in a global variable so that I can later use it.
public Startup(IHostingEnvironment env)
{
    // Set up configuration sources.
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json")
        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

    builder.AddEnvironmentVariables();
    this.Configuration = builder.Build();

    // saving the site connection string
    SiteSettings.ConnectionString = this.Configuration.GetConnectionString("MegaMine");
}

ConfigureServices
In this method I am configuring the following services
  • Configuring Entity Framework
  •  Configure ASP.NET Identity system
  • Configure MVC
  • Configure our Authorization filter
  • Dependency injection configuration for classes related to security
  • Automapper configuration for classes related to security

Here is the relevant code in this method
public void ConfigureServices(IServiceCollection services)
{
    // configuring Entity Framework
    services.AddEntityFrameworkSqlServer()
    .AddDbContext<SecurityDbContext>(options =>
    {
        options.UseSqlServer(SiteSettings.ConnectionString);
    });
   
    // Configuring ASP.NET Identity
    services.AddIdentity<ApplicationUser, ApplicationRole>()
    .AddEntityFrameworkStores<SecurityDbContext>()
    .AddDefaultTokenProviders();

    services.AddMvc()
    .AddMvcOptions(options =>
    {
        options.Filters.Add(new NTAuthorizeFilter()); // Adding our Authorization filter
    })
    .AddJsonOptions(options =>
    {
        options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
        options.SerializerSettings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
    });

    // dependency injection
    services.AddScoped<SignInManager<ApplicationUser>, ApplicationSignInManager>();
    services.AddTransient<AccountDomain>();
    services.AddTransient<SecurityRepository>();

    // Automapper configurations
    Mapper.Initialize(x =>
    {
        x.AddProfile<SecurityMappingProfile>();
    });
}

Configure

In this Configure method, apart from standard request processing configuration, I added the following configurations:
  • Enable ASP.NET Identity
  • Enable my own middleware which stores User information in a custom request context

Here is the code for this configure method

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    // Middleware for storing context for the request
    app.UseContextMiddleware();

    // To enable deliverying static content
    app.UseStaticFiles();

    // Enabling ASP.NET Identity
    app.UseIdentity();

    // Custom middleware to store user details
    app.UseProfileMiddleware();

    // Enabling MVC
    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "webapi",
            template: "api/{controller}/{action}/{id?}",
            defaults: new { controller = "Home", action = "Index" });

        routes.MapRoute(
            name: "error",
            template: "Error",
            defaults: new { controller = "Home", action = "Error" });

        routes.MapRoute(
            name: "default",
            template: "{controller}/{action}",
            defaults: new { controller = "Home", action = "Index" });
    });
}


With the above Configurations in the Startup class, the application is configure to utilize Multi-Tenant Claim Based Identity.

Thursday, January 5, 2017

Upgrading Angular 1 to Angular 2


I have an open source medium size application (about 100 pages) which is written in Angular 1.x. I used javascript for developing this application. In addition I am using UI Router, UI Grid and Material for developing pages in this application. Now I am upgrading this application to Angular 2. This blog is my experience in upgrading this application to Angular 2.
From the beginning of this application, I was following most of the patterns recommended in the style guide (when I started this application, there is no recommended style guide). As per Angular upgrade docs if we follow the recommended style guide then it should easy to upgrade. I hope my upgrade will be easy.
Here are the 7 steps I followed for this migration.
  1. Preparation
  2. Switching JavaScript to TypeScript
  3. Bootstrapping with UpgradeModule
  4. Wrap Angular 1 Modules
  5. Upgrading Components and Services
  6. Routing Configuration
  7. Goodbye Angular 1