Как передать даты UTC в веб-API?
Передача 2010-01-01
работает нормально, но когда я передаю дату в формате UTC, например 2014-12-31T22:00:00.000Z
(с компонентом времени), я получаю ответ HTTP 404. Так
http://domain/api/controller/action/2012-12-31T22:00:00.000Z
дает ответ об ошибке 404, а
http://domain/api/controller/action/2012-12-31
работает отлично.
Как тогда передать даты UTC в веб-API - или хотя бы указать дату и время?
asp.net
datetime
asp.net-web-api
Николодеон
источник
источник
http://domain/api/controller/action/2012-12-31T22%3A00%3A00.000Z
DateTime
- который, как я предполагаю, является типом данных paramater вашего метода.Ответы:
Проблема двоякая:
1. На
.
маршрутеПо умолчанию IIS обрабатывает все URI с точкой в них как статический ресурс, пытается вернуть его и вообще пропустить дальнейшую обработку (через веб-API). Это настраивается в вашем Web.config в разделе
system.webServer.handlers
: обработчик по умолчанию обрабатываетpath="*."
. Вы не найдете много документации относительно странного синтаксиса этогоpath
атрибута (регулярное выражение имело бы больше смысла), но, по-видимому, это означает «все, что не содержит точки» (и любой символ из пункта 2 ниже). Отсюда и слово «без расширения» в названииExtensionlessUrlHandler-Integrated-4.0
.На мой взгляд, в порядке «правильности» возможно несколько решений:
path="*."
атрибут наpath="*"
. Тогда он все поймает. Обратите внимание, что с этого момента ваш веб-API больше не будет интерпретировать входящие вызовы с точками как статические ресурсы! Если вы размещаете статические ресурсы на своем веб-API, это не рекомендуется!<system.webserver>
:<modules runAllManagedModulesForAllRequests="true">
2. На
:
маршрутеПосле того, как вы изменили вышеуказанное, по умолчанию вы получите следующую ошибку:
Вы можете изменить предопределенные запрещенные / недопустимые символы в своем Web.config. Под
<system.web>
, добавить следующее:<httpRuntime requestPathInvalidCharacters="<,>,%,&,*,\,?" />
. Я удалил:
из стандартного списка недопустимых символов.Более простые / безопасные решения
Хотя это не ответ на ваш вопрос, более безопасным и простым решением было бы изменить запрос, чтобы все это не требовалось. Это можно сделать двумя способами:
?date=2012-12-31T22:00:00.000Z
..000
от каждого запроса. Вам все равно нужно разрешить:
(см. Пункт 2).источник
:
s, я думаю, вы можете просто использовать%3A
вместо,:
и это должно быть хорошо.в вашем контроллере 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(); } } }
проверить метод GetProductPeriodOrders в Fiddler - 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');
источник
Я чувствую вашу боль ... еще один формат даты и времени ... именно то, что вам нужно!
Используя Web Api 2, вы можете использовать атрибуты маршрута для указания параметров.
поэтому с атрибутами вашего класса и вашего метода вы можете закодировать URL-адрес REST, используя этот формат utc, с которым у вас возникли проблемы (по-видимому, его 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)
.... НО, хотя это работает с одной датой (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
источник
endDate
будет работать, если URL-адрес запроса включал косую черту в конце. К сожалению, я не могу вспомнить, где я нашел эту информацию, и не знаю способа обойти это.В качестве альтернативы ответу sk я могу передать дату, отформатированную
Date.prototype.toISOString()
в строке запроса. Это стандартный формат ISO 8601, который принимается контроллерами .Net Web API без какой-либо дополнительной настройки маршрута или действия.например
var dateString = dateObject.toISOString(); // "2019-07-01T04:00:00.000Z"
источник
dateObject
- инициализированныйDate
объект.Это решение и модель возможных решений. Используйте 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. Метод DateTime в Unix
источник
Раньше это было болезненной задачей, но теперь мы можем использовать toUTCString ():
Пример:
[HttpPost] public ActionResult Query(DateTime Start, DateTime End)
Поместите ниже в почтовый запрос Ajax
data: { Start: new Date().toUTCString(), End: new Date().toUTCString() },
источник
Фактически, указание параметров в явном виде как? Date = 'fulldatetime' работало как шарм. Так что это будет решением на данный момент: не используйте запятые, а используйте старый подход GET.
источник
Поскольку я кодирую операционную систему ISO-8859-1, формат даты «dd.MM.yyyy HH: mm: sss» не был распознан, что действительно помогло использовать строку InvariantCulture.
string url = "GetData?DagsPr=" + DagsProfs.ToString(CultureInfo.InvariantCulture)
источник
Глядя на ваш код, я предполагаю, что вы не беспокоитесь о «времени» объекта 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. Вот как я обычно передаю DateTime в качестве параметра запроса в запросах Angular GET.
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; }
источник
Одно из возможных решений - использовать Ticks:
общедоступные длинные тики {получить; }
Затем в методе контроллера:
общедоступный DateTime (длинные тики);
источник