【问题标题】:Prevent Azure TableEntity property from being serialized in MVC 4 WebAPI防止 Azure TableEntity 属性在 MVC 4 WebAPI 中被序列化
【发布时间】:2013-03-07 12:31:31
【问题描述】:

所以我有一个模型 Subscription,它继承自 Azure 的 TableEntity 类,用于 WebApi Get 方法,如下所示:

[HttpGet]
public IEnumerable<Subscription> Subscribers()

在这个方法中,我对我的订阅者表执行Select 查询以查找所有订阅者,但我只想返回一些列(属性),如下所示:

var query = new TableQuery<Subscription>().Select(new string[] {
    "PartitionKey", 
    "RowKey", 
    "Description", 
    "Verified"
    });

模型定义如下:

public class Subscription : TableEntity
{
    [Required]
    [RegularExpression(@"[\w]+",
     ErrorMessage = @"Only alphanumeric characters and underscore (_) are allowed.")]
    [Display(Name = "Application Name")]
    public string ApplicationName
    {
        get
        {
            return this.PartitionKey;
        }
        set
        {
            this.PartitionKey = value;
        }
    }

    [Required]
    [RegularExpression(@"[\w]+",
     ErrorMessage = @"Only alphanumeric characters and underscore (_) are allowed.")]
    [Display(Name = "Log Name")]
    public string LogName
    {
        get
        {
            return this.RowKey;
        }
        set
        {
            this.RowKey = value;
        }
    }

    [Required]
    [EmailAddressAttribute]
    [Display(Name = "Email Address")]
    public string EmailAddress { get; set; }

    public string Description { get; set; }

    public string SubscriberGUID { get; set; }

    public bool? Verified { get; set; }
}

以下是 API 查询的 XML 响应:

<ArrayOfSubscription>
    <Subscription>
        <ETag>W/"datetime'2013-03-18T08%3A54%3A32.483Z'"</ETag>
        <PartitionKey>AppName1</PartitionKey><RowKey>Log1</RowKey>
        <Timestamp>
            <d3p1:DateTime>2013-03-18T08:54:32.483Z</d3p1:DateTime>
            <d3p1:OffsetMinutes>0</d3p1:OffsetMinutes>
        </Timestamp>
        <ApplicationName>AppName1</ApplicationName>
        <Description>Desc</Description>
        <EmailAddress i:nil="true"/>
        <LogName>Log1</LogName>
        <SubscriberGUID i:nil="true"/>
        <Verified>false</Verified>
    </Subscription>
</ArrayOfSubscription>

正如你所看到的,模型不仅有一些额外的属性,比如SubscriberGUID,我不想在响应中被序列化(因为它们不在选择查询中,所以它们无论如何都是空的),但 TableEntity 本身也有 PartitionKeyRowKeyEtagTimestamp 等字段,这些字段也在序列化中。

如何继续使用 Azure 表但避免在响应中序列化这些我不希望用户看到的不需要的字段。

【问题讨论】:

    标签: c# serialization asp.net-mvc-4 asp.net-web-api azure-table-storage


    【解决方案1】:

    不同意使用特定 DTO 的答案,但 Microsoft.WindowsAzure.Storage 程序集现在提供了一个属性 IgnorePropertyAttribute,您可以用它来装饰您的公共属性以避免序列化。

    我还没有真正尝试过,但是TableEntity 上有一个名为ShouldSkipProperty() 的方法,它在返回false 之前检查了许多事情(即不要跳过):

    • 属性名称是“PartitionKey”、“RowKey”、“Timestamp”还是“ETag”之一 -> 跳过
    • getter 和 setter 中的任何一个都是非公开的 -> 跳过
    • 是静态的 -> 跳过
    • 属性是否有属性 IgnorePropertyAttribute -> 跳过

    看起来它可以解决问题。

    【讨论】:

    • 您有示例如何在继承 TableEntity 的序列化和反序列化类时使用此 IgnorePropertyAttribute (ShouldSkipProperty) 来处理 Etag、RowKey PartitionKey 和 TimeStamp。
    • @Parag 你不需要IgnorePropertyAttribute 装饰来忽略PartitionKeyRowKeyTimestampETag,因为ShouldSkipProperty() 方法意味着这些字段总是被跳过.
    • 默认是不跳过的,能否举个例子来调用这个方法?
    • 我刚刚尝试了 IgnorePropertyAttribute,但它仍在序列化。这应该适用于最新版本的 SDK 吗?我在 Microsoft.WindowsAzure.Storage 7.2.1.0 上。
    • @JoeyEng 这是一篇很老的帖子——你可以反编译库,看看过程是否相同或改变——查看TableEntity对象中一个名为ShouldSkipProperty()的方法,看看如何它的行为。如果基本算法没有改变,这就是它的位置——如果他们改变了它(他们可能也改变了),你应该寻找属性然后做一个参考查找,看看他们是否在任何地方使用它
    【解决方案2】:

    我建议使用 DTO(数据传输对象)来解决此类问题。 DTO 可能意味着更多代码(更多类),但从长远来看会使您受益。您可以更好地控制电线上的内容。从安全的角度来看,它们也比使用某些序列化程序特定的属性来控制在线上的内容更好。

    更多信息请参考thisasp.net web API 教程。

    【讨论】:

    • 这与我所做的唯一区别是 DTO 继承自 TableEntity,这是我与 Azure 存储表集成所需要的。
    • 我没有看到 DTO 继承后端实体对象的理由。您应该有两种类型,一种是代表您的表的模型类型,在您的情况下为Subscription,它继承TableEntity。然后,您将拥有一个不能继承 TableEntitySubscriptionDto 并包含您希望通过 Web API 公开的字段/属性。
    【解决方案3】:

    使用 DTO 是可行的方法,恕我直言,但要澄清一下,因为从帖子中并不明显在哪里实施 DTO。我希望我可以将它用作查询的一部分,但我不能。相反,我必须这样做:

    query.SelectColumns = new List<string> { "QuoteId", "RateId", "Date" };
    var results = await MyCloudTable.ExecuteQuerySegmentedAsync(query, null);
    return results.Select(d => new MyDto { QuoteId = d.QuoteId, RateId = d.RateId, Date = d.Date }).ToList();
    

    您必须从您的 TableQuery 返回您的 TableEntity 派生对象,但由于所有属性均为空(通过显式选择所需的列),因此在线路上没有其他数据。然后,您可以投影到您的 DTO 中,这样您就可以准确地返回您需要的对象。

    【讨论】:

      【解决方案4】:

      您不需要从 TableEntity 类继承。您可以使用 TableEntity.Flatten 方法从您的 Subscription 类创建一个 DynamicTableEntity 并写入表存储。当您从天蓝色表存储中读取 DynamicTableEntity 时,您可以使用 TableEntity.ConvertBack 方法重构您的订阅对象。这些静态帮助方法在 Azure 表存储 SDK 版本 >= 8.0.0

      中可用

      TableEntity.Flatten:https://msdn.microsoft.com/en-us/library/azure/mt775434.aspx TableEntity.ConvertBack:https://msdn.microsoft.com/en-us/library/azure/mt775432.aspx

      消除您在 DTO 和业务数据模型之间进一步编写转换器类的需要

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-08-04
        • 1970-01-01
        • 2018-08-03
        • 1970-01-01
        • 1970-01-01
        • 2010-12-16
        相关资源
        最近更新 更多