0
votes

I have a simple TodoItem example with offline sync. ALl works good. The conflicts are detected and client catches MobileServicePreconditionFailedException exception.

Now, when I modify TableController to use Dto mappings and to use custom MappedEntityDomainManager I never get MobileServicePreconditionFailedException exception.

What am I missing?

i modified Microsoft TodoItem sample to demonstrate the problem, so the only difference is DomainManager and TableController.

Both DTO and Entity are derived from EntityData, so the do have all necessary properties Version, UpdatedAt, etc.....

public class TodoItemDto : EntityData
    {
        public string Text { get; set; }

        public bool Complete { get; set; }

        public bool bWorks { get; set; }
    }

public class TodoItem : EntityData
    {
        public string Text { get; set; }

        public bool Complete { get; set; }
    }

The sql table is the same as in microsoft example.

if i remove DomainManager and use in TableController Entity instead of DTOs then all is good.

Thank you

the controller looks like this:

using System;
using System.Linq;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.OData;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using Microsoft.Azure.Mobile.Server;
using TimeCardSyncSrv.DataObjects;
using TimeCardSyncSrv.Models;

namespace TimeCardSyncSrv.Controllers
{
    public class TodoItemController : TableController<TodoItemDto>
    {


        protected override void Initialize(HttpControllerContext controllerContext)
        {
            base.Initialize(controllerContext);
            MobileServiceContext context = new MobileServiceContext();
            DomainManager = new TodoItemMappedEntityDomainManager(context, Request);
        }

        // GET tables/TodoItem
        public IQueryable<TodoItemDto> GetAllTodoItems()
        {
            return Query();
        }

        // GET tables/TodoItem/48D68C86-6EA6-4C25-AA33-223FC9A27959
        public SingleResult<TodoItemDto> GetTodoItem(string id)
        {
            return Lookup(id);
        }

        // PATCH tables/TodoItem/48D68C86-6EA6-4C25-AA33-223FC9A27959
        public Task<TodoItemDto> PatchTodoItem(string id, Delta<TodoItemDto> patch)
        {
            return UpdateAsync(id, patch);
        }

        // POST tables/TodoItem
        public async Task<IHttpActionResult> PostTodoItem(TodoItemDto item)
        {
            TodoItemDto 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);
        }


        public static void AddMap(IConfiguration cfg)
        {
            cfg.CreateMap<TodoItem, TodoItemDto>();
            cfg.CreateMap<TodoItemDto, TodoItem>();

        }
    }

}

The mappedentity manager looks like this:

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using System.Web.Http.OData;
using Microsoft.Azure.Mobile.Server;
using TimeCardSyncSrv.DataObjects;
using TimeCardSyncSrv.Models;

namespace TimeCardSyncSrv.Controllers
{


    public class TodoItemMappedEntityDomainManager
        : MappedEntityDomainManager<TodoItemDto, TodoItem>
    {
        public TodoItemMappedEntityDomainManager(DbContext context,
            HttpRequestMessage request)
            : base(context, request)
        {
        }

        public override SingleResult<TodoItemDto> Lookup(string id)
        {
            return this.LookupEntity(p => p.Id == id);
        }

        public override Task<TodoItemDto> UpdateAsync(string id, Delta<TodoItemDto> patch)
        {
            return this.UpdateEntityAsync(patch, id);
        }

        public override Task<bool> DeleteAsync(string id)
        {
            return this.DeleteItemAsync(id);
        }
    }
}

both TodoItem and TodoItemDto are derived from EntityData.

1
What does your DTO look like? Does it have Version, UpdatedAt, etc. fields? What does the SQL table look like?Adrian Hall
Adrian, I edited my question with information. Thank youh8tow8

1 Answers

0
votes

Reference for the MappedEntityDomainManager in my book: https://adrianhall.github.io/develop-mobile-apps-with-csharp-and-azure/chapter3/domainmgr/#existing-table-relationships-with-the-mappedentitydomainmanager

The information you posted does not indicate a complete setup. I've tested the setup in the book. Have you initialized the Automapper in your Startup code? That seems to be the bit that might be missing.