我正在关注下面的示例博客,以删除并添加请求ODataEntry类中的属性。
但即使代码工作正常并在我放置断点时正确添加和删除属性,所有实体属性都会转到服务器未更改。
唯一区别我看到这个我正在使用OData V4和新的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;
}
}
}
如果我改变并开始收听RequestPipeline.OnEntryStarting,我会收到验证错误,即未在拥有实体中定义新属性。但是根据Microsoft.OData.CLient的代码,这个错误不应该发生,因为检查IEdmStructuredType.IsOpen但仍然发生错误。因此,如何计算owningStructuredType的问题似乎很深。在我的容器上,我确实看到了正确的edm模型,其实体标记为IsOpen = true。
应该通过但是失败的Odata lib代码
internal static IEdmProperty ValidatePropertyDefined(string propertyName, IEdmStructuredType owningStructuredType)
{
Debug.Assert(!string.IsNullOrEmpty(propertyName), "!string.IsNullOrEmpty(propertyName)");
if (owningStructuredType == null)
{
return null;
}
IEdmProperty property = owningStructuredType.FindProperty(propertyName);
// verify that the property is declared if the type is not an open type.
if (!owningStructuredType.IsOpen && property == null)
{
throw new ODataException(Strings.ValidationUtils_PropertyDoesNotExistOnType(propertyName, owningStructuredType.ODataFullName()));
}
return property;
}
客户代码:
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()
答案 0 :(得分:0)
我使用客户端上定义的部分类来添加我需要的额外属性。这允许我在其中放置任何逻辑以及具有属性更改通知。我使用以下扩展方法来删除这些属性。我想我实际上已经从您链接的文章中获得了原始代码。
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。文章中的代码挂钩了OnEntryEnded,它一度为我工作,然后在我更新到更新版本的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);
}
});
}
我还为Container创建了一个分部类,并实现了部分方法OnContextCreated。这是您使用扩展方法删除不会发送到服务器的属性的地方。
partial void OnContextCreated()
{
Configurations.RequestPipeline.RemoveProperties<Customer>(new string[] { "FullName", "VersionDetails" });
Configurations.RequestPipeline.RemoveProperties<SomeOtherType>(new string[] { "IsChecked", "IsReady" });
}
确保您的部分类和DBContextExtensions类与我们的容器位于同一名称空间中,一切都应该正常工作。
希望有所帮助。