Microsoft Azure Back-End

I want to talk about another topic on which so far there are extremely few materials. It's about developing a back-end based on Microsoft Azure Mobile Services. Although there are many introductory articles on this subject, it is easy to see that the traditional TodoItems example (which the vast majority of introductions are limited to) contains potential problems for a large project.

The main disadvantage of the demo project is in the features of EntityDomainManager, which forces you to send the same classes through JSON that are used in ORM (let's say we use the Entity Framework). First, the serializable class must inherit from EntityData, it turns out that the database does not always have the necessary and convenient fields (for example, it is identified by a string, but is it good to build indexes always on strings?). Secondly, EF disposes to class inheritance only for the code first scheme, which does not provide mapping for stored procedures in the current version (again, the question is about the speed of the database). And in the end, where is the logic layer then? After all, the structure of the database is not necessarily identical to the external interface.

For these reasons, consider another method. I will also emphasize the fact that there will be no introduction to the basics, it is assumed that the reader is already familiar with the brief introduction.

So, to overcome the above disadvantages, we replace EntityDomainManager with MappedEntityDomainManager. The latter is focused on using the AutoMapper module, which is easy to find through NuGet, and this module is also part of the Azure Mobile Services project. You will need to use its functions in the WebApiConfig.cs file.

For an example, we will transform the entire TodoItems project and we will assume that work with the database is carried out through EF based on model first. The corresponding ORM model allows mapping entity classes to representations and stored procedures, and making calls to stored procedures. When working with EF, even a simple selection of data through stored procedures occurs at least twice as fast, ceteris paribus. Consideration of database and EF features is beyond the scope of this Micrsoft Azure description. In this case, the context created in the project will be used, but it will be replaceable.

Let us pay attention to this fact that the MappedEntityDomainManager class, in contrast to the EntityDomainManager, is abstract, so there is no way to simply replace the string:

DomainManager = new EntityDomainManager(context, Request, Services);

to create an instance of the MappedEntityDomainManager class. Therefore, create the TodoItemsDomainManager class. But before that, we denote the data transformation class (or serialization class) by the name TodoItemDTO in order to avoid confusion of the classes of different layers of the application. Another generic parameter of the inherited class will be the database mapping class, in which we will use a numerical value for identification, as the best option for database indices. As a result, the class will look like this:

    public class TodoItemsDomainManager : MappedEntityDomainManager
    {
        private readonly AzureBackendDemoContext _context;
        public TodoItemsDomainManager(AzureBackendDemoContext context, HttpRequestMessage request, ApiServices services)
            : base(context, request, services)
        {
            _context = context;
        }
        public override System.Threading.Tasks.Task DeleteAsync(string id)
        {
            return base.DeleteItemAsync(id);
        }
        public override System.Web.Http.SingleResult Lookup(string id)
        {
            return base.LookupEntity(c => c.Id.ToString() == id);
        }
        public override System.Threading.Tasks.Task UpdateAsync(string id, System.Web.Http.OData.Delta patch)
        {
            return base.UpdateEntityAsync(patch, id);
        }
    }

Here and below, the simplest example of implementation is given, but, unlike the original version, it is much more adapted to further development. There remains such a moment that TodoItemsDomainManager does not yet know how to map the classes TodoItemDTO and TodoItemDA. Therefore, we find the WebApiConfig class and add the lines to the Register method:

            Mapper.Initialize(cfg =>
            {
                cfg.CreateMap().
                    ForMember(dst => dst.Id, map => map.MapFrom(c => c.Id.ToString()))
                    .ForMember(dst => dst.Text, map => map.MapFrom(c => c.Text))
                    .ForMember(dst => dst.Complete, map => map.MapFrom(c => c.Complete));
                cfg.CreateMap().
                    ForMember(dst => dst.Id, map => map.MapFrom(c => int.Parse(c.Id)))
                    .ForMember(dst => dst.Text, map => map.MapFrom(c => c.Text))
                    .ForMember(dst => dst.Complete, map => map.MapFrom(c => c.Complete));                
            });

Note that mapping classes is not necessarily one-to-one. The details of using AutoMapper will not be considered here, since there are a lot of materials on this topic.

Now replace the line for creating the domain manager in the table controller:

DomainManager = new TodoItemsDomainManager(context, Request, Services);

Also, in the context class and all classes associated with it, you need to replace TodoItemDTO with TodoItemDA and register this class inside the OnModelCreating method:

modelBuilder.Entity();

I’ll make a small caveat - since this example did not create a real data model, the original AzureBackendDemoInitializer class was used, inherited from DropCreateDatabaseIfModelChanges. In a real project that connects to the database via the connection string, I recommend implementing the IDatabaseInitializer interface, which in this case would look like this:

    public class DatabaseModelInitializer : IDatabaseInitializer
    {
        public void InitializeDatabase(SomeDatabaseContext context)
        {
            context.Set().Load();
        }
    }

Run the project with the original sample test data and add the line / tables / TodoItem to the address. As a result, we will see the result of the request:

[{"id":"1","complete":false,"text":"First item"},{"id":"2","complete":false,"text":"Second item"}]

As a small addition, I will give an example of the front-end to the project. To simplify the example, the version for Windows based on WPF will be used. But the implementation is also possible for mobile devices on the operating systems Android, iOS, Windows Phone and Windows RT. At the same time, the WPF project is not considered compatible with Azure Mobile Services, although in reality there is compatibility, so in the NuGet console, enter:

Install-Package WindowsAzure.MobileServices

Then just add these links to the project. Let's create a class to receive data. For a query by the name of the class, it will have to be called TodoItem, then the call will be to the appropriate controller. But this name can refer both to the data model and to the local serialization class for data uploading, etc., therefore, we will apply the DataTableAttribute and declare the class like this:

    [DataTable("TodoItem")]
    public class TodoItemDTO
    {
        [CreatedAt]
        public DateTimeOffset? CreatedAt { get; set; }
        public string Id { get; set; }
        [UpdatedAt]
        public DateTimeOffset? UpdatedAt { get; set; }
        [Version]
        public byte[] Version { get; set; }
        public string Text { get; set; }
        public bool Complete { get; set; }
    }

Then the query strings will be as follows:

        public async Task Load()
        {
            MobileServiceClient client = new MobileServiceClient("http://localhost:1146/");
            try
            {
                IEnumerable items = await client.GetTable().ToEnumerableAsync();
                _items = items.Select(slo => new TodoItemModel
                {
                    Complete = slo.Complete,
                    Text = slo.Text
                }).ToList();
            }
            catch (MobileServiceInvalidOperationException ex)
            {
                OnGotError();
            }
            catch (TaskCanceledException ex)
            {
                OnGotError();
            }
        }

The layer of server logic was not considered here, but the very use of inheritance from an abstract class indicates the possibility of invoking the necessary logical objects in the corresponding methods. As an example, it was shown how to replace a string identifier with a numeric one. Let's not forget about ApiController.

Naturally, the name itself speaks of the purpose of the back-end not for desktop, but for mobile devices, but these same lines can be performed in PCL for the above-mentioned operating systems. This concludes the example, for clarity, what I want to provide the source code file for the example (correct me if it can be provided somehow better), because I myself do not like tutorials without complete source code for the example.

Also popular now: