wake-up-neo.com

So erhalten Sie Web API OData v4 zur Verwendung von DateTime

Ich habe ein ziemlich großes Datenmodell, das ich mit Web-API-OData unter Verwendung des OData V4-Protokolls verfügbar machen möchte.

Die zugrunde liegenden Daten werden in einer SQL Server 2012-Datenbank gespeichert. Diese Datenbank enthält viele DateTime-Spalten.

Als ich es verdrahtete, bekam ich eine Fehlermeldung, dass System.DateTime nicht unterstützt wird.

Hier also meine Frage: Was kann ich tun, damit meine DateTime-Spalten im OData-Feed angezeigt werden?

HINWEIS: Ich kann nicht alle Spalten in DateTimeOffset-Spalten ändern.

Ich habe versucht, den Typ der Spalte in Entity Framework edmx zu ändern, aber es gab diesen Fehler: 

Die angegebene Mitgliederzuordnung ist nicht gültig. Der Typ 'Edm.DateTimeOffset [Nullable = False, DefaultValue =, Precision =]' des Members 'MyPropertyHere' im Typ 'MyProject.MyEntity' ist nicht kompatibel mit 'SqlServer.datetime [Nullable = False, DefaultValue =, Precision = 3]. 'des Mitglieds' MyColumnName 'im Typ' MyDataModel.Store.MyEntity '.

(Grundsätzlich gilt, dass DateTime nicht mit DateTimeOffset kompatibel ist.)

Hat das Web-API-OData-Team wirklich jeden ausgeschlossen, der den SQL Server-Typ DateTime verwenden muss?

Update: Ich habe Problemumgehungen dafür gefunden, aber das EF-Modell muss aktualisiert werden, damit es funktioniert. Ich möchte lieber nicht mehrere hundert Eigenschaften einzeln aktualisieren, wenn ich es vermeiden kann.

Update: Durch dieses Problem wurde mir klar, dass Microsoft bei der Verwaltung seiner OData-Produkte erhebliche Mängel aufweist. Es gibt viele Probleme, aber diese ist am eklatantesten. In den Web-API-OData fehlen große Funktionen. Transaktionen und Reihenfolge der Einfügungen sind zwei davon. Diese beiden Elemente (die in der OData-Spezifikation enthalten sind und in WCF Data Services waren, bevor Microsoft sie beendet hat) sind für jedes reale System von entscheidender Bedeutung. 

Anstatt sich jedoch an den kritischen Stellen, an denen die in der OData-Spezifikation enthaltene Funktionalität fehlt, Zeit zu widmen, entscheiden sie sich dafür, ihre Zeit mit dem Entfernen von Funktionen zu verbringen, die für viele Entwickler sehr hilfreich waren .. _. Es verkörpert schlechtes Management, um das Entfernen von Arbeitsmerkmalen gegenüber dem Hinzufügen von dringend benötigten Merkmalen zu priorisieren.

Ich habe versucht, diese mit dem Web-API-Vertreter von OData zu besprechen, und am Ende bekam ich eine Ausgabe/ein Ticket, das einige Tage später geschlossen wurde. Das war das Ende dessen, was sie bereit waren zu tun.

Wie bereits erwähnt, gibt es viele weitere Probleme (nicht mit DateTime verbunden, daher werde ich sie hier nicht aufführen) bei der Verwaltung von Web-API-OData. Ich war ein sehr starker Befürworter von OData, aber die offensichtlichen Probleme mit der Web-API von OData haben mich und mein Team/Unternehmen dazu gezwungen, es aufzugeben.

Glücklicherweise kann die normale Web-API für die Verwendung der OData-Syntax eingerichtet werden. Es ist mehr Arbeit, die Controller einzurichten, aber am Ende funktioniert es gut. Und es unterstützt DateTime. (Und scheint ein Management zu haben, das sich wenigstens von wahnsinnig schlechten Entscheidungen fernhalten kann.)

26
Vaccano

Bisher ist DateTime nicht Teil des OASIS OData V4-Standards und die Web-API unterstützt den DateTime-Typ nicht, während sie den DateTimeOffset-Typ unterstützt. 

Allerdings, das OData-Team arbeitet jetzt an der Unterstützung des DataTime-Typs. Ich denke, Sie können den DateTime-Typ in der nächsten Web-API-Version verwenden. Wenn Sie nicht auf die nächste Version warten können, habe ich ein Beispiel geschrieben, das auf blog basiert. Ich hoffe es kann dir helfen. Vielen Dank.

Modell

public class Customer
{
    private DateTimeWrapper dtw;

    public int Id { get; set; }

    public string Name { get; set; }

    public DateTime Birthday
    {
        get { return dtw; }
        set { dtw = value; }
    }

    [NotMapped]
    public DateTimeOffset BirthdayOffset
    {
        get { return dtw; }
        set { dtw = value; }
    }
}

public class DateTimeWrapper
{
    public static implicit operator DateTimeOffset(DateTimeWrapper p)
    {
        return DateTime.SpecifyKind(p._dt, DateTimeKind.Utc);
    }

    public static implicit operator DateTimeWrapper(DateTimeOffset dto)
    {
        return new DateTimeWrapper(dto.DateTime);
    }

    public static implicit operator DateTime(DateTimeWrapper dtr)
    {
        return dtr._dt;
    }

    public static implicit operator DateTimeWrapper(DateTime dt)
    {
        return new DateTimeWrapper(dt);
    }

    protected DateTimeWrapper(DateTime dt)
    {
        _dt = dt;
    }

    private readonly DateTime _dt;
}

DB-Kontext

public DbSet<Customer> Customers { get; set; }

EdmModel

ODataConventionModelBuilder builder = new ODataConventionModelBuilder();

builder.EntitySet<Customer>("Customers");

var cu = builder.StructuralTypes.First(t => t.ClrType == typeof(Customer));
cu.AddProperty(typeof(Customer).GetProperty("BirthdayOffset"));
var customer = builder.EntityType<Customer>();

customer.Ignore(t => t.Birthday);
var model = builder.GetEdmModel();

config.MapODataServiceRoute("odata", "odata", model);

Controller

Fügen Sie den OData Controller wie gewohnt hinzu.

Prüfung

Customer Data in the DB

Nutzlast

The customers payload

17
Sam Xu

Schließlich unterstützt die Web-API-OData-Version v4 in Version 5.5 jetzt den Typ DateTime. Holen Sie sich das neueste Nuget-Paket und vergessen Sie nicht, dies einzustellen:

config.SetTimeZoneInfo(TimeZoneInfo.Utc);

andernfalls wird die Zeitzone der dateTime -Eigenschaft als lokale Zeitzone betrachtet.

Weitere Informationen: ASP.NET Web API for OData V4 Docs DateTime support

17

Eine alternative Lösung besteht darin, das Projekt so zu patchen, dass DateTime wieder zulässig ist. Das habe ich getan. Sie können den Code hier abrufen, wenn Sie möchten:

https://aspnetwebstack.codeplex.com/SourceControl/network/forks/johncrim/datetimefixes

Ich habe auch ein NuGet-Paket gepusht, um die Verwendung zu vereinfachen. Sie können das Paket mithilfe der Informationen hier erhalten:

http://www.nuget.org/packages/Patches.System.Web.OData/5.3.0-datetimefixes

Ich weiß nicht, ob es in Ordnung ist, ein NuGet-Paket mit einer gepatchten Microsoft-Bibliothek zu posten. Ich hoffe, es ist einfacher, um Vergebung als um Erlaubnis zu bitten.

Beachten Sie, dass das Arbeitselement zum offiziellen Wiederherstellen der Verwendung von DateTime in OData 4 hier nachverfolgt wird: https://aspnetwebstack.codeplex.com/workitem/2072 möchte es sehen; Es sieht zwar so aus, als wäre es für 5.4 geplant, also sollte es eines Tages kommen.

3
crimbo

Leider unterstützt https://aspnetwebstack.codeplex.com/SourceControl/network/forks/johncrim/datetimefixes fork, die von crimbo gegeben wird, nicht wirklich DateTime.

Es gibt die neue Fork https://aspnetwebstack.codeplex.com/SourceControl/network/forks/kj/odata53datetime? Branch = odata-v5.3-rtm basierend auf OData v5.3 RTM: DateTime-Eigenschaften in Entitäten und komplexen Typen werden in Serverantworten, POST/PUT/PATCH-Anforderungen von Clients, $ orderby- und $ filters-Klauseln, Funktionsparametern und Rückgabewerten unterstützt. Wir beginnen damit, es im Produktionscode zu verwenden und werden diese Verzweigung unterstützen, bis der DateTime-Support in zukünftigen offiziellen Releases wieder verfügbar ist.

Diese Problemumgehungen und die eine von http://damienbod.wordpress.com/2014/06/16/web-api-and-odata-v4-crud-and-actions-part-3/ , weder arbeiten. Sie funktionieren nur in eine Richtung, was bedeutet, dass das Abfragen von odata datetimeoffset mit dem Filterbefehl fehlschlägt, da es nicht Teil des Modells ist.

Sie können nicht mehr nach diesen Feldern filtern oder sortieren oder erhalten diesen Fehler

/ Aas/Aktivitäten? $ Top = 11 & $ orderby = CreatedAt

Gibt diesen Fehler aus:

"code":"","message":"An error has occurred.","innererror":{
  "message":"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; odata.metadata=minimal'.","type":"System.InvalidOperationException","stacktrace":"","internalexception":{
    "message":"The specified type member 'CreatedAt' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.","type":"System.NotSupportedException","stacktrace":"   

Dies funktioniert aber so, wie es indirekt angesprochen wird:

/ Aas/AppUsers% 28102% 29/AppUserActivities? $ Expand = Fall & $ filter =% 28Reminder% 20ne% 20null% 20und% 20IsComplete% 20eq% 20null% 29 & $ top = 15 & $ orderby = Erinnerung & $ count = true

Erinnerung und Iscomplete sind Datum und Datum der Aktivität durch AppUserActivities. 

Das ist seltsam, dass das funktioniert. Hat jemand eine Lösung?

Ich verbinde mich mit MySQL. Es gibt kein datetimeoffset.

Und jeder wundert sich, warum niemand für Microsoft-Technologien entwickeln will.

1
Jon Alberghini

Da ich eine Odata-Bibliothek mit eckig verwende, habe ich sie dort untersucht:

https://github.com/devnixs/ODataAngularResources/blob/master/src/odatavalue.js

Dort kann man sehen (Javascript)

var generateDate = function(date,isOdataV4){
        if(!isOdataV4){
            return "datetime'" + date.getFullYear() + "-" + ("0" + (date.getMonth() + 1)).slice(-2) + "-" + ("0" + date.getDate()).slice(-2) + "T" + ("0" + date.getHours()).slice(-2) + ":" + ("0" + date.getMinutes()).slice(-2)+':'+("0" + date.getSeconds()).slice(-2) + "'";
        }else{
            return date.getFullYear() + "-" + ("0" + (date.getMonth() + 1)).slice(-2) + "-" + ("0" + date.getDate()).slice(-2) + "T" + ("0" + date.getHours()).slice(-2) + ":" + ("0" + date.getMinutes()).slice(-2)+':'+("0" + date.getSeconds()).slice(-2) + "Z";
        }
    };

Und der Test erwartet (vgl. hier )

 $httpBackend.expectGET("/user(1)?$filter=date eq 2015-07-28T10:23:00Z")

Das sollte also Ihre "Formatierung" sein

2015-07-28T10:23:00Z
1
NicoJuicy
public class Customer
{
    private DateTimeWrapper dtw;

    public int Id { get; set; }

    public string Name { get; set; }

    public DateTime Birthday
    {
       get { return dtw; }
       set { dtw = value; }
    }

    [NotMapped]
    public DateTimeOffset BirthdayOffset
    {
        get { return dtw; }
        set { dtw = value; }
    }
}


var customer = builder.EntityType<Customer>();
customer.Ignore(t => t.Birthday);
customer.Property(t => t.BirthdayOffset).Name = "Birthday";
1
Ivan Petrov

Beide der folgenden funktionieren mit ODATA 4

  1. dies ist das neueste Update, das ich mit .Net 4.7 und Microsoft.Aspnet.ODATA 5.3.1 sehe.

    $ filter = DateofTravel lt cast (2018-05-15T00: 00: 00.00Z, Edm.DateTimeOffset)

  2. das funktioniert auch, es muss in diesem jjjj-mm-ddThh: mm: ss.ssZ sein

    $ filter = DateofTravel lt 2018-02-02T00: 00: 00.00Z

0
Sundara Prabu

Installieren Sie System.Web.OData 5.3.0-datetimefixes unter https://www.nuget.org/packages/Patches.System.Web.OData/

0
JeeShen Lee

Nachdem ich einen frustrierenden Tag damit verbracht habe, genau das zu tun, stolperte ich über die einzige Möglichkeit, wie ich es schaffen konnte. Wir wollten mit OData und Web API 2.2 nach Datumsbereichen filtern können, was kein ungewöhnlicher Anwendungsfall ist. Unsere Daten befinden sich in SQL Server und werden als DateTime gespeichert, und wir verwenden EF in der API.

Versionen:

  • Microsoft.AspNet.WebApi.OData 5.7.0 
  • Microsoft.AspNet.Odata 5.9.0
  • Microsoft.OData.Core 6.15.0 
  • Microsoft.OData.Edm 6.15.0
  • Microsoft.Data.OData 5.7.0

Entity-Snippet:

[Table("MyTable")]
public class CatalogueEntry
{
    [Key]
    public Guid ContentId { get; set; }
    [StringLength(15)]
    public string ProductName { get; set; }
    public int EditionNumber { get; set; }
    public string Purpose { get; set; }
    public DateTime EditionDate { get; set; }
}

WebApiConfig

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Routes.MapODataServiceRoute("ProductCatalogue", "odata", GetImplicitEdm());

        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Filters.Add(new UnhandledExceptionFilter());

        var includeVersionHeaders = ConfigurationManager.AppSettings["IncludeVersionHeaders"];
        if (includeVersionHeaders != null && bool.Parse(includeVersionHeaders))
        {
            config.Filters.Add(new BuildVersionHeadersFilter());
        }

        config.SetTimeZoneInfo(TimeZoneInfo.Utc);
    }

    private static IEdmModel GetImplicitEdm()
    {
        ODataModelBuilder builder = new ODataConventionModelBuilder();
        builder.EntitySet<CatalogueEntry>("ProductCatalogue");
        return builder.GetEdmModel();
    }
}

Controller-Snippet:

public class ProductCatalogueController : EntitySetController<CatalogueEntry, string>
{
    [EnableQuery]
    public override IQueryable<CatalogueEntry> Get()
    {
        return _productCatalogueManager.GetCatalogue().AsQueryable();
    }

    protected override CatalogueEntry GetEntityByKey(string key)
    {
        return _productCatalogueManager.GetCatalogue().FirstOrDefault(c => c.ContentId.ToString() == key);
    }
}

Hier ist das magische Bit - siehe unten auf dieser MSDN-Seite unter der Überschrift "Auf verschiedene Datentypen in Filterausdrücken verweisen". Dort finden Sie eine Notiz mit folgendem Hinweis:

DateTime-Werte müssen durch einfache Anführungszeichen und .__ begrenzt werden. vorangestellt von Word datetime, wie datetime'2010-01-25T02: 13: 40.1374695Z '.

http://localhost/Product-Catalogue/odata/ProductCatalogue?$filter=EditionDate lt datetime'2014-05-15T00:00:00.00Z'

Bisher arbeiten wir bei Postman daran, und wir bauen jetzt den Client, der hoffentlich mit dieser Anforderung arbeiten sollte, um 'datetime' vor dem tatsächlichen Wert zu halten. Ich bin damit beschäftigt, Simple.OData.Client in einem MVC-Controller zu verwenden, aber wir können uns sogar dazu entscheiden, die clientseitige JavaScript-Komponente direkt aufzurufen, je nachdem, wie viel Refactoring wir tun müssen. Ich würde auch gerne Swagger UI mit Swashbuckle.OData zum Laufen bringen, aber das erweist sich auch als schwierig. Sobald ich so viel getan habe, wie ich Zeit habe, werde ich ein Update mit nützlichen Informationen für die folgen, da ich es sehr frustrierend fand, dass es so schwer war, herauszufinden, wie etwas getan werden kann, was scheinbar eine einfache Anforderung ist .

0
Steve Pettifer

Sieht aus, als würde eine Zuordnung DateTimeOffset <-> DateTime in Microsoft ASP.NET Web API 2.2 für OData v4.0 5.4.0 aufgenommen werden:

https://github.com/OData/WebApi/commit/2717aec772fa2f69a2011e841ffdd385823ae822

0
Craig Boland