¿Cómo pasar las fechas UTC a la API web?
Pasar 2010-01-01
funciona bien, pero cuando paso una fecha UTC como 2014-12-31T22:00:00.000Z
(con un componente de tiempo), obtengo una respuesta HTTP 404. Entonces
http://domain/api/controller/action/2012-12-31T22:00:00.000Z
produce una respuesta de error 404, mientras que
http://domain/api/controller/action/2012-12-31
funciona bien.
¿Cómo pasar las fechas UTC a la API web entonces, o al menos especificar la fecha y la hora?
asp.net
datetime
asp.net-web-api
Nickolodeon
fuente
fuente
http://domain/api/controller/action/2012-12-31T22%3A00%3A00.000Z
DateTime
, que supongo que es el tipo de datos del parámetro en su método.Respuestas:
El problema es doble:
1. El
.
en la rutaDe forma predeterminada, IIS trata todos los URI con un punto como recurso estático, intenta devolverlo y omitir el procesamiento adicional (por API web) por completo. Esto se configura en su Web.config en la sección
system.webServer.handlers
: los manejadores del manejador predeterminadopath="*."
. No encontrará mucha documentación sobre la sintaxis extraña en estepath
atributo (la expresión regular habría tenido más sentido), pero lo que aparentemente significa es "cualquier cosa que no contenga un punto" (y cualquier carácter del punto 2 a continuación). De ahí el 'Sin extensión' en el nombreExtensionlessUrlHandler-Integrated-4.0
.Son posibles múltiples soluciones, en mi opinión en el orden de 'corrección':
path="*."
atributo apath="*"
. Entonces lo atrapará todo. Tenga en cuenta que a partir de ese momento, su API web ya no interpretará las llamadas entrantes con puntos como recursos estáticos. Si está alojando recursos estáticos en su API web, ¡esto no se recomienda!<system.webserver>
:<modules runAllManagedModulesForAllRequests="true">
2. El
:
en la rutaUna vez que haya cambiado lo anterior, de forma predeterminada, obtendrá el siguiente error:
Puede cambiar los caracteres no permitidos / no válidos predefinidos en su Web.config. Bajo
<system.web>
, añada la siguiente:<httpRuntime requestPathInvalidCharacters="<,>,%,&,*,\,?" />
. Eliminé el:
de la lista estándar de caracteres no válidos.Soluciones más fáciles / seguras
Aunque no es una respuesta a su pregunta, una solución más segura y sencilla sería cambiar la solicitud para que todo esto no sea necesario. Esto se puede hacer de dos maneras:
?date=2012-12-31T22:00:00.000Z
..000
de cada solicitud. Aún necesitaría permitir:
's (cfr punto 2).fuente
:
s, creo que puede usarlo%3A
en lugar de:
y debería estar bien.en el controlador de API web de su producto:
[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(); } } }
probar el método GetProductPeriodOrders en Fiddler - Composer:
http://localhost:46017/api/product/orders?productCode=100&dateStart=2016-12-01T00:00:00&dateEnd=2016-12-31T23:59:59
Formato de fecha y hora:
yyyy-MM-ddTHH:mm:ss
parámetro de paso javascript use moment.js
const dateStart = moment(startDate).format('YYYY-MM-DDTHH:mm:ss'); const dateEnd = moment(endDate).format('YYYY-MM-DDTHH:mm:ss');
fuente
Siento tu dolor ... otro formato de fecha y hora ... ¡justo lo que necesitabas!
Con Web Api 2, puede usar atributos de ruta para especificar parámetros.
así que con los atributos en su clase y su método puede codificar una URL REST usando este formato utc con el que tiene problemas (aparentemente es ISO8601, presumiblemente llegó a usar 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)
.... PERO, aunque esto funciona con una fecha (startDate), por alguna razón no funciona cuando endDate está en este formato ... depurado durante horas, la única pista es que la excepción dice que no le gustan los dos puntos ":" (incluso aunque web.config está configurado con:
<system.web> <compilation debug="true" targetFramework="4.5.1" /> <httpRuntime targetFramework="4.5.1" requestPathInvalidCharacters="" /> </system.web>
Entonces, hagamos otro formato de fecha (tomado del polyfill para el formato de fecha ISO) y agréguelo a la fecha de Javascript (por brevedad, solo convierta a minutos):
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'; }; }()); }
Luego, cuando envíe las fechas al método Web API 2, puede convertirlas de cadena a fecha:
[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; }
entonces la url sería
http://domain/api/myrecordtype/daterange/20140302T0003Z/20140302T1603Z
Hanselman da información relacionada aquí:
http://www.hanselman.com/blog/OnTheNightmareThatIsJSONDatesPlusJSONNETAndASPNETWebAPI.aspx
fuente
endDate
funcionaría si la URL de la solicitud incluyera una barra diagonal al final. Desafortunadamente, no puedo recordar dónde encontré esta información, ni conozco una forma de evitarlo.Como alternativa similar a la respuesta de sk, puedo pasar una fecha formateada por
Date.prototype.toISOString()
en la cadena de consulta. Este es el formato estándar ISO 8601 y es aceptado por los controladores .Net Web API sin ninguna configuración adicional de la ruta o acción.p.ej
var dateString = dateObject.toISOString(); // "2019-07-01T04:00:00.000Z"
fuente
dateObject
es unDate
objeto inicializado .Esta es una solución y un modelo de posibles soluciones. Use Moment.js en su cliente para formatear fechas, convertir a tiempo Unix.
$scope.startDate.unix()
Configure los parámetros de su ruta para que sean largos.
[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! }
Cree un método de extensión para la hora Unix. Método DateTime de Unix
fuente
Solía ser una tarea dolorosa, pero ahora podemos usar toUTCString ():
Ejemplo:
[HttpPost] public ActionResult Query(DateTime Start, DateTime End)
Ponga lo siguiente en la solicitud de publicación de Ajax
data: { Start: new Date().toUTCString(), End: new Date().toUTCString() },
fuente
De hecho, especificar parámetros explícitamente como? Date = 'fulldatetime' funcionó a las mil maravillas. Entonces, esta será una solución por ahora: no use comas, use el antiguo enfoque GET.
fuente
Como he codificado el sistema operativo ISO-8859-1, el formato de fecha "dd.MM.yyyy HH: mm: sss" no se reconoció, lo que funcionó fue usar la cadena InvariantCulture.
string url = "GetData?DagsPr=" + DagsProfs.ToString(CultureInfo.InvariantCulture)
fuente
Al mirar su código, supongo que no le preocupa la 'Hora' del objeto DateTime. Si es así, puede pasar la fecha, el mes y el año como parámetros enteros. Consulte el siguiente código. Este es un ejemplo práctico de mi proyecto actual.
La ventaja es; este método me ayuda a evitar problemas de formato de fecha y hora e incompatibilidades culturales.
/// <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); }
Si también está interesado en ver la interfaz, no dude en leer el código a continuación. Desafortunadamente, eso está escrito en Angular. Así es como normalmente paso un DateTime como un parámetro de consulta en las solicitudes 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; }
fuente
Una posible solución es utilizar Ticks:
public long Ticks {get; }
Luego, en el método del controlador:
Public DateTime (tics largos);
fuente