ASP.NET的WebAPI和部分缓解 [英] ASP.NET WebApi and Partial Responses

查看:131
本文介绍了ASP.NET的WebAPI和部分缓解的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有我工作的一个ASP.NET的WebAPI项目。老板想的回报,以支持部分缓解,这意味着虽然数据模型可能包含50场,客户端应该能够请求特定字段的响应。原因是,如果他们正在实施例如列表他们根本不需要所有50场的开销,他们可能只是想姓,姓名和身份证生成列表。到目前为止,我已经通过使用自定义合同解析器(DynamicContractResolver)这样,当一个请求进来时,我偷看其通过OnActionExecuting方法过滤器(FieldListFilter),并确定了一个名为FieldList中字段是$ P实施的解决方案$ psent然后如果这是我与我的DynamicContractResolver的新实例替换当前ContractResolver和我通过字段列表来构造。

I have a ASP.NET WebApi project that I am working on. The boss would like the returns to support "partial response", meaning that though the data model might contain 50 fields, the client should be able to request specific fields for the response. The reason being that if they are implementing for example a list they simply don't need the overhead of all 50 fields, they might just want the First Name, Last Name and Id to generate the list. Thus far I have implemented a solution by using a custom Contract Resolver (DynamicContractResolver) such that when a request comes in I am peeking into it through a filter (FieldListFilter) in the OnActionExecuting method and determining if a field named "FieldList" is present and then if it is I am replacing the current ContractResolver with a new instance of my DynamicContractResolver and I pass the fieldlist to the constructor.

一些示例code

DynamicContractResolver.cs

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;
    }

FieldListFilter.cs

FieldListFilter.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内容有效载荷为寻找这样的要求:

I can then send a request with the json content payload looking as such:

{
  "FieldList":"NameFirst,NameLast,Id",
  "Data":[
    {
      "Id":1234
    },
    {
      "Id":1235
    }
  ]
}

和我会收到像这样的响应:

and I will receive a response like so:

{
  "FieldList":"NameFirst,NameLast,Id",
  "Data":[
    {
      "NameFirst":"Brian",
      "NameLast":"Mueller",
      "Id":1234
    },
    {
      "NameFirst":"Brian",
      "NameLast":"Mueller",
      "Id":1235
    }
  ]
}

我相信使用ContractResolver可能会遇到线程问题。如果我改变了一个请求这将是适用于所有的请求之后,直到有人改变了它的另一个请求(通过测试看起来如此),如果是这样的话,那么我看不到我的目的是有用的。

I believe that using the ContractResolver might run into threading issues. If I change it for one request is it going to be valid for all requests thereafter until someone changes it on another request (seems so through testing) If that is the case, then I don't see the usefulness for my purpose.

总之,我正在寻找一种方式来拥有动态的数据模型,使得来自请求的输出是通过要求基础上请求的客户端配置。谷歌在其Web API实现了这一点,他们把它称为部分缓解,它的伟大工程。我工作的实施,到一个点,但我担心它会为多个同时请求被打破。

In summary, I am looking for a way to have dynamic data models such that the output from a request is configurable by the client on a request by request basis. Google implements this in their web api and they call it "partial response" and it works great. My implementation works, to a point but I fear that it will be broken for multiple simultaneous requests.

建议?提示?

推荐答案

一个简单的解决方案,可能会工作。

A simpler solution that may work.

与所有50个成员与可空类型创建模型类。
值分配给所请求的成员。
刚刚回到正常方式的结果。

Create a model class with all 50 members with nullable types. Assign values to the requested members. Just return the result in the normal way.

在你的WebApiConfig.Register()必须设置为空值处理。

In your WebApiConfig.Register() you must set the null value handling.

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

这篇关于ASP.NET的WebAPI和部分缓解的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆