31
votes

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.

5
Do you also get a 404 when you try hitting the endpoint directly using Fiddler?lindydonna
@lindydonna-msft I have updated the question, but yes I still get 404.JTIM
What happens if you use the quickstart project? It will install an API Controller for you. Can you access that one?lindydonna
Can you email your server project to mobileser [email protected]? 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
Sorry, I had a typo. The address is [email protected].lindydonna

5 Answers

15
votes

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.

5
votes

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.

2
votes

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);
1
votes

Try switching inheriting from ApiController to TableController.

1
votes

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.