Brian Heilig
Brian Heilig

Reputation: 648

ASP.NET Core API - Get 404 on Azure App Service, but works ok on Localhost

I have an ASP.NET Core 2.1 app that I've hosted in an Azure app service. When executed locally I'm able to access the controller. But when I host in an Azure app I receive a 404. Here are the minimal steps to reproduce.

In Visual Studio 2017 add a new project. Select ASP.NET Core Web Application. Select ASP.NET Core 2.1, API project template, no authentication, configure for HTTPS. Run the new app as a self hosted (not using IIS). Browse to https://localhost:5001/api/values. I get the expected response (although there is an exception on the command line about failure to authenticate HTTPS connection).

Right click the project and select publish. Select to create a new app service. I selected my existing subscription, hosting plan, and resource group. I left the default app name. Create the app.

Browse to the url https://app_name.azurewebsites.net and I see the default page. Browse to https://appname.azurewebsites.net/api/values and I get a 404.

I'm sure I'm missing something quite stupid, but I just can't figure it out.

Upvotes: 20

Views: 12205

Answers (3)

tomRedox
tomRedox

Reputation: 30543

Similarly to the @StuartLC's answer, there's another development-time-only option to be wary of with Visual Studio's .NET Core Web API template:

I spent a very frustrating hour foolishly expecting a newly deployed Azure WebApp to show me the Swagger page for my API when I navigated to it in the browser. Instead I was just getting a 404. What I should have done was used Postman or whatever to check.

Only when I checked the code did I realise that the Swagger UI is only wired in at development time by default in the template:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseSwagger();
        app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebApplication6 v1"));
    }

Upvotes: 9

StuartLC
StuartLC

Reputation: 107387

One possible cause of differing behaviour is the standard if (env.IsDevelopment()) branch in Startup.cs -> Configure(), which will change depending on the value of the ASPNETCORE_ENVIRONMENT or DOTNET_ENVIRONMENT env vars. These will default to production

In my case, I had removed the Home controller entirely, but inadvertently left the app.UseExceptionHandler middleware in Startup.Configure pointed at the default Home/Error.

So when my app was deployed to Azure, an exception happened which I didn't receive during local testing (e.g. SQL Firewall IP blocking issue), and this meant that any redirection to the error page resulted in a 404.

if (env.IsDevelopment())
   ... << Local environment (ASPNETCORE_ENVIRONMENT = 'Development')
else
{
    app.UseExceptionHandler("/Home/Error"); << Watch for this
    ...
}

Upvotes: 13

Monika Reddy
Monika Reddy

Reputation: 973

I was able to reproduce the error and below solution worked for me. Try this if you haven't tried earlier.

  1. Ensure the configuration is set to Release Mode before publishing the app to Azure.
  2. Add [Route("/")] attribute on top of your GET method in ValuesController like below.

    [Route("/")]
    [HttpGet("{id}")]
    public ActionResult<string> Get(int id)
    {
        return "value";
    }
    

Basically, Any controller methods that do not have a route attribute use convention-based routing.

When you use [Route] attribute, you define attribute routing and so conventional routing is not used for that action/controller.

As an option, you can use the fact, that attribute routes can be combined with inheritance. Set a Route attribute on the entire controller and this will work as route prefix (the same behavior as [RoutePrefix] attribute in WebApi):

[Route("api/[controller]")]
public class ValuesController: ControllerBase
{

}

Upvotes: 8

Related Questions