C# 忽略Web Api中的空属性/值,并在自身主机中使用OData响应

C# 忽略Web Api中的空属性/值,并在自身主机中使用OData响应,c#,.net,asp.net-web-api,odata,owin,C#,.net,Asp.net Web Api,Odata,Owin,我希望在自主机启动中使用OData响应省略Web Api中的Null属性/值,以减小内容大小 我有112个控制器继承自一个抽象的ApiController类,因此使用了CustomDirectRouteProvider。(不重要) 我运行的是Framework4.8,而不是CORE 我需要帮助实现一个类似的解决方案 我已经阅读了几乎所有关于这个主题的帖子,“Stas Natalenko”解决方案对于OData v3和更老的版本似乎很好,但我不确定如何在self-host上实现OData v4的“

我希望在自主机启动中使用OData响应省略Web Api中的Null属性/值,以减小内容大小

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

我运行的是Framework4.8,而不是CORE

我需要帮助实现一个类似的解决方案

我已经阅读了几乎所有关于这个主题的帖子,“Stas Natalenko”解决方案对于OData v3和更老的版本似乎很好,但我不确定如何在self-host上实现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);
        };
    }
}
公共类CustomDirectRouteProvider:DefaultDirectRouteProvider
{
受保护的覆盖System.Collections.Generic.IReadOnlyList
GetActionRouteFactorys(HttpActionDescriptor actionDescriptor)
{
//继承基类控制器动作上修饰的路由属性
返回actionDescriptor.GetCustomAttributes
(继承:正确);
}
}
公营创业
{
公共静态无效配置(IAppBuilder appBuilder)
{
使用(var config=new HttpConfiguration())
{
config.EnableSwagger(c=>c.SingleApiVersion(“v1”、“MyAPI”))
.EnableSwaggerUi();
config.maphttpAttribute路由(新的CustomDirectRouteProvider());
config.EnableCors();
config.Routes.MapHttpRoute(
名称:“DefaultApi”,
routeTemplate:“{controller}/{id}”,
默认值:新建{id=RouteParameter.Optional}
);
config.AddODataQueryFilter();
config.Formatters.Clear();
config.Count().Filter().OrderBy().Expand().Select().MaxTop(null)
.EnableDependencyInjection();
config.Formatters.Add(新的System.Net.Http.Formatting.JsonMediaTypeFormatter
{
UseDataContractJsonSerializer=false,
SerializerSettings=新JsonSerializerSettings
{
ContractResolver=new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver(),
ReferenceLoopHandling=ReferenceLoopHandling.Ignore,
DateFormatHandling=DateFormatHandling.IsoDateFormat,
DateParseHandling=DateParseHandling.DateTimeOffset,
DateTimeZoneHandling=DateTimeZoneHandling.RoundtripKind,
格式化=格式化。无,
NullValueHandling=NullValueHandling.Ignore
}
});
config.Formatters.Add(新的System.Net.Http.Formatting.BsonMediaTypeFormatter());
appBuilder.UseWebApi(配置);
};
}
}

经过两个晚上的讨论,我想我已经找到了一个可能的解决方案,但是,资源已经找到了您提到的答案,就我个人而言,依赖注入的一部分注册序列化程序是最困难的,但我必须承认这个问题,它很有帮助:

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

按照创建项目的Microsoft文档

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);
    }
}
最后,Api的输出:

输入:

公共静态列表项=新列表()
{
新项目{Id=1,Name=“name1”,OptionalField=“Value Present”},
新项目{Id=3,Name=“name2”}
};

并具有以下价值:

输入:

公共静态列表项=新列表()
{
新项目{Id=1,Name=“name1”,OptionalField=“Value Present”},
新项目{Id=3,Name=“name2”,OptionalField=“Value Present2”}
};


我希望这能有所帮助。

这是我有生以来第一个关于StackOverFlow的问题。这些年来,我一直很干净,你使用的是什么版本的Microsoft.AspNet.WebApi.OData(Nuget)?也许还有很长的路要走,但是这些设置有可能在MvcJsonOptions中被覆盖吗?builder.Services.Configure(opts=>opts.SerializerSettings.NullValueHandling…@Julián最新稳定版本7+不使用MVC,只有WebApi。要使其正常工作,必须使用“app.UseMVC”或者其他什么,然后从mvc控制器而不是api控制器继承。我将您的答案标记为已接受的答案,尽管我尚未测试。手动授予奖金为时已晚,但我认为它可能会在几天内自动分配…在我的情况下不起作用,ODataController不断返回406我将尝试剥离所有内容让一切尽可能简单,顺便说一句,你没有使用OWIN Self host,但你确实给了我一些很好的见解。
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();
    }
}
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" }
};