This system shows many features in Azure Mobile Services in an insurance agency scenario. This is a new agency which wants to provide a more personalized service to its clients. Instead of dealing with call centers for most of their interaction with the agency, real people will be sent to accident locations to help the clients handle their claims processing. The agency is able to charge a premium for the personalized service, and will use Azure Mobile Services in the backend to store most of its data.
The system: There are two apps for this scenario. The first is a web application used by the insurange agency call-centers - when a client is in an accident or in need of help, the call operator will use the app to create a new event. The app will then contact an agent (*) who will be designated to the client.
The system is composed of a server component (the mobile service) and two client applications. The first is a console-based application which is used by the agency call centers - when a client is involved in an accident or in need of help, they will call the operator which will use the app to create a new claim. The service will then assign this claim to one of the field agents, which will use the second client application: a Windows Store app which can be used even offline, as the agent will go to the client and cannot count on having connectivity to the mobile service.
This sample demonstrates several features in the Mobile Services, as listed below:
One thing which this sample does not have is a nice UI. The goal was to showcase the features of the Azure Mobile Services platform (client and server), so we didn't spend a lot of time beautifying the application.
There are some setup steps needed to use the application, and they're described here.
On the Azure portal, select "New", "Compute", "Mobile Service", "Create". In the dialog, choose a name for your service, and on the "backend" option (the last one), select ".NET". When the service is created, select the application and take a note of the mobile service URL in the dashboard tab.
This is required for the Azure Active Directory authentication for the mobile agent app. Go to the Windows Store Dashboard, and create a new application. The name does not have to match the name of your mobile service. Go to the Live Connect dashboard, find your application and take note of the Package SID which is displayed in the app summary.
With the solution opened in Visual Studio, select the MobileAgent project, right-click it, select "Store", "Associate App With Store". Enter your credentials and select the application created above.
If you don't already have an active directory, create one in the portal. Create some users in your active directory to be able to use them in the application (both call center operator and field agent). Follow the steps in this tutorial to create and configure your application.
These are the values which will be needed:
Open the MainPage.xaml.cs file in the mobile agent application, find the
LoginAndGetAgentId method and replace the values of the
the values from above.
Open the Program.cs file in the call center operator application, find the
Login method and replace the values of the
the values from above. Notice that even though the NuGet packageMicrosoft.IdentityModel.Clients.ActiveDirectory (version 2.5.1-alpha, as of the time of the writing
of this document) is the same for both projects, it has a different API so that in the console application it requires the package SID as the redirect URI.
The application can be run locally, using the local runtime provided in the mobile services .NET backend. Select the MobileService project in Visual Studio and run it. At first, there are no agents registered in the database, and the agents register themselves when they log in to their applications. So select the MobileAgent project, run it and select "Sync with server", so that after logging in the agent will register itself (in a more real scenario, some other entity would register the agents, but we decided the agents to register themselves for simplicity sake). The app will tell that there are no claims assigned to the agent, since we haven't added any yet.
At this point you can run the call center application to submit new claims - when running that application make sure to use a different user as created in your active directory. The database comes pre-registered with three vehicles for which claims can be made, with ids "car1", "car2" and "car3", so feel free to use them for creating some new claims.
Once the claim is created, it will be assigned to a random field agent (and if you only logged in once it will be assigned to the single field agent). The operator can add notes to the claim (for example, if the customer calls again to update some information).
Now you can click the "sync with server" again, and the app should display the claims which are assigned to that agent. Notice that the app shouldn't have logged in again if this was done a few minutes after the previous login, even if you closed and reopened the application. And the agent will now work completely offline - the app only talks to the server when the "sync" button is pressed, and the agent can add notes or even close the claim (in the real world that would mean that the agent talked to the customer and verified that any repairs have been completed to satisfaction, for example).
Before the agent synchronizes the information with the server, you can try to query the claims for a given vehicle, and verify that the data does not come from the server. You can even close and reopen the agent app, but all the changes to the claims are persisted in a local store for when the app is reopened. If you now sync the agent app, and query again from the operator (console) app, you should see the changes reflected in the service.
Now let's see the technical details of the projects themselves, to help understanding the features used in the system.
This mobile service exposes a few entities from the database via table controllers, as is the way in the .NET backend of mobile services. There are four entity types in this service:
Those types are all defined in the MobileServiceContext class (under Models). To expose them to clients, we need to define table controllers. There are many ways of implementing such controllers, and this sample shows some of those. Let's look at them one at a time.
The table for vehicles is the simplest table implementation, with some boilerplate code (there will soon be support in Visual Studio to create such tables given a class from the model). All CRUD methods are simply delegated to the base class, and the method
needs to initialize the
DomainManager property with an
The agent controller has a different logic than the one for vehicles. First of all, only GET (all) and POST requests are handled, meaning that there's no way to delete or get information about a single agent via this controller. The POST behavior is actually
an upsert operation instead of a simple insert, and it's also restricted to only authenticated users (since its logic uses the authenticated user id). But the controller is still exposing the same shape as the Agent entity, with no transformations made, which
is why it also uses the simple
EntityDomainManager<T> class to initialize its domain manager.
This is where the bulk of the logic in the server-side code lives. This table applies some modifications to the object so that its shape is changed when moving between the network and storage layer. To do that we defined data transfer objects (DTO) for the
claim and history items (in the DataObjects folder). The first modification is the name of the navigation property: instead of
HistoryItems, the clients prefer to refer to them as
Notes, so that's what we called the property
in the ClaimDTO class. Also, many times when the client is displaying a claim it's also displaying additional information about the associated entities, such as the vehicle owner and name, and the assigned agent name. To make this easier for the clients (so
that they didn't have to first send a HTTP request to get the claim, then additional requests for the information on the related tables), we're exposing them directly in the DTO (see the properties
Now, to perform the mapping, the .NET backend has integrated support for AutoMapper, a "convention-based object-object mapper". When we're initializing the service (under
we initialize the mapper. If you look at the code you'll see the mapping to rename the navigation property ("Notes" <--> "HistoryItems") and the assigned agent name. What you won't see, however, is the mapping to fill the
Since the navigation property for that relationship is called
Vehicle, and the Vehicle class has properties called
Description, AutoMapper automatically creates the mapping for us.
Back to the claim table controller class. Since we're not exposing the entity directly to the wire, we cannot use the
EntityDomainManager<T> class. We need to use a
MappedEntityDomainManager<TData, TModel> class
instead (it's an abstract class, so we need to implement our own, but the implementation is fairly trivial). In the controller actions, the GET and DELETE are trivial (since on the context we defined that the Claim / ClaimHistoryItem relationship has an
DELETE CASCADE semantics, we can just delete the parent and all the children will be removed as well).
When creating a new claim, we have some custom logic to ensure that the claim starts out empty (no notes). Notice that if we were fine in having claims created with some notes, the implementation wouldn't need to change, as Entity Framework handles inserting children entities via the parent directly. The action also assigns an agent to handle the client. In a real application we'd find the agent that is closer to the client to have a better service, but in this sample we're just picking a field agent at random.
Updating the claim is an interesting scenario. Web API / EF doesn't support updating related entities in a PATCH request, so we had to write the code to handle that scenario, by extracting the notes from the client. Also, to demonstrate how to handle synchronization conflicts in the offline client, we imposed a rule that if a client is sending a claim with some note missing, we'll mark this as a conflict and return an error to the client (as a 412 Precondition Failed response, which is what the client expects for conflicts). If there are no conflicts, then the action will update the claim entity first, and then (in the absence of errors) insert any new notes which the client sent.
One last note on the claim controller: since the table controller is written on top of the Web API OData library, it gets the expansion of related entities "for free". By returning an
IQueryable<ClaimDTO> in get
if the client sends a request with an
$expand query string parameter, it will automatically join the two tables and retrieve
the related notes.
This simple console application is a quick way to insert claims in the system, and it doesn't really showcase many of the features of Azure Mobile Services. One notable exception is the integration with Azure Active Directory login, via the Active Directory Authentication Library, and requiring an expanded view of the claims when querying the service. Since they are also used in the mobile agent app, I'll leave it to talk there.
A Windows Store application which shows many features, especially the new offline support in the Azure Mobile Services managed SDK. Let's look into some aspects of the application.
The first thing we can look at that application is the data object folder, which contains the data objects. One difference which is worth noting is that, on the mobile service project, there were no
[JsonProperty] annotations on the
properties of the types. And if you had looked at the requests on the wire, the casing of the properties are changed to
camelCase (for example, the property
ClaimDTO class is
written to the wire as
"accidentDate"). That is done automatically as the default in the .NET backend (by using a JSON.NET contract
resolver which does that). On the client side we could either use the same resolver (setting it in theMobileServiceClient.SerializerSettings property),
or decorate the properties themselves. In the client application we use the latter option (personal preference).
Onto the main body of the client application: MainPage.xaml.cs. In order for the application to use the offline store, when the app is created (in the
OnNavigatedTo method, when the navigation mode is
we initialize an instance of a type which implements the
IMobileServiceLocalStore interface. In this release we're providing one such implementation, based on SQLite (and the Portable
Class Library for SQLite NuGet package), the
MobileServiceSQLiteStore, which can be initialized with the name of the file which will host the local database. We then need to determine, for the store, which tables we'll use in the
application, and that can be done with a simple
DefineTable<T> call for the data type we want to store. At that point, we should initialize the
SyncContext in the mobile service client.
One nice feature which I should point out - in that project we call
store.DefineTable<Claim>, and the
Claim class has, in addition to scalar properties (description, id, date, etc.), a complex property (Notes,
List<ClaimNotes>). That just works - when you insert a claim into the local store (I'll talk about that later), the complex properties will be serialized to a string column into the database and can be retrieved later. You cannot
filter based on those complex properties, though, but if that's a requirement you can always split it into a separate table.
After defining the table, the application checks whether there are any cached credentials for the client. The authentication tokens issued by the mobile service backend are valid for a some time, so there's no need to authenticate every time if you need to send protected data to the server. We're also using the provider id as the key (id) in the agent table, so we need to authenticate at least once before we can use the application.
Now once the application is opened, you can now work completely offline (see the
btnWorkOffline_Click method), in which the app will query the claims from the local table and work from there. Another alternative is to sync with the
server (see the
btnSyncWithServer_Click method), which will basically cause the local table to be populated based on data from the server, after which it will be stored and the agent can go offline again.
Another noteworthy feature shown in the app is how to handle conflicts which happen during the sync operation. Remember on the mobile service project where we're enforcing that if an update request for the
ClaimController comes with
a missing note, the server will return a 412 (Precondition Failed) response. On the client, we have an auto-conflict-resolution logic to deal with those errors, in the
SyncHandler class, under the DataConnection folder, you can see how
the client handles those errors. Basically, when executing an operation, if a
MobileServicePreconditionFailedException is thrown, we can modify the request and try it again. In our sample, the "merge" logic consists in merging the notes
from the client and the server item, so that when we re-submit them, we'll guarantee that the request has all notes from the server.
Hopefully this sample will help you to understand many features provided by the Azure Mobile Services client and runtime. For more comments / questions, feel free to contact us in our forums.