Wie übergebe ich UTC-Daten an die Web-API?
Das Übergeben 2010-01-01
funktioniert einwandfrei, aber wenn ich ein UTC-Datum wie 2014-12-31T22:00:00.000Z
(mit einer Zeitkomponente) übergebe, erhalte ich eine HTTP 404-Antwort. Damit
http://domain/api/controller/action/2012-12-31T22:00:00.000Z
ergibt eine 404-Fehlerantwort, während
http://domain/api/controller/action/2012-12-31
funktioniert gut.
Wie übergebe ich dann UTC-Daten an die Web-API - oder gebe zumindest Datum und Uhrzeit an?
asp.net
datetime
asp.net-web-api
Nickolodeon
quelle
quelle
http://domain/api/controller/action/2012-12-31T22%3A00%3A00.000Z
DateTime
Ich gehe davon aus, dass dies der Datentyp des Parameters für Ihre Methode ist.Antworten:
Das Problem ist zweifach:
1. Die
.
in der RouteStandardmäßig behandelt IIS alle URIs mit einem Punkt als statische Ressource, versucht, sie zurückzugeben und die weitere Verarbeitung (über die Web-API) insgesamt zu überspringen. Dies wird in Ihrer Web.config im Abschnitt konfiguriert
system.webServer.handlers
: Die Standardhandler-Handlespath="*."
. Sie werden in diesempath
Attribut nicht viel Dokumentation über die seltsame Syntax finden (Regex hätte mehr Sinn gemacht), aber was dies anscheinend bedeutet, ist "alles, was keinen Punkt enthält" (und jedes Zeichen aus Punkt 2 unten). Daher das 'Extensionless' im NamenExtensionlessUrlHandler-Integrated-4.0
.Meiner Meinung nach sind mehrere Lösungen in der Reihenfolge "Korrektheit" möglich:
path="*."
Attribut inpath="*"
. Es wird dann alles fangen. Beachten Sie, dass Ihre Web-API von nun an eingehende Anrufe mit Punkten nicht mehr als statische Ressourcen interpretiert! Wenn Sie statische Ressourcen auf Ihrer Web-API hosten, wird dies daher nicht empfohlen!<system.webserver>
:<modules runAllManagedModulesForAllRequests="true">
2. Die
:
in der RouteNachdem Sie das oben Gesagte geändert haben, wird standardmäßig der folgende Fehler angezeigt:
Sie können die vordefinierten unzulässigen / ungültigen Zeichen in Ihrer Web.config ändern. Unter
<system.web>
fügen Sie die folgende:<httpRuntime requestPathInvalidCharacters="<,>,%,&,*,\,?" />
. Ich habe das:
aus der Standardliste ungültiger Zeichen entfernt.Einfachere / sicherere Lösungen
Obwohl dies keine Antwort auf Ihre Frage ist, besteht eine sicherere und einfachere Lösung darin, die Anfrage so zu ändern, dass all dies nicht erforderlich ist. Dies kann auf zwei Arten erfolgen:
?date=2012-12-31T22:00:00.000Z
..000
von jeder Anfrage. Sie müssten noch zulassen:
(siehe Punkt 2).quelle
:
s zuzulassen , diese%3A
anstelle von verwenden,:
und es sollte in Ordnung sein.Ich fühle deinen Schmerz ... noch ein Datum-Zeit-Format ... genau das, was du brauchst!
Mit Web Api 2 können Sie Routenattribute verwenden, um Parameter anzugeben.
Mit Attributen für Ihre Klasse und Ihre Methode können Sie eine REST-URL mit diesem utc-Format codieren, mit dem Sie Probleme haben (anscheinend mit ISO8601, vermutlich mit 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)
.... ABER, obwohl dies mit einem Datum (startDate) funktioniert, funktioniert es aus irgendeinem Grund nicht, wenn das endDate in diesem Format vorliegt ... stundenlang debuggt, nur ein Hinweis ist eine Ausnahme, die besagt, dass es keinen Doppelpunkt ":" (gerade) mag obwohl web.config gesetzt ist mit:
<system.web> <compilation debug="true" targetFramework="4.5.1" /> <httpRuntime targetFramework="4.5.1" requestPathInvalidCharacters="" /> </system.web>
Erstellen Sie also ein anderes Datumsformat (aus der Polyfüllung für das ISO-Datumsformat entnommen) und fügen Sie es dem Javascript-Datum hinzu (der Kürze halber nur bis zu Minuten konvertieren):
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'; }; }()); }
Wenn Sie dann die Daten an die Web API 2-Methode senden, können Sie sie von einer Zeichenfolge in ein Datum konvertieren:
[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; }
so wäre die url
http://domain/api/myrecordtype/daterange/20140302T0003Z/20140302T1603Z
Hanselman gibt hier einige verwandte Informationen:
http://www.hanselman.com/blog/OnTheNightmareThatIsJSONDatesPlusJSONNETAndASPNETWebAPI.aspx
quelle
endDate
würde funktionieren, wenn die Anforderungs- URL einen abschließenden Schrägstrich enthalten würde. Leider kann ich mich nicht erinnern, wo ich auf diese Informationen gestoßen bin, und ich weiß auch nicht, wie ich das umgehen kann.in Ihrem Product Web API-Controller:
[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(); } } }
Testen Sie die GetProductPeriodOrders-Methode in Fiddler - Composer:
http://localhost:46017/api/product/orders?productCode=100&dateStart=2016-12-01T00:00:00&dateEnd=2016-12-31T23:59:59
DateTime-Format:
yyyy-MM-ddTHH:mm:ss
Javascript-Pass-Parameter verwenden moment.js
const dateStart = moment(startDate).format('YYYY-MM-DDTHH:mm:ss'); const dateEnd = moment(endDate).format('YYYY-MM-DDTHH:mm:ss');
quelle
Als ähnliche Alternative zur Antwort von sk kann ich ein Datum übergeben, das
Date.prototype.toISOString()
in der Abfragezeichenfolge formatiert ist . Dies ist das Standardformat ISO 8601 und wird von .NET Web API-Controllern ohne zusätzliche Konfiguration der Route oder Aktion akzeptiert.z.B
var dateString = dateObject.toISOString(); // "2019-07-01T04:00:00.000Z"
quelle
dateObject
es sich um ein initialisiertesDate
Objekt handelt.Dies ist eine Lösung und ein Modell für mögliche Lösungen. Verwenden Sie Moment.js in Ihrem Client, um Daten zu formatieren und in Unix-Zeit zu konvertieren.
$scope.startDate.unix()
Richten Sie Ihre Routenparameter so ein, dass sie lang sind.
[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! }
Erstellen Sie eine Erweiterungsmethode für die Unix-Zeit. Unix DateTime-Methode
quelle
Früher war es eine schmerzhafte Aufgabe, aber jetzt können wir toUTCString () verwenden:
Beispiel:
[HttpPost] public ActionResult Query(DateTime Start, DateTime End)
Fügen Sie das Folgende in die Ajax-Postanfrage ein
data: { Start: new Date().toUTCString(), End: new Date().toUTCString() },
quelle
Tatsächlich funktionierte die explizite Angabe von Parametern als? Date = 'fulldatetime' wie ein Zauber. Dies ist also vorerst eine Lösung: Verwenden Sie keine Kommas, sondern den alten GET-Ansatz.
quelle
Da ich das Betriebssystem ISO-8859-1 codiert habe, wurde das Datumsformat "dd.MM.yyyy HH: mm: sss" nicht erkannt. Die Verwendung der InvariantCulture-Zeichenfolge funktionierte.
string url = "GetData?DagsPr=" + DagsProfs.ToString(CultureInfo.InvariantCulture)
quelle
Wenn Sie sich Ihren Code ansehen, gehen Sie davon aus, dass Sie keine Bedenken hinsichtlich der 'Zeit' des DateTime-Objekts haben. In diesem Fall können Sie Datum, Monat und Jahr als ganzzahlige Parameter übergeben. Bitte beachten Sie den folgenden Code. Dies ist ein Arbeitsbeispiel aus meinem aktuellen Projekt.
Der Vorteil ist; Diese Methode hilft mir, Probleme mit dem DateTime-Format und Kulturinkompatibilitäten zu vermeiden.
/// <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); }
Wenn Sie auch das Front-End sehen möchten, lesen Sie bitte den folgenden Code. Leider ist das in Angular geschrieben. So übergebe ich normalerweise eine DateTime als Abfrageparameter in Angular GET-Anforderungen.
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; }
quelle
Eine mögliche Lösung ist die Verwendung von Zecken:
öffentliche lange Zecken {get; }}
Dann in der Methode des Controllers:
public DateTime (lange Häkchen);
quelle