使用 Microsoft 的 ASP.NET API Web API 2 和 ODATA 版本控制在 api 版本之间更改 JSON 属性的大小写?

Change casing of JSON properties between api versions using Microsoft's ASP.NET API Versioning for Web API 2 and ODATA?

我正在向现有 API 引入 API 版本控制。现有的 JSON 为其 属性 名称使用 Pascal 大小写,例如"FooBar":"foo"。对于 API 的 v2,我想使用常见的驼峰式大小写,"fooBar":"foo"。我需要保留 v1 Pascal 外壳,这样它就不会影响任何已经拉动该版本 API.

的客户端

我的项目是

我的配置如下

public static class WebApiConfig
{
    public static void Register(HttpConfiguration configuration)
    {
        configuration.AddApiVersioning(options => options.ReportApiVersions = true);

        var modelBuilder = new VersionedODataModelBuilder(configuration);

        AppDomain.CurrentDomain.GetAssemblies()
            .SelectMany(x => x.GetTypes())
            .Where(x => typeof(IModelConfiguration).IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract)
            .ForEach(t => modelBuilder.ModelConfigurations.Add((IModelConfiguration)Activator.CreateInstance(t)));

        var models = modelBuilder.GetEdmModels();

        configuration.MapVersionedODataRoutes("odata-bypath", "api/v{apiVersion}", models, builder =>
        {
            builder.AddService<IODataPathHandler>(Singleton, sp => new DefaultODataPathHandler { UrlKeyDelimiter = Parentheses });
            builder.AddService<ODataUriResolver>(Singleton, sp => new UnqualifiedCallAndEnumPrefixFreeResolver { EnableCaseInsensitive = true });
        });

        configuration.Count().Filter().OrderBy().Expand().Select().MaxTop(null);

        configuration.MapHttpAttributeRoutes();
    }
}

阅读文档后,特别是 Versioned ODataModelBuilder 我还没有找到一种方法来根据正在构建模型的 API 版本更改外壳。我可以得到它是所有 Pascal 外壳或所有骆驼外壳,但不是 v1 Pascal 外壳和 v2 骆驼外壳。

调整以上配置

var modelBuilder = new VersionedODataModelBuilder( configuration )
{
    ModelBuilderFactory = () => new ODataConventionModelBuilder().EnableLowerCamelCase()
};

将使用驼峰式大小写(是的,我知道显式调用是不必要的,因为它是默认设置)。然后我构建了自己的扩展方法 ODataConventialModelBuilder().EnablePascalCase(),它模仿 EnableLowerCamelCase() 方法来让 Pascal 大小写工作。

var modelBuilder = new VersionedODataModelBuilder( configuration )
{
    ModelBuilderFactory = () => new ODataConventionModelBuilder().EnablePascalCase()
};

但是,我永远无法找到一种方法来了解我正在为哪个版本的 API 构建模型。

有一次,我以为我可以使用 OnModelCreating 添加

((ODataConventionModelBuilder) builder).OnModelCreating += new PascalCaser().ApplyCase;

每个 v1 IModelConfiguration 类,但是一旦我构建了多个模型,它就不起作用了。

有没有办法根据模型适用的 API 版本更改 JSON 属性 命名?

使用描述的 OData 模型配置方法 here 首先将派生自 IModelConfiguration 的 class 添加到您的项目中。

像这样:

public class VersionedModelConfiguration : IModelConfiguration
{
    private void ConfigureV1(ODataModelBuilder builder)
    {
        builder.EntitySet<Product>("Products");
    }

    private void ConfigureV2(ODataModelBuilder builder)
    {
        if (builder.GetType().Equals(typeof(ODataConventionModelBuilder)))
        {
            ((ODataConventionModelBuilder)builder).EnableLowerCamelCase();
        }
        builder.EntitySet<Product>("Products");
    }

    public void Apply(ODataModelBuilder builder, ApiVersion apiVersion)
    {

        switch (apiVersion.MajorVersion)
        {
            case 1:
                ConfigureV1(builder);
                break;
            case 2:
                ConfigureV2(builder);
                break;
            default:
                ConfigureV1(builder);
                break;
        }
    }
}

然后在Register方法中:

// ...
var modelBuilder = new VersionedODataModelBuilder(configuration)
{
    ModelBuilderFactory = () => new ODataConventionModelBuilder(),
    ModelConfigurations = { new VersionedModelConfiguration() }
};

var models = modelBuilder.GetEdmModels();
// ...

不要试图省略行 ModelBuilderFactory = () => new ODataConventionModelBuilder()

/api/v1/$metadata:

<?xml version="1.0" encoding="UTF-8"?>
<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
   <edmx:DataServices>
      <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="NS.Models">
         <EntityType Name="Product">
            <Key>
               <PropertyRef Name="Id" />
            </Key>
            <Property Name="Id" Type="Edm.Int32" Nullable="false" />
            <Property Name="Name" Type="Edm.String" />
         </EntityType>
      </Schema>
      <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="Default">
         <EntityContainer Name="Container">
            <EntitySet Name="Products" EntityType="NS.Models.Product" />
         </EntityContainer>
      </Schema>
   </edmx:DataServices>
</edmx:Edmx>

/api/v2/$metadata:

<?xml version="1.0" encoding="UTF-8"?>
<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
   <edmx:DataServices>
      <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="NS.Models">
         <EntityType Name="Product">
            <Key>
               <PropertyRef Name="id" />
            </Key>
            <Property Name="id" Type="Edm.Int32" Nullable="false" />
            <Property Name="name" Type="Edm.String" />
         </EntityType>
      </Schema>
      <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="Default">
         <EntityContainer Name="Container">
            <EntitySet Name="Products" EntityType="NS.Models.Product" />
         </EntityContainer>
      </Schema>
   </edmx:DataServices>
</edmx:Edmx>