json - ASP.NET Web Api 和部分响应

标签 json model-view-controller asp.net-web-api

我有一个正在处理的 ASP.NET WebApi 项目。老板希望返回支持“部分响应”,这意味着尽管数据模型可能包含 50 个字段,但客户端应该能够为响应请求特定字段。原因是,如果他们正在实现例如一个列表,他们根本不需要所有 50 个字段的开销,他们可能只需要名字、姓氏和 ID 来生成列表。到目前为止,我已经通过使用自定义契约(Contract)解析器 (DynamicContractResolver) 实现了一个解决方案,这样当一个请求进来时,我通过 OnActionExecuting 方法中的过滤器 (FieldListFilter) 窥视它并确定是否存在名为“FieldList”的字段,并且那么如果是我用我的 DynamicContractResolver 的新实例替换当前的 ContractResolver 并将字段列表传递给构造函数。

一些示例代码

DynamicContractResolver.cs

protected override IList<JsonProperty> CreateProperties(Type type, Newtonsoft.Json.MemberSerialization memberSerialization)
    {
        List<String> fieldList = ConvertFieldStringToList();

        IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
        if (fieldList.Count == 0)
        {
            return properties;
        }
        // If we have fields, check that FieldList is one of them.
        if (!fieldList.Contains("FieldList"))
            // If not then add it, FieldList must ALWAYS be a part of any non null field list.
            fieldList.Add("FieldList");
        if (!fieldList.Contains("Data"))
            fieldList.Add("Data");
        if (!fieldList.Contains("FilterText"))
            fieldList.Add("FilterText");
        if (!fieldList.Contains("PageNumber"))
            fieldList.Add("PageNumber");
        if (!fieldList.Contains("RecordsReturned"))
            fieldList.Add("RecordsReturned");
        if (!fieldList.Contains("RecordsFound"))
            fieldList.Add("RecordsFound");
        for (int ctr = properties.Count-1; ctr >= 0; ctr--)
        {
            foreach (string field in fieldList)
            {
                if (field.Trim() == properties[ctr].PropertyName)
                {
                    goto Found;
                }
            }
            System.Diagnostics.Debug.WriteLine("Remove Property at Index " + ctr + " Named: " + properties[ctr].PropertyName);
            properties.RemoveAt(ctr);
        // Exit point for the inner foreach.  Nothing to do here.
        Found: { }
        }
        return properties;
    }

字段列表过滤器.cs
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        if (!actionContext.ModelState.IsValid)
        {
            throw new HttpResponseException(HttpStatusCode.BadRequest);
        }
        // We need to determine if there is a FieldList property of the model that is being used.
        // First get a reference to the model.
        var modelObject = actionContext.ActionArguments.FirstOrDefault().Value;
        string fieldList = string.Empty;
        try
        {
            // Using reflection, attempt to get the value of the FieldList property
            var fieldListTemp = modelObject.GetType().GetProperty("FieldList").GetValue(modelObject);
            // If it is null then use an empty string
            if (fieldListTemp != null)
            {
                fieldList = fieldListTemp.ToString();
            }
        }
        catch (Exception)
        {
            fieldList = string.Empty;
        }

        // Update the global ContractResolver with the fieldList value but for efficiency only do it if they are not the same as the current ContractResolver.
        if (((DynamicContractResolver)GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver).FieldList != fieldList)
        {
            GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new DynamicContractResolver(fieldList);
        }
    }

然后我可以发送一个带有 json 内容负载的请求,如下所示:
{
  "FieldList":"NameFirst,NameLast,Id",
  "Data":[
    {
      "Id":1234
    },
    {
      "Id":1235
    }
  ]
}

我会收到这样的回复:
{
  "FieldList":"NameFirst,NameLast,Id",
  "Data":[
    {
      "NameFirst":"Brian",
      "NameLast":"Mueller",
      "Id":1234
    },
    {
      "NameFirst":"Brian",
      "NameLast":"Mueller",
      "Id":1235
    }
  ]
}

我相信使用 ContractResolver 可能会遇到线程问题。如果我为一个请求更改它,它是否对所有请求都有效,直到有人在另一个请求上更改它(通过测试似乎是这样)如果是这种情况,那么我看不到我的目的的用处。

总而言之,我正在寻找一种拥有动态数据模型的方法,以便客户端可以在逐个请求的基础上配置请求的输出。谷歌在他们的 web api 中实现了这一点,他们称之为“部分响应”,效果很好。我的实现在某种程度上有效,但我担心它会因多个同时请求而被破坏。

建议?提示?

最佳答案

一个可能有效的更简单的解决方案。

创建一个包含所有 50 个可空类型成员的模型类。
为请求的成员分配值。
只需以正常方式返回结果。

在您的 WebApiConfig.Register() 中,您必须设置空值处理。

   config.Formatters.JsonFormatter.SerializerSettings =
        new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };

关于json - ASP.NET Web Api 和部分响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17033357/

相关文章:

php - 良好的 JSON 但浏览器抛出错误

json - Firebase 更新特定字段?

asp.net-mvc - 在 MVC 中捕获 form.submit() 响应

php - 布局和 View 有什么区别?以 Zend_Layout 和 Zend_View 为例

asp.net-mvc - 在 Asp.Net 5 中确保 SSL 的正确方法是什么

c# - 将 JSON 反序列化为可读格式

javascript - 使用 javascript 和 Ajax POST 形成 JSON [LARAVEL]

c# - ASP.NET MVC 需要两个不同版本的 Newtonsoft.Json.dll

jquery - JSONP 与 ASP.NET Web API

javascript - 如何从 HttpResponseMessage 获取 jqxhr.responseText?