如何限制web api返回的列?

时间:2014-10-18 08:42:09

标签: entity-framework asp.net-web-api

如何限制web api&amp ;;返回的列数实体框架? 我会尽可能多地欣赏信息,因为我还是新手;)

我的控制器:

         //GET: api/Creditors
    public IQueryable<Creditor> GetCreditors()
    {
        return db.Creditors;
    }

我的班级:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;

namespace PurchaseOrders.Models
{
public class Creditor
{
    [Key]
    public int CreditorID { get; set; }

    [MaxLength(10, ErrorMessage = "Maximum of 10 characters")]
    public string CRKEY { get; set; }

    [Display(Name = "Business Name")]
    [MaxLength(40, ErrorMessage = "Maximum of 40 characters")]
    public string BusinessName { get; set; }

    [MaxLength(40, ErrorMessage = "Maximum of 40 characters")]
    public string Address { get; set; }

    [MaxLength(40, ErrorMessage = "Maximum of 40 characters")]
    public string City { get; set; }

    [MaxLength(4, ErrorMessage = "Maximum of 4 characters")]
    public string State { get; set; }

    [MaxLength(4, ErrorMessage = "Maximum of 4 characters")]
    public string Postcode { get; set; }

    [MaxLength(15, ErrorMessage = "Maximum of 15 characters")]
    public string Phone { get; set; }

    [MaxLength(15, ErrorMessage = "Maximum of 15 characters")]
    public string Fax { get; set; }

    [MaxLength(60, ErrorMessage = "Maximum of 60 characters")]
    public string Email { get; set; }

    [MaxLength(60, ErrorMessage = "Maximum of 60 characters")]
    public string Website { get; set; }

    [MaxLength(30, ErrorMessage = "Maximum of 30 characters")]
    public string ContactName { get; set; }

    [MaxLength(15, ErrorMessage = "Maximum of 15 characters")]
    public string ABN { get; set; }

    [Display(Name = "Registered for GST")]
    public bool RegisteredForGST { get; set; }

}

}

目前返回:

[{"CreditorID":1,"CRKEY":"test1","BusinessName":"test1","Address":"7 Smith Street","City":"Melbourne","State":"VIC","Postcode":"3000","Phone":null,"Fax":null,"Email":null,"Website":null,"ContactName":null,"ABN":"null","RegisteredForGST":true},{"CreditorID":2,"CRKEY":"test2","BusinessName":"test2","Address":"10 Smith Street","City":"SYDNEY","State":"NSW","Postcode":"2000","Phone":null,"Fax":null,"Email":null,"Website":null,"ContactName":null,"ABN":"null","RegisteredForGST":true}]

这是我想要的结果(只有“CreditorID”和“BusinessName”):

[{"CreditorID":1,"BusinessName":"test1"},{"CreditorID":2,"BusinessName":"test2"}]

3 个答案:

答案 0 :(得分:1)

这可以使用投影来完成,这里是使用匿名类型的示例:

db.Creditors
  .Select(x => new {
      x.CreditorID,
      x.BusinessName,
  })
  .ToArray()

这将导致对数据库的查询,这将只需要包含在匿名类中的两个字段。您可以使用JSON结果直接从WebAPI控制器返回它。

如果您需要在图层之间传递结果(类型为SomeAnonymousClassICanNotReference[]),您可以使用dymanic关键字(实际上不是一个好的选项),也可以使用自定义类{{1 }}

答案 1 :(得分:1)

在您的问题中,您显示了查询的json输出,因此我假设您正在从Javascript发出GET请求。当您使用IQueryable作为API方法的返回值类型时,您应该能够利用WebApi提供的OData支持,以便您可以发出OData查询以仅选择你想要的列。有关OData支持的更多详细信息,请this article

首先,javascript方面,假设jQuery易于回答:

$.get('api/Creditors?$select=CreditorId,BusinessName', onSuccess)

您想要的列名在$select参数的逗号分隔列表中指定。 (onSuccess是一个回调函数,您将定义哪个函数将传递从API返回的数据。有关详细信息,请参阅jQuery documentation。)

在服务器端,您可能需要从ODataController而不是ApiController派生您的控制器,您需要添加[Queryable][EnableQuery]属性您的GetCreditors()方法取决于您使用的WebApi版本。

如果您发现需要继承ODataController以使其正常工作,那么您必须添加另一部分配置,即配置OData端点。为此,您需要类似以下的代码:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        ODataModelBuilder builder = new ODataConventionModelBuilder();
        builder.EntitySet<Creditor>("Creditors");
        config.MapODataServiceRoute(
            routeName: "ODataRoute",
            routePrefix: null, // or "api" ?
            model: builder.GetEdmModel());
    }
}

在您的网络启动代码中的某处(例如Application_Start),您需要按以下方式调用此方法:

GlobalConfiguration.Configure(WebApiConfig.Register);

根据您设置项目的方式,后一种配置中的一些可能不是必需的,因为它已经完成,但我认为我已经提到它了。有关详细信息,请查看this page

答案 2 :(得分:1)

在没有OData的情况下,有几种不同的方法可以处理此要求。我倾向于使用投影查询(正如Lanorkin在他的回答中提到的)。以下是一些例子。

<强> 1。从WebAPI控制器返回动态类型:

这是最快捷,最简单的方法。有些人认为动态回报类型是草率的,但他们完成了工作。

[HttpGet]
public dynamic GetCreditors() {
    return db.Creditors
      .Select(x => new {
      x.CreditorID,
      x.BusinessName,
    }).ToArray()
}

<强> 2。在控制器中使用显式返回类型:

这适用于WebAPI以及不允许动态返回类型的WCF。这是一个更好的&#34;如果你的标准做法是使用静态回报类型,那就接近。

为您的返回类型创建一个类:

public class CreditorResult {
    public int CreditorID { get; set; }
    public string BusinessName { get; set; }
}

然后您的API方法如下所示:

[HttpGet]
public CreditorResult[] GetCreditors() {
    return db.Creditors
      .Select(x => new CreditorResult() {
      x.CreditorID,
      x.BusinessName,
    }).ToArray()
}

第3。使用模型属性来控制输出字段:

当前版本的WebAPI使用JSON.NET作为其序列化程序,旧版本也可以设置为使用它。您可以在模型上指定数据属性,以告知JSON.NET要包含或忽略哪些属性。

如果您使用实体框架的代码优先方法,则可以将属性直接添加到您的类中。如果您正在使用数据库优先方法(代码生成),那么将您的属性放在元数据类中是最安全的。 http://www.ozkary.com/2015/01/add-data-annotations-to-entity.html

如果您只想包含几个字段,则应将[DataContract]添加到类中,并将[DataMember]添加到属性中。只有[DataMember]的属性才会包含在输出中。例如,以下内容仅返回CreditorID和BusinessName:

[DataContract]
public class Creditor
{
    [DataMember]
    [Key]
    public int CreditorID { get; set; }

    [DataMember]
    [Display(Name = "Business Name")]
    [MaxLength(40, ErrorMessage = "Maximum of 40 characters")]
    public string BusinessName { get; set; }
...

如果您想要包含大部分字段并忽略一些字段,则更容易的选择是将[JsonIgnore]添加到您要隐藏的属性中。

public class Creditor
{
    [Key]
    public int CreditorID { get; set; }

    [JsonIgnore]
    [MaxLength(10, ErrorMessage = "Maximum of 10 characters")]
    public string CRKEY { get; set; }

    [Display(Name = "Business Name")]
    [MaxLength(40, ErrorMessage = "Maximum of 40 characters")]
    public string BusinessName { get; set; }
...

还有很多其他方法可以微调输出。查看http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size了解详情。