使用 OData 响应 Owin Self-Host 忽略 Web Api 中的 Null 属性/值

Posted

技术标签:

【中文标题】使用 OData 响应 Owin Self-Host 忽略 Web Api 中的 Null 属性/值【英文标题】:Ignore Null properties/values in Web Api with OData response Owin Self-Host 【发布时间】:2021-01-20 14:40:56 【问题描述】:

我想通过 OData 响应 Owin Self-Host Startup 省略 Web Api 中的 Null 属性/值,以减少内容大小。

我有 112 个控制器从单个抽象 ApiController 类继承,因此使用 CustomDirectRouteProvider。 (不重要)

我正在运行 Framework 4.8,而不是 CORE。

我需要帮助实施与 How to Ignore Null values while serializing OData response 类似的解决方案

我已经阅读了几乎所有关于该主题的帖子,“Stas Natalenko”解决方案似乎适用于 OData v3 及更早版本,但我不确定如何在自托管上为 Odata v4 实施“Chris Schaller”解决方案。

这是我的启动课:

public class CustomDirectRouteProvider : DefaultDirectRouteProvider

    protected override System.Collections.Generic.IReadOnlyList<IDirectRouteFactory>

    GetActionRouteFactories(HttpActionDescriptor actionDescriptor)
    
        // inherit route attributes decorated on base class controller's actions
        return actionDescriptor.GetCustomAttributes<IDirectRouteFactory>
        (inherit: true);
    


public class Startup

    public static void Configuration(IAppBuilder appBuilder)
    
        using (var config = new HttpConfiguration())
        
            config.EnableSwagger(c => c.SingleApiVersion("v1", "MyAPI"))
                .EnableSwaggerUi();

            config.MapHttpAttributeRoutes(new CustomDirectRouteProvider());
            config.EnableCors();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "controller/id",
                defaults: new  id = RouteParameter.Optional 
                );

            config.AddODataQueryFilter();
            config.Formatters.Clear();

            config.Count().Filter().OrderBy().Expand().Select().MaxTop(null)
                .EnableDependencyInjection();

            config.Formatters.Add(new System.Net.Http.Formatting.JsonMediaTypeFormatter
            
                UseDataContractJsonSerializer = false,
                SerializerSettings = new JsonSerializerSettings
                
                    ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver(),
                    ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                    DateFormatHandling = DateFormatHandling.IsoDateFormat,
                    DateParseHandling = DateParseHandling.DateTimeOffset,
                    DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind,
                    Formatting = Formatting.None,
                    NullValueHandling = NullValueHandling.Ignore
                
            );

            config.Formatters.Add(new System.Net.Http.Formatting.BsonMediaTypeFormatter());
            appBuilder.UseWebApi(config);
        ;
    

【问题讨论】:

这是我人生中关于 *** 的第一个问题。这些年来我一直很干净facepalm 你使用什么版本的Microsoft.AspNet.WebApi.OData (Nuget)? 也许是一个长镜头,但是这些设置是否可以在 MvcJsonOptions 中被覆盖? builder.Services.Configure(opts => opts.SerializerSettings.NullValueHandling...... @Julián 最新稳定版 7+ 不使用 MVC,仅使用 WebApi。为了使其工作,必须“app.UseMVC”或其他东西,然后从 mvc 控制器而不是 api 控制器继承。 【参考方案1】:

在处理了两个晚上的可能答案之后,我想我找到了一个可能的解决方案,但是,资源有你提到的答案,个人 依赖注入 注册序列化程序的部分是最多的困难,但我必须感谢这个问题,它很有帮助:How to register an OData Serializer Provider with AspNet.OData v6

最后我分享一个解决方案可以代表什么:

按照 Microsoft 文档 创建项目:

https://docs.microsoft.com/en-us/aspnet/web-api/overview/odata-support-in-aspnet-web-api/odata-v4/create-an-odata-v4-endpoint

1. 使用 WebApi 模板创建一个 ASP .NET 4.7.2 项目 2. 在其版本7.5.0 中使用Microsoft.AspNet.OData 包:

3.控制器是这样的:

public class ItemsController : ODataController

    public static List<Item> items = new List<Item>()
    
        new Item  Id = 1, Name = "name1", OptionalField = "Value Present" ,
        new Item  Id = 3, Name = "name2" 
    ;

    [EnableQuery]
    public IQueryable<Item> Get()
    
        return items.AsQueryable();
    

    protected override void Dispose(bool disposing)
    
        base.Dispose(disposing);
    

根据文档,这个版本的OData 继承自ODataController[Queryable] 代表一个过时的标记,这就是我使用[EnableQuery] 的原因

4. 在 Models 中,我将解决方案复制到您正在回答的问题就足够了(将 IngoreNullEntityPropertiesSerializerProviderIngoreNullEntityPropertiesSerializer 类复制并粘贴到新文件夹中:

还有最困难的部分,在WebApiConfig.cs 中配置序列化器:

public static class WebApiConfig

    public static void Register(HttpConfiguration config)
    
        // Configuración y servicios de API web

        // Rutas de API web
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/controller/id",
            defaults: new  id = RouteParameter.Optional 
        );

        config.MapODataServiceRoute("ODataRoute", null, b => b
           .AddService(Microsoft.OData.ServiceLifetime.Singleton, typeof(IEdmModel), s => GetEdmModel())               
           .AddService(Microsoft.OData.ServiceLifetime.Singleton, typeof(IEnumerable<IODataRoutingConvention>), s => ODataRoutingConventions.CreateDefaultWithAttributeRouting("ODataRoute", config))              
           .AddService(Microsoft.OData.ServiceLifetime.Singleton, typeof(ODataSerializerProvider), sp => new IngoreNullEntityPropertiesSerializerProvider(sp))
        );
    

    private static IEdmModel GetEdmModel()
    
        ODataConventionModelBuilder builder = new ODataConventionModelBuilder();

        builder.EntitySet<Item>("Items");        

        return builder.GetEdmModel();
    

最后是Api的输出:

输入:

public static List<Item> items = new List<Item>()

    new Item  Id = 1, Name = "name1", OptionalField = "Value Present" ,
    new Item  Id = 3, Name = "name2" 
;

并带有值:

输入:

public static List<Item> items = new List<Item>()

    new Item  Id = 1, Name = "name1", OptionalField = "Value Present" ,
    new Item  Id = 3, Name = "name2",  OptionalField = "Value Present2" 
;

我希望这会有所帮助。

【讨论】:

我将您的答案标记为已接受的答案,即使我尚未对其进行测试。手动奖励赏金为时已晚,但我认为它可能会在几天后自动分配...... 在我的情况下不起作用,ODataController 一直返回 406 我会再试一次,把所有东西都去掉,把所有东西都降到最低限度,顺便说一句,你没有使用 OWIN 自托管,但你确实给了我一些很好的见解。 直到今天,我一直困扰着你没有及时得到你的赏金。朱利安总有一天我会补偿你的! 放松,没问题的兄弟:)

以上是关于使用 OData 响应 Owin Self-Host 忽略 Web Api 中的 Null 属性/值的主要内容,如果未能解决你的问题,请参考以下文章

我们可以使用OData客户端为syncfusion网格创建我们的请求但是使用正常响应(Reqular WebAPI)

Owin 身份令牌认证令牌端点以 404 响应

odata.nextLink 不是响应的一部分

如何使用命令(API)和查询(odata)控制器将位置标头传递给响应

如何在自托管 Web API 应用程序中配置 OData 端点

OData 带更新的实例,并能取得元数据格式类型