Как передать параметр datetime?
Как передать даты 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 в Web API, а затем - или, по крайней мере, указать дату и время?
Ответы
Ответ 1
Проблема двоякая:
1. .
в пути
По умолчанию IIS рассматривает все URI с точкой в них как статический ресурс, пытается вернуть его и вообще пропустить дальнейшую обработку (через Web API). Это настраивается в вашем файле Web.config в разделе system.webServer.handlers
: обработчик по умолчанию обрабатывает path="*."
, Вы не найдете много документации относительно странного синтаксиса в этом атрибуте path
(регулярное выражение имело бы больше смысла), но это, очевидно, означает "все, что не содержит точку" (и любой символ из пункта 2 ниже). Отсюда и "Расширение без расширения" в названии ExtensionlessUrlHandler-Integrated-4.0
.
Множество решений возможно, на мой взгляд, в порядке "правильности":
- Добавьте новый обработчик специально для маршрутов, которые должны разрешать точку. Обязательно добавьте его до значения по умолчанию. Чтобы сделать это, убедитесь, что вы сначала удалили обработчик по умолчанию, а затем добавили его обратно после своего.
- Изменить
path="*."
атрибут path="*"
. Это тогда поймает все. Обратите внимание, что с этого момента ваш веб-интерфейс больше не будет интерпретировать входящие вызовы с точками как статические ресурсы! Если вы размещаете статические ресурсы в своем веб-интерфейсе, это не рекомендуется! - Добавьте следующее в ваш Web.config для безусловной обработки всех запросов: в
<system.webserver>
: <modules runAllManagedModulesForAllRequests="true">
2. :
в маршруте
После того, как вы изменили вышеуказанное, по умолчанию вы получите следующую ошибку:
От клиента было обнаружено потенциально опасное значение Request.Path(:).
Вы можете изменить предопределенные запрещенные/недействительные символы в вашем файле Web.config. В разделе <system.web>
добавьте следующее: <httpRuntime requestPathInvalidCharacters="<,>,%,&,*,\,?"/>
<httpRuntime requestPathInvalidCharacters="<,>,%,&,*,\,?"/>
. Я удалил :
из стандартного списка недопустимых символов.
Более простые/безопасные решения
Хотя это и не ответ на ваш вопрос, более безопасным и простым решением было бы изменить запрос так, чтобы все это не требовалось. Это можно сделать двумя способами:
- Передайте дату в качестве параметра строки запроса, например
?date=2012-12-31T22:00:00.000Z
. -
.000
с каждого запроса. Вам все еще нужно разрешить :
(см. Пункт 2).
Ответ 2
Я чувствую вашу боль... еще один формат даты... просто то, что вам нужно!
С помощью 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>
Итак, давайте создадим другой формат даты (взятый из polyfill для формата даты 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
Ответ 3
в вашем API-интерфейсе 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();
}
}
}
test Метод GetProductPeriodOrders в Fiddler - Композитор:
http://localhost:46017/api/product/orders?productCode=100&dateStart=2016-12-01T00:00:00&dateEnd=2016-12-31T23:59:59
Формат DateTime:
yyyy-MM-ddTHH:mm:ss
Использовать параметр javascript pass use moment.js
const dateStart = moment(startDate).format('YYYY-MM-DDTHH:mm:ss');
const dateEnd = moment(endDate).format('YYYY-MM-DDTHH:mm:ss');
Ответ 4
Это решение и модель возможных решений. Используйте 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-времени. Unix DateTime Method
Ответ 5
Фактически, задание параметров явно как? date = 'fulldatetime' работало как шарм. Таким образом, это будет решением на данный момент: не используйте запятые, но используйте старый подход GET.
Ответ 6
Раньше это была болезненная задача, но теперь мы можем использовать toUTCString():
Пример:
[HttpPost]
public ActionResult Query(DateTime Start, DateTime End)
Поместите нижеприведенный запрос на отправку Ajax
data: {
Start: new Date().toUTCString(),
End: new Date().toUTCString()
},
Ответ 7
В качестве Date.prototype.toISOString()
альтернативы sk answer, я могу передать дату, отформатированную Date.prototype.toISOString()
в строке запроса. Это стандартный формат ISO 8601, и он принят контроллерами .Net Web API без какой-либо дополнительной настройки маршрута или действия.
например
var dateString = dateObject.toISOString(); // "2019-07-01T04:00:00.000Z"