UTC日付をWeb APIに渡す方法は?
2010-01-01
を渡すことは正常に機能しますが、2014-12-31T22:00:00.000Z
(時間コンポーネントを含む)などのUTC日付を渡すと、HTTP 404応答が返されます。そう
http://domain/api/controller/action/2012-12-31T22:00:00.000Z
404エラー応答を返しますが、
http://domain/api/controller/action/2012-12-31
正常に動作します。
UTC日付をWeb APIに渡す方法-または少なくとも日付を指定するand time?
問題は2つあります。
.
デフォルトでは、IISは、ドットを含むすべてのURIを静的リソースとして扱い、それを返し、(Web APIによる)さらなる処理を完全にスキップしようとします。これはsystem.webServer.handlers
セクションのWeb.configで構成されます。デフォルトのハンドラーはpath="*."
を処理します。このpath
属性には奇妙な構文に関するドキュメントはあまりありません(正規表現の方が理にかなっています)が、これは明らかに「ドットを含まないもの」(およびポイントからの文字) 2以下)。したがって、ExtensionlessUrlHandler-Integrated-4.0
という名前の「Extensionless」です。
私の意見では、「正確さ」の順序で複数の解決策が可能です。
path="*."
属性をpath="*"
に変更します。その後、すべてをキャッチします。それ以降、Web APIはドット付きの着信呼び出しを静的リソースとして解釈しなくなることに注意してください! Web APIで静的リソースをホストしている場合、これはお勧めしません!<system.webserver>
:<modules runAllManagedModulesForAllRequests="true">
:
上記を変更すると、デフォルトで次のエラーが表示されます。
潜在的に危険なRequest.Path値がクライアント(:)から検出されました。
Web.configで定義済みの許可されない/無効な文字を変更できます。 <system.web>
の下に、以下を追加します:<httpRuntime requestPathInvalidCharacters="<,>,%,&,*,\,?" />
。無効な文字の標準リストから:
を削除しました。
質問への答えではありませんが、より安全で簡単な解決策は、要求を変更して、これがすべて不要になるようにすることです。これは2つの方法で実行できます。
?date=2012-12-31T22:00:00.000Z
のようなクエリ文字列パラメーターとして日付を渡します。.000
を取り除きます。 :
's(cfrポイント2)を許可する必要があります。私はあなたの痛みを感じます...さらに別の日付時刻形式...まさにあなたが必要なもの!
Web Api 2を使用すると、ルート属性を使用してパラメーターを指定できます。
したがって、クラスとメソッドの属性を使用すると、このUTCフォーマットを使用してREST URLをコーディングできます(明らかにISO8601、おそらくstartDate.toISOString()を使用して到着しました)
[Route(@"daterange/{startDate:regex(^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$)}/{endDate:regex(^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$)}")]
[HttpGet]
public IEnumerable<MyRecordType> GetByDateRange(DateTime startDate, DateTime endDate)
....しかし、これは1つの日付(startDate)で機能しますが、何らかの理由でendDateがこの形式の場合は機能しません...何時間もデバッグされますが、コロン ":"(ただし、web.configは次のように設定されます。
<system.web>
<compilation debug="true" targetFramework="4.5.1" />
<httpRuntime targetFramework="4.5.1" requestPathInvalidCharacters="" />
</system.web>
したがって、別の日付形式(ISO日付形式のポリフィルから取得)を作成し、それをJavascript日付に追加します(簡潔にするため、最大で数分まで変換します)。
if (!Date.prototype.toUTCDateTimeDigits) {
(function () {
function pad(number) {
if (number < 10) {
return '0' + number;
}
return number;
}
Date.prototype.toUTCDateTimeDigits = function () {
return this.getUTCFullYear() +
pad(this.getUTCMonth() + 1) +
pad(this.getUTCDate()) +
'T' +
pad(this.getUTCHours()) +
pad(this.getUTCMinutes()) +
'Z';
};
}());
}
次に、日付をWeb API 2メソッドに送信すると、文字列から日付に変換できます。
[RoutePrefix("api/myrecordtype")]
public class MyRecordTypeController : ApiController
{
[Route(@"daterange/{startDateString}/{endDateString}")]
[HttpGet]
public IEnumerable<MyRecordType> GetByDateRange([FromUri]string startDateString, [FromUri]string endDateString)
{
var startDate = BuildDateTimeFromYAFormat(startDateString);
var endDate = BuildDateTimeFromYAFormat(endDateString);
...
}
/// <summary>
/// Convert a UTC Date String of format yyyyMMddThhmmZ into a Local Date
/// </summary>
/// <param name="dateString"></param>
/// <returns></returns>
private DateTime BuildDateTimeFromYAFormat(string dateString)
{
Regex r = new Regex(@"^\d{4}\d{2}\d{2}T\d{2}\d{2}Z$");
if (!r.IsMatch(dateString))
{
throw new FormatException(
string.Format("{0} is not the correct format. Should be yyyyMMddThhmmZ", dateString));
}
DateTime dt = DateTime.ParseExact(dateString, "yyyyMMddThhmmZ", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
return dt;
}
だからURLは
http://domain/api/myrecordtype/daterange/20140302T0003Z/20140302T1603Z
Hanselmanが関連情報をここに提供します。
http://www.hanselman.com/blog/OnTheNightmareThatIsJSONDatesPlusJSONNETAndASPNETWebAPI.aspx
product Web APIコントローラーで:
[RoutePrefix("api/product")]
public class ProductController : ApiController
{
private readonly IProductRepository _repository;
public ProductController(IProductRepository repository)
{
this._repository = repository;
}
[HttpGet, Route("orders")]
public async Task<IHttpActionResult> GetProductPeriodOrders(string productCode, DateTime dateStart, DateTime dateEnd)
{
try
{
IList<Order> orders = await _repository.GetPeriodOrdersAsync(productCode, dateStart.ToUniversalTime(), dateEnd.ToUniversalTime());
return Ok(orders);
}
catch(Exception ex)
{
return NotFound();
}
}
}
fiddlerでGetProductPeriodOrdersメソッドをテストします-作曲者:
http://localhost:46017/api/product/orders?productCode=100&dateStart=2016-12-01T00:00:00&dateEnd=2016-12-31T23:59:59
日時形式:
yyyy-MM-ddTHH:mm:ss
javascriptパスパラメータはmoment.jsを使用します
const dateStart = moment(startDate).format('YYYY-MM-DDTHH:mm:ss');
const dateEnd = moment(endDate).format('YYYY-MM-DDTHH:mm:ss');
これは解決策であり、可能な解決策のモデルです。クライアントでMoment.jsを使用して日付をフォーマットし、Unix時間に変換します。
$scope.startDate.unix()
ルートパラメータを長く設定します。
[Route("{startDate:long?}")]
public async Task<object[]> Get(long? startDate)
{
DateTime? sDate = new DateTime();
if (startDate != null)
{
sDate = new DateTime().FromUnixTime(startDate.Value);
}
else
{
sDate = null;
}
... your code here!
}
Unix時間の拡張メソッドを作成します。 nix DateTimeメソッド
実際のところ、パラメータを明示的に?date = 'fulldatetime'として指定すると、魅力のように機能しました。したがって、これは当面の解決策になります。コンマを使用せず、古いGETアプローチを使用します。
かつては骨の折れる作業でしたが、今ではtoUTCString()を使用できます。
例:
[HttpPost]
public ActionResult Query(DateTime Start, DateTime End)
以下をAjaxのポストリクエストに入れます
data: {
Start: new Date().toUTCString(),
End: new Date().toUTCString()
},
S kの答えの代替として、クエリ文字列で Date.prototype.toISOString()
でフォーマットされた日付を渡すことができます。これは標準のISO 8601形式であり、ルートまたはアクションの追加構成なしで.Net Web APIコントローラーで受け入れられます。
例えば.
var dateString = dateObject.toISOString(); // "2019-07-01T04:00:00.000Z"