【问题标题】:How to create custom entity for Web API 2 OData Data controller如何为 Web API 2 OData 数据控制器创建自定义实体
【发布时间】:2016-04-05 15:20:28
【问题描述】:

我需要将传统的 Web API 2 数据控制器迁移到 OData v4 样式的数据控制器。这很容易使用标准的一对一表到实体关系,但我现在需要在我的数据控制器响应中使用几个不同的表(没有真正的约束)。我无法弄清楚如何在我的 WebAPI.config 文件中注册这个新的自定义“实体”。

这是我的 WebAPIconfig.cs 的示例:

using System.Linq;
using System.Web.Http;
using System.Web.OData.Builder;
using System.Web.OData.Extensions;
using System.Web.OData.Routing;
using System.Web.OData.Routing.Conventions;
using MyProject.Models;

namespace MyProject
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and routes
            config.MapHttpAttributeRoutes();

            //OData configuration
            ODataModelBuilder builder = new ODataConventionModelBuilder();
            builder.EntitySet<Order>("orders");
            builder.EntitySet<Customer>("customers");

            //what goes here for my "custom" entity?

            var _model = builder.GetEdmModel();
            var defaultConventions = ODataRoutingConventions.CreateDefaultWithAttributeRouting(config, _model);

            //var defaultConventions = ODataRoutingConventions.CreateDefault();
            var conventions = defaultConventions.Except(
                    defaultConventions.OfType<MetadataRoutingConvention>());

            config.MapODataServiceRoute(
                routeName: "ODataRoute",
                routePrefix: "api",
                routingConventions: conventions,
                pathHandler: new DefaultODataPathHandler(),
                model: _model);         

            //ensure JSON responses
            var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");
            config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
        }
    }
}

这是我的 Web API 2 数据控制器的示例:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using MyProject.Models;

namespace MyProject.DataControllers
{
    public class OrderDetailsController : ApiController
    {
        public OrderDetails GetOrderDetails(int id)
        {
            var ctx = new MyDatabaseEntities();
            var details = new OrderDetails();
            var order = ctx.Orders.FirstOrDefault(o => o.orderID == id);
            if (order == null)
            {
                return details; //return an empty details object to the UI and abandon this code
            }

            //Data objects necessary for the order details page
            IEnumerable<orderCertification> coupons = ctx.Coupons;
            var importances     = ctx.OrderImportances.Where(x => x.ImportanceId == order.ImportanceId).Where(x => (x.Type == "IMPORTANCES")) ?? null;
            var rankings        = ctx.OrderImportances.Where(x => x.ImportanceId == order.ImportanceId).Where(x => (x.Type == "RANK")) ?? null;
            var profits         = ctx.OrderImportances.Where(x => x.ImportanceId == order.ImportanceId).Where(x => (x.Type == "PROFIT")) ?? null;
            var address         = ctx.CustomerAddress.Where(c => c.OrderId == order.Id) ?? null;
            var email           = ctx.CustomerEmail.Where(c => c.Id == order.Id).Where(x => x.Type == "EMAIL") ?? null;         
            var giftcards       = ctx.GiftCardAssignments.Where(c => c.CardID == order.CardID).FirstOrDefault().ToList() ?? null;
            var customerCoupons = coupons.Where(c => giftCards.Any(o => o.GiftCardID == c.Id)).OrderBy(c => c.CouponName) ?? null;

            //lots of other fun and crazy properties get set here!! etc etc.

            //Set the order details properties 
            details.OrderImportances    = importances;
            details.OrderRankings       = rankings;
            details.OrderProfits        = profits;
            details.OrderAddress        = address;
            details.OrderEmail          = email;
            details.OrderGiftCards      = giftcards;
            details.OrderCoupons        = customerCoupons;
            details.OrderDescription    = "This is my order description string.";

            return details;
        }
    }
}

下面是我的 OrderDetails() 类当前的示例:

using System.Collections.Generic;

namespace MyProject.Models
{
    public class OrderDetails
    {

        public IEnumerable<OrderImportance> OrderImportances { get; set; }
        public IEnumerable<OrderImportance> OrderRankings { get; set; }
        public IEnumerable<OrderImportance> OrderProfits { get; set; }
        public string OrderAddress { get; set; }
        public string OrderEmail { get; set; }
        public IEnumerable<OrderGiftCard> OrderGiftCards { get; set; }
        public IEnumerable<OrderCoupon> OrderCoupons { get; set; }
        public string OrderDescription { get; set; }

    }
}

如何制作此 Web API 控制器的 OData 版本以及如何在我的 WebAPIConfig.cs 中为其注册 OrderDetails 类?

【问题讨论】:

    标签: entity-framework odata asp.net-web-api2 data-modeling odatacontroller


    【解决方案1】:

    OrderDetails 似乎没有密钥属性。因此,它不是实体类型(有键的命名结构化类型),而是复杂类型(由一组属性组成的无键命名结构化类型) .

    由于复杂类型没有自己的标识(即键),因此它们不能在 OData 服务中作为实体集公开。这意味着您不会在模型构建器中配置OrderDetails,也不会为OrderDetails 创建单独的控制器。

    将现有 GetOrderDetails 方法迁移到 OData 的最直接方法是将其重新定义为绑定到 orders 实体集的 OData functionActions and Functions in OData v4 Using ASP.NET Web API 2.2 提供了关于定义和配置 OData 函数的很好的教程,但这里是您需要做的事情的要点。

    WebApiConfig.Register中声明函数:

    builder.EntityType<Order>().Function("GetOrderDetails").Returns<OrderDetails>();
    

    在控制器中为orders实体集定义函数:

    public class OrdersController : ODataController
    {
        // Other methods for GET, POST, etc., go here.
    
        [HttpGet]
        public OrderDetails GetOrderDetails([FromODataUri] int key)
        {
            // Your application logic goes here.
        }
    }
    

    最后调用函数如下:

    GET http://host/api/orders(123)/Default.GetOrderDetails
    

    注意Default 是服务的默认命名空间,通常在调用绑定函数时需要。要更改此设置,您可以设置builder.Namespace,也可以使用config.EnableUnqualifiedNameCall(true) 启用不合格的函数调用。

    【讨论】:

    • 美丽。我最终在配置中使用了 EnableUnqualifiedNameCall(true)。我的 api 调用现在看起来像这样:/api/orders(250)/GetOrderDetails/ 这看起来很棒!也很容易实现。谢谢你的解释。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-20
    • 2016-05-03
    • 1970-01-01
    • 2015-08-18
    • 2017-11-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多