gpt4 book ai didi

Odata Webapi - 如何在 7.0 核心中注入(inject) ODataResourceDeserializer?

转载 作者:行者123 更新时间:2023-12-03 21:20:25 24 4
gpt4 key购买 nike

文档非常稀少,我尝试的所有结果都注入(inject)了反序列化器,但正常的 odata url 不再起作用。

https://github.com/OData/WebApi/issues/158有 5.6 的解决方案。

最后的相关评论是:

@dbenzhuser - In that commit, look at ODataFormatterTests.cs for how inject a custom deserializer/deserializer provider. You can still use a custom DeserializerProvider but it's injected through DI instead of injecting it through ODataMediaTypeFormatters.



这是毫无意义的。我在那里尝试了代码,但正如我所说,它破坏了 URL。

现在我的 Odata 设置很简单:
    services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddOData();

\UnitTest\Microsoft.AspNet.OData.Test.Shared\Formatter\ODataFormatterTests.cs

有注入(inject)它们的示例(如第 379-383 行)
        config.MapODataServiceRoute("IgnoredRouteName", null, builder =>
builder.AddService(Microsoft.OData.ServiceLifetime.Singleton, sp => ODataTestUtil.GetEdmModel())
.AddService<ODataSerializerProvider>(ServiceLifetime.Singleton, sp => new CustomSerializerProvider())
.AddService<IEnumerable<IODataRoutingConvention>>(ServiceLifetime.Singleton, sp =>
ODataRoutingConventions.CreateDefaultWithAttributeRouting("IgnoredRouteName", config)));

但如果不删除核心 odata 路由,我似乎无法使其正常工作。

有人知道如何在不破坏基本功能的情况下将其用于当前版本吗?

最佳答案

如果要维护基本功能,则需要三个步骤:

  • 您的 DeserializerProvider 实现应默认为您的自定义 Deserializer 无法管理的所有场景的基本实现。在以下示例中,自定义反序列化器仅对资源而不是集合进行操作:
    public class EntityTypeDeserializerProvider : DefaultODataDeserializerProvider
    {
    private readonly DataContractDeserializer _dataContractDeserializer;
    public EntityTypeDeserializerProvider(IServiceProvider rootContainer)
    : base(rootContainer)
    {
    _dataContractDeserializer = new DataContractDeserializer(this);
    }

    public override ODataEdmTypeDeserializer GetEdmTypeDeserializer(IEdmTypeReference edmType)
    {
    if(edmType.Definition.TypeKind == EdmTypeKind.Complex || edmType.Definition.TypeKind == EdmTypeKind.Entity)
    return _dataContractDeserializer;
    else
    return base.GetEdmTypeDeserializer(edmType);
    }
    }
  • 与提供者一样,您的自定义 _Deserializer 应该为您不需要自定义的所有内容调用基本实现。在下面的实现中,我们只尝试强制执行反序列化的属性的顺序以及调用 DataContract OnDeserializingOnDeserialized方法,其余的反序列化不受影响:
    /// <summary>
    /// OData serializer that oberys the DataMember Order Attribute and OnDeserializing and OnDeserialized attributes on the resource definition
    /// </summary>
    public class DataContractDeserializer : ODataResourceDeserializer
    {
    public DataContractDeserializer(ODataDeserializerProvider provider)
    : base(provider) { }

    public override object CreateResourceInstance(IEdmStructuredTypeReference structuredType, ODataDeserializerContext readContext)
    {
    var resource = base.CreateResourceInstance(structuredType, readContext);
    var type = resource.GetType();
    if(type.GetCustomAttributesData().Any(x => x.AttributeType == typeof(DataContractAttribute)))
    {
    // manually call OnDeserializing
    var init = type.GetMethods(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic).FirstOrDefault(x => x.GetCustomAttributesData().Any(a => a.AttributeType == typeof(OnDeserializingAttribute)));
    if(init != null)
    {
    init.Invoke(resource, new object[] { new StreamingContext(StreamingContextStates.Remoting, readContext ) });
    }
    }
    return resource;
    }

    public override object ReadResource(ODataResourceWrapper resourceWrapper, IEdmStructuredTypeReference structuredType, ODataDeserializerContext readContext)
    {
    var resource = base.ReadResource(resourceWrapper, structuredType, readContext);
    var type = resource.GetType();
    if (type.GetCustomAttributesData().Any(x => x.AttributeType == typeof(DataContractAttribute)))
    {
    // manually call OnDeserialized
    var final = type.GetMethods(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic).FirstOrDefault(x => x.GetCustomAttributesData().Any(a => a.AttributeType == typeof(OnDeserializedAttribute)));
    if (final != null)
    {
    final.Invoke(resource, new object[] { new StreamingContext(StreamingContextStates.Remoting, readContext) });
    }
    }
    return resource;
    }
    public override void ApplyStructuralProperties(object resource, ODataResourceWrapper resourceWrapper, IEdmStructuredTypeReference structuredType, ODataDeserializerContext readContext)
    {
    var type = resource.GetType();
    var memberDescriptors = type.GetProperties().Where(x => x.HasAttribute<DataMemberAttribute>());
    if (memberDescriptors.Any())
    {
    var orderedProperties = from p in resourceWrapper.Resource.Properties
    let clsProperty = memberDescriptors.FirstOrDefault(m => m.Name == p.Name)
    let memberAtt = (DataMemberAttribute)(clsProperty?.GetCustomAttributes(true).FirstOrDefault(a => a.GetType() == typeof(DataMemberAttribute)))
    orderby (memberAtt?.Order).GetValueOrDefault()
    select p;
    foreach (var property in orderedProperties)
    {
    ApplyStructuralProperty(resource, property, structuredType, readContext);
    }
    }
    else
    base.ApplyStructuralProperties(resource, resourceWrapper, structuredType, readContext);
    }
    }
  • 最后,您需要将默认的 DeserializerProvider 注册替换为自己的,以下是重载到 MapODataServiceRoute 的示例它注册了前面 2 个示例中的 DeserializerProvider。
    我已经注释掉了注册特定 SerializerProvider 的示例
    private static ODataRoute MapODataServiceRoute(this HttpConfiguration configuration, string routeName,
    string routePrefix, IEdmModel model, ODataBatchHandler batchHandler = null, ODataUriResolver uriResolver = null, IList<IODataRoutingConvention> routingConventions = null)
    {
    return configuration.MapODataServiceRoute(routeName, routePrefix, builder =>
    builder
    .AddService(ServiceLifetime.Singleton, sp => model)
    //.AddService<ODataSerializerProvider>(ServiceLifetime.Singleton, sp => new DefaultODataSerializerProvider(sp))
    .AddService<ODataDeserializerProvider>(ServiceLifetime.Singleton, sp => new EntityTypeDeserializerProvider(sp))
    .AddService(ServiceLifetime.Singleton, sp => batchHandler ?? new DefaultODataBatchHandler(GlobalConfiguration.DefaultServer))
    .AddService(ServiceLifetime.Singleton, sp => uriResolver ?? new ODataUriResolver())
    .AddService<IEnumerable<IODataRoutingConvention>>(ServiceLifetime.Singleton, sp =>
    routingConventions ??
    ODataRoutingConventions.CreateDefaultWithAttributeRouting(routeName, configuration)
    )
    );
    }
  • 关于Odata Webapi - 如何在 7.0 核心中注入(inject) ODataResourceDeserializer?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51825765/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com