Web API请求对象中强类型和任意属性

时间:2014-01-03 12:57:13

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

我有一个看起来非常像这样的对象:

public class MyNiceRequest 
{
    [Required]
    public string FirstName { get; set; }
    [Required]
    public string LastName { get; set; }

    public string SomeOptionalField { get; set; }
}

我的控制器看起来如下,相当标准:

public MyNiceResponse Post(MyNiceRequest request) {
...
}

从调用应用程序的前端,我想要包含比对象中指定的三个字段更多的字段。这些字段是运行时生成的(通过管理界面控制),因此我无法将它们应用于我的请求类。但是,我找不到在控制器中检索它们的好方法。

我可以让我的请求对象(MyNiceRequest)继承自Dictionary<string,string> - 然后我会全部获取它们,但它们不会被绑定到强类型类的各自属性(似乎就像在使用任何模型的活页夹之前,在其余部分之前绑定了Dictionary。此外,更重要的是,验证 - 这对应用程序至关重要 - 停止工作。

我已经看到了this的问题,但它没有给我任何内容,因为Request.Content.Read... - 方法给我空结果(因为它已经被读取并绑定到模型?)。

假设我想从前端获得以下字段:

  • FirstName(应绑定到强类型,其他地方)
  • LastName(应绑定到强类型,其他地方)
  • SomeOptionalField(应绑定到强类型,其他地方)
  • RuntimeGenerated1(应该以词典结尾)
  • RuntimeGenerated2(应该以词典结尾)

我想要两种解决方案之一:

  • 要么能够从Dictionary<string,string>继承,要让字典在强类型属性之后绑定,以便验证能够正常工作
  • MyNiceRequest上有一个单独的属性,可能类似于Dictionary<string,string> TheRest { get; set; },并将其绑定到其余的传入属性。

重写前端以传递运行时生成的字段作为单独的集合不是一种选择。

..这可以通过重用/重新排序现有的东西来实现,还是我必须从头开始编写完整的媒体类型格式化程序和/或模型绑定器?

2 个答案:

答案 0 :(得分:3)

对于application/json内容类型,您可以将DynamicObject与WebAPI的默认JSON格式化程序一起使用。

public class MyNiceRequest : DynamicObject
{
    private Dictionary<string, string> _dynamicMembers = new Dictionary<string, string>();

    [Required]
    public string FirstName { get; set; }

    [Required]
    public string LastName { get; set; }

    public string SomeOptionalField { get; set; }

    [JsonIgnore]
    public Dictionary<string, string> DynamicMembers
    {
        get { return _dynamicMembers; }
    }

    public override bool TryGetMember(GetMemberBinder binder, out object value)
    {
        string stringValue;
        var isFound = _dynamicMembers.TryGetValue(binder.Name, out stringValue);
        value = stringValue;
        return isFound;
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        if (value is string)
        {
            _dynamicMembers[binder.Name] = (string)value;
            return true;
        }
        return false;
    }
}

修改

  1. 如果您希望使用相同的格式序列化对象,请实现IDictionary<string, string>。这很简单,只需将接口实现委托给_dynamicMembers

  2. 此解决方案不适用于默认的XML和x-www-form-urlencoded格式化程序:(

答案 1 :(得分:2)

你可以像这样使用DTO。

public class MyNiceRequest
{
    [Required]
    public string FirstName { get; set; }
    [Required]
    public string LastName { get; set; }

    public string SomeOptionalField { get; set; }

    public Dictionary<string, string> TheRest { get; set; }
}

如果您在请求正文中发布JSON,则会填充此{"firstname":"arve", "therest":{"key":"value"}}FirstName属性。 TheRest会有一个带有键“key”和值“value”的项目。当然,ModelState.IsValid将为false,因为JSON不包含LastName