ODataWebAPI-如何在7.0内核中注入ODataResourceSerializer?

ODataWebAPI-如何在7.0内核中注入ODataResourceSerializer?,odata,asp.net-core-webapi,Odata,Asp.net Core Webapi,文档非常稀疏,我尝试的所有结果都是在反序列化器中注入的,但是普通的ODataURL不再工作 具有5.6版的解决方案buut 最后的相关评论是: @dbenzhuser-在该提交中,查看ODataFormatterTests.cs了解如何 插入自定义反序列化程序/反序列化程序提供程序。你仍然可以使用 自定义反序列化提供程序,但它是通过DI而不是 通过ODataMediaTypeFormatters注入它 这是毫无意义的。我在那里尝试了代码,但正如我所说的,它破坏了URL 现在,我的Odata设置很

文档非常稀疏,我尝试的所有结果都是在反序列化器中注入的,但是普通的ODataURL不再工作

具有5.6版的解决方案buut

最后的相关评论是:

@dbenzhuser-在该提交中,查看ODataFormatterTests.cs了解如何 插入自定义反序列化程序/反序列化程序提供程序。你仍然可以使用 自定义反序列化提供程序,但它是通过DI而不是 通过ODataMediaTypeFormatters注入它

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

现在,我的Odata设置很简单:

    services.AddMvc()
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    services.AddOData();
\UnitTest\Microsoft.AspNet.OData.Test.Shared\Formatter\ODataFormatterTests.cs

有注入它们的示例(如第379-383行)

config.MapODataServiceRoute(“ignoreDrootename”,null,builder=>
builder.AddService(Microsoft.OData.ServiceLifetime.Singleton,sp=>ODataStutil.GetEdmModel())
.AddService(ServiceLifetime.Singleton,sp=>new CustomSerializerProvider())
.AddService(ServiceLifetime.Singleton,sp=>
ODataRoutingConventions.CreateDefaultWithAttributeRouting(“ignoreDrootename”,config));
但是,如果不删除核心odata路由,我似乎无法使其正常工作


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

如果要维护基本功能,请执行三个步骤:

  • 对于自定义反序列化程序无法管理的所有场景,反序列化程序提供程序实现应默认为基本实现。在以下示例中,自定义反序列化程序仅对资源而不是集合进行操作:

    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);
        }
    }
    
  • 与提供程序一样,对于不需要自定义的所有内容,您的自定义反序列化程序都应该调用基本实现。在以下实现中,我们仅尝试强制执行反序列化属性的顺序,以及调用
    DataContract
    OnDeserialization
    OnDeserialized
    方法,反序列化的其余部分不受影响:

    /// <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);
        }
    }
    

  • 我知道这很古老,但是如果您发布您的实现,或者您已经尝试过的内容,而不是来自您在解释时遇到困难的资源的实现,那么它会有所帮助。
    /// <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);
        }
    }
    
    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)
                        )
                    );
        }