不使用EF

时间:2017-02-23 15:29:04

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

我正在构建WebApi2项目以公开一些RESTful服务。让我们说我有以下模型对象。

public class Person
{
    public string Name { get; set; }

    public DateTime? Birthdate { get; set; }

    public int Status { get; set; }

    public List<Account> Accounts { get; set; }
}

public class Account
{
    public decimal Amount { get; set; }

    public string Code { get; set; }

    public DateTime Expiry { get; set; }
}

在我的服务中,我必须转到2个不同的系统来检索Person的数据和Person的帐户信息。显然,服务实现看起来像

    [HttpGet]
    [Route("Person/{id:int}")]
    public IHttpActionResult Get(string id)
    {
        var person = new Person();
        person = GetPersonFromSystemA(id);

        if (person.Status == 2)
        {
            person.Accounts = GetPersonAccountsFromSystemB(id);
        }

        return this.Ok(person);
    }

在这种情况下我根本不能使用EF,因此OData非常棘手。

我有一些要求,我需要为服务客户端提供过滤功能。客户端可以决定返回对象的哪些字段,这也意味着如果客户端不喜欢包含该人的帐户信息,我应该跳过对系统B的第二次调用以避免整个子对象。

我做了一些快速搜索,但我找不到类似的解决方案了。我知道我可以实现自己的过滤语法,并使用所有自定义代码来使用过滤(通过大量的i​​f / else)。

我正在寻找更优雅解决方案的一些想法。

2 个答案:

答案 0 :(得分:0)

构建OData服务不需要实体框架。如果您不使用OData,您可能必须实现自己的IQueryable,这是OData开箱即用的。

一些示例代码。

具有一些附加属性的模型类

public class Person
{
    [Key]
    public String Id { get; set; }
    [Required]
    public string Name { get; set; }
    public DateTime? Birthdate { get; set; }
    public int Status { get; set; }
    public List<Account> Accounts { get; set; }
}

public class Account
{
    [Key]
    public String Id { get; set; }
    [Required]
    public decimal Amount { get; set; }
    public string Code { get; set; }
    public DateTime Expiry { get; set; }
}

<强> WebApiConfig.cs

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.MapODataServiceRoute("odata", null, GetEdmModel(), new DefaultODataBatchHandler(GlobalConfiguration.DefaultServer));
        config.EnsureInitialized();
    }

    private static IEdmModel GetEdmModel()
    {
        ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
        builder.Namespace = "YourNamespace";
        builder.ContainerName = "DefaultContainer";
        builder.EntitySet<Person>("People");
        builder.EntitySet<Account>("Accounts");
        var edmModel = builder.GetEdmModel();
        return edmModel;
    }
}

控制器方法

[EnableQuery]
public class PeopleController : ODataController
{
    public IHttpActionResult Get()
    {
        return Ok(SomeDataSource.Instance.People.AsQueryable());
    }
}

您需要包含 Microsoft.AspNet.OData Nuget包。

有关更多指导,请参阅以下内容。它使用内存数据源,但概念无论如何都是一样的。

http://www.odata.org/blog/how-to-use-web-api-odata-to-build-an-odata-v4-service-without-entity-framework/

答案 1 :(得分:0)

在构建网络API时,您通常希望过滤您的响应并仅获取某些字段。您可以通过多种方式实现,其中一种方式如上所述。另一种方法是,您可以在Web api中使用数据整形。

如果您有控制器操作:

public IHttpActionResult Get(string fields="all")
{
    try
    {
        var results = _tripRepository.Get();
        if (results == null)
            return NotFound();
        // Getting the fields is an expensive operation, so the default is all,
        // in which case we will just return the results
        if (!string.Equals(fields, "all", StringComparison.OrdinalIgnoreCase))
        {
            var shapedResults = results.Select(x => GetShapedObject(x, fields));
            return Ok(shapedResults);
        }
        return Ok(results);
    }
    catch (Exception)
    {
        return InternalServerError();
    }
}

然后你的GetShapedData方法可以进行过滤:

public object GetShapedObject<TParameter>(TParameter entity, string fields)
{
    if (string.IsNullOrEmpty(fields))
        return entity;
    Regex regex = new Regex(@"[^,()]+(\([^()]*\))?");
    var requestedFields = regex.Matches(fields).Cast<Match>().Select(m => m.Value).Distinct();
    ExpandoObject expando = new ExpandoObject();

    foreach (var field in requestedFields)
    {
        if (field.Contains("("))
        {
            var navField = field.Substring(0, field.IndexOf('('));

            IList navFieldValue = entity.GetType()
                                    ?.GetProperty(navField, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public)
                                    ?.GetValue(entity, null) as IList;
            var regexMatch = Regex.Matches(field, @"\((.+?)\)");
            if (regexMatch?.Count > 0)
            {
                var propertiesString = regexMatch[0].Value?.Replace("(", string.Empty).Replace(")", string.Empty);
                if (!string.IsNullOrEmpty(propertiesString))
                {
                    string[] navigationObjectProperties = propertiesString.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

                    List<object> list = new List<object>();
                    foreach (var item in navFieldValue)
                    {
                        list.Add(GetShapedObject(item, navigationObjectProperties));
                    }

                    ((IDictionary<string, object>)expando).Add(navField, list);
                }
            }
        }
        else
        {
            var value = entity.GetType()
                          ?.GetProperty(field, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public)
                          ?.GetValue(entity, null);
            ((IDictionary<string, object>)expando).Add(field, value);
        }
    }

    return expando;
}

查看我的博客,了解详细信息:https://jinishbhardwaj.wordpress.com/2016/12/03/web-api-supporting-data-shaping/