【问题标题】:Conditional call to webApi对 webApi 的条件调用
【发布时间】:2015-01-24 21:19:11
【问题描述】:

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

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

这会在我的 webapi 控制器上触发以下方法:

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

【问题讨论】:

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


    【解决方案1】:

    引用自专业 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。模型绑定器

    条件过滤器类

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

    【讨论】:

    • 很好的答案,谢谢!假设我的演员表有一个代表一个国家的外键。我希望能够将该 Int 传递给我的查询字符串。我用 db-call 的样子更新了我的问题。谢谢
    • 在这种情况下,您已经完成了。你应该像这样调用你的 API 方法var response = await client.GetAsync("api/actors/?countrId=42");
    • 啊哈完美!谢谢
    猜你喜欢
    • 2015-08-02
    • 2012-06-20
    • 2013-12-19
    • 2018-11-26
    • 1970-01-01
    • 1970-01-01
    • 2020-01-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多