1
votes

I am trying to use Azure Mobile Apps with a Xamarin Forms client and a .net backend. I am using MikeCodesDotNet/App-Service-Helpers to help my get started on the client side. The first Entity I am trying is a simple Game Entity.

When the client loads it makes the GET request to get the Games but it uses updatedAt and it seems like the server wants UpdatedAt.

The request is: http://192.168.0.105/Backend/tables/Game?$filter=(updatedAt%20ge%20datetimeoffset%271970-01-01T00:00:00.0000000%2B00:00%27)&$orderby=updatedAt&$skip=0&$top=50&__includeDeleted=true

which fails with

{ $id: "1", message: "The query specified in the URI is not valid. Could not find a property named 'updatedAt' on type 'Backend.DataObjects.Game'.", exceptionMessage: "Could not find a property named 'updatedAt' on type 'AthelinkBackend.DataObjects.Game'.", exceptionType: "Microsoft.Data.OData.ODataException", stackTrace: " at Microsoft.Data.OData.Query.EndPathBinder.GeneratePropertyAccessQueryForOpenType(EndPathToken endPathToken, SingleValueNode parentNode) at Microsoft.Data.OData.Query.EndPathBinder.BindEndPath(EndPathToken endPathToken, BindingState state) at Microsoft.Data.OData.Query.MetadataBinder.Bind(QueryToken token) at Microsoft.Data.OData.Query.OrderByBinder.ProcessSingleOrderBy(BindingState state, OrderByClause thenBy, OrderByToken orderByToken) at Microsoft.Data.OData.Query.OrderByBinder.BindOrderBy(BindingState state, IEnumerable`1 orderByTokens) at Microsoft.Data.OData.Query.ODataUriParser.ParseOrderByImplementation(String orderBy, IEdmType elementType, IEdmEntitySet entitySet) at System.Web.Http.OData.Query.OrderByQueryOption.get_OrderByClause() at System.Web.Http.OData.Query.Validators.OrderByQueryValidator.Validate(OrderByQueryOption orderByOption, ODataValidationSettings validationSettings) at System.Web.Http.OData.Query.OrderByQueryOption.Validate(ODataValidationSettings validationSettings) at System.Web.Http.OData.Query.Validators.ODataQueryValidator.Validate(ODataQueryOptions options, ODataValidationSettings validationSettings) at System.Web.Http.OData.Query.ODataQueryOptions.Validate(ODataValidationSettings validationSettings) at System.Web.Http.OData.EnableQueryAttribute.ValidateQuery(HttpRequestMessage request, ODataQueryOptions queryOptions) at System.Web.Http.OData.EnableQueryAttribute.ExecuteQuery(Object response, HttpRequestMessage request, HttpActionDescriptor actionDescriptor) at System.Web.Http.OData.EnableQueryAttribute.OnActionExecuted(HttpActionExecutedContext actionExecutedContext)" }

in Chrome but I run the same with UpdatedAt in the GET vars it completes correctly.

I don't know how to resolve this issue or if its a client issue or server issue.

On the Client:

namespace GamesClient.Models
{
    public class Game : AppServiceHelpers.Models.EntityData
    {
        public string Name { get; set; }
        public string Type { get; set; }
    }
}

On the Server:

namespace Backend.DataObjects
{
    public class Game : EntityData
    {
        public string Name { get; set; }
        public string Type { get; set; }

        public virtual Collection<Participant> Participants { get; set; }
    }
}

namespace Backend.Controllers
{
    [AllowAnonymous]
    public class GameController : TableController<Game>
    {
        protected override void Initialize(HttpControllerContext controllerContext)
        {
            base.Initialize(controllerContext);
            MobileServiceContext context = new MobileServiceContext();
            DomainManager = new EntityDomainManager<Game>(context, Request, Services);
        }

        // GET tables/Game
        public IQueryable<Game> GetAllGame()
        {
            return Query(); 
        }

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

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

        // POST tables/Game
        public async Task<IHttpActionResult> PostGame(Game item)
        {
            Game current = await InsertAsync(item);
            return CreatedAtRoute("Tables", new { id = current.Id }, current);
        }

        // DELETE tables/Game/48D68C86-6EA6-4C25-AA33-223FC9A27959
        public Task DeleteGame(string id)
        {
             return DeleteAsync(id);
        }

    }
}

Update #1

I have checked the database and it looks like the tables are being created correctly. I can even do a POST/INSERT from the Xamarin client which works correctly.

Database tables and data in the Games table

I really think its an issue between UpdatedAt and updatedAt capitalization in the filter on the GET request.

(1) GET from Xamarin Client (which is using updatedAt):

$filter=(updatedAt%20ge%20datetimeoffset%271970-01-01T00:00:00.0000000%2B00:00%27)&$orderby=updatedAt&$skip=0&$top=50&__includeDeleted=true

result in the error message above

(2) GET from Chrome (changing the request to use UpdatedAt) :

$filter=(UpdatedAt%20ge%20datetimeoffset%271970-01-01T00:00:00.0000000%2B00:00%27)&$orderby=UpdatedAt&$skip=0&$top=50&__includeDeleted=true

result in the correct response

[
{
$id: "1",
id: "46d3db2c-c8d4-4a15-8724-d7ce95611a63",
type: "football ",
name: "game1"
},
{
$id: "2",
id: "02d02477-2618-4eda-90ad-34e4117ed423",
type: "basketball ",
name: "game2"
}
]

On the Server side my Game is a child of Microsoft.WindowsAzure.Mobile.Service.EntityData

And on the Client side the Game object is a child of a EntityData class with the following UpdatedAt property definition

[Microsoft.WindowsAzure.MobileServices.UpdatedAt]
public DateTimeOffset UpdatedAt { get; set; }

Also, please let me know which logs I can provide to help, Thanks!

2

2 Answers

2
votes

The solution that worked for me was to set the following property on your mobile client.

var client = new MobileServiceClient(...);
client.SerializerSettings.CamelCasePropertyNames = false;

This prevents your property names being serialized to camel case in the odata queries.

0
votes

It looks like the database table is not set up properly. There are a bunch of reasons this could be. One of the more common ones is that you started with the TodoItem table, published that (which created the TodoItems database table), then updated the server backend to create the new table and it fails. This is because creation of the database (the initial schema create) is done for you, but the updates are not. You need to use code first migrations to properly update the database (just like any other Entity Framework based service). There could be other things going on as well - unfortunately, the logs you provide don't show anything.

If you can, wipe out your database and start with a blank database.

Also, read the book - http://aka.ms/zumobook