ASP.NET Core

ASP.NET Core Password Options and Custom Validators

ASP.NET Core provides a lot of identity feature out of the box when individual user accounts is selected during project creation. Using the default settings a user’s password is required to be at least 6 characters and contain a number, a lower case letter, an uppercase letter and a special character. This post is going to cover changing the the above options as well as creating custom validators.

Password Options

The following is the default registration of identity in the ConfigureServices  function of the Startup  class with the default settings mentioned above.

services.AddIdentity<ApplicationUser, IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

AddIdentity  can accept options part of which allows control over the basic characteristics of what is required for user passwords. Here is the same AddIdentity but with all the options for passwords listed.

services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
    options.Password.RequireDigit = true;
    options.Password.RequireLowercase = true;
    options.Password.RequireNonLetterOrDigit = true;
    options.Password.RequireUppercase = true;
    options.Password.RequiredLength = 6;
})
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

All the options do what you would expect. One thing to note is if you change the required length by setting options.Password.RequiredLength then the new setting will only be validated on post back to the server, which is the case of most password validation anyway, but for pre-post validation on length then the string length data annotation needs to be updated on RegisterViewModel.Password, ResetPasswordViewModel.Password, ChangePasswordViewModel.NewPassword and SetPasswordViewModel.NewPassword.

Custom Password Validators

The above is great for changing simple aspects of password validation, but we all know password rules for organizations are not always simple enough to be covered by the above. Thankfully Microsoft has provided the AddPasswordValidator  extension method to the IdentityBuilder class which is what is returned by AddIdentity.

AddPasswordValidator takes a type that implements IPasswordValidator. The custom validator only has to implement the  ValidateAsync defined by IPasswordValidator. The following validator checks to make sure that all the characters of the password are not the same and returns an IdentityResult based on the conditions passing. Forgive the contrived example, but I wanted to keep the class as simple as possible.

public class SameCharacterPasswordValidator<TUser>: IPasswordValidator<TUser> 
       where TUser : class
{
    public Task<IdentityResult> ValidateAsync(UserManager<TUser> manager, 
                                              TUser user, 
                                              string password)
    {
        return Task.FromResult(password.Distinct().Count() == 1 ? 
            IdentityResult.Failed(new IdentityError
            {
                Code = "SameChar",
                Description = "Passwords cannot be all the same character."
            }) : 
            IdentityResult.Success);
    }
}

If validation failed is the result then is added to the list of validation messages the user sees just like with the built in password validations.

Here is registration of identity with the custom password validation which is on the last line.

services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
    options.Password.RequireDigit = true;
    options.Password.RequireLowercase = true;
    options.Password.RequireNonLetterOrDigit = true;
    options.Password.RequireUppercase = true;
    options.Password.RequiredLength = 6;
})
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders()
    .AddPasswordValidator<SameCharacterPasswordValidator<ApplicationUser>>();

Potential Use

Imagine you have a requirement to make sure a user doesn’t reuse the same password for a period of time. This would be a great place for a custom password validator. You could use dependency injection to get reference to a history of password hashes and use that to verify the user is not repeating the same password. Of course would have to first write the password hash history.

ASP.NET Core Password Options and Custom Validators Read More »

Dependency Injection Conditional Registration in ASP.NET Core

Now that I know emailing and SMS are working I wanted a way to get the information from the out going messages without actually hitting a third party service or having to use break points. To do this I wrote a new class that implemented IEmailSender and ISmsSender that wrote the messages to a file instead of hitting Mailgun and Twilio.

Dependency Injection (DI)

ASP.NET Core comes with dependency injection built-in the details of which are described in the docs and the code can be found here. The docs article does a great job of explaining DI so I am going to keep my description limited to the example at hand.

In ASP.NET Core services are registered in the ConfigureServices of the StartUp class. When an application first starts running the StartUp constructor runs followed by ConfigureServices and finally Configure.

Configuration Based Services

One potential way to handle decisions on which services to register is via configuration settings.  Using the following configuration as an example if WriteToFile is true then the file writer version of the email service should be used instead of the version that actually emails users.

{
  "EmailSettings": {
    "WriteToFile": true,
    "Path": "C:\Email\"
  }
}

With this configuration in place ConfigureServices uses the following to load the proper service based on the config value.

if (Configuration.Get<bool>("EmailSettings:WriteToFile"))
{
    services.AddTransient<IEmailSender, AuthMessageSenderFileWriter>();
}
else
{
    services.AddTransient<IEmailSender, AuthMessageSender>();
}

Environment Based Services

ASP.NET Core’s IHostingEnvironment defines an EnvironmentName which automatically gets loaded by the host from an environment variable. To quote Visual Studio’s Object Browser on EnvironmentName:

Gets or sets the name of the environment. This property is automatically set by the host to the value of the “Hosting:Environment” (on Windows) or “Hosting__Environment” (on Linux & OS X) environment variable.

I found this post by Armen Shimoon which clued me in on the fact that ConfigureServices is only called ASP.NET Core if no Configure{EnvironmentName}Services is found. This means that if EnviromentName is set to Development then ConfigureDevelopmentServices will be called instead of ConfigureServices. Extensions are provided out of the box to help support Development, Staging and Production values.

For development runs of the application to write to a file instead of emailing I added a ConfigureDevelopmentServices.

public void ConfigureDevelopmentServices(IServiceCollection services)
{
    ConfigureServices(services);
    services.AddTransient<IEmailSender, AuthMessageSenderFileWriter>();
}

The first thing this function does is to call ConfigureServices since that is where the majority of service registrations is done. ConfigureServices registers an IEmailSender with AuthMessageSender, but that registration is overwritten with AuthMessageSenderFileWriter in ConfigureDevelopmentServices after the ConfigureServices function returns.

Final Thoughts

I have presented a couple of ways to handled varying registrations with ASP.NET Core’s built in dependency injection. I see using the ability to run different version of ConfigureServices to be the one I will get the most use out of, but I am sure basing the decision off of configuration could come in handy as well.

If you know of other options please leave a comment.

Dependency Injection Conditional Registration in ASP.NET Core Read More »

SMS using Twilio Rest API in ASP.NET Core

A couple of weeks ago I went over using email in ASP.NET Core which left the provided MessageService class half implemented.  This post is going to cover the implementation of the other MessageService function that is used to send SMS as part of two-factor authentication.

View

In Views/Manage/Index.cshtml uncomment the following to enable the UI bit associated with phone numbers.

@(Model.PhoneNumber ?? "None")
    @if (Model.PhoneNumber != null)
    {
        <br />
        <text>[&nbsp;&nbsp;<a asp-controller="Manage" asp-action="AddPhoneNumber">Change</a>&nbsp;&nbsp;]</text>
        <form asp-controller="Manage" asp-action="RemovePhoneNumber" method="post" role="form">
            [<button type="submit" class="btn-link">Remove</button>]
        </form>
    }
    else
    {
        <text>[&nbsp;&nbsp;<a asp-controller="Manage" asp-action="AddPhoneNumber">Add</a>&nbsp;&nbsp;]</text>
    }

And this as well.

@if (Model.TwoFactor)
    {
        <form asp-controller="Manage" asp-action="DisableTwoFactorAuthentication" method="post" class="form-horizontal" role="form">
            Enabled [<button type="submit" class="btn-link">Disable</button>]
        </form>
    }
    else
    {
        <form asp-controller="Manage" asp-action="EnableTwoFactorAuthentication" method="post" class="form-horizontal" role="form">
            [<button type="submit" class="btn-link">Enable</button>] Disabled
        </form>
    }

Twilio

I spend a lot of time trying to find a services that allows sending of SMS for free and had zero luck. I ended up going with  Twilio as they do provide free messaging with their trial account. The usage section of the web site will make it looking like you will be changed, but that is just to provide an idea of what the service would cost and will not actually be charged.

Storing Configuration

Just as a couple of weeks ago for EmailSetting I created a SmsSettings class that will be loaded from user secrets in the StartUp class of the application. For more details on general configuration in ASP.NET Core check out this post and then this post for more details on user secrets. The following is my SMS settings class.

public class SmsSettings
{
    public string Sid { get; set; }
    public string Token { get; set; }
    public string BaseUri { get; set; }
    public string RequestUri { get; set; }
    public string From { get; set; }
}

And this is the config file looks like with the curly braces needed to be replace with values from your Twilio account. For example if your Twilio phone number was 15554447777 then the from line would be: “From”: “+15554447777”

{
  "SmsSettings": {
    "Sid": "{TwilioAccountSid}",
    "Token": "{TwilioAuthToken}",
    "BaseUri": "https://api.twilio.com",
    "RequestUri": "/2010-04-01/Accounts/{TwilioAccountSid}/Messages.json",
    "From": "+{TwilioPhoneNumber}"
  }
}

Then in ConfigureServices function of Startup.cs add a reference to the SmsSettings class to make it available using dependency injection.

services.Configure<SmsSettings>(Configuration.GetSection("SmsSettings"));

Message Services

In Services/MessageService.cs there is an empty implementation for sending SMS base on ISmsSender which defines a single SendSmsAsync function which is called when the application wants to send a SMS.

Add a constructor to the class if it doesn’t already have one so that the SmsSettings can be injected by the framework and add a field to store the settings in. I have removed the email related items from the constructor but you can look at this post if you want to include the email related bits a well.

private readonly SmsSettings _smsSettings;

public AuthMessageSender(IOptions<SmsSettings> smsSettings)
{
    _smsSettings = smsSettings.Value;
}

Then the SendSmsAsync function which uses the HttpClient with basic authentication and form url encoded content to make a post request to the Twilio API looks like the following.

public async Task SendSmsAsync(string number, string message)
{
    using (var client = new HttpClient { BaseAddress = new Uri(_smsSettings.BaseUri) })
    {
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
            Convert.ToBase64String(Encoding.ASCII.GetBytes($"{_smsSettings.Sid}:{_smsSettings.Token}")));

        var content = new FormUrlEncodedContent(new[]
        {
            new KeyValuePair<string, string>("To",$"+{number}"),
            new KeyValuePair<string, string>("From", _smsSettings.From),
            new KeyValuePair<string, string>("Body", message)
        });

        await client.PostAsync(_smsSettings.RequestUri, content).ConfigureAwait(false);
    }
}

Now you application is capable of sending SMS.

ASP.NET Docs

As I was writing this I came across Rick Anderson’s post in the official docs that covers two-factor authentication. I highly recommend you read Rick’s post as he covers the UI portion in more depth than I did. Another note Rick is using the Twilio helper client were I am using the HttpClient in order to maintain dnxcore50 compatibility.

SMS using Twilio Rest API in ASP.NET Core Read More »

Emails using Mailgun in ASP.NET Core

Updated version of this post can be found here.

At last month’s Nashville .Net Users Group meeting Michael McCann when over some of the aspects of ASP.NET’s membership provider (non-core version). One of the things he talked about was enabling email as part of the user sign up process and for use in password recovery. This post is going to cover the same emailing aspect but in ASP.NET core using mailgun to actually send emails.

Account Controller

In the account controller most of the code needed is already present and just needs to be uncommented. In the Register function uncomment the following which will send the user an email asking that the address be confirmed. This of course stops users from signing up with email addresses they don’t actually have access to.

var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
var callbackUrl = Url.Action("ConfirmEmail", 
                             "Account", 
                             new { userId = user.Id, code = code }, 
                             protocol: HttpContext.Request.Scheme);
await _emailSender.SendEmailAsync(model.Email, "Confirm your account",
  "Please confirm your account by clicking this link: <a href=\"" + callbackUrl + "\">link</a>");

And then comment out this next line which would sign the user in before they have used the email above to confirm their account.

//await _signInManager.SignInAsync(user, isPersistent: false);

Next in the Login function add the following bit of code just before the call to _signInManager.PasswordSignInAsync. This looks up the user by email address and returns an error if the account has not been confirmed.

var user = await _userManager.FindByNameAsync(model.Email);
if (user != null)
{
    if (!await _userManager.IsEmailConfirmedAsync(user))
    {
        ModelState.AddModelError(string.Empty, 
                                 "You must have a confirmed email to log in.");
        return View(model);
    }
}

The last change is in the ForgotPassword function. Uncomment the following code to send the user an email to reset their password.

var code = await _userManager.GeneratePasswordResetTokenAsync(user);
var callbackUrl = Url.Action("ResetPassword", 
                             "Account", 
                             new { userId = user.Id, code = code }, 
                             protocol: HttpContext.Request.Scheme);
await _emailSender.SendEmailAsync(model.Email, "Reset Password",
 "Please reset your password by clicking here: <a href=\"" + callbackUrl + "\">link</a>");
return View("ForgotPasswordConfirmation");

Forgot Password View

In ForgotPassword.cshtml uncomment the following section to show the UI associated with email based password reset.

<form asp-controller="Account" asp-action="ForgotPassword" method="post" class="form-horizontal" role="form">
    <h4>Enter your email.</h4>
    <hr />
    <div asp-validation-summary="ValidationSummary.All" class="text-danger"></div>
    <div class="form-group">
        <label asp-for="Email" class="col-md-2 control-label"></label>
        <div class="col-md-10">
            <input asp-for="Email" class="form-control" />
            <span asp-validation-for="Email" class="text-danger"></span>
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <button type="submit" class="btn btn-default">Submit</button>
        </div>
    </div>
</form>

Caution for existing sites

With the changes above if a user has not confirmed their email address then they will not be able to log in or reset their password. Any existing users would need to have their accounts marked as confirmed manually by updating the EmailConfirmed bit field in the AspNetUsers table or be provided away to confirm their account.

Mailgun

Mailgun is an email service that provides a simple API for sending emails and allows up to 10,000 emails to be sent free every month. I have only used mailgun for sending test emails so I can’t speak to how it holds up at scale.

After signing up for an account click on the domains tab and select the only existing active domain which should start with something like sandbox.

Storing Configuration

In my project I created an EmailSettings class that will be loaded from user secrets in the start up of the application. For more details on general configuration in ASP.NET Core check out this post and thenthis post for more details on user secrets. The following is my email settings class.

public class EmailSettings
{
    public string ApiKey { get; set; }
    public string BaseUri { get; set; }
    public string RequestUri { get; set; }
    public string From { get; set; }
}

If using mailgun the above fields map to the following from the mailgun domain page.

EmailSettings Mailgun Example
ApiKey API Key key-*
BaseUri API Base URL https://api.mailgun.net/v3/
RequestUri API Base URL sandbox*.mailgun.org
From Default SMTP Login postmaster@sandbox*.mailgun.org

A couple of notes to the above table on what I actually saved in my config files.

EmailSettings Field Note Example
ApiKey Used with basic auth and needs username api:key-*
RequestUri Needs the API end point to call sandbox*.mailgun.org/messages

The following is what my actual config files ends up looking like.

{
  "EmailSettings": {
    "ApiKey": "api:key-*",
    "BaseUri": "https://api.mailgun.net/v3/",
    "RequestUri": "sandbox*.mailgun.org/messages",
    "From": "postmaster@sandbox*.mailgun.org"
  }
}

In the ConfigureServices function Startup.cs I added a reference to the new settings class so it would be available for dependency injection.

services.Configure<EmailSettings>(Configuration.GetSection("EmailSettings"));

Message Services

In the Services folder there is a MessageServices.cs file which contains the AuthMessageSender class that has an empty implementation for sending email base on an IEmailSender interface which defines a single SendEmailAsync method. This function is already being called in the code that was uncommented above so I am going to use it to call mailgun’s API.

First I need to get the email settings defined above injected into the AuthMessageSenderClass by adding a class level field and a constructor. The only thing the constructor is doing is saving a reference to the injected settings class.

private readonly EmailSettings _emailSettings;

public AuthMessageSender(IOptions<EmailSettings> emailSettings)
{
    _emailSettings = emailSettings.Value;
}

Next is the SendEmailAsync function mentioned above which I changed to an async function and added the code to send an email using mailgun’s API.

public async Task SendEmailAsync(string email, string subject, string message)
{
    using (var client = new HttpClient { BaseAddress = new Uri(_emailSettings.BaseUri) })
    {
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
            Convert.ToBase64String(Encoding.ASCII.GetBytes(_emailSettings.ApiKey)));

        var content = new FormUrlEncodedContent(new[]
        {
            new KeyValuePair<string, string>("from", _emailSettings.From),
            new KeyValuePair<string, string>("to", email),
            new KeyValuePair<string, string>("subject", subject),
            new KeyValuePair<string, string>("text", message)
        });

        await client.PostAsync(_emailSettings.RequestUri, content).ConfigureAwait(false);
    }
}

This code is using the HttpClient to send a request to mailgun’s API using basic authorization and form url encoded content to pass the API the relevant bit of information.

With that your application will now email account conformations and password resets.

Other Email Options

Mailgun is obviously not the only option for sending emails. This post from Mashape lists 12 API providers. In addition SMTP is also an option which this post by Steve Gordon covers.

Emails using Mailgun in ASP.NET Core Read More »

ASP.NET Core Project with Angular 2, Aurelia and an API

I have been exploring Aurelia and more recently Angular 2 and while doing so I thought it might be nice to run both frameworks from the same project.  My first crack at this can be found in this repo on Github.

Content

  • Contact model, a simplified version of the one used in previous blogs
  • ContactsController and related razor views created using Visual Studio’s scaffolding tools based on the contact mode
  • ContactsApiController is the end point for the Angular 2 and Aurelia applications
  • Angular 2 application that closely match the one from last week’s post
  • Aurelia application is currently just a proof that Angular 2 and Aurelia could run in the same project. This application will be updated to connect to the project’s web API.

Getting Started

Ensure that node and jspm are install.

After acquiring the code open the solution. If using Visual Studio the npm based packages will be restored automatically. If not using Visual Studio then run  npm install from the console. This will handle all the files needed by Angular 2.

Next run the jspm install -y  command to install the Aurelia related packages.

Make sure the database is created and up to date with the following two commands.

dnx ef database update -c ApplicationDbContext
dnx ef database update -c ContactsDbContext

In wwwroot open the config.js file and verify the paths section looking like the following. Jspm install seems to rewrite the github and npm portions of the paths section which removed the “../”. This is more than likely a configuration issue that I hope to fix in the future.

paths: {
  "*": "../Aurelia/*",
  "github:*": "../jspm_packages/github/*",
  "npm:*": "../jspm_packages/npm/*"
}

Finally run the angular2 gulp task from the task runner. The application should now run with no issues.

First Run

Make sure to register a new user as both the contacts controllers require an authorized user and filter down the contacts to display based on the logged in user.

The menu bar will contain links for Angular 2, Aurelia and Razor. Use the razor link to create some data. This is the generated razor views mentioned above. It is also the only way to add data through the application currently.

The Angular 2 link will of course launch the Angular 2 application that will display a list of contacts for the current user.

The  Aurelia like will launch the Aurelia application which just contains the very basic application from the getting started guide.

Going Forward

The plan is to develop the Angular 2 and Aurelia applications together. The Aurelia application will be the first to get some time to get up to the same level as the Angular 2 application.

It is also my hope that having this project will be a good reference for you when reading the examples in future blog posts.

ASP.NET Core Project with Angular 2, Aurelia and an API Read More »

Angular 2 with ASP.NET Core Web API

Updated version of this post can be found here.

This post will be expanding on the basic Angular 2 application from last week’s post to download data from an ASP.NET Core web API. This is the same contacts API used in all of my Aurelia and Web API posts.

Contact Interface

First add a contacts.ts typescript file in the Angular2 folder to hold an interface that defines a contact. This will be used as a definition of what the application expects a contact to look like. A class could be used instead of an interface if some sort of functionality was need on a contact.

export interface Contact {
    Id: number;
    Name: string;
}

Contact Service

This is the service that will be used to connect to the web API and retrieve a list of contacts.

import {Injectable} from 'angular2/core';
import {Http} from 'angular2/http';
import {Contact} from './contact';
import {Observable} from 'rxjs/Observable';

@Injectable()
export class ContactService {
    private _url = 'http://localhost:38218/api/contacts/';

    constructor(private http: Http) { }
    
    getContacts() {
        return this.http.get(this._url)
            .map(responce => <Contact[]>responce.json())
            .catch(error => {
                console.log(error);
                return Observable.throw(error);
            });
    }
}

The @Injectable() is required for typescript to output the proper metadata for Angular to know what need to be injected into the service. For more information on Angular’s dependency injection look here.

Http from angular2/http is a library used for http interactions. Http interaction is not included in the core of Angular and will require a dependency on a new file.

Contact is just a reference to the contact interface from above.

Observable is a reference to a rxjs type. Rxjs is a set of libraries that help with async programming and is used heavily by Angular 2.

The service’s  constructor get a reference to the http library and saves it to a http variable.

Here is just the getContacts() from above.

getContacts() {
    return this.http.get(this._url)
        .map(responce => <Contact[]>responce.json())
        .catch(error => {
            console.log(error);
            return Observable.throw(error);
        });
}

http.get returns an rxjs observable which is then processed with the rxjs map function. Map takes the json data from the http response and maps it to a contact array.

The url used here will need to be moved to configuration at some point.

App.component Changes

Imports

import {Component, OnInit} from 'angular2/core';
import {HTTP_PROVIDERS} from 'angular2/http';
import {Contact} from './contact';
import {ContactService} from './contact.service';
import 'rxjs/Rx';

A couple of notes on the imports. OnInit is an Angular lifecycle hook that will be used to get a list of contacts. rxjs/Rx import the full set of rxjs libraries and is added here so they will be available to the full application level. rxjs is a fairly sizable and this should be replace with only the parts needed, but for this example the full set of libraries is easier.

AppComponent

The AppComponent class has been expanded and will server as the view model for the contact list. New properties were added for a title and an array of contacts.

A constructor was added to allow the injection of the ContactService.

Notice the class now implements OnInit and a ngOnInit function has been added. This is taking advantage of Angular’s lifecycle hooks. On initialization the class will call getContacts on the ContactService and subscribe to the returned observable and assign the values to the local contacts array.

export class AppComponent implements OnInit {
    public title = 'Contact List';
    public contacts: Contact[];

    constructor(private _contactService: ContactService) { }

    ngOnInit() {
        this._contactService.getContacts()
            .subscribe(
            contacts => {
                console.log(contacts);
                this.contacts = contacts;
            },
            error => alert(error));
    }
}

@Component

The template has expanded to display the title and contact data.

{{title}} binds the title property of the AppComponent class.

The array of contacts is shown in an unordered list. The list items are created used *ngFor which loops each item in the contacts array. When inside the li element items can be bound using {{contact.PropertyName}} as one would expect.

@Component({
    selector: 'my-app',
    template: `
              <h1>{{title}}</h1>
              <ul class="list-unstyled">
                <li *ngFor="#contact of contacts">
                  <span class="badge">{{contact.Id}}</span> {{contact.Name}}
                </li>
              </ul>
              `,
    providers: [
        HTTP_PROVIDERS,
        ContactService
    ]
})

The providers section is new and is a list of items that will be available for injection to this component and any of its child components.

app.component.ts

Here is the full app.companent.ts all together for reference.

import {Component, OnInit} from 'angular2/core';
import {HTTP_PROVIDERS} from 'angular2/http';
import {Contact} from './contact';
import {ContactService} from './contact.service';
import 'rxjs/Rx';

@Component({
    selector: 'my-app',
    template: `
              <h1>{{title}}</h1>
              <ul class="list-unstyled">
                <li *ngFor="#contact of contacts">
                  <span class="badge">{{contact.Id}}</span> {{contact.Name}}
                </li>
              </ul>
              `,
    providers: [
        HTTP_PROVIDERS,
        ContactService
    ]
})
export class AppComponent implements OnInit {
    public title = 'Contact List';
    public contacts: Contact[];

    constructor(private _contactService: ContactService) { }

    ngOnInit() {
        this._contactService.getContacts()
            .subscribe(
            contacts => {
                console.log(contacts);
                this.contacts = contacts;
            },
            error => alert(error));

    }
}

ASP.NET View

The Angualr2.cshtml view that contains the angular application needs the following new script tag for the new http library.

<script src="~/Angular/http.dev.js"></script>

Gulp

The gulpfile.js needs also needs to change to move the new http.dev.js file to wwwroot as part of the angualr2:moveLibs task.

gulp.task("angular2:moveLibs", function () {
    return gulp.src([
            "node_modules/angular2/bundles/angular2-polyfills.js",
            "node_modules/systemjs/dist/system.src.js",
            "node_modules/systemjs/dist/system-polyfills.js",
            "node_modules/rxjs/bundles/Rx.js",
            "node_modules/angular2/bundles/angular2.dev.js",
            "node_modules/angular2/bundles/http.dev.js"
        ])
        .pipe(gulp.dest(paths.webroot + "Angular"));

});

Running the application should now display the list of contact returned by the web API.

Angular 2 with ASP.NET Core Web API Read More »

Angular 2 Quickstart with ASP.NET Core

Updated version of this post can be found here.

After working with Aurelia over last couple of months it seemed prudent to try out Angular 2. This post is going to cover the installation of Angular 2 and launching a basic Angular 2 application from an ASP.NET Core (the new name for ASP.NET 5) controller. Make sure to check out the official quickstart guide here.

Installation

Open the package.json file and add the following dependencies and devDependencies. This project is using gulp and is using the typescript based version of the quickstart guide which is why the gulp and typescript references are there.

  "dependencies": {
    "angular2":"2.0.0-beta.1",
    "systemjs": "0.19.16",
    "es6-promise": "^3.0.2",
    "es6-shim": "^0.33.3",
    "reflect-metadata": "0.1.2",
    "rxjs": "5.0.0-beta.0",
    "zone.js": "0.5.10"
  },
  "devDependencies": {
    "gulp": "3.9.0",
    "gulp-concat": "2.6.0",
    "gulp-cssmin": "0.1.7",
    "gulp-uglify": "1.5.1",
    "gulp-typescript": "2.10.0",
    "rimraf": "2.5.0",
    "typescript": "1.7.5"
  }

If inside Visual Studio 2015 the proper packages will be restored when package.js is saved, but outside of Visual Studio open a command prompt to the same directory as the package.js file and run npm install  which will download the required packages.

Typescript Configuration

Next add a tsconfig.json file to the project. This file marks the root of a typescript project and contains configuration setting for that project. Details on configuration options can be found here.

{
  "compilerOptions": {
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "module": "system",
    "moduleResolution": "node",
    "noImplicitAny": false,
    "noEmitOnError": true,
    "removeComments": false,
    "sourceMap": true,
    "target": "es5"
  },
  "exclude": [
    "node_modules"
  ]
}

Angular 2 Bootstrap and Basic App

Create an Angular folder in the project’s root folder. Next add a app.component.ts file which is used to manage a view. This component is super simple and was pulled from the official quickstart guide.

import {Component} from 'angular2/core';

@Component({
    selector: 'my-app',
    template: '<h1>My First Angular 2 App</h1>'
})
export class AppComponent { }

Next add boot.ts which is used to bootstrap Angular 2.

import {bootstrap}    from 'angular2/platform/browser'
import {AppComponent} from './app.component'

bootstrap(AppComponent);

Gulp Tasks

This is the project that was the inspiration for the gulpjs introduction post. The first task is to move the Angular 2 dependencies from the node_modules folder to an Angular folder in wwwroot  so they will be available to be served.

gulp.task("angular2:moveLibs", function () {
    return gulp.src([
            "node_modules/angular2/bundles/angular2-polyfills.js",
            "node_modules/systemjs/dist/system.src.js",
            "node_modules/systemjs/dist/system-polyfills.js",
            "node_modules/rxjs/bundles/Rx.js",
            "node_modules/angular2/bundles/angular2.dev.js"
        ])
        .pipe(gulp.dest(paths.webroot + "Angular"));

});

The next task move the js files created by the typescript compiler when a ts file is saved from the Angular folder in the root of the project to wwwroot/Angular.

gulp.task("angular2:moveJs", function () {
    return gulp.src(["Angular/**/*.js"])
        .pipe(gulp.dest(paths.webroot + "Angular/app/"));

});

The last task just runs both of the previous tasks.

gulp.task("angular2", ["angular2:moveLibs", "angular2:moveJs"])

ASP.NET Controller

The Angular application is going to be run from the ASP.NET’s HomeController. Here is the new action that will load the yet to be created view.

public IActionResult Angular2()
{
    return View();
}

ASP.NET View

This is the view that when loaded kicks off the Angular 2 application. Add a new file called Angular2.cshtml in the Views/Home folder.  In the following first Angular related scripts are loaded. Then system.js is configured and the boot module is imported and the app is rendered inside of the my-app tag.

<html>
<head>
    <title>Angular 2 QuickStart</title>

    <script src="~/Angular/angular2-polyfills.js"></script>
    <script src="~/Angular/system.src.js"></script>
    <script src="~/Angular/Rx.js"></script>
    <script src="~/Angular/angular2.dev.js"></script>

    <script>
        System.config({
            packages: {
                '../Angular': {
                    format: 'register',
                    defaultExtension: 'js'
                }
            }
        });
        System.import('../Angular/app/boot')
              .then(null, console.error.bind(console));
    </script>

</head>

<body>
    <my-app>Loading...</my-app>
</body>

</html>

This is where the trouble started for me. It took a bit of searching, but the problem turned out to be with the system.js configuration. Since the view is in the HomeController it gets rendered out of as Home/Angular2.html and this project’s Angular files are up a directory so in order for system.js to find the Angular files the package configuration needed to be set to look up one folder.

This issue took longer to find than I would like to admit, but that is the danger is using libraries one is not familiar with. System.js was not my first thought since it was used in my Aurelia without issue. If you run into an issue check out the docs for system.js configuration.

Finally add the new view to main application’s nav bar. In Views/Shared/_Layout.cshtml add a link to Angular 2 on using the Home controller.

<div class="navbar-collapse collapse">
    <ul class="nav navbar-nav">
        <li><a asp-controller="Home" asp-action="Index">Home</a></li>
        <li><a asp-controller="Home" asp-action="Angular2">Angular 2</a></li>
        <li><a asp-controller="Home" asp-action="About">About</a></li>
        <li><a asp-controller="Home" asp-action="Contact">Contact</a></li>
    </ul>
    @await Html.PartialAsync("_LoginPartial")
</div>

Follow Up

This is a very basic Angular 2 application. Expect a follow up post in the new few weeks with this application build out more to utilize the same contacts web API as my Aurelia posts.

Update

If you are having issues upgrading beta 7 check out this post for a solution.

Angular 2 Quickstart with ASP.NET Core Read More »