OData客户端请求管道在OData V4中不工作

OData客户端请求管道在OData V4中不工作,odata,asp.net-web-api,Odata,Asp.net Web Api,我在下面的示例博客中删除和添加request ODataEntry类中的属性 但是,即使代码工作正常,并且在放置断点时正确添加和删除了属性,所有实体属性都会在未更改的情况下转到服务器 我看到的唯一区别是,我正在使用ODataV4和新的Ondata客户端进行连接 我的代码如下所示 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.T

我在下面的示例博客中删除和添加request ODataEntry类中的属性

但是,即使代码工作正常,并且在放置断点时正确添加和删除了属性,所有实体属性都会在未更改的情况下转到服务器

我看到的唯一区别是,我正在使用ODataV4和新的Ondata客户端进行连接

我的代码如下所示

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Client.Default;

namespace Client
{

using Client.MvcApplication1.Models;

using Microsoft.OData.Core;

internal class Program
{
    private static void Main(string[] args)
    {
        Container container = new Container(new Uri("http://localhost:55000/api/"));

        container.Configurations.RequestPipeline.OnEntryEnding(
            w =>
            {
                w.Entry.RemoveProperties("Name");
            });

        Test test = new Test();
        test.Name = "Foo";
        CustomFields cs = new CustomFields { ServiceId = 3 };
        cs.Foo1 = 2;
        test.S_1 = cs;
        container.AddToTests(test);
        container.SaveChanges();
    }
}

public static class Extensions
{

    public static void RemoveProperties(this ODataEntry entry, params string[] propertyNames)
    {

        var properties = entry.Properties as List<ODataProperty>;
        if (properties == null)
        {
            properties = new List<ODataProperty>(entry.Properties);
        }

        var propertiesToRemove = properties.Where(p => propertyNames.Any(rp => rp == p.Name));
        foreach (var propertyToRemove in propertiesToRemove.ToArray())
        {
            properties.Remove(propertyToRemove);
        }

        entry.Properties = properties;

    }

    public static void AddProperties(this ODataEntry entry, params ODataProperty[] newProperties)
    {
        var properties = entry.Properties as List<ODataProperty>;
        if (properties == null)
        {
            properties = new List<ODataProperty>(entry.Properties);
        }

        properties.AddRange(newProperties);

        entry.Properties = properties;

    }
}
}
客户端代码:

container.Configurations.RequestPipeline.OnEntryStarting(
                w =>
                {
                    w.Entry.RemoveProperties("Name");
                    w.Entry.AddProperties(new ODataProperty
                                              {
                                                  Name = "NewProperty",
                                                  Value = 1
                                              });
                });
错误:

The property 'NewProperty' does not exist on type 'Client.MvcApplication1.Models.Test'. Make sure to only use property names that are defined by the type.

   at Microsoft.OData.Core.WriterValidationUtils.ValidatePropertyDefined(String propertyName, IEdmStructuredType owningStructuredType)
   at Microsoft.OData.Core.JsonLight.ODataJsonLightPropertySerializer.WriteProperty(ODataProperty property, IEdmStructuredType owningType, Boolean isTopLevel, Boolean allowStreamProperty, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties)
   at Microsoft.OData.Core.JsonLight.ODataJsonLightPropertySerializer.WriteProperties(IEdmStructuredType owningType, IEnumerable`1 properties, Boolean isComplexValue, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties)
   at Microsoft.OData.Core.JsonLight.ODataJsonLightWriter.StartEntry(ODataEntry entry)
   at Microsoft.OData.Core.ODataWriterCore.<>c__DisplayClass14.<WriteStartEntryImplementation>b__12()
   at Microsoft.OData.Core.ODataWriterCore.InterceptException(Action action)
   at Microsoft.OData.Core.ODataWriterCore.WriteStartEntryImplementation(ODataEntry entry)
   at Microsoft.OData.Core.ODataWriterCore.WriteStart(ODataEntry entry)
   at Microsoft.OData.Client.ODataWriterWrapper.WriteStart(ODataEntry entry, Object entity)
   at Microsoft.OData.Client.Serializer.WriteEntry(EntityDescriptor entityDescriptor, IEnumerable`1 relatedLinks, ODataRequestMessageWrapper requestMessage)
   at Microsoft.OData.Client.BaseSaveResult.CreateRequestData(EntityDescriptor entityDescriptor, ODataRequestMessageWrapper requestMessage)
   at Microsoft.OData.Client.BaseSaveResult.CreateChangeData(Int32 index, ODataRequestMessageWrapper requestMessage)
   at Microsoft.OData.Client.SaveResult.CreateNonBatchChangeData(Int32 index, ODataRequestMessageWrapper requestMessage)
   at Microsoft.OData.Client.SaveResult.CreateNextChange()

我使用客户机上定义的分部类来添加我需要的额外属性。这使我可以在它们中加入任何逻辑,也可以更改属性通知。我使用以下扩展方法删除这些属性。我想我实际上从你链接的文章中得到了原始代码

public static class DbContextExtensions
{
    public static void RemoveProperties(this ODataEntry entry, params string[] propertyNames)
    {
        var properties = entry.Properties as List<ODataProperty>;
        if (properties == null)
        {
            properties = new List<ODataProperty>(entry.Properties);
        }
        var propertiesToRemove = properties.Where(p => propertyNames.Any(rp => rp == p.Name));
        foreach (var propertyToRemove in propertiesToRemove.ToArray())
        {
            properties.Remove(propertyToRemove);
        }
        entry.Properties = properties;
    }

    public static DataServiceClientResponsePipelineConfiguration RemoveProperties<T>(this DataServiceClientResponsePipelineConfiguration responsePipeline, Func<string, Type> resolveType, params string[] propertiesToRemove)
    {
        return responsePipeline.OnEntryEnded((args) =>
        {
            Type resolvedType = resolveType(args.Entry.TypeName);
            if (resolvedType != null && typeof(T).IsAssignableFrom(resolvedType))
            {
                args.Entry.RemoveProperties(propertiesToRemove);
            }
        });
    }

    public static DataServiceClientRequestPipelineConfiguration RemoveProperties<T>(this DataServiceClientRequestPipelineConfiguration requestPipeline, params string[] propertiesToRemove)
    {
        return requestPipeline.OnEntryStarting((args) =>
        {
            if (typeof(T).IsAssignableFrom(args.Entity.GetType()))
            {
                args.Entry.RemoveProperties(propertiesToRemove);
            }
        });
    }
}
请注意,在下面的方法中,它是钩住OnEntryStarted。文章中的代码钩住了OnEntryEnd,它曾一度对我有效,但当我更新到新版本的ODataClient时,它就崩溃了。在这种方法中,OnEntryStarted是一种方法

public static DataServiceClientRequestPipelineConfiguration RemoveProperties<T>(this DataServiceClientRequestPipelineConfiguration requestPipeline, params string[] propertiesToRemove)
    {
        return requestPipeline.OnEntryStarting((args) =>
        {
            if (typeof(T).IsAssignableFrom(args.Entity.GetType()))
            {
                args.Entry.RemoveProperties(propertiesToRemove);
            }
        });
    }
我还为容器创建了一个分部类,并实现了分部方法OnContextCreated。在这里,您可以使用扩展方法删除不会发送到服务器的属性

  partial void OnContextCreated()
    {
        Configurations.RequestPipeline.RemoveProperties<Customer>(new string[] { "FullName", "VersionDetails" });
        Configurations.RequestPipeline.RemoveProperties<SomeOtherType>(new string[] { "IsChecked", "IsReady" });
    }
确保您的分部类和DbContextensions类与我们的容器位于同一名称空间中,并且一切都应该正常工作


希望这会有所帮助。

是的,我知道分部类会有所帮助,但我的情况是,我们的UI和系统处于中间,在两个系统之间同步数据。现在,由于开放类型属性是由最终用户配置的,用户界面不知道何时会添加新的peoperties。因此,我需要挂接请求管道并发送这些属性,而无需重新编译并添加新的peoperties。希望这能解释为什么我不能使用分部类。
  partial void OnContextCreated()
    {
        Configurations.RequestPipeline.RemoveProperties<Customer>(new string[] { "FullName", "VersionDetails" });
        Configurations.RequestPipeline.RemoveProperties<SomeOtherType>(new string[] { "IsChecked", "IsReady" });
    }