Community

This is a departure from the types of post I normally do so please bear with me.

Early in my career I followed some bad advice that steered me away from the great development community that Nashville has to offer. Following that advice is the thing I regret most in my career. That advice is what lead me down the path of the dark matter developer that I mention in the about page for this site.

I spent a lot of years working very hard at my job with my only interaction with other developers being my co-workers. It was comfortable and the easy thing to do. I did not realize how much I was limiting myself. Limiting my growth as a developer, but more so limiting my personal development.

Thankfully this is not where the story ends. A lot of life happened and I ended up being exposed to a group of people who loved being involved with the Nashville development community. They were excited by what they do and involved at levels I had never seen. It was a breath of fresh air and a turning point for me. I am a shy and introverted person but exposure to the community helped me to start getting passed my shyness.

To start I began attending the local .Net User Group. For me this user group was a great place to start. I could listen to the speaker and slip out after the talk was over without too much interaction with others. Over time interactions got easier and I met a ton of great people. User groups are a great for learning new things, but I have come to realize that the connections made with other people are by far the most valuable benefit. I have even expanded to some social only events like the Geek Social.

If you are not involved with the community in your area I encourage you to start. Get to know your fellow developers. They are the greatest resource to be found.

If you need more convincing check out this content from Scott Hanselman and Rob Conery.

Community Read More »

Adding Authorize to a Web API

In the post Aurelia with ASP.NET 5 and Web API I removed the authorize attribute from the contacts API controller to reduce complexity. That change simplified some things but it also effectively made the API useless for multiple users.

In this post I am going to add back in authorization as well as making sure a user identifier is used in contact creation and retrieval. Also note that this authorization is taking place in the web application not via the API so the user must logged in via the main site before access to the API is allowed.

All the changes are in the controller class that needs to be protected. First add two new namespaces.

using Microsoft.AspNet.Authorization;
using System.Security.Claims;

Microsoft.AspNet.Authorization is where the Authorize attribute is found and System.Security.Claims contains an extension method on to the User class to make it easy to get the user ID.

Next add the Authorize attribute to the class level if the whole class should require authorization or at the function level if only some functions need authorization.

[Authorize]
[Route("api/[controller]")]
public class ContactsController : Controller

Next add a filter to the query for contacts to makes sure a user only sees their contacts. User is provided by the Controller base class and the GetUserId is the extension method from System.Security.Claims namespace referenced above.

private IQueryable<Contact> GetContacts()
{
    var contacts = from c in _dbContext.Contacts
                             .Include(c => c.Addresses)
                             .Include(c => c.EmailAddresses)
                             .Include(c => c.PhoneNumbers)
                   where c.UserId == User.GetUserId()
                   select c;
    return contacts;
}

In the create function, which handles HTTP post, the contact user ID must be set based on the current user before the contact is added to the DB context.

[HttpPost]
public async Task Create([FromBody] Contact contact)
{
    if (contact == null)
    {
        return HttpBadRequest();
    }

    if (!ModelState.IsValid)
    {
        return new BadRequestObjectResult(ModelState);
    }

    contact.UserId = User.GetUserId();

    _dbContext.Add(contact);
    await _dbContext.SaveChangesAsync();
    return CreatedAtRoute("GetById",
                          new
                          {
                              controller = "Contacts",
                              id = contact.Id
                          },
                          contact);
}

Adding Authorize to a Web API Read More »

Aurelia Routing with a Parameter

A post covering the same concepts but with updated versions of ASP.NET and Aurelia can be found here.

I have spent some time building out the client side of my contacts application using Aurelia. For a starting point with Aurelia check out my previous post on Aurelia with ASP.NET 5 and Web API and Start Aurelia from an ASP.NET 5 Controller. In this post I am going to cover passing a parameter via routing.

Keep in mind I am serving this application from ASP.NET 5 and all the Aurelia related files are in the wwwroot folder of my ASP.NET 5 project. App.html and app.js in wwwroot with the remaining Aurelia files in an Aurelia folder.

project

In app.js a new route was added for the detail view. Make special note that the new route expects an id parameter.

import 'lib/bootstrap/dist/js/bootstrap';

export class App {
    configureRouter(config, router) {
        config.title = 'Contacts';
        config.map([
            {
                route: ['', 'list'],
                name: 'list',
                moduleId: './Aurelia/list',
                nav: true,
                title: 'List'
            },
            {
                route: 'add',
                name: 'add',
                moduleId: './Aurelia/add',
                nav: true,
                title: 'Add'
            },
            {
                route: 'detail/:id',
                name: 'detail',
                moduleId: './Aurelia/detail',
                nav: false,
                title: 'Detail'
            }
        ]);

        this.router = router;
    }
}

In list.html the contacts need to be rendered with an anchor that will lead to the proper detail view. To accomplish this Aurelia has a route-href custom attribute that can be used with an anchor.

<template>
    <div>
        <ul class="list-group">
            <li repeat.for="contact of contacts" class="list-group-item">
                <h4 class="list-group-item-heading">
                    <a route-href="route: detail; 
                                   params.bind: {id:contact.Id}">
                        ${contact.Name}
                    </a>
                </h4>
                <p repeat.for="emailaddress of contact.EmailAddresses"
                   class="list-group-item-text">
                    <a href="mailto:${emailaddress.Address}">
                        ${emailaddress.Address}
                    </a> 
                </p>
            </li>
        </ul>
    </div>
</template>

With route-href route, set to detail above, defines the name of the route from the route config. Parms.bind creates an object with an id property which is bound to the id defined on the route. Any property on the object that does not have a in the route definition will be added to the query string.

When one of the routing links is clicked then on activation detail.js queries the Web API for the contact details based on the id in the parms.

import {inject} from 'aurelia-framework';
import {HttpClient, json} from 'aurelia-fetch-client';
import 'fetch';

@inject(HttpClient)
export class Detail{
    contact = '';

    constructor(http){
        http.configure(config => {
            config
              .useStandardConfiguration()
              .withBaseUrl('https://localhost:13102/api/');
        });

        this.http = http;
    }

    activate(params) {
        return this.http.fetch('contacts/' + params.id)
          .then(response => response.json())
          .then(contact => this.contact = contact);
    }
}

No real new concepts in the above. On active the Web API is called and the resulting json is used to populate a contact property.

The detail view then uses the contact property to bind to the contact information.

<template>
    <div>
        <div class="row">
            <label class="label label-info">${contact.Id}</label>
        </div>
        <div class="row">
            <label class="col-sm-1 control-label">Name</label>
            <div class="col-sm-11">
                <p class="control-label">${contact.Name}</p>
            </div>
        </div>
        <div class="row">
            <label class="col-sm-1 control-label">Addresses</label>
            <div class="col-sm-11">
                <p repeat.for="address of contact.Addresses"
                   class="list-group-item-text">
                    ${address.City}, ${address.State}
                </p>
            </div>
        </div>
        <div class="row">
            <label class="col-sm-1 control-label">Email Addresses</label>
            <div class="col-sm-11">
                <p repeat.for="emailaddress of contact.EmailAddresses"
                   class="list-group-item-text">
                    <a href="mailto:${emailaddress.Address}">${emailaddress.Address}</a>
                </p>
            </div>
        </div>
        <div class="row">
            <label class="col-sm-1 control-label">Phone Numbers</label>
            <div class="col-sm-11">
                <p repeat.for="phone of contact.PhoneNumbers"
                   class="list-group-item-text">
                    ${phone.Number}
                </p>
            </div>
        </div>
    </div>
</template>

The above results in the following view.

contactDetailView

Aurelia Routing with a Parameter Read More »

Migration from ASP.NET 5 Beta 7 to Beta 8

ASP.NET 5 beta 8 was released on October 15th. Read the main announcement here and the entity framework 7 specific announcement here.

The tooling update can be found here. The relevant files are either DotNetVersionManager-x64.msi or DotNetVersionManager-x86.msi depending on what your system supports and WebToolsExtensionsVS14.msi.

The above gets everything needed for use inside Visual Studio for more details on other options check out Microsoft’s documentation for getting started with Windows, Mac or Linux.

After completing the upgrade open global.json and update the sdk version to beta 8.

{
  "projects": [ "src", "test" ],
  "sdk": {
    "version": "1.0.0-beta8"
  }
}

Next up is project.json which has more changes than other migrations due to the move from hosting in Helios to Kestrel. First update beta7 to beta8 in the dependencies section.

  "dependencies": {
    "EntityFramework.SqlServer": "7.0.0-beta8",
    "EntityFramework.Commands": "7.0.0-beta8",
    "Microsoft.AspNet.Mvc": "6.0.0-beta8",
    "Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-beta8",
    "Microsoft.AspNet.Authentication.Cookies": "1.0.0-beta8",
    "Microsoft.AspNet.Authentication.Facebook": "1.0.0-beta8",
    "Microsoft.AspNet.Authentication.Google": "1.0.0-beta8",
    "Microsoft.AspNet.Authentication.MicrosoftAccount": "1.0.0-beta8",
    "Microsoft.AspNet.Authentication.Twitter": "1.0.0-beta8",
    "Microsoft.AspNet.Diagnostics": "1.0.0-beta8",
    "Microsoft.AspNet.Diagnostics.Entity": "7.0.0-beta8",
    "Microsoft.AspNet.Identity.EntityFramework": "3.0.0-beta8",
    "Microsoft.AspNet.IISPlatformHandler": "1.0.0-beta8",
    "Microsoft.AspNet.Server.Kestrel": "1.0.0-beta8",
    "Microsoft.AspNet.StaticFiles": "1.0.0-beta8",
    "Microsoft.AspNet.Tooling.Razor": "1.0.0-beta8",
    "Microsoft.Framework.Configuration.Abstractions": "1.0.0-beta8",
    "Microsoft.Framework.Configuration.Json": "1.0.0-beta8",
    "Microsoft.Framework.Configuration.UserSecrets": "1.0.0-beta8",
    "Microsoft.Framework.Logging": "1.0.0-beta8",
    "Microsoft.Framework.Logging.Console": "1.0.0-beta8",
    "Microsoft.Framework.Logging.Debug": "1.0.0-beta8",
    "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0-beta8"
  }

Note that Microsoft.AspNet.Server.IIS and Microsoft.AspNet.Server.WebListener have been removed. Microsoft.AspNet.IISPlatformHandler and Microsoft.AspNet.Server.Kestrel have been added.

In the commands section the web command has been updated to use Kestrel.

Before:
"web": "Microsoft.AspNet.Hosting --config hosting.ini"

After:
"web": "Microsoft.AspNet.Server.Kestrel"

As a result of the move to Kestrel both hosting.ini and wwwroot\bin\AspNetLoader.dll can be deleted. In wwwroot the web.config file changed to the following.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <handlers>
      <add name="httpPlatformHandler" 
           path="*" 
           verb="*" 
           modules="httpPlatformHandler" 
           resourceType="Unspecified"/>
    </handlers>
    <httpPlatform processPath="%DNX_PATH%" 
                  arguments="%DNX_ARGS%" 
                  stdoutLogEnabled="false" 
                  startupTimeLimit="3600"/>
  </system.webServer>
</configuration>

Startup.cs had a few changes. First in the constructor the application’s base path moved out of the constructor of ConfigurationBuilder to the SetBasePath function.

Before:
var builder = new ConfigurationBuilder(appEnv.ApplicationBasePath);

After:
var builder = new ConfigurationBuilder()
                .SetBasePath(appEnv.ApplicationBasePath);

In ConfigureServices the setup for third-party authentication has been removed. For example the following has been removed.

services.Configure<FacebookAuthenticationOptions>(options =>
{
    options.AppId = Configuration["Authentication:Facebook:AppId"];
    options.AppSecret = Configuration["Authentication:Facebook:AppSecret"];
});

Third party authentication options are now set in the Configure function. Here is an example with Facebook.

app.UseFacebookAuthentication(options =>
{
    options.AppId = Configuration["Authentication:Facebook:AppId"];
    options.AppSecret = Configuration["Authentication:Facebook:AppSecret"];
});

Also in the Configure function app.UseErrorPage is now app.UseDeveloperExceptionPage and app.UserErrorHandler is now app.UseExceptionHandler.

Before:
app.UseErrorPage();
app.UseErrorHandler("/Home/Error");

After:
app.UseDeveloperExceptionPage();
app.UseExceptionHandler("/Home/Error");

Add the platform handler to the request pipeline before app.UseStaticFiles.

// Add the platform handler to the request pipeline.
app.UseIISPlatformHandler();

// Add static files to the request pipeline.
app.UseStaticFiles();

In AccountController.GetCurrentUserAsync and ManageController.GetCurrentUserAsync Context is now HttpContext.

Before:
return await _userManager.FindByIdAsync(Context.User.GetUserId());

After:
return await _userManager.FindByIdAsync(HttpContext.User.GetUserId());

Next up are the changes related to entity framework 7. EF7 had a lot of API changes with this release. I am covering the ones related to the app I am working with and others can be found by looking at the commits related to this issue.

The designer.cs that goes with migrations drop the override of Id in favor of a migration attribute instead. The new attribute can be found in Microsoft.Data.Entity.Migrations.

[DbContext(typeof(ApplicationDbContext))]
[Migration("00000000000000_CreateIdentitySchema")]
partial class CreateIdentitySchema
Migration related renames
Old New
Key HasKey
Reference HasOne
InverseCollection WithMany
ConcurrencyToken IsConcurrencyToken
isNullable nullable

After all the above changes my project built, but would error because entity framework was trying to run migrations that had already been applied. After some digging I found that the table used to check if a migration has been applied or not had been renamed from MigrationHistory to EFMigrationsHistory. The following SQL will move the migrations that have been applied from the old table to the new one.

INSERT INTO dbo.__EFMigrationsHistory (MigrationId, ProductVersion) 
SELECT MigrationId, ProductVersion FROM dbo.__MigrationHistory

After fixing the migration issue the app ran with no problems. Make sure and check out the release page and the breaking changes page for this release.

Also note that the ASP.NET 5 project templates for Visual Studio have been open sourced and can be found here. The templates are a great resource which I used to work through a couple of issues when doing the migration to beta 8.

Migration from ASP.NET 5 Beta 7 to Beta 8 Read More »

Configuration in ASP.NET 5

ASP.NET 5 offer a lot of options for loading configuration data such as json files, ini files, XML files, in memory collections, command line arguments, user secrets and environment variables.

The following has at least one example of each type of configuration. Configurations are setup in the constructor of the Startup class.

public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
{
    // Setup configuration sources.
    var builder = new ConfigurationBuilder(appEnv.ApplicationBasePath)
        .AddJsonFile("config.json")
        .AddJsonFile($"config.{env.EnvironmentName}.json", optional: true)
        .AddIniFile("config.ini", optional: true)
        .AddInMemoryCollection(new Dictionary<string, string="">
        {
            {
            "AppSettings:TagLine",
            "InMemoryCollection"
            }
        })
        .AddXmlFile("config.xml", optional:true);

    if (env.IsDevelopment())
    {
        builder.AddUserSecrets();
    }
    builder.AddEnvironmentVariables();
    Configuration = builder.Build();
}

As you can see from the example all the different configuration sources can be used together without any issues. A critical thing to keep in mind is if a configuration option is set in multiple places the last configuration source’s value will be used. For example, using the code above, if the title of a site was sent in config.json and config.ini then the value from config.ini would be used.

An example I have seen the ASP.NET team use many times is to use user secrets for API key when in development and then store the keys in environment variables for production.

Here are the relevant lines from the dependencies section of the project.json file.

"Microsoft.Framework.Configuration.Abstractions": "1.0.0-beta7",
"Microsoft.Framework.Configuration.Json": "1.0.0-beta7",
"Microsoft.Framework.Configuration.UserSecrets": "1.0.0-beta7",
"Microsoft.Framework.Configuration.Xml" : "1.0.0-beta7"

Another great feature is being able to load an object with the values from a configuration section. The following is a class created to hold the settings for an application.

public class AppSettings
{
    public string Title { get; set; }
    public string TagLine { get; set; }
}

Then in the ConfigureServices function this is all that is needed to load the class.

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

Now instead of directly accessing the configuration classes in the HomeController the AppSettings class can be used instead. Here is an example of using ASP.NET 5’s built-in dependency to automatically get a reference to AppSetting via constructor injection.

private readonly IOptions _appSettings;

public HomeController(IOptions appSettings)
{
    _appSettings = appSettings;
}

And then using the _appSettings in the index action to pass values to the view.

public IActionResult Index()
{
    ViewData["Title"] = $"{_appSettings.Options.Title} - " +
                        $"{_appSettings.Options.TagLine}";
    return View();
}

The above is using C# 6’s new interpolated string feature.  The dollar sign before the string is what triggers the feature and allow use variables when wrapped in curly braces.

Check out this github repo for the internals of configuration in ASP.NET 5 .

I also recommend checking out the new Introduction to ASP.NET 5 course on Microsoft Virtual Academy. It covers a lot of good information including live.asp.net which is a production site used to for the ASP.NET 5 community stand up.

Configuration in ASP.NET 5 Read More »

Add and Delete from an API

A few weeks ago I covered creating a basic API to retrieve contacts. In this post I am going to expand on that example by adding the ability to create and delete contacts. Before starting it would be a good idea to review my post on API basics as well as make sure you have a tool such as Postman to exercise your API.

First is the function for the creation of a new contact which will be an http post that accepts a contact, does some validation and inserts the contact to the database.

[HttpPost]
public async Task Create([FromBody] ContactModel contact)
{
    if (contact == null)
    {
        return HttpBadRequest();
    }

    if (!ModelState.IsValid)
    {
        return new BadRequestObjectResult(ModelState);
    }

    _dbContext.Add(contact);
    await _dbContext.SaveChangesAsync();

    return CreatedAtRoute("GetById", 
                          new {controller = "Contacts",
                               id = contact.Id}, 
                          contact);
}

First thing to notice is the HttpPost attribute that says this function only handles HTTP posts. Next notice the FromBody attribute on the contact parameter of the function call. This tells ASP to bind the contact object to the data provided by the request body so that the function has a hydrated contact object to work with.

Both if statements are doing validation. The first is making sure that contact has a value. The second if is a bit of magic provided by ASP. ModelState contains information about the state of the model, a contact in this case, after it is bound to the values from the HTTP request. The contact model has data annotations which will cause ModelState.IsValid to return false if the model fails to validate against any of the data annotations. Both set of variations return a HttpBadRequest, but the ModelState version passes back the ModelState to the client since it contains details of all failed validation.

If all validation passed then the new contact is added to the controller’s dbContext and the dbContext saves changes inserts the new contact into the database.

Finally a route to the newly inserted contact is returned to the client. CreatedAtRoute takes a route name, route values and a value. In this case it is saying run the “GetById” route for the contacts controller with the ID of the new contact.

In order to get CreatedAtRoute to work the Get overload that takes an ID needed a name which is provided as part of the HttpGet attribute.

[HttpGet("{id}", Name = "GetById")]
public async Task Get(int id)

Now to add a contact with the API using Postman. First click Get which will drop down a list of HTTP verb to choose from. For adding a new contact we need to use Post.

postmanHttpVerb

After selecting post the body tab will be enabled. On the body tab select raw from the radio buttons. Next click the drop down that says text and select JSON (application/json) since the data for the contact will be sent to the API as JSON.

postmanBodyTypeFinally enter the appropriate JSON and click send. All that is required to create a new contact with my API is a name so the follow JSON is what I used to test.

{"Name" : "John McTest"}

At this point if all went well you will find John McTest in database. If all went well Postman will give the option to view the response which would include the Id which was set when dbContext.SaveChangesAsync was called.

The delete function is much simpler. It just needs the HttpDelete attribute and takes the ID of the contact to be deleted.

[HttpDelete("{id}")]
public async Task Delete(int id)
{
    var contact = await GetContacts()
                          .Where(c => c.Id == id).FirstOrDefaultAsync();

    if (contact == null) return;

    _dbContext.Remove(contact);
    await _dbContext.SaveChangesAsync();
}

Using the dbContext the contact is retrieved for the ID passed in. If the contact is not found the function just returns since the contact has already been removed from the database. If the contact is found then the remove function of the dbContext is used to mark the contact for delete and then save changes of dbContext is used to send the delete command to the database.

To test with Postman select delete from the list of HTTP verbs, this is the same drop down that was used to select post above. Next enter the ID to be deleted in the URL box and click send. In the screenshot below the API will be told to delete the contact with the ID of 108.

postmanDelete

Check out the ASP.NET 5 docs for a great API example that uses Fiddler instead of Postman.

Add and Delete from an API Read More »

Start Aurelia from an ASP.NET 5 Controller

Last week was all about getting Aurelia up and running from inside of Visual Studio with an ASP.NET 5 project. In last week’s post I started Aurelia from an html page in the wwwroot folder. This week I am going to use a controller action to kick off Aurelia.

Start by modifying the default HomeController, or any controller of your choice, to add an Aurelia action that just returns a view.

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

Next right-click on the View/Home folder and add a new item.

AddNewItem

Select MVC View Page and enter a name that matches the above controller action, Aurelia.cshtml for this example.

AddNewItemDialog

The contents of Aurelia.cshtml are very close to the html page from last week except for a couple of items. The aurelia-app is on a div instead of the body and the script source has been changed to go up a folder level since the view will be running out of the Home folder but the scripts will still be in the root of the site when it is being served.

<div aurelia-app>
    <script src="../jspm_packages/system.js"></script>
    <script src="../config.js"></script>
    <script>
        System.import("aurelia-bootstrapper");
    </script>
</div>

Now change _Layout.cshtml in the Views/Shared folder to provide a link to the new Aurelia action. In this case it is being added to the navigation bar.

<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="Aurelia">Aurelia</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>

A couple of use cases for this might be to split a really large application into multiple sub-spas to keep user from having to load data for parts of the application they may use infrequently. I bet this same concept could be achieved with Aurelia itself, but with an existing application the approach above maybe an easier way to start.

Start Aurelia from an ASP.NET 5 Controller Read More »

Aurelia with ASP.NET 5 and Web API

Update: A series of posts has been made covering this same topic with the RTM versions of both ASP.NET Core and Aurelia. The first post in the series can be found here.

Now that I have a web API for my contacts I wanted to go back and add a front end to view them. I decided this would also be a good time to try out one of the single-page application frameworks instead of using razor. The number of choices for a spa framework is almost over whelming. Angular, Ember, Meteor, etc. In the end I decided to try out Aurelia mostly based on the fact that Rob Eisenberg is behind it.

To get going I highly recommend going through Aurelia’s get started guide. In addition to being a great introduction to Aurelia I also had to pull at least one file out of the sample project to get up and running in my ASP.NET project.

A couple more resources I recommend reading before getting started are a couple of blog post by Scott Allen. The first covers getting jspm going in ASP.NET 5 and the second is a guide to get started with Aurelia in ASP.NET 5.

Now to get started. The first step is to install jspm which is yet another package manager. It can be installed using with the following npm command.

npm install -g jspm@beta

jspm utilizes GitHub in some cases to install packages so it is recommended that jspm be configured with a login or api token for GitHub to avoid any anonymous API request limits.

jspm registry config github

The remaining commands should be run from the project directory that contains the project.json file.

Next run jspm’s init command. This command will ask a series of questions. The default is fine for most of them. The exceptions being the server baseURL should be ./wwwroot and I chose to use Babel as my transpiler.

jspm init

Now to install all the Aurelia bits that will be need to get an application up and hit a web API.

jspm install aurelia-framework
jspm install aurelia-bootstrapper
jspm install aurelia-fetch-client

Next add an html file (any name is fine) to the wwwroot folder. This html file will be how the Aurelia application is accessed and the file does not have a lot in it. If you read either Aurelia’s getting started or Scott’s blog the following contents will look very similar.

<!doctype html>
<html>
<head>
    <title>Hello from Aurelia</title>
</head>
<body aurelia-app>
    <script src="jspm_packages/system.js"></script>
    <script src="config.js"></script>
    <script>
        System.import("aurelia-bootstrapper");
    </script>
</body>
</html>

When the above page loads Aurelia kicks in and looks for app.js and app.html. My app.js is based on the users.js from the getting started guide.

import {inject} from 'aurelia-framework';
import {HttpClient} from 'jspm_packages/github/aurelia/[email protected]/aurelia-fetch-client.js';
import 'fetch';

@inject(HttpClient)
export class App{
    heading = 'Contacts';
    contacts = [];

    constructor(http){
        http.configure(config => {
            config
              .useStandardConfiguration()
              .withBaseUrl('https://localhost:14830/api/');
        });

        this.http = http;
    }

    activate(){
        return this.http.fetch('contacts')
          .then(response => response.json())
          .then(contacts => this.contacts = contacts);
    }
}

This class acts as the view model for my contact list. In the constructor function an http client is set up with a base url that matches the base url for the project’s web API which is http://localhost:14830/api/ in this case. The activate function is called by Aurelia and is where the contacts API is called using http.fetch. The import to fetch is the file I had to copy out of the Aurelia get started application into the wwwroot folder. You may also notice that the other imports are referencing specific folders with specific versions. This is not something that should be done for anything other than a short demo. I need to do some learning on gulp and what exactly Aurelia requires to get that fixed.

The following is the app.html.

<template>
    <section>
        <h2>${heading}</h2>
        <div repeat.for="contact of contacts">
            <p>${contact.Name}</p>
            <div repeat.for="emailaddress of contact.EmailAddressModels">
                <p>${emailaddress.Address}</p>
            </div>
        </div>
    </section>
</template>

The ${heading} is binding the value that will be displayed to the heading property defined in the app class. Next notice the repeat.for which will repeat the element it is defined on and its children foreach in the container to the right of the of statement. For example the above is going to print the name of each contact and all that contact’s email address contained in the contacts property of the app class. The resulting page is ugly, but the point is to prove Aurelia running and displaying the proper data.

At this point to remove some complexity I removed the authorize attribute off of the contacts controller and ran a test. As you may have guessed the test failed.

The failure was caused by the API returning a single object that then contain all the contacts instead of an array of contacts. The cause of this issue is the changes I made to work around serialization issue I was having with circular references  from my entity framework navigation properties.

The fix was to remove the following from the ConfigureServices function of the Startup class.

services.ConfigureMvcJson(options =>
{
    options.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.All;
});

Then in all the contact related classes I added the JsonIgnore attribute to the property that pointed back to the contact model.

public class ContactEmailModel
{
    public int ContactId { get; set; }
    public int Id { get; set; }
    [EmailAddress]
    public string Address { get; set; }

    [JsonIgnore]
    public ContactModel Contact {get; set;}
}

With those two changes everything started working. At this point I am not sure if that is the proper way to handle my issue or not. I have a feeling it will be something I will end up revisiting as I continue to learn more.

Aurelia with ASP.NET 5 and Web API Read More »

Migration from ASP.NET 5 Beta 6 to Beta 7

On September 2nd ASP.NET 5 beta 7 was released. As with beta 6 this release includes a tooling update for Visual Studio. Read the announcement here.

The tooling update can be found here. The relevant files are either DotNetVersionManager-x64.msi or DotNetVersionManager-x86.msi depending on what your system supports and WebToolsExtensionsVS14.msi.

After installing the tooling update change the sdk version in global.json to beta 7.

{
  "projects": [ "src", "test" ],
  "sdk": {
    "version": "1.0.0-beta7"
  }
}

In the project.js file update beta6 to beta7 in the dependencies section.

  "dependencies": {
    "EntityFramework.SqlServer": "7.0.0-beta7",
    "EntityFramework.Commands": "7.0.0-beta7",
    "Microsoft.AspNet.Mvc": "6.0.0-beta7",
    "Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-beta7",
    "Microsoft.AspNet.Authentication.Cookies": "1.0.0-beta7",
    "Microsoft.AspNet.Authentication.Facebook": "1.0.0-beta7",
    "Microsoft.AspNet.Authentication.Google": "1.0.0-beta7",
    "Microsoft.AspNet.Authentication.MicrosoftAccount": "1.0.0-beta7",
    "Microsoft.AspNet.Authentication.Twitter": "1.0.0-beta7",
    "Microsoft.AspNet.Diagnostics": "1.0.0-beta7",
    "Microsoft.AspNet.Diagnostics.Entity": "7.0.0-beta7",
    "Microsoft.AspNet.Identity.EntityFramework": "3.0.0-beta7",
    "Microsoft.AspNet.Server.IIS": "1.0.0-beta7",
    "Microsoft.AspNet.Server.WebListener": "1.0.0-beta7",
    "Microsoft.AspNet.StaticFiles": "1.0.0-beta7",
    "Microsoft.AspNet.Tooling.Razor": "1.0.0-beta7",
    "Microsoft.Framework.Configuration.Abstractions": "1.0.0-beta7",
    "Microsoft.Framework.Configuration.Json": "1.0.0-beta7",
    "Microsoft.Framework.Configuration.UserSecrets": "1.0.0-beta7",
    "Microsoft.Framework.Logging": "1.0.0-beta7",
    "Microsoft.Framework.Logging.Console": "1.0.0-beta7",
    "Microsoft.Framework.Logging.Debug": "1.0.0-beta7",
    "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0-beta7"
  }

In Startup.cs replace the Microsoft.Framework.Runtime namespace with Microsoft.Dnx.Runtime.

using Microsoft.Dnx.Runtime;

The remaining changes are related to entity framework 7. ApplyMigrations has been change to Migrate.

Before:
Database.ApplyMigrations();

After:
Database.Migrate();

Any migration designer.cs files will need the following changes. The Microsoft.Data.Entity.Migrations.Infrastructure namespace is now Microsoft.Data.Entity.Infrastructure.

using Microsoft.Data.Entity.Infrastructure;

ContextType has changed to DbContext.

Before:
[ContextType(typeof(ContactsDbContext))]

After:
[DbContext(typeof(ContactsDbContext))]

The ProductVersion property has been removed and BuildTargetModel is now protected.

Before:
public override string ProductVersion
{
    get { return "7.0.0-beta6-13815"; }
}

public override void BuildTargetModel(ModelBuilder builder)

After:
protected override void BuildTargetModel(ModelBuilder builder)

The Microsoft.Data.Entity.Migrations.Builders namespace is now Microsoft.Data.Entity.Migrations.Operations.Builders.

using Microsoft.Data.Entity.Migrations.Operations.Builders;

Any classes that inherit from the Migration need the Up and Down functions changed to protected.

Before:
public override void Up(MigrationBuilder migration)
public override void Down(MigrationBuilder migration)

After:
protected override void Up(MigrationBuilder migration)
protected override void Down(MigrationBuilder migration)

The AddCoumn of MigrationBuilder now needs a type specified and nullable has changed to isNullable.

Before:
migration.AddColumn(name: "UserId", 
                    table: "ContactModel",
                    type: "nvarchar(max)",
                    nullable: true);

After:
migration.AddColumn<string>(name: "UserId",
                            table: "ContactModel",
                            type: "nvarchar(max)",
                            isNullable: true);

The last change to MigrationBuilder that I ran into was with table.ForeginKey. referencedTable and referencedColumn changed to principleTable and principalColumns.

Before:
table.ForeignKey(name: "FK_ContactAddressModel_ContactModel_ContactId",
                 columns: x => x.ContactId,
                 referencedTable: "ContactModel",
                 referencedColumn: "Id");

After:
table.ForeignKey(name: "FK_ContactAddressModel_ContactModel_ContactId",
                 columns: x => x.ContactId,
                 principalTable: "ContactModel",
                 principalColumns: new []{"Id"});

That was all the changes needed to get my test project updated. Here is the Github release page and breaking changes page for this release.

Migration of an existing project through the betas does work, but I recommend creating a new project every couple of betas. Things are changing in the project templates as well the core of ASP.NET 5. At the very least create a new project and look through the startup class and implement anything new that you find useful.  For example the debug logger is now included when creating a new project.

Migration from ASP.NET 5 Beta 6 to Beta 7 Read More »

Web API with Get Filter and Security

This is a slight extension on the web API contacts controller from last week.

The first change is to the get that returns all contacts. Getting all contacts is great, but it would be helpful to be able to filter the data down. The following code is all the changes to the get function.

// GET: api/values
[HttpGet]
public async Task Get(string filter = null)
{
  var contacts = GetContacts();

  if (!string.IsNullOrWhiteSpace(filter))
  {
    contacts = contacts
         .Where(c => c.Name.IndexOf(filter, 0, StringComparison.CurrentCultureIgnoreCase) > -1 ||
                     c.AddressModels.Exists(a => a.Address.IndexOf(filter, 0, StringComparison.CurrentCultureIgnoreCase) > -1 ||
                                                 a.City.IndexOf(filter, 0, StringComparison.CurrentCultureIgnoreCase) > -1 ||
                                                 a.Country.IndexOf(filter, 0, StringComparison.CurrentCultureIgnoreCase) > -1 ||
                                                 a.PostalCode.IndexOf(filter, 0, StringComparison.CurrentCultureIgnoreCase) > -1 ||
                                                 a.State.IndexOf(filter, 0, StringComparison.CurrentCultureIgnoreCase) > -1) ||
                     c.EmailAddressModels.Exists(e => e.Address.IndexOf(filter, 0, StringComparison.CurrentCultureIgnoreCase) > -1) ||
                     c.PhoneModels.Exists(p => p.Number.IndexOf(filter, 0, StringComparison.CurrentCultureIgnoreCase) > -1));
  }

  return await contacts.ToListAsync();
}

The get function call now has an optional string for filter. If the filter has a value then a linq statement checks to see if any contact fields matches the filter. In the past I had used the contains function, but during tested I noticed that contains function was dong a case-sensitive matching and I wanted case-insensitive so I switch to the IndexOf function of the string class.

The filter is passed via a query string which seem to the be more restful way of doing filtering type stuff instead of creating a different get function. Keep in mind I am new to web API and rest so if I have any of this wrong please let me know.

The second thing I changed this round was to require authorization to use the API.

[Authorize]
[Route("api/[controller]")]
public class ContactsController : Controller

As you can see the only thing I did was add the authorize attribute to the controller class. That is all that is required and now the API will require the user be logged in. This is using ASP’s authorization and means that the user must be logged in via the web site and then use that same session to hit the API.

Requiring the user to already be logged may or may not be what you are looking for with your API. If you are using the API for run a SPA that could be fine, but if your API is being used to back another scenario than authorization will need to be fleshed out more.

I hope to address both the SPA and other authorization type in a future blog post so stay tuned.

Web API with Get Filter and Security Read More »