为什么我在这个 Web API 请求上收到 HTTP 404?
Why do I get an HTTP 404 on this one Web API request?
我正在发出 POST
请求,并将 404 - Not Found
错误返回给此控制器和操作:
[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;
}
}
WPF 客户端使用 Microsoft.AspNet.WebApi.Client
包中的 HttpClient
发出请求。客户端配置如下:
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"));
}
}
并调用如下:
var response = await Client.PostAsJsonAsync("api/Appt", model, cancellationToken);
response
上的属性包括:
StatusCode: 404`
ReasonPhrase: 'Not Found'`
RequestMessage:
{Method: POST, RequestUri: 'http://localhost:51009/api/Appt'`
这是我对 POST
操作发出的唯一请求,带有 model
参数,但具有讽刺意味的是,POST
请求对 GET
在几乎相同的控制器上执行的操作工作正常。带控制器:
[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();
}
}
如下所示的请求工作正常并且 returns 我所有的 Person
对象:
HttpResponseMessage response = await Client.PostAsync("api/Person", null, cancellationToken);
对 GET
操作的两个类似请求也能完美运行。
那为什么一个资源找到了,另一个找不到呢?除了未找到所请求的资源之外,还有其他隐藏的原因会返回 404 吗?
会不会是两种路由冲突导致的,例如
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
我必须在一个地方使用属性路由,评论解释原因:
[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();
}
您使用了错误的路由前缀属性。
System.Web.Mvc.RoutePrefix("api/Appt")
适用于 MVC 而非 Web API。
您需要System.Web.Http
中的那个
System.Web.Http.RoutePrefix("api/Appt")
person 控制器示例起作用的原因是因为它默认返回基于约定的路由。
如果您通过基于约定的路由调用 POST http://localhost:51009/api/Appointment
,原始方法会起作用。
我正在发出 POST
请求,并将 404 - Not Found
错误返回给此控制器和操作:
[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;
}
}
WPF 客户端使用 Microsoft.AspNet.WebApi.Client
包中的 HttpClient
发出请求。客户端配置如下:
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"));
}
}
并调用如下:
var response = await Client.PostAsJsonAsync("api/Appt", model, cancellationToken);
response
上的属性包括:
StatusCode: 404`
ReasonPhrase: 'Not Found'`
RequestMessage:
{Method: POST, RequestUri: 'http://localhost:51009/api/Appt'`
这是我对 POST
操作发出的唯一请求,带有 model
参数,但具有讽刺意味的是,POST
请求对 GET
在几乎相同的控制器上执行的操作工作正常。带控制器:
[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();
}
}
如下所示的请求工作正常并且 returns 我所有的 Person
对象:
HttpResponseMessage response = await Client.PostAsync("api/Person", null, cancellationToken);
对 GET
操作的两个类似请求也能完美运行。
那为什么一个资源找到了,另一个找不到呢?除了未找到所请求的资源之外,还有其他隐藏的原因会返回 404 吗?
会不会是两种路由冲突导致的,例如
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
我必须在一个地方使用属性路由,评论解释原因:
[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();
}
您使用了错误的路由前缀属性。
System.Web.Mvc.RoutePrefix("api/Appt")
适用于 MVC 而非 Web API。
您需要System.Web.Http
System.Web.Http.RoutePrefix("api/Appt")
person 控制器示例起作用的原因是因为它默认返回基于约定的路由。
如果您通过基于约定的路由调用POST http://localhost:51009/api/Appointment
,原始方法会起作用。