route - web api rest c#
Control del formato del parámetro DateTime en WebAPI 2 (4)
Entonces tengo un controlador WebAPI 2 escrito en C # que toma entre otras cosas un parámetro de consulta de tipo DateTime. Esta es una API que devuelve todos los valores del almacén de datos basados en un filtro de fecha. Algo como, digamos:
public MyThing GetThing([FromUri]DateTime startTime)
{
// filter and return some results
}
Me estoy topando con 2 problemas:
- Por alguna razón, a pesar de haber pasado una fecha con formato UTC ISO 8601 (con una Z), WebAPI la está serializando como DateTime local, en lugar de Utc. Esto es obviamente indeseable. No estoy seguro de cómo modificar la canalización para que comprenda correctamente los Tiempos de Fecha UTC-0.
- Estoy devolviendo un enlace al recurso como parte del cuerpo de la respuesta, en el que utilizo los objetos UrlHelper (obtenidos del método Link () de la clase abstracta principal de ApiController) para generar un href. Estoy pasando una colección de parámetros de consulta que quiero agregar a la ruta. Por el motivo que sea, al pasar el DateTime lo formatea en un formato que no es ISO8601. No puedo encontrar donde se controla esto. No quiero usar ToString () explícitamente, ya que no se puede aplicar universalmente.
En resumen, quiero averiguar cómo asegurarme de que
- Los tiempos de fecha que se pasan a través de los parámetros de consulta FromUri se entienden correctamente como ISO8601, incluidas las compensaciones de zona horaria apropiadas
- UrlHelper.Link () genera DateTimes compatibles con ISO8601 en la cadena de URI de salida de una forma estática de ejecución universal.
WebAPI 2 proporciona excelentes enlaces para el formato JSON, que sí utilizo, por lo que simplemente devolver un DateTime en un cuerpo JSON lo formatea como se desee utilizando el formato ISO8601, y también se entiende correctamente en un cuerpo [FromBody] JSON. Sin embargo, no puedo encontrar formas de mover cadenas alrededor del manejo de URI, ¡y realmente me gustaría!
El valor del parámetro de cadena de consulta que está enviando es la hora UTC . Entonces, lo mismo se traduce a una hora según su reloj local y si llama a
ToUniversalTime()
, se convierte de nuevo a UTC.Entonces, ¿cuál es exactamente la pregunta? Si la pregunta es por qué sucede esto si se envía como una cadena de consulta pero no cuando se publica en el cuerpo de la solicitud, la respuesta a esa pregunta es que la API web de ASP.NET vincula la ruta del URI, la cadena de consulta, etc. mediante el enlace del modelo y el cuerpo mediante vinculación de parámetros. Para este último, utiliza un formateador de medios. Si envía JSON, se utiliza el formateador de medios JSON y se basa en JSON.NET.
Ya que ha especificado DateTimeZoneHandling.Utc, usa esa configuración y obtiene la fecha y hora que desea. Por cierto, si cambia esta configuración a DateTimeZoneHandling.Local, verá el mismo comportamiento que el enlace del modelo.
Con el fin de obtener el formato deseado que desea, todo lo que necesita hacer es llamar al método ToUniversalTime()
.
¿Por qué no usar DateTimeOffset lugar de DateTime si desea mantener el desplazamiento UTC? Aquí hay algunos códigos que trabajan con la serialización JSON:
Controlador Api:
public class ValuesController : ApiController
{
public object Get(DateTimeOffset dt)
{
return new {
Input = dt,
Local = dt.LocalDateTime,
Utc = dt.UtcDateTime
};
}
}
Código de muestra de Razor View (asumiendo que tiene la ruta de api predeterminada creada en una plantilla de estudio visual de MVC + Web API)
<a href="@Url.RouteUrl("DefaultApi",new {httproute = "",controller = "values",dt = DateTimeOffset.UtcNow})">Utc Now</a>
Prestado como:
<a href="/api/values?dt=06%2F26%2F2018%2009%3A37%3A24%20%2B00%3A00">Utc Now</a>
Y puede llamar a su API con el desplazamiento de fecha y hora:
2018-06-26T08:25:48Z: http://localhost:1353/api/values?dt=2018-06-26T08:25:48Z
{"Input":"2018-06-26T08:25:48+00:00","Local":"2018-06-26T10:25:48+02:00","Utc":"2018-06-26T08:25:48Z"}
2018-06-26T08:25:48+01:00: http://localhost:1353/api/values?dt=2018-06-26T08%3A25%3A48%2B01%3A00 (note that : and + must be url encoded)
{"Input":"2018-06-26T08:25:48+01:00","Local":"2018-06-26T09:25:48+02:00","Utc":"2018-06-26T07:25:48Z"}
1.
Debe verificar la zona horaria de su parámetro ''startTime'' (que debería ser la zona horaria de su servidor / computadora).
El DateTime proporcionado por la API web es correcto, solo depende de TU zona horaria.
2.
Cree un serializador Json DateTime para generar la fecha con formato ISO8601.
Puede usar modelbinder para transformar los datos entrantes a su modelo.
GetThings([ModelBinder(typeof(UtcDateTimeModelBinder)), FromUri] DateTime dt){//do somthing}
public class UtcDateTimeModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
if (bindingContext.ModelMetadata.ModelType == typeof(DateTime))
{
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
var str = valueProviderResult.AttemptedValue;
return DateTime.Parse(str).ToUniversalTime();
}
return null;
}
De esa manera, puedes configurarlo como creador de modelo predeterminado de DateTime.
ModelBinders.Binders.Add(typeof(DateTime), new UtcDateTimeModelBinder());