私はWeb APIコントローラのGETメソッド用に変更されていない304のステータスコードを返そうとしています。
私が成功した唯一の方法は、次のようなものでした。
public class TryController : ApiController
{
public User GetUser(int userId, DateTime lastModifiedAtClient)
{
var user = new DataEntities().Users.First(p => p.Id == userId);
if (user.LastModified <= lastModifiedAtClient)
{
throw new HttpResponseException(HttpStatusCode.NotModified);
}
return user;
}
}
ここでの問題はそれが例外ではないということです、それは単に修正されないのでクライアントキャッシュはOKです。また、戻り値の型がUserであり(すべてのWeb APIの例がGETで示されているように)HttpResponseMessageなどを返さないようにする必要があります。
私は答えを知りませんでしたので、ここでASP.NETチーム に尋ねました 。
そのためのコツは、シグネチャをHttpResponseMessage
に変更してRequest.CreateResponse
を使用することです。
[ResponseType(typeof(User))]
public HttpResponseMessage GetUser(HttpRequestMessage request, int userId, DateTime lastModifiedAtClient)
{
var user = new DataEntities().Users.First(p => p.Id == userId);
if (user.LastModified <= lastModifiedAtClient)
{
return new HttpResponseMessage(HttpStatusCode.NotModified);
}
return request.CreateResponse(HttpStatusCode.OK, user);
}
Userを返すときにアクションシグネチャを保持したい場合は、次のこともできます。
public User GetUser(int userId, DateTime lastModifiedAtClient)
200
以外のものを返したい場合は、アクションにHttpResponseException
を投入し、クライアントに送信したいHttpResponseMessage
を渡します。
GetXxx APIメソッドをHttpResponseMessageを返すように変更してから、フルレスポンスの型付きバージョンとNotModifiedレスポンスの型なしバージョンを返します。
public HttpResponseMessage GetComputingDevice(string id)
{
ComputingDevice computingDevice =
_db.Devices.OfType<ComputingDevice>()
.SingleOrDefault(c => c.AssetId == id);
if (computingDevice == null)
{
return this.Request.CreateResponse(HttpStatusCode.NotFound);
}
if (this.Request.ClientHasStaleData(computingDevice.ModifiedDate))
{
return this.Request.CreateResponse<ComputingDevice>(
HttpStatusCode.OK, computingDevice);
}
else
{
return this.Request.CreateResponse(HttpStatusCode.NotModified);
}
}
* ClientHasStaleデータは、ETagおよびIfModifiedSinceヘッダーをチェックするための私の拡張です。
MVCフレームワークはまだあなたのオブジェクトをシリアル化して返すべきです。
NOTE
ジェネリック版は将来のバージョンのWeb APIで削除されると思います。
MVC 5では、物事はより簡単になりました:
return new StatusCodeResult(HttpStatusCode.NotModified, this);
私は古い記事をぶつけて嫌いですが、これはグーグル検索でこれのための最初の結果であり、私はこの問題に多少の時間がありました(あなたたちのサポートでさえ)。だからここでは何もしない...
うまくいけば私の解決策はまた混乱していたものを助けるでしょう。
namespace MyApplication.WebAPI.Controllers
{
public class BaseController : ApiController
{
public T SendResponse<T>(T response, HttpStatusCode statusCode = HttpStatusCode.OK)
{
if (statusCode != HttpStatusCode.OK)
{
// leave it up to Microsoft to make this way more complicated than it needs to be
// seriously i used to be able to just set the status and leave it at that but nooo... now
// i need to throw an exception
var badResponse =
new HttpResponseMessage(statusCode)
{
Content = new StringContent(JsonConvert.SerializeObject(response), Encoding.UTF8, "application/json")
};
throw new HttpResponseException(badResponse);
}
return response;
}
}
}
そしてBaseControllerから継承する
[RoutePrefix("api/devicemanagement")]
public class DeviceManagementController : BaseController
{...
そしてそれを使って
[HttpGet]
[Route("device/search/{property}/{value}")]
public SearchForDeviceResponse SearchForDevice(string property, string value)
{
//todo: limit search property here?
var response = new SearchForDeviceResponse();
var results = _deviceManagementBusiness.SearchForDevices(property, value);
response.Success = true;
response.Data = results;
var statusCode = results == null || !results.Any() ? HttpStatusCode.NoContent : HttpStatusCode.OK;
return SendResponse(response, statusCode);
}
.netコア2.2が304ステータスコードを返しています。これはApiControllerを使用しています。
[HttpGet]
public ActionResult<YOUROBJECT> Get()
{
return StatusCode(304);
}
必要に応じて、レスポンスと共にオブジェクトを返すことができます
[HttpGet]
public ActionResult<YOUROBJECT> Get()
{
return StatusCode(304, YOUROBJECT);
}
public HttpResponseMessage Post(Article article)
{
HttpResponseMessage response = Request.CreateResponse<Article>(HttpStatusCode.Created, article);
string uriToTheCreatedItem = Url.Route(null, new { id = article.Id });
response.Headers.Location = new Uri(Request.RequestUri, uriToTheCreatedItem);
return response;
}
ASP.NET Web Api 2の場合、 このMSからの投稿 では、メソッドの戻り値の型をIHttpActionResult
に変更することをお勧めします。 IHttpActionResult
やOk
などのような組み込みのBadRequest
実装を返すこともできますし、( こちら を参照)または独自の実装を返すこともできます。
あなたのコードでは、次のようになります。
public IHttpActionResult GetUser(int userId, DateTime lastModifiedAtClient)
{
var user = new DataEntities().Users.First(p => p.Id == userId);
if (user.LastModified <= lastModifiedAtClient)
{
return StatusCode(HttpStatusCode.NotModified);
}
return Ok(user);
}
IHttpActionResultを返し、エラーコードとメッセージを返したい場合は、次のようにします。
return ResponseMessage(Request.CreateErrorResponse(HttpStatusCode.NotModified, "Error message here"));
別のオプション:
return new NotModified();
public class NotModified : IHttpActionResult
{
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = new HttpResponseMessage(HttpStatusCode.NotModified);
return Task.FromResult(response);
}
}
HttpCreateResponseタイプを使用するように署名を変更する必要がないので、それを隠すための拡張ソリューションを少し思いついた。
public class HttpActionResult : IHttpActionResult
{
public HttpActionResult(HttpRequestMessage request) : this(request, HttpStatusCode.OK)
{
}
public HttpActionResult(HttpRequestMessage request, HttpStatusCode code) : this(request, code, null)
{
}
public HttpActionResult(HttpRequestMessage request, HttpStatusCode code, object result)
{
Request = request;
Code = code;
Result = result;
}
public HttpRequestMessage Request { get; }
public HttpStatusCode Code { get; }
public object Result { get; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
return Task.FromResult(Request.CreateResponse(Code, Result));
}
}
それから、あなたのApiController(あるいはもっと良いあなたのベースコントローラ)に次のようなメソッドを追加することができます。
protected IHttpActionResult CustomResult(HttpStatusCode code, object data)
{
// Request here is the property on the controller.
return new HttpActionResult(Request, code, data);
}
それから、あなたはそれを組み込みメソッドのいずれかと同じように返すことができます。
[HttpPost]
public IHttpActionResult Post(Model model)
{
return model.Id == 1 ?
Ok() :
CustomResult(HttpStatusCode.NotAcceptable, new {
data = model,
error = "The ID needs to be 1."
});
}
@Aliostadsの更新は、Web API 2で導入されたより現代的なIHttpActionResult
を使用して回答します。
public class TryController : ApiController
{
public IHttpActionResult GetUser(int userId, DateTime lastModifiedAtClient)
{
var user = new DataEntities().Users.First(p => p.Id == userId);
if (user.LastModified <= lastModifiedAtClient)
{
return StatusCode(HttpStatusCode.NotModified);
// If you would like to return a Http Status code with any object instead:
// return Content(HttpStatusCode.InternalServerError, "My Message");
}
return Ok(user);
}
}