.NET Runtime for Azure Mobile Services – First Impressions
It’s been now about a month since the .NET runtime for Azure Mobile Services was released, but I haven’t seen a post comparing it with what we had before (a node.js runtime). I think that’s one good way to understand what the .NET backend gives, and what it lacks compared to the node.js runtime, and therefore shed some light on which scenarios each runtime is better suited for. In this post I’ll go briefly about many concepts in the two backend implementations, where they’re similar and where they’re different.
Before I start, however, I’d like to point out that the .NET runtime is not a simple port of the node.js runtime to .NET. Node and .NET are fundamentally different, and the two backend types reflects that. In many ways, it’s almost like comparing apples to oranges – they’re similar in a way that they’re both fruits, but have different tastes – they’re both good in their own way :)
.NET is not a scripting platform. Granted, there are some ways of using .NET in a scripting way (scriptcs and edge.js come to mind), but what most people associate with .NET is a way to build applications using executables, DLLs and other such artifacts. So developing for the mobile services .NET backend means building a Visual Studio project and uploading it (via the VS Publishing option or a Git-based push) to Azure. Not exactly a model adequate to portal-based editing, which is why in the first version this is not available (it’s possible that if we get enough requests we’ll add that feature in the future).
Another difference in the developer experience: the node.js is written on top of express.js, a web application framework. This is somewhat hidden in the table scripts (which have their own little programming model) but quite clear on the custom APIs, which expose directly the express.js request and response objects. The .NET backend is written on top of the ASP.NET Web API, and that integration is clear in all aspects of the backend, as we’ll cover below.
Tables / data model
I think that’s the main difference in the two runtimes. In node, the runtime is fairly integrated with SQL Azure, and that makes it for a simple experience with basic scenarios – you create a table in the portal, you’re ready to send requests to it to insert / update / read / delete data. You can define some custom scripts which are executed when such requests arrive, but they’re not really required.
In the .NET model tables are classes which inherit from TableController<T> (itself a subclass of Web API’s ApiController), a class which implements some of the boilerplate code for dealing with entities. But you still need to extend that class and implement two things: an initialize method to define the domain manager used by the class, and the actual methods which will receive the requests (POST / GET / PUT / PATCH / DELETE) from the clients – if there is no method (action) that responds to a certain HTTP verb, then requests with that verb cannot be made for that “table”. There will be soon some item templates in Visual Studio which will make this process easier, though, scaffolding through some model to define the table controller with all relevant actions.
As far as accessing data, the most common way to access SQL data will be via Entity Framework (EF). If you’re familiar with EF, it should not be hard to start using .NET mobile services. If not, there may be an initial ramp up cost (especially in scenarios with relationships of multiple entities, although once you understand EF better, this scenario is a lot simpler to implement than in the node.js case – a topic for a future post), but the whole power of EF is available in the mobile services, including EF Code First (similar to the way the node.js runtime works, where the runtime itself will create the tables in a schema specific to the mobile service in your database). But since EF is used under the covers, you can also connect the runtime with an existing database, as long as there is a connection string which a context class can access.
Another feature in the .NET backend is the ability to choose different domain managers, and use a data layer other than EF. We already shipped NuGet packages that expose domain managers for Azure Table Storage and MongoDB. We should have samples of those storage layers in future posts.
That’s an area where the two runtimes are fairly similar. APIs in the node runtime are essentially express.js handlers, in which the request object has some additional properties (user, service) which provide access to the service runtime. Likewise, custom APIs in the .NET runtime are nothing more than ASP.NET Web API controllers – classes derived from ApiController (or to be more specific, classes which implement the IHttpController interface, but the large majority of uses is done via the ApiController class), and in the class implementation if your class has a public property of type ApiServices, the dependency injection of Web API will set the proper instance to let the code access the service runtime.
In the node.js runtime there are two ways to send push notifications to clients. By default, you can use the push object to access objects that can send notification to individual push notification systems (apns, gcm, mpns, wns). Or you can enable the enhanced push feature, which uses Notification Hubs to simplify common scenarios and remove the need to explicitly manage push channels.
The .NET runtime only has the Notification Hubs option – there’s no simple way to push directly to individual push notification systems. You can still use their SDKs (or REST APIs) to do so, but it’s not integrated in the runtime.
Local / remote debugging
One feature request which we’ve received a few times for mobile services is to make debugging of the service easier. In the node.js runtime, the best way to do that is to add some tracing to the console in parts of the scripts and check the logs after executing the code. In the .NET runtime you can run the service locally and try most of the scenarios in your own machine – simply F5 the project in Visual Studio and a service in localhost will be ready to receive requests and hit any breakpoints you set in the web mobile service application. You can also set up remote debugging, where you can debug the service running live in production, as Henrik explained in his post.
A word of caution when doing local debugging: when running in the local machine, the project’s web.config will be used to determine the settings of the application, including keys, connection strings, and many others. When the project is deployed to the Azure Mobile Service, however, the web.config is ignored, as the settings will come from the server and can be set via the portal. Another difference between running the service locally and in production is that the authentication is relaxed locally – HTTP requests don’t need to have keys (application or user), even for tables / actions marked with an AuthorizationLevel.User attribute (that can be changed by calling the SetIsHosted method in the configuration object during initialization).
The main difference, which surprised some users, is that there is no “data” or “api” tabs in the portal for services with the .NET runtime. Since there’s no script editing for those two features (they’re all controllers, as I mentioned above), all tables and APIs are defined in the service code itself and are not reflected in the portal.
The .NET runtime backend is still only about a month old, so there are some features which have yet to be implemented. The most notable ones are the following:
- Client-side login flow, where you use an authentication provider SDK to login the application and then send a token obtained from the application to log in to the mobile service
- Azure Active Directory login (server-side flow)
- HTML/JS support – there is a bug in the CORS handling which should be fixed soon. There is a workaround described here.
- Tables with integer ids – this is actually not entirely a missing feature, since we can define an entity with integer ids (and other types) to be stored in the database, but the type which is exposed in the TableController class needs to have a string id (for the REST API) and we can use a mapping between the two types. Another topic for a future post.
That’s it. I hope to provide a quick comparison chart between the two runtimes. As I mentioned, we’re actively working on the .NET runtime (and in the node.js as well, we’re not forgetting about it :) so new features should be coming up soon, and we’ll announce them in the Azure Mobile blog.