A new set of Windows Azure enhancements were released today,
one of which is support for ASP.Net Web API backend on Mobile Services. Prior
to this update, all backend services were written in NodeJS which is a
fantastic platform, but it can feel a bit alien to a lot of .Net developers to
develop server-side code in JavaScript.
This article is the first of a series I plan on writing on
the new Web API backend feature, in a follow up to my book released last month on Learning
Windows Azure Mobile Services for Windows 8 and Windows Phone 8 https://www.packtpub.com/learning-windows-azure-mobile-services-for-windows-8-and-windows-phone-8/book.
We’ll look at creating a new service using the new Web API
backend, download the service template and see what’s in there.
ASP.Net Web API
Microsoft ASP.Net Web API is a framework for creating
RESTful web services using the .Net Framework which can be hosted on a web
server or self-hosted inside a process like a client application or Windows
Service. Web API is similar to MVC where HTTP requests routed (Web API used
convention-based routing where a URI is matched to a controller action and Web
API 2 adds attribute routing) through to
a controller which actions the request and returns a response.
Creating a Web API Backend Mobile Service
1. If you haven’t got a Windows Azure Account, go and create
one
2. In the portal, click on the Mobile Services tab down the
left side, then click the ‘+ NEW’ button on the bottom toolbar.
3. Select COMPUTE | MOBILE SERVICE | CREATE:
4. Next, choose a name for your API, pick the subscription you
want to use, the hosting region where the service will reside and most
importantly select ‘.NET (PREVIEW)’ from the ‘BACKEND’ picker:
5. Now enter the details for the database server you want to
use (I’m using a server I already have, if you haven’t got one yet, you will
have the option to create one):
6. Finally we will see our newly created service listed in the ‘MOBILE
SERVICES’ tab. Here you can see a Node.js and .NET (Web API) service listed:
Backend Differences
If we compare a Node.js and .Net services, we will see some
differences due to the nature of these platforms:
DATA and API Tabs
First off, there are some tabs missing from the portal of the Web API service:
We no longer have ‘DATA’ and ‘API’ tabs. In the Node.js
(top) service, we can go into the ‘DATA’ tab, create tables and customise their
REST API scripts; we can also go and create our own bespoke REST API scripts in
the API tab. These customisations can be done in the portal directly with the
JavaScript editor and become live immediately (they can also be pulled and
modified locally using Git).
Our new Web API doesn’t have these tabs as all these API
customisations are done locally, compiled and then published. The big difference
is the Node.js script is interpreted at runtime and the Web API code is compiled.
Source Control
If we look at the ‘CONFIGURE’ tab, we see ‘source control’ ‘dynamic
schema’ and ‘cross-origin resource sharing (cors)’ is missing. Node.js services
can use Git source control to manage service scripts, however this is not
needed for Web API as we publish directly to the service from visual studio.
Dynamic Schema
This is a really nice feature of Node.js services; whereby you
can create typed models in your apps, then as the services discover them
through table APIs, it dynamically adjusts the database schema to match. Web
API doesn’t do this because the controller methods are strongly-typed, so the
models need pre-defining in the service; however, Entity Framework code-first
migrations are used, which means the database schema can be adjusted to match
these models (depending on the initialiser used).
CORS
Browser security stops pages making AJAX requests to hosts
other than to its originating host. The Cross Origin Site Scripting (CORS) settings
in the Node.js service allows you to add trusted domains to you service. Web
API 2 allows you to control this in the code yourself. There’s a good example
of doing this here: http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api.
Exploring the Template API
From the Mobile Service portal under ‘CONNECT AN EXISTING
WINDOWS STORE APP’ click ‘Download’:
Unblock and unzip the file, then open the solution in Visual
Studio 2013. The solution explorer should look something like this:
DataObjects
If we take a look at ‘TodoItem.cs’ we see we have two simple
properties:
using
Microsoft.WindowsAzure.Mobile.Service;
using Microsoft.WindowsAzure.Mobile.Service;
namespace
TileTapperWebAPIService.DataObjects
{
public class TodoItem : EntityData
{
public string Text { get; set; }
public bool Complete { get; set; }
}
}
You’ll notice though that it’s not
just a POCO, it actually has an 'EntityData' base class which is an abstract
implementation of ‘ITableData’ which enforces the default table requirements:
public abstract class EntityData : ITableData
{
protected EntityData();
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Index(IsClustered = true)]
[TableColumn(TableColumnType.CreatedAt)]
public DateTimeOffset? CreatedAt { get; set; }
[TableColumn(TableColumnType.Deleted)]
public bool Deleted { get; set; }
[Key]
[TableColumn(TableColumnType.Id)]
public string Id { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
[TableColumn(TableColumnType.UpdatedAt)]
public DateTimeOffset? UpdatedAt { get; set; }
[TableColumn(TableColumnType.Version)]
[Timestamp]
public byte[] Version { get; set; }
}
The attributes on these properties
help Entity framework build the table schema from the model.
Database Context
If we look at the ‘YourServiceWebAPIContext’
we see that it is a standard Entity Framework DbContext:
namespace
TileTapperWebAPIService.Models
{
public class TileTapperWebAPIContext : DbContext
{
// You can add custom code to this file.
Changes will not be overwritten.
//
// If you want Entity Framework to alter
your database
// automatically whenever you change your
model schema, please use data migrations.
// For more information refer to the
documentation:
//
http://msdn.microsoft.com/en-us/data/jj591621.aspx
private const string connectionStringName = "Name=MS_TableConnectionString";
public TileTapperWebAPIContext() : base(connectionStringName)
{
}
// When using code first migrations, ensure
you use this constructor
// and you specify a schema, which is the
same as your mobile service name.
// You can do that by registering an
instance of IDbContextFactory<T>.
public TileTapperWebAPIContext(string schema) : base(connectionStringName)
{
Schema = schema;
}
public string Schema { get; set; }
public DbSet<TodoItem> TodoItems { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
if (Schema != null)
{
modelBuilder.HasDefaultSchema(Schema);
}
modelBuilder.Conventions.Add(
new AttributeToColumnAnnotationConvention<TableColumnAttribute, string>(
"ServiceTableColumn", (property,
attributes) => attributes.Single().ColumnType.ToString()));
}
}
}
We have a ‘TodoItems’ property for
accessing the ‘TodoItem’ table and an overridden ‘OnModelCreating’ method which
tells EF how to build the model.
The Controller
The ‘TodoItemController’ has a set of HTTP methods which map
onto database CRUD operations:
namespace
TileTapperWebAPIService.Controllers
{
public class TodoItemController : TableController<TodoItem>
{
protected override void Initialize(HttpControllerContext
controllerContext)
{
base.Initialize(controllerContext);
TileTapperWebAPIContext context = new TileTapperWebAPIContext(Services.Settings.Name.Replace('-', '_'));
DomainManager = new EntityDomainManager<TodoItem>(context, Request,
Services);
}
// GET tables/TodoItem
public IQueryable<TodoItem> GetAllTodoItems()
{
return Query();
}
// GET
tables/TodoItem/48D68C86-6EA6-4C25-AA33-223FC9A27959
public SingleResult<TodoItem> GetTodoItem(string id)
{
return Lookup(id);
}
// PATCH
tables/TodoItem/48D68C86-6EA6-4C25-AA33-223FC9A27959
public Task<TodoItem> PatchTodoItem(string id, Delta<TodoItem> patch)
{
return UpdateAsync(id, patch);
}
// POST
tables/TodoItem/48D68C86-6EA6-4C25-AA33-223FC9A27959
public async Task<IHttpActionResult> PostTodoItem(TodoItem item)
{
TodoItem current = await InsertAsync(item);
return CreatedAtRoute("Tables", new { id = current.Id }, current);
}
// DELETE
tables/TodoItem/48D68C86-6EA6-4C25-AA33-223FC9A27959
public Task DeleteTodoItem(string id)
{
return DeleteAsync(id);
}
}
}
The controller implements the ‘TableController<T>’
base class which itself derived from TableController and APIController and
enforces the methods required to make a Mobile Service Table API. The EntityDomainManager
manages access to the EF database context.
WebApiConfig
This contains code to bootstrap the Web API service and
Entity Framework. We can see by default database initialiser class derives from
DropCreateDatabaseIfModelChanges<T> which is one to be careful of as your
database will be dropped and recreated if the model changes, losing all your
data! There are a number of other database initialisers available.
Scheduled Jobs
The ‘SampleJob’ class shows us how to
create a job which can be run on demand or on a schedule. This class stands out
from the other template code as it’s not a standard Web API project component,
it does not derive from APIController, but can be called via a POST request:
namespace
TileTapperWebAPIService
{
// A simple scheduled job which can be
invoked manually by submitting an HTTP
// POST request to the path
"/jobs/sample".
public class SampleJob : ScheduledJob
{
public override Task ExecuteAsync()
{
Services.Log.Info("Hello from
scheduled job!");
return Task.FromResult(true);
}
}
}
There is actually a 'JobsController' controller with a single POST method built into 'Microsoft.WindowsAzure.Mobile.Service.Controllers' which controls the jobs:
Finally
I think this is a really exciting addition to Windows Azure Mobile Services, it will greatly enhance the development experience for .Net developers by offering a familiar technology to build back-end services with. Because we now full control of the database using Entity
Framework, we can easily create a relational database schema, which was
previously unsupported.
Great post Geoff. I've been struggling for a while with Azure Mobile Services, and your article made the differences between both backends really clear. The only thing I can't get real info about is on how to set code migrations, but it's cause I'm fairly new to EF (I've alwas used Telerik Open Access as my ORM).
ReplyDeleteThanks a lot.
Really helpful..Good job!!
ReplyDeleteThank you Geoff. This is a great summary of what has been added and what are major differences. Exactly what I needed. Great job!
ReplyDelete