ASP.NET Core User Options and Custom Validators

Last week’s post looked at ASP.NET Core’s password options and custom validators and this week I am going to cover the built-in user options as well as writing custom user validators.

User Options

Just as last week I am going to start off showing the default registration of identity with ASP.NET Core’s built in dependency injection which is found in the ConfigureServices function of the Startup class.

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

Using the same overload of  AddIdentity  as last week which accepts an IdentityOptions there are two built-in user options for AllowedUserNameCharacters and RequireUniqueEmail. The following example shows both options.

services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
     options.User.AllowedUserNameCharacters = "[email protected]";
     options.User.RequireUniqueEmail = true;
})
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

When using AllowedUserNameCharacters make sure to include all the characters needed to make up a valid email address. My first test I left out the @ symbol and couldn’t create an account.

Custom User Validtors

The above built-in user validation options are pretty limited, but this just reflects that validation on users has standardized on email addresses for the most part. In the case that you require more specialized user validation the AddUserValidator extension to IdentityBuilder can be used in the AddIdentity chain to add custom validation based on the IUserValidator interface.

The only function on this interface is ValidateAsync. The following is an example user validator that limits users to a specific set of domains. For this example the domains are part of the validator class, but if this is something actually needed I would recommend storing the domains in a different way such as in a database or configuration.

public class UserDomainValidator<TUser> : IUserValidator<TUser> 
       where TUser : IdentityUser
{
    private readonly List<string> _allowedDomains = new List<string>
    {
        "elanderson.net",
        "test.com"
    };

    public Task<IdentityResult> ValidateAsync(UserManager<TUser> manager, 
                                              TUser user)
    {
        if (_allowedDomains.Any(allowed => 
               user.Email.EndsWith(allowed, StringComparison.CurrentCultureIgnoreCase)))
        {
            return Task.FromResult(IdentityResult.Success);
        }

        return Task.FromResult(
                 IdentityResult.Failed(new IdentityError
                 {
                     Code = "InvalidDomain",
                     Description = "Domain is invalid."
                 }));
    }
}

If the user’s email address doesn’t end with one of the domains in _allowedDomains the user will fail validation and the reason will be added to the list of identity validation errors which end up being show to the user. This validation is on the server side.

The following is what identity registration looks like with the user options and custom user validation.

services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
    options.User.AllowedUserNameCharacters = "abccom.";
    options.User.RequireUniqueEmail = true;
})
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders()
    .AddUserValidator<UserDomainValidator<ApplicationUser>>();

Wrapping Up

Following the above you can see how easy it to add any custom user validation that might be needed. It is also nice that adding custom validation on user and passwords are very similar.

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.PasswordResetPasswordViewModel.PasswordChangePasswordViewModel.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.

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.

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.

A Year of Blogging

Tuesday will mark one year since I made my first post on this blog. I don’t normally do a lot of nontechnical posts, but this will be one of the exceptions.

The Build Up

Over the years I had heard numerous people such as Scott Hanselman  and Cory House recommend blogging and community involvement in general. As I mentioned in this post I have been making an effort to be move involved with the community in the Nashville area over the last couple of years, but had up until this point ignored the advice to start a blog.

This started to change when I read John Sonmez’s book Soft Skills. John’s book really started make me feel the push to create content not just consume it. After reading Soft Skills I signed up for John’s free blogging course which I read, but didn’t take action on. After the course was done John continued to send the occasional blog related email one of which I finally got me to take action.

The Beginning

My first challenge was deciding on a topic area to focus on and I decided to go with ASP.NET. My first post LocalDB v11.0 or MSSQLLocalDB came from an issue I faced when trying to get started with ASP.NET. I remember pushing publish on that first post and being worried about people might say or what mistake I might have made that someone would use rip me to pieces.

What actually happen was nothing. The first few months I basically got no traffic. I had told almost no one about this blog and was not doing post notifications to Twitter.

ASP.NET 5

As I got more in to the world of ASP.NET I came across the beta releases of ASP.NET 5 (now ASP.NET Core) and this became the source of a lot of my entries. I really enjoyed doing entries that provided a guide from one beta to the next. The migration entries are also when I started to feel that I was providing some value to the community.

Exploration of ASP.NET 5 lead me to try Aurelia and Angular 2. This also lead to some exploration of gulp, systemjs, jspm, etc. There is so much to learn, but that is the great thing about being in software.

The Next Year

I am excited to see what the next year brings. ASP.NET Core will hopefully get updated release dates soon and along with that will come the .NET CLI. Both Aurelia and Angular 2 are moving forward toward release. There is never a shortage of things to learn!

If anyone has an topics they would like to see covered drop me a comment. Thanks for all the support over the last year!

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 [email protected]*.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": "[email protected]*.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.

Migration from Angular 2 Beta 3 to Beta 7

I was recently working on getting Angular 2 up and running in a new project and hit some issues getting typescript to compile. I had been using beta 3 on samples for this blog.  The issues I was having are with typescript trying to build and resulting in multiple TS2304 errors similar to “Build: Cannot find name ‘x'”.

I am going to go over the update process first and then the fix for the typescript build issue.

Upgrade

In the dependencies section of the project’s package.json file the following versions need to be updated to the versions listed.

"dependencies": {
  "angular2": "2.0.0-beta.7",
  "systemjs": "0.19.22",
  "es6-promise": "^3.1.2",
  "es6-shim": "^0.33.4",
  "reflect-metadata": "0.1.2",
  "rxjs": "5.0.0-beta.2",
  "zone.js": "0.5.15"
}

Not a lot of changes, but this is also the point that the build typescript build errors kick in. This reference application I found from Dan Wahlin was a huge help it tracking down what the issue was.

Fixing TS2304 Errors

The errors I was getting related mostly to promise and map which turns out to be related to es6-shim. Turns out this issues can be fixed by adding a typings references for es6-shim.

In package.json add a reference to typings in the devDependencies section. Here is an example from my project.

"devDependencies": {
  "es6-module-loader": "^0.17.8",
  "gulp": "3.8.11",
  "gulp-concat": "2.5.2",
  "gulp-cssmin": "0.1.7",
  "gulp-uglify": "1.2.0",
  "rimraf": "2.2.8",
  "jspm": "0.16.15",
  "typings": "^0.6.8"
}

Next from a console run typings init  to get typings setup for the project. This adds a typings.json file. If you are already using typing this step can be skipped. If you were previously using TSD then make sure to check out the typings upgrade command handle converting your project to the new format.

Now the typing for es6-shim can be installed by running typings install es6-shim –ambient –save in the console.

Finally add two new lines to the exclude section of the tsconfig.json file for main and main.d.ts. This prevents duplicate identifier errors.

"exclude": [
  "node_modules",
  "typings/main",
  "typings/main.d.ts"
]

After the above changes the project is now running on beta 7 of Angular 2. I updated the reference application on GitHub with the changed from this post and which can be found here.

If you hit any issues during your upgrade to beta 7 please leave a comment.

Angular 2 vs Aurelia Basic Syntax

The ASP.NET Core project with Angular 2 and Aurelia from last week’s post now has feature parity between Angular 2 and Aurelia. With the applications in sync now is a good time to compare syntax for basic operations between the two frameworks.

Templates

Function Angular 2 Aurelia
Binding {{title}}  ${title}
Input Binding <input [(ngModel)]="contact.Name">  <input value.bind="contact.Name">
Loops *ngFor="#contact of contacts"  repeat.for="contact of contacts"
Events (click)="onSelect(contact)"  click.delegate="$parent.select(contact)"
Conditional Elements <div *ngIf="contact">  <div if.bind="contact">
Conditional CSS [class.selected]="contact === selectedContact"  class="${contact === $parent.selectedContact ? 'selected' : "}"
Component Rendering <contact-detail [contact]="selectedContact"></contact-detail>  <contact-detail contact.bind="selectedContact"></contact-detail>

Component Lifecycle Hooks

The hooks provided by the frameworks don’t exactly line up, but the following is a list with a list of hooks and descriptions taken for the docs of both frameworks. The hooks are listed in the order they are executed in the component’s lifecycle. For more details look at the docs for Angular 2 and Aurelia (search for “The Component Lifecycle”).

Angular 2

ngOnChanges Called when an input or output binding value changes
ngOnInit After the first ngOnChanges
ngDoCheck Developer's custom change detection
ngAfterContentInit After component content initialized
ngAfterContentChecked After every check of component content
ngAfterViewInit After component's view(s) are initialized
ngAfterViewChecked After every check of a component's view(s)
ngOnDestroy Just before the directive is destroyed

Aurelia

constructor() The view-model's constructor is called first.
created(owningView: View, myView: View) If the view-model implements the created callback it is invoked next. At this point in time, the view has also been created and both the view-model and the view are connected to their controller. The created callback will receive the instance of the "owningView". This is the view that the component is declared inside of. If the component itself has a view, this will be passed second.
bind(bindingContext: Object, overrideContext: Object) Databinding is then activated on the view and view-model. If the view-model has a bind callback, it will be invoked at this time. The "binding context" to which the component is being bound will be passed first. An "override context" will be passed second. The override context contains information used to traverse the parent hierarchy and can also be used to add any contextual properties that the component wants to add.
attached() Next, the component is attached to the DOM (in document). If the view-model has an attached callback, it will be invoked at this time.
detached() At some point in the future, the component may be removed from the DOM. If/When this happens, and if the view-model has a detached callback, this is when it will be invoked.
unbind() After a component is detached, it's usually unbound. If your view-model has the unbind callback, it will be invoked during this process.

The Winner?

Both Angular 2 and Aurelia continue to improve as they progress through their beta stages. Aurelia seems to be more stable at this point with little to no breaking changes since they entered beta. Angular 2 will have an initial head start with the inertia of Angular 1 which will make it an easier sell at some organizations.

As is evident by the comparison above these frameworks are taking different approaches. There is no clear winner and thankfully there doesn’t have to be. Both frameworks will be successful.

At this point in time I would be comfortable going live with a project on Aurelia. Angular 2 is making huge steps forward, but feels like it need a little more time to bake before I would want to use it in a production application.

If you had an application going live soon which would you chose?

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.

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.