有条件地调用web Api

时间:2015-01-23 19:05:06

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

我在数据库中有一个actors的集合,我可以通过以下对webApi的调用获得:

HttpResponseMessage response = await client.GetAsync("api/actors");

这会在我的webapi-controller上触发以下方法:

 // GET: api/Actors
    public IQueryable<Actor> GetActors()
    {
        return db.Actors;
    }

现在我们可以说,我在获取所有赢得奥斯卡奖的演员方面取得了成功。在没有webapi的情况下直接调用DB可能看起来像这样:

return db.actors.where(o=>o.OscarWinner==true);

但是如何使用webApi进行类似的调用呢? Api是否仅限于让我获取所有演员:

HttpResponseMessage response = await client.GetAsync("api/actors");

或一个特定的演员:

HttpResponseMessage response = await client.GetAsync("api/actors/1");

这一定是我认为的常见请求,能够根据某些条件获取对象列表吗?

编辑:

 public IQueryable<Actor> GetUsers(int CountrId)
    {
        var list = db.Actors.Where(o => o.CountryId == CountryId);
        return list;
    }

1 个答案:

答案 0 :(得分:0)

引用来自Professional ASP.NET MVC 4的书

  

要接受来自请求的传入值,您可以将参数放在您的操作上,就像MVC一样,Web API框架将自动为这些操作参数提供值。与MVC不同,HTTP主体的值和从其他地方(例如来自URI)获取的值之间存在强烈的界线。
  默认情况下,Web API将假定简单类型的参数(即内部类型,字符串,日期,时间以及来自字符串的类型转换器的任何内容)取自非正文值和复杂类型(其他所有内容)是从身体中取出的。还有一个额外的限制:只有一个值可以来自身体,该值必须代表整个身体。

所以你有两个选择。如果您只想使用简单的过滤器,那么它就足以从查询字符串中获取它。更好的选择是编写一个类,它将从JSON请求体中映射其属性。我将提供一个示例,我如何从查询字符串中映射过滤器数据,因为我想允许我的用户通过查询字符串查询数据。我写了一个用ModelBinder绑定的过滤器类。

1。查询字符串

HttpResponseMessage response = await client.GetAsync("api/actors/?oscarWinner=true");

相应的行动方法

// GET: api/Actors
public IQueryable<Actor> GetActors(bool oscarWinner = false)
{
    return db.Actors.Where(actor=>actor.OscarWinner == oscarWinner);
}

2。 ModelBinder的

条件过滤器类

/// <summary>
/// Condition Filter
/// </summary>
public class ConditionFilter
{
    /// <summary>
    /// Oscar Winner
    /// </summary>
    public bool? OscarWinner { get; set; }
    /// <summary>
    /// Page you want to get. Counting from 0.
    /// </summary>
    public int? Page { get; set; }
    /// <summary>
    /// Number of jobs on page. Default page size 1000.
    /// </summary>
    public int? PageSize { get; set; }
}

条件过滤器活页夹

public class ConditionFilterBinder : IModelBinder
{
    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType != typeof (ConditionFilter))
        {
            return false;
        }

        var val = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        if (val == null)
        {
            return false;
        }

        var queryString = HttpUtility.ParseQueryString(val.RawValue.ToString());

        var conditionFilter = new ConditionFilter
        {
            Page = queryString.GetValueFromQueryString<int>("page"), 
            PageSize = queryString.GetValueFromQueryString<int>("pageSize"),
            OscarWinner = queryString.GetValueFromQueryString<bool>("oscarWinner")
         };

         bindingContext.Model = conditionFilter;

         return true;
         }
    }
}

并将其与您的操作方法一起使用

public List<Actor> GetActors([ModelBinder(BinderType = typeof(ConditionFilterBinder))] ConditionFilter conditionFilter = null)
{
    //just to be sure, that we will not take some huge amount of data from database
    const int MAX_ACTOR_COUNT = 1000;
    var page = 0;
    var pageSize = MAX_ACTOR_COUNT;
    var actors = db.Actors;
    if (conditionFilter != null)
    {
        if(conditionFilter.OscarWinner.HasValue && conditionFilter.OscarWinner.Value)
        {
            actors = actors.Where(actor => actor.OscarWinner)
        }
        if (conditionFilter.Page.HasValue)
        {
            page = conditionFilter.Page.Value;
        }

        if (conditionFilter.PageSize.HasValue)
        {
            pageSize = conditionFilter.PageSize.Value > MAX_ACTOR_COUNT ? MAX_ACTOR_COUNT : conditionFilter.PageSize.Value;
        }
    }
    return actors.Skip(page * pageSize).Take(pageSize);
}

通过此实现,您可以调用您的操作方法,例如此

HttpResponseMessage response = await client.GetAsync("api/actors?oscarWinner=true&page=3&pageSize=100");

只是为了完成,这是我的GetValueFromQueryString助手类

/// <summary>
/// Extension method for name value collection
/// </summary>
public static class NameValueCollectionExtensions
{
    /// <summary>
    /// Get typed value from query string
    /// </summary>
    /// <param name="queryString"></param>
    /// <param name="value"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static T? GetValueFromQueryString<T>(this NameValueCollection queryString, string value) where T : struct, IConvertible
    {
        if (queryString[value] != null)
        {
            var thisType = default(T);
            var typeCode = thisType.GetTypeCode();

            switch (typeCode)
            {
                case TypeCode.Boolean:
                    {
                        bool queryStringValue;
                        if (bool.TryParse(queryString[value], out queryStringValue))
                        {
                            return (T)Convert.ChangeType(queryStringValue, typeCode);
                        }
                    }
                    break;
                case TypeCode.Int32:
                case TypeCode.Int64:
                    {
                        if (typeof(T).IsEnum)
                        {
                            var numberValue = queryString.GetValueFromQueryString<int>(value);
                            if (numberValue.HasValue && Enum.IsDefined(typeof(T), numberValue.Value))
                            {
                                return (T)(object)numberValue;
                            }
                            else
                            {
                                T queryStringValueForEnum;
                                if (Enum.TryParse(queryString[value], true, out queryStringValueForEnum))
                                {
                                    return queryStringValueForEnum;
                                }
                            }
                        }

                        int queryStringValue;
                        if (int.TryParse(queryString[value], out queryStringValue))
                        {
                            return (T)Convert.ChangeType(queryStringValue, typeCode);
                        }
                    }
                    break;
                case TypeCode.DateTime:
                    {
                        DateTime queryStringValue;
                        if (DateTime.TryParse(queryString[value], out queryStringValue))
                        {
                            return (T)Convert.ChangeType(queryStringValue, typeCode);
                        }
                        break;
                    }
            }
        }

        return null;
    }

    /// <summary>
    /// Get string value from query string
    /// </summary>
    /// <param name="queryString"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static string GetValueFromQueryString(this NameValueCollection queryString, string value)
    {
        return queryString[value];
    }
}