简体   繁体   中英

Why do I get an HTTP 404 on this one Web API request?

I am making a POST request, and getting a 404 - Not Found error back, to this controller and action:

[AllowAnonymous]
[System.Web.Mvc.RoutePrefix("api/Appt")]
public class AppointmentController : BaseController
{
    [HttpPost]
    [Route("")]
    public AppointmentDto Post(AppointmentDto model)
    {
        Db.Appointments.Add(model);
        Db.SaveChanges();
        Logger.Info($"Appointment ID {model.Id} created.");
        return model;
    }
}

The request is made from a WPF client using HttpClient from the Microsoft.AspNet.WebApi.Client package. The client is configured like so:

public abstract class BaseRestClient
{
    protected const string BaseAddress = "http://localhost:51009";
    protected HttpClient Client;

    protected virtual void ConfigureClient()
    {
        Client = new HttpClient { BaseAddress = new Uri(BaseAddress) };
        Client.DefaultRequestHeaders.Clear();
        Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    }
}

And called as follows:

var response = await Client.PostAsJsonAsync("api/Appt", model, cancellationToken);

Properties on response include:

StatusCode: 404`
ReasonPhrase: 'Not Found'`
RequestMessage: 
    {Method: POST, RequestUri: 'http://localhost:51009/api/Appt'`

This is the only request I'm making to a POST action, with a model parameter, but, ironically, a POST request to a GET action on an almost identical controller works fine. With the controller:

[System.Web.Mvc.RoutePrefix("api/Person")]
public class PersonController : BaseController
{
    [HttpPost]
    public async Task<IEnumerable<PersonDto>> Get()
    {
        Db.Configuration.LazyLoadingEnabled = false;
        return await Db.Persons.ToListAsync();
    }
}

the request made as below works fine and returns all my Person objects:

HttpResponseMessage response = await Client.PostAsync("api/Person", null, cancellationToken);

Two similar requests to GET actions also work perfectly.

So why would the one resource be found, and the other not? Are the any other, hidden reasons a 404 would be returned other than the requested resource not being found?

Could this be due to a conflict with two types of routing, eg

config.MapHttpAttributeRoutes();

config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

I have to use attribute routing in one place, the comment explains why:

[HttpPost]
[Route("Get")] 
// NOTE HTTP 405 - Method not allowed when this action is named 'Get'.
public async Task<IEnumerable<BranchDto>> Fetch()
{
    Db.Configuration.LazyLoadingEnabled = false;
    return await Db.Branches.ToListAsync();
}

You are using the wrong route prefix attribute.

System.Web.Mvc.RoutePrefix("api/Appt")

is for MVC not Web API.

You need the one in System.Web.Http

System.Web.Http.RoutePrefix("api/Appt")

The reason the person controller example worked is because it defaulted back to convention-based routing.

original would have worked if you called POST http://localhost:51009/api/Appointment via convention-based routing.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM