处理oData客户端上的动态属性

时间:2015-07-13 20:39:51

标签: c# asp.net-web-api odata asp.net-web-api2

我在服务器和客户端上都有以下类

public class Entity
{
    public string Id {get; set;}
    public string Name {get; set;}
    public Dictionary<string, object> DynamicProperties {get; set;}
}

据我所知,open类型的所有示例都描述了在服务器端具有动态属性,但是客户端上的属性需要显式声明。当我从客户端发送POST请求时如何发送动态属性?我无法在客户端声明所有动态属性。有许多属性,每个对象将在客户端包含不同的动态属性集。这些动态属性存储在客户端的DynamicProperties字典中。如何将上述实体类的对象发送到服务器端,以便服务器将DynamicProperties字典的内容解释为动态属性?任何帮助表示赞赏。

===========================对山姆回答的跟进======= ================

    static void Main(string[] args1)
    {
        container.Customers.ToList();
        Customer newCustomer = new Customer();
        newCustomer.Id = 19;
        newCustomer.Properties = new Dictionary<string, object>
        {
            {"IntProp", 9},
            {"DateTimeOffsetProp", new DateTimeOffset(2015, 7, 16, 1, 2, 3, 4, TimeSpan.Zero)},
            {"blah","ha"}
        };
        try
        {
            addCustomer(newCustomer);
            container.AddToCustomers(newCustomer);
            container.SaveChanges();
        }
        catch (Exception)
        {

        }
        Customer newCustomer1 = new Customer();
        newCustomer1.Id = 20;
        newCustomer1.Properties = new Dictionary<string, object>
        {
            {"IntProp", 10},
            {"dir","north"}
        };
        addCustomer(newCustomer1);
        container.AddToCustomers(newCustomer1);
        container.SaveChanges();
        newCustomer1.Properties["dir"] = "south";
        container.UpdateObject(newCustomer1);
        container.SaveChanges();
        Console.ReadKey();
    }

    private static void addCustomer(Customer customer)
    {
        container.Configurations.RequestPipeline.OnEntryStarting(args =>
        {
            foreach (var property in customer.Properties)
            {
                args.Entry.AddProperties(new ODataProperty
                {
                    Name = property.Key,
                    Value = property.Value // for enum, complex type, should to create ODataEnumValue and ODataComplexValue.
                });
            }
        });
    }

我收到一条错误,指出多个属性名称为&#39; IntProp&#39;在条目或复杂值中检测到。在OData中,不允许重复的属性名称。另外,我怀疑每次在发送一个对象之前创建一个动作,就像我现在正在做的那样是一种有效的方法,因为我从源中获取了大量对象并将其发送到服务器。如果我为每个对象创建一个动作,那么当oData客户端在内存中保存这些动作时,它可能会炸毁内存。我该如何处理我的场景?请帮助我。

另外,还有一个问题,如果我评论 container.Customers.ToList(),它会失败,说明我正在尝试添加未声明的属性。那是为什么?

2 个答案:

答案 0 :(得分:0)

如果您使用的是OData Client Code Generator,则可以使用partial class来定义/检索/保存动态属性。

例如,在您的客户端,您可以为Entity

定义部分类
public partial class Entity
{
    // Dynamic property "Email"
    [global::Microsoft.OData.Client.OriginalNameAttribute("Email")]
    public string Email
    {
        get
        {
            return this._Email;
        }
        set
        {
            this.OnEmailChanging(value);
            this._Email = value;
            this.OnEmailChanged();
            this.OnPropertyChanged("Email");
        }
    }

    private string _Email;
    partial void OnEmailChanging(string value);
    partial void OnEmailChanged();
}

然后,您可以使用它来插入/检索/保存动态属性“电子邮件”。

你可以这样做:

Container container = new Container(new Uri("http://..."));
Entity entity = new Entity();
...
entity.Email = "xxxx";
container.AddToEntities(entity);
container.SaveChanges();

对于类似的实施,您可以参考my sample project

==========迭代2 ================

对于Entity的客户IDictionary<string,object>班级,我认为您正在寻找钩子。

例如,在客户端:

public partial class Entity
{
    public IDictionary<string, object> Properties { get; set; }

    .....
}

如果在

之前插入以下代码,它应该有效

container.AddToEntities(entity);

例如:

Entity entity = new Entity();
...
entity.Properties = new Dictionary<string, object>
{
    {"IntProp", 9},
    {"DateTimeOffsetProp", new DateTimeOffset(2015, 7, 16, 1, 2, 3, 4, TimeSpan.Zero)}
};

container.Configurations.RequestPipeline.OnEntryStarting(args =>
{
    foreach (var property in entity.Properties)
    {
        args.Entry.AddProperties(new ODataProperty
        {
            Name = property.Key,
            Value = property.Value
        });
    }
});

container.AddToEntities(entity);
container.SaveChanges();

其中,AddProperties是一种扩展方法。你可以在my sample project找到它  和the latest commit

此外,引擎盖方法仅适用于 OData Client V6.12或更高版本。

希望它可以帮到你。

==========迭代3 ================

  1. 首先,您调用以下方法,

    container.Configurations.RequestPipeline.OnEntryStarting(...);

    这意味着添加将在以后执行中调用的操作。在您的代码中,您将其调用两次,因此,添加了两个操作。执行保存newCustomer1时,将逐个调用这两个操作 那就是newCustomer1将拥有newCustomer的动态属性(动作1),同时,它将拥有自己的动态属性(动作2)。这就是为什么你得到重复的属性名称异常。

  2. 要解决此问题,您只需续订Container即可。查看我的项目更新。

    1. 对于container.Customers.ToList(),它似乎是OData客户端问题。

答案 1 :(得分:0)

[回答我自己的问题:另一种方法]

扩展Sam Xu的迭代方法2.我们可以这样做。 (为了清楚起见,我们假设所讨论的类的名称为Book)

public partial class Book
{
    public string ISBN {get; set;}
    public IDictionary<string, object> DynamicProperties { get; set; }
}

// This portion can be put in a function and can be invoked only once 
container.Configurations.RequestPipeline.OnEntryStarting(args =>
{
   if(args.Entity.GetType() == typeof(Book))
   {
      var book = args.Entity as Book
      foreach (var property in book.DynamicProperties)
      {
         args.Entry.AddProperties(new ODataProperty
         {
           Name = property.Key,
           Value = property.Value
         });
      }
    }
 });
Sam Xu的实现中提供了

AddProperties 扩展方法实现