MSDN Forum の「ASP.net MVC5 WEB APIのキャンセル(特定のデータの返却)する方法はありますか?」という表題のスレッドでの話です。
[クライアント]⇒[閲覧用ページ]⇒[Web API]⇒[DB サーバー]
という構成で、(1) [Web API]が要求を受けたらそこで時間外か否かを判断し、(2) 時間外であれば[Web API]のアクションメソッドは実行せず、(3) [閲覧用ページ]に時間外メッセージと遷移先の URL を応答として返し、(4) [閲覧用ページ]は応答の内容をチェックして時間外であれば遷移先に指定された URL に JavScript で遷移する・・・という方法を考えてみます。
もちろん時間外でなければ、上記で、(2)[Web API]でアクションメソッドを実行し、(3) 通常の応答を[閲覧用ページ]に返し、(4)[閲覧用ページ]は応答を処理して表示するということになります。
それを実現するためには、[Web API]において以下のような AuthorizationFilterAttribute を継承したフィルターを作って、OnAuthorization メソッドを override し、そこでアクションメソッドが実行される前に時間外か否かをチェックし、時間外であればその旨メッセージを返すようにします。(以下のコードは既存のコードを流用したため日付の範囲で制限してます)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Net.Http;
using System.Web.Http.Filters;
using System.Web.Http.Controllers;
namespace WebApi1.Filters
{
[AttributeUsage(
AttributeTargets.Method | AttributeTargets.Class,
Inherited = true, AllowMultiple = false)]
public class TimeLimitAttribute : AuthorizationFilterAttribute
{
public TimeLimitAttribute(string dateBegin, string dateEnd)
{
this.Begin = dateBegin;
this.End = dateEnd;
}
private DateTime _begin = DateTime.MinValue;
private DateTime _end = DateTime.MaxValue;
public string Begin
{
set
{
DateTime dateSet = DateTime.Parse(value);
if (dateSet >= this._end)
{
throw new ArgumentException("開始日設定エラー");
}
this._begin = dateSet;
}
}
public string End
{
set
{
DateTime dateSet = DateTime.Parse(value);
if (dateSet <= this._begin)
{
throw new ArgumentException("終了日設定エラー");
}
this._end = dateSet;
}
}
public override void OnAuthorization(
HttpActionContext actionContext)
{
if (actionContext == null)
{
throw new ArgumentNullException("context が null");
}
DateTime current = DateTime.Now;
if (current < this._begin || current > this._end)
{
HttpResponseMessage response =
new HttpResponseMessage();
response.Content =
new StringContent("時間外,<リダイレクト先 URL>");
actionContext.Response = response;
}
base.OnAuthorization(actionContext);
}
}
}
ASP.NET MVC 用と ASP.NET Web API 用とでは Filter は違うそうなので注意してください。詳しくは記事「Web API における操作ごとの制御 (Validation, 認証/権限, Exception 処理 など)」を見てください。
上のフィルター属性を ApiController のクラスに付与することで制限がかけられます。たとえば、以下のようにフィルター属性を付与すれば、2013/12/1 ~ 2013/12/31 以外の日時にアクセスした場合、"時間外,<リダイレクト先 URL>" という文字列が[Web API]から応答として返ってきます。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using WebApi1.Models;
namespace WebApi1.Controllers
{
[WebApi1.Filters.TimeLimit("2013/12/1", "2013/12/31")]
public class HeroesController : ApiController
{
private List<Hero> heroes = new List<Hero> {
new Hero {Id = 1, Name = "スーパーマン"},
new Hero {Id = 2, Name = "バットマン"},
new Hero {Id = 3, Name = "ウェブマトリクスマン"},
new Hero {Id = 4, Name = "チャッカマン"},
new Hero {Id = 5, Name = "スライムマン"}
};
public IEnumerable<Hero> Get()
{
return heroes;
}
public Hero Get(int id)
{
return heroes[id - 1];
}
//・・・中略・・・
}
}
それを[閲覧用ページ]で jQuery.Ajax + JavaScript を使って、例えば上のアクションメソッドの public IEnumerable<Hero> Get() を呼んだ場合は以下のようの処置すれば、時間外であれば[Web API]からの応答に含まれる <リダイレクト先 URL> にリダイレクトされます。
function apiHeroesGet() {
$.ajax({
type: "GET",
url: "api/heroes",
contentType: "application/json; charset=utf-8",
success: function (data, textStatus, jqXHR) {
if (typeof(data) == "string" &&
data.indexOf("時間外") == 0) {
// 時間外の場合はリダイレクト
var results = data.split(",");
window.location.href = results[1];
}
else {
// 時間内の場合の処置(省略)
}
},
error: function (jqXHR, textStatus, errorThrown) {
// エラーの場合の処置(省略)
}
});
}