How to get Web API OData v4 to use DateTime

前端 未结 12 1237
时光取名叫无心
时光取名叫无心 2020-12-02 14:50

I have a fairly large data model that I want to expose using Web API OData using the OData V4 protocol.

The underlying data is stored in a SQL Server 2012 database.

12条回答
  •  予麋鹿
    予麋鹿 (楼主)
    2020-12-02 15:18

    Having spent a frustrating day trying to do this very thing, I have just stumbled across the only way I could get it to work. We wanted to be able to filter by date ranges using OData and Web API 2.2, which isn't an uncommon use case. Our data is in SQL Server and is stored as DateTime and we're using EF in the API.

    Versions:

    • 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("ProductCatalogue");
            return builder.GetEdmModel();
        }
    }
    

    Controller Snippet:

    public class ProductCatalogueController : EntitySetController
    {
        [EnableQuery]
        public override IQueryable Get()
        {
            return _productCatalogueManager.GetCatalogue().AsQueryable();
        }
    
        protected override CatalogueEntry GetEntityByKey(string key)
        {
            return _productCatalogueManager.GetCatalogue().FirstOrDefault(c => c.ContentId.ToString() == key);
        }
    }
    

    Here's the magic bit - see the bottom of this MSDN page under the heading 'Referencing Different Data Types in Filter Expressions' and you will find a note saying:

    DateTime values must be delimited by single quotation marks and preceded by the word datetime, such as datetime'2010-01-25T02:13:40.1374695Z'.

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

    So far we have this working in Postman and we're now building the client which should hopefully work with this requirement to stick 'datetime' in front of the actual value. I'm looking at using Simple.OData.Client in an MVC controller but we may even decide to call straight to the API from client side JavaScript depending on how much refactoring we have to do. I'd also like to get Swagger UI working using Swashbuckle.OData but this is also proving to be tricky. Once I've done as much as I have time to, I'll post an update with useful info for those who follow as I found it very frustrating that it was so hard to find out how to do something that is ostensibly a simple requirement.

提交回复
热议问题