31

I have had a MobileService running on Azure, and have decided to create a new service and migrate the code myself. The new service is of the new type called: Azure Mobile App Service.

Currently I have Authentication working, and can do migrations/update-database. I am following the TodoItem example. I now want to create my own Custom API, which easily worked on MobileService, but I cannot get it working on Azure Mobile App :/

I have followed these two links web-Api-routing and app-service-mobile-backend. And I now have the following:

I have created a new controller:

[MobileAppController]
public class TestController : ApiController
{
    // GET api/Test
    [Route("api/Test/completeAll")]
    [HttpPost]
    public async Task<ihttpactionresult> completeAll(string info)
    {
        return Ok(info + info + info);
    }
}

In the mobileApp.cs I have added the below code according to backend:

HttpConfiguration config = new HttpConfiguration();
config.MapHttpAttributeRoutes();

Additionally I have installed the below package according to web-api-routing:

Microsoft.AspNet.WebApi.WebHost 

and the call from the client:

string t = await App.MobileService.InvokeApiAsync<string,string>("Test/completeAll", "hej");

Debug shows, that it is the correct URL:

{Method: POST, RequestUri: 'https://xxxxxxx.azurewebsites.net/api/Test/completeAll', Version: 1.1, Content: System.Net.Http.StringContent, Headers:{ X-ZUMO-FEATURES: AT X-ZUMO-INSTALLATION-ID: e9b359df-d15e-4119-a4ad-afe3031d8cd5 X-ZUMO-AUTH: xxxxxxxxxxx Accept: application/json User-Agent: ZUMO/2.0 User-Agent: (lang=Managed; os=Windows Store; os_version=--; arch=Neutral; version=2.0.31125.0) X-ZUMO-VERSION: ZUMO/2.0 (lang=Managed; os=Windows Store; os_version=--; arch=Neutral; version=2.0.31125.0) ZUMO-API-VERSION: 2.0.0 Content-Type: application/json; charset=utf-8 Content-Length: 3}}

But keep getting: 404 (Not Found) Debug Message "The request could not be completed. (Not Found)"

What am I missing :/ ?

Update

I have tried expanding the code in The mobileApp.cs, with:

HttpConfiguration config = new HttpConfiguration();
        new MobileAppConfiguration()
            .UseDefaultConfiguration().MapApiControllers()
            .ApplyTo(config);
        config.MapHttpAttributeRoutes();
        app.UseWebApi(config);

based on app-service-backend, however still no access :/

Update

I used fiddler2 to access the endpoint through a browser and got the following results:

Fiddler output

Update Again

I have tried to create another minimal solution, but still get the same error. Are there any great tutorials that I can follow to achieve this functionality?

The positive feeling is slowly evaporating . . .

The question is also running now on msdn, I will update here if any information is shown there.


Update

Tested Lindas comment, and I can in fact access the value converter:

// Use the MobileAppController attribute for each ApiController you want to use  
// from your mobile clients 
[MobileAppController]
public class ValuesController : ApiController
{
    // GET api/values
    public string Get()
    {
        MobileAppSettingsDictionary settings = this.Configuration.GetMobileAppSettingsProvider().GetMobileAppSettings();
        ITraceWriter traceWriter = this.Configuration.Services.GetTraceWriter();

        string host = settings.HostName ?? "localhost";
        string greeting = "Hello from " + host;

        traceWriter.Info(greeting);
        return greeting;
    }

    // POST api/values
    public string Post()
    {
        return "Hello World!";
    }

}

This I access using the both the post and get function:

string t = await App.MobileService.InvokeApiAsync<string, string>("values", null, HttpMethod.Post, null);

or

string t = await App.MobileService.InvokeApiAsync<string, string>("values", null, HttpMethod.Get, null);

But the code I pasted has no route so why can I access it using values? What would the path be to the original controller if did not use the route parameter?


Extra Information

I have now created a support ticket with Microsoft and will update with additional information. . . Hopefully.

Update Info from MSDN Forum: try MS_SkipVersionCheck Reading about the attribute here, it does not seem applicable. But I tried it. Still Not Found for my API but the original one is still working. So it did not have an impact on this issue.

JTIM
  • 2,774
  • 1
  • 34
  • 74
  • Do you also get a 404 when you try hitting the endpoint directly using Fiddler? – lindydonna Mar 02 '16 at 01:24
  • @lindydonna-msft I have updated the question, but yes I still get 404. – JTIM Mar 02 '16 at 08:10
  • Try rebuilding your solution, and when you publish, check "Remove additional files at destination." Also, make sure you are using the latest version of the server SDK, the current version is 1.1.157. https://www.nuget.org/packages/Microsoft.Azure.Mobile.Server/ – lindydonna Mar 03 '16 at 23:05
  • @lindydonna-msft The installed version on my PC is 1.1.157.1, so I assume this is the newest :) (there are no updates for any package on my system). I have rebuiled checked, "Remove..." as requested and republished. . . . The same error persist (404), no better response using fiddler. Are there a minimal solution that you know works, I can get? So I only need to change the connection strings? – JTIM Mar 04 '16 at 08:09
  • @lindydonna-msft do you have any other suggestions or minimal solutions? Should I try to acquire a support ticket? – JTIM Mar 07 '16 at 19:39
  • 1
    What happens if you use the quickstart project? It will install an API Controller for you. Can you access that one? – lindydonna Mar 12 '16 at 00:57
  • @lindydonna-msft The quickstart project is the todo-item-project I assume ? In this project there is the ValueController I have tried to access it and I am able to do so with `string t = await App.MobileService.InvokeApiAsync("values", null, HttpMethod.Post, null);`, updated the question. – JTIM Mar 12 '16 at 09:14
  • 1
    Can you email your server project to mobileser ices@microsoft.com? I haven't been able to repro the issue you're describing. (Make sure to clean your project before you zip it up, to reduce the attachment dose.) – lindydonna Mar 14 '16 at 21:43
  • @lindydonna-msft I have send it now (hope it is the correct email). – JTIM Mar 15 '16 at 16:28
  • 1
    Sorry, I had a typo. The address is mobileservices@microsoft.com. – lindydonna Mar 16 '16 at 02:20
  • @lindydonna-msft I guessed correct yesterday, is it possible to get an acknowledgement that it is received and being processed ? – JTIM Mar 16 '16 at 07:03
  • I didn't get your email (possibly due to the attachment), but I created a controller and I can register the route just fine. See my answer below, which includes a working Gist. – lindydonna Mar 16 '16 at 20:38

5 Answers5

15

Yes !!!

So I finally got it working, I copied the usings from lidydonna - msft git and read about .net backend for mobileservice.

This ended with the following:

using System.Web.Http;
using Microsoft.Azure.Mobile.Server.Config;
using System.Threading.Tasks;
using System.Web.Http.Tracing;
using Microsoft.Azure.Mobile.Server;

namespace BCMobileAppService.Controllers
{
[MobileAppController]
public class TestController : ApiController
{
    // GET api/Test
    [HttpGet, Route("api/Test/completeAll")]
    public string Get()
    {
        MobileAppSettingsDictionary settings = this.Configuration.GetMobileAppSettingsProvider().GetMobileAppSettings();
        ITraceWriter traceWriter = this.Configuration.Services.GetTraceWriter();

            string host = settings.HostName ?? "localhost";
            string greeting = "Hello from " + host;

            traceWriter.Info(greeting);
            return greeting;
        }

        // POST api/values
        [HttpPost, Route("api/Test/completeAll")]
        public string Post(string hej)
        {
            string retVal = "Hello World!" + hej;
            return retVal;
        }
    }
}

This is a new controller and not the one that comes with it as lidydonna used. It seemed like it wants both functions get and post. This resulted in the API was registered and could be accessed. This means the client call to the server I used was:

t = await App.MobileService.InvokeApiAsync<string, string>("Test/completeAll", null, HttpMethod.Post, new Dictionary<string, string>() { { "hej", " AWESOME !" }});

dialog = new MessageDialog(t);
dialog.Commands.Add(new UICommand("OK"));
await dialog.ShowAsync();

AND I GOT A RESPONSE YAY!!

Extra Information

The controllers that you create, i.e. the class needs to end with Controller, you can have text before but not after. This information was given on a MSDN forum discussion.

If the post and the get has the same input the server returns Not found. Having different inputs solves the issue.

In case of weird Internal Server Error, i.e. weird you can step through the entire server code all variables that you want to return are initialized, but the client receives the error. Then refer to Internal Server Error - Azure App Service Custom Controller where simple fix to the configuration can solve the issue.

Community
  • 1
  • 1
JTIM
  • 2,774
  • 1
  • 34
  • 74
  • 1
    It still does not work without ZUMO-API-VERSION header: http://go.microsoft.com/fwlink/?LinkId=690568#2.0.0 – Andrei Drynov Apr 15 '16 at 12:42
  • @AFD I think this is handled when you utilize the Azure command `InvokeApiAsync()` ? At least this has not given me any issues. Could you describe how you access the API? – JTIM Apr 15 '16 at 12:57
  • I used Fiddler/Postman. Guess could set a breakpoint and call InvokeApiAsync from another project. – Andrei Drynov Apr 15 '16 at 16:17
  • @AFD I remember that the old version of azure muget package and sdk needed the key, when it was initialised. Are you sure you have the azure sdk 2.8.1 and the right muget package (cant remember that one of the top of my head :D) – JTIM Apr 15 '16 at 19:37
  • @winnicki did you solve the issue? I could not see a typo, could you point me to what you want me to change? – JTIM Jan 15 '17 at 12:04
  • @JTIM My mistake. I pasted it into VS and it's fine, but at first glance it looked like the Post was nested in the Get becuase of the { formatting. –  Jan 16 '17 at 19:06
  • 1
    My personal hero! – Sean Stayns Sep 15 '17 at 15:20
5

You must have something wrong in your project configuration. I have a working sample here: https://gist.github.com/lindydonna/6fca7f689ee72ac9cd20

After creating the HttpConfiguration object, call config.MapHttpAttributeRoutes(). I added the route attribute [Route("api/Test/completeAll")] and I can confirm that the route is registered correctly.

Try adding this attribute to the ValuesController and check the route.

lindydonna
  • 3,874
  • 17
  • 26
  • I have copied your using statements. I can sometimes get too many linking to the same address (okay great they exist). Delete clean upload new one, with only one route, the error return `Not Found`. Instead of having the `Task<>` I changed it to get set functions, but now I get method not allowed. I can simply not understand what is the issue here with the server :/ – JTIM Mar 17 '16 at 17:52
2

I found another cause for the 404 errors when it came to use attribute routing.

The code above originally had this in mobileApp.cs:

HttpConfiguration config = new HttpConfiguration();
    new MobileAppConfiguration()
        .UseDefaultConfiguration().MapApiControllers()
        .ApplyTo(config);
    config.MapHttpAttributeRoutes();
    app.UseWebApi(config);

The config.MapHttpAttributeRoutes() needs to be moved above the .ApplyTo:

HttpConfiguration config = new HttpConfiguration();
 config.MapHttpAttributeRoutes();
 new MobileAppConfiguration()
        .UseDefaultConfiguration().MapApiControllers()
        .ApplyTo(config);
mdorson
  • 21
  • 1
1

Try switching inheriting from ApiController to TableController.

viktorh
  • 152
  • 13
  • I will try this later. However it specifically is stated in the documentation that it should be ApiController? But i'll give it a go :) – JTIM Mar 03 '16 at 12:05
  • @viktoh the code compiles and can be published, but the error persists, so unfortunately not the solution :/ – JTIM Mar 03 '16 at 21:40
  • For this use case, ApiController is actually more appropriate. – lindydonna Mar 17 '16 at 00:38
  • @lindydonna-msft When is ApiController more appropriate than TableController? I'm just getting started with Azure App Service, and I would like further details to help me decide when to use which. – HappyNomad May 04 '16 at 20:26
  • TableController is good for when you want CRUD operations on a logical entity. Use an ApiController if you have only one action. Offline sync only works with table controllers. – lindydonna May 04 '16 at 21:31
  • @lindydonna-msft By "logical entity" I guess you mean a table row without its related data since TableController doesn't retrieve or update related data. Why limit my ApiController to only one action? For example, I may have one operation to upsert a root along with its related data, and another to delete it. – HappyNomad May 04 '16 at 22:22
  • The ApiController could certainly have multiple actions, but if you have only one action, an ApiController is probably right choice. By logical entity, I meant the DTO that you are performing CRUD operations on. It doesn't have to map to one database table. – lindydonna May 04 '16 at 22:36
  • @lindydonna-msft Got it. By "logical entity" you meant DTO. By "table row" I meant DTO. So we were actually talking about the same thing ;) – HappyNomad May 04 '16 at 23:15
  • @lindydonna-msft I [answered](http://stackoverflow.com/a/37042206/) a related question which led to another question. Please comment over there as to why `Include` alone doesn't return related data. – HappyNomad May 05 '16 at 04:44
1

It is really strange but simple API request is not working in azure app service So I have figure out solution which has worked for me. I have tested http requests with c# http post/get, android post/get, and objective C post/get So first of all you need to update your Startup.MobileApp.cs class :

  new MobileAppConfiguration()
    .UseDefaultConfiguration()   
    .MapApiControllers()                /* /api endpoints **missing part***/ 
    .ApplyTo(config);

Then create Azure Mobile App Custom Controller. After that modify little bit your controller to get proper json response

    public class Mes
    {
        public string message { get; set; }
    }

    // GET api/My
    public Mes Get()
    {

        return new Mes { message = "thanks" };


       // return "Hello from custom controller!";
    }
    // POST api/My
    public Mes Post(Mes chal)
    {

        return new Mes { message = chal.message + "asnwer" };


        // return "Hello from custom controller!";
    }
}

You can simple leave first variant and get response, but OBjective C will say to you that JSON text did not start with array or object and option to allow fragments...and so on.. This happens because you getting simple string not object. So that is why I have modified my response with class Mes But it is also depends how you make request and what type of object you expect. So .MapApiControllers() it is the main key for API and WEB API controller is now changed to azure custom controller. Hope this helps.

Jevgenij Kononov
  • 1,210
  • 16
  • 11