日時パラメータを渡す方法は?


91

UTC日付をWebAPIに渡す方法は?

受け渡し2010-01-01は正常に機能しますが、2014-12-31T22:00:00.000Z(時間コンポーネントを使用して)などのUTC日付を渡すと、HTTP404応答が返されます。そう

http://domain/api/controller/action/2012-12-31T22:00:00.000Z

404エラー応答を生成しますが、

http://domain/api/controller/action/2012-12-31

正常に動作します。

UTC日付をWebAPIに渡す方法、または少なくとも日付時刻を指定する方法は?


2
日付の「:」は容疑者ですか?それをエスケープしてみてください。http://domain/api/controller/action/2012-12-31T22%3A00%3A00.000Z
shahkalpesh 2013年

2
エスケープは役に立ちません。それでも404
Nickolodeon

渡された文字列から日付への変換が失敗する理由を理解するためにデバッグを有効にできますか?アイデアは、URLを使用して渡した日付を変換するためにどのメソッドが使用されているかを把握することです。DateTimeこれは、メソッドのパラメーターのデータ型であると思います。
shahkalpesh 2013年

4
やります。メソッドは.NETDateTimeパラメーターを必要とします。時間コンポーネントを渡すことができず、その方法に関するドキュメントが見つからないのはばかげていると思います。
ニコロデオン2013年

2
完了したら、ソリューションを投稿してください。それは同様の問題を抱えている他の人々を助けることができます。ありがとう。
shahkalpesh 2013年

回答:


34

問題は2つあります。

1..ルート内

デフォルトでは、IISはドットが含まれるすべてのURIを静的リソースとして扱い、それを返そうとして、(Web APIによる)それ以上の処理を完全にスキップします。これは、Web.configのセクションsystem.webServer.handlers「デフォルトハンドラーが処理する」で構成されますpath="*."。このpath属性の奇妙な構文に関するドキュメントはあまりありませんが(正規表現の方が理にかなっています)、これが明らかに意味するのは、「ドットを含まないもの」(および以下のポイント2の文字)です。したがって、名前の「Extensionless」ExtensionlessUrlHandler-Integrated-4.0

私の意見では、「正しさ」の順に複数の解決策が可能です。

  • ドットを許可する必要があるルート専用の新しいハンドラーを追加します。必ずデフォルトのに追加してください。これを行うには、最初にデフォルトハンドラーを削除し、その後に追加し直してください。
  • path="*."属性をに変更しますpath="*"。その後、すべてをキャッチします。それ以降、WebAPIはドット付きの着信呼び出しを静的リソースとして解釈しなくなることに注意してください。Web APIで静的リソースをホストしている場合、これはお勧めできません。
  • 以下をWeb.configに追加して、すべてのリクエストを無条件に処理します<system.webserver><modules runAllManagedModulesForAllRequests="true">

2.:ルート内

上記を変更すると、デフォルトで次のエラーが発生します。

潜在的に危険なRequest.Path値がクライアントから検出されました(:)。

Web.configで事前定義された許可されていない/無効な文字を変更できます。の下<system.web>に、以下を追加します<httpRuntime requestPathInvalidCharacters="&lt;,&gt;,%,&amp;,*,\,?" />:無効な文字の標準リストからを削除しました。

より簡単で安全なソリューション

あなたの質問への答えではありませんが、より安全で簡単な解決策は、これがすべて必要とされないようにリクエストを変更することです。これは2つの方法で行うことができます。

  1. のように、日付をクエリ文字列パラメータとして渡します?date=2012-12-31T22:00:00.000Z
  2. .000すべてのリクエストからを削除します。それでも、を許可する必要があります:(cfrポイント2)。

あなたの「より簡単な解決策」は、私が数秒を必要としなかったので、基本的に私のためにそれをしました。
ネビル

あなたは命の恩人です:)
Moeez 2017年

1
あなたの「簡単ソリューション」では、代わりにできるの:Sを、私はあなただけを使用することができると思う%3Aの代わりに:、それは問題ないはずです。
MayerSpitzer19年

22

製品WebAPIコントローラー内:

[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メソッドをテストします-Composer:

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');

18

私はあなたの痛みを感じます...さらに別の日時形式...あなたが必要なものだけです!

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

ハンゼルマンはここにいくつかの関連情報を与えます:

http://www.hanselman.com/blog/OnTheNightmareThatIsJSONDatesPlusJSONNETAndASPNETWebAPI.aspx


WebAPIメソッドでは、datetimeパラメーターをnull許容DateTime(DateTime?startDateString、DateTime?endDateDtring)として持つことができます
DotNet Fan

toISOStringについて言及してくれてありがとう-それは私を救った。私のRESTfulWCFサービスはURIの2つの日付で正常に機能するため、複雑な日付変換は必要ありませんでした。たぶん、設定設定にもかかわらず、WebAPIがコロンを好まないという癖です...奇妙です。
ネビル

@Simon、endDateリクエストUrlに末尾のスラッシュが含まれている場合は機能します。残念ながら、この情報に出くわした場所を思い出せません。また、これを回避する方法もわかりません。
Pooven 2016

これを使用したい24時間制のユーザーは、日付形式でhhをHHに変更する必要があります。
snaits 2017

1
これが正解です。StackOverflow、回答の反対意見をやめましょう!
mghaoui 2018

9

skの回答の同様の代替手段としてDate.prototype.toISOString()、クエリ文字列でフォーマットされた日付を渡すことができます。これは標準のISO8601形式であり、ルートやアクションを追加で構成しなくても、.Net WebAPIコントローラーで受け入れられます。

例えば

var dateString = dateObject.toISOString(); // "2019-07-01T04:00:00.000Z"

1
それは...ですか?これが機能する例を教えてください。私は同じ回避策を実行しましたが、機能しません。
アナトール

@anatolどのような結果が得られますか?提供されているコードはdateObject、初期化されたDateオブジェクトである前提条件を備えた実用的な例です。
ボンドリン

これはおそらく少し投票する必要があります。これは、UTCをISOに変更することで私の問題を解決しました。最も単純な
Regianni

1
@Regianniそれが助けてくれてうれしい:
ボンドリン


7

これは解決策であり、考えられる解決策のモデルです。クライアントで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時間の拡張メソッドを作成します。UnixDateTimeメソッド


4

以前は面倒な作業でしたが、今ではtoUTCString()を使用できます。

例:

[HttpPost]
public ActionResult Query(DateTime Start, DateTime End)

以下をAjaxのPOSTリクエストに入れてください

data: {
    Start: new Date().toUTCString(),
    End: new Date().toUTCString()
},

3

実際のところ、パラメーターを?date = 'fulldatetime'として明示的に指定することは魅力のように機能しました。したがって、これは今のところ解決策になります。コンマは使用せず、古いGETアプローチを使用してください。


0

ISO-8859-1オペレーティングシステムをエンコードしているので、日付形式「dd.MM.yyyy HH:mm:sss」が認識されませんでした。InvariantCulture文字列を使用すると機能しました。

string url = "GetData?DagsPr=" + DagsProfs.ToString(CultureInfo.InvariantCulture)

0

コードを見ると、DateTimeオブジェクトの「時間」については心配していないと思います。その場合、日付、月、年を整数パラメーターとして渡すことができます。次のコードを参照してください。これは私の現在のプロジェクトの実例です。

利点は次のとおりです。この方法は、DateTime形式の問題とカルチャの非互換性を回避するのに役立ちます。

    /// <summary>
    /// Get Arrivals Report Seven Day Forecast
    /// </summary>
    /// <param name="day"></param>
    /// <param name="month"></param>
    /// <param name="year"></param>
    /// <returns></returns>
    [HttpGet("arrivalreportsevendayforecast/{day:int}/{month:int}/{year:int}")]
    public async Task<ActionResult<List<ArrivalsReportSevenDayForecastModel>>> GetArrivalsReportSevenDayForecast(int day, int month, int year)
    {
        DateTime selectedDate = new DateTime(year, month, day);
        IList<ArrivalsReportSevenDayForecastModel> arrivingStudents = await _applicationService.Value.GetArrivalsReportSevenDayForecast(selectedDate);
        return Ok(arrivingStudents);
    }

フロントエンドも見たい場合は、以下のコードをお読みください。残念ながら、それはAngularで書かれています。これは、私が通常、AngularGETリクエストのクエリパラメーターとしてDateTimeを渡す方法です。

public getArrivalsReportSevenDayForecast(selectedDate1 : Date): Observable<ArrivalsReportSevenDayForecastModel[]> {
const params = new HttpParams();
const day = selectedDate1.getDate();
const month = selectedDate1.getMonth() + 1
const year = selectedDate1.getFullYear();

const data = this.svcHttp.get<ArrivalsReportSevenDayForecastModel[]>(this.routePrefix +
  `/arrivalreportsevendayforecast/${day}/${month}/${year}`, { params: params }).pipe(
  map<ArrivalsReportSevenDayForecastModel[], ArrivalsReportSevenDayForecastModel[]>(arrivingList => {
    // do mapping here if needed       
    return arrivingList;
  }),
  catchError((err) => this.svcError.handleError(err)));

return data;
}

0

考えられる解決策の1つは、ティックを使用することです。

public long Ticks {get; }

次に、コントローラーの方法で:

public DateTime(long ticks);

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.