【问题标题】:ASP.Net Core + EF + OData V4 Core Beta 2ASP.Net Core + EF + OData V4 Core Beta 2
【发布时间】:2018-09-27 14:23:06
【问题描述】:

在配置了 EF 的 ASP.NET Core 上有一个相当基本的 Web API 项目,该项目可以正常使用 Web API。我正在关注this 文章以转换为使用 Odata,但我无法让它正常工作。

我有一个名为 customer 的父对象,它有 2 个子对象:Addresses 和 Person。我已为数据库播种,因此我可以看到那里有数据,并且 Odata 端点看起来不错,因为当您启动项目时,它会显示实体,而 odata/$metadata 会按预期显示 EDM 结构。

我目前唯一遇到的问题是,当我导航到 /odata/customers 等 URL 时,我收到一个空白屏幕。在邮递员中它返回 404。

我已经梳理了 Lucas 的示例项目(我正在关注的文章)并在网上进行了相当多的研究,但不太明白我做错了什么。

我确信这很简单/愚蠢,但欢迎任何建设性的指导:)

** 编辑 ** 为简单起见删除了附加代码(并基于反馈)。如果需要其他信息,请告诉我。

干杯,

亚当

文件路径:Odata\BookingsModelBuilder.cs

using System;
using Microsoft.AspNet.OData.Builder;
using Microsoft.OData.Edm;
using Bookings_Server.OData.Models;


namespace Bookings_Server
{
    public class BookingsModelBuilder
    {
        public IEdmModel GetEdmModel(IServiceProvider serviceProvider)
        {
            var builder = new ODataConventionModelBuilder(serviceProvider);

            builder.EntitySet<Address>("addresses")
                           .EntityType
                           .Filter() // Allow for the $filter Command
                           .Count() // Allow for the $count Command
                           .Expand() // Allow for the $expand Command
                           .OrderBy() // Allow for the $orderby Command
                           .Page() // Allow for the $top and $skip Commands
                           .Select();// Allow for the $select Command; 

            builder.EntitySet<Customer>("customers")
                           .EntityType
                           .Filter() // Allow for the $filter Command
                           .Count() // Allow for the $count Command
                           .Expand() // Allow for the $expand Command
                           .OrderBy() // Allow for the $orderby Command
                           .Page() // Allow for the $top and $skip Commands
                           .Select();// Allow for the $select Command; 

            builder.EntitySet<Person>("people")
                            .EntityType
                            .Filter() // Allow for the $filter Command
                            .Count() // Allow for the $count Command
                            .Expand() // Allow for the $expand Command
                            .OrderBy() // Allow for the $orderby Command
                            .Page() // Allow for the $top and $skip Commands
                            .Select();// Allow for the $select Command; 

            return builder.GetEdmModel();
        }
    }
}

文件路径:EF\DataContext.CS

using Microsoft.EntityFrameworkCore;
using Bookings_Server.OData.Models;

namespace Bookings_Server.EF
{
    public class DataContext : DbContext
    {
        public DataContext(DbContextOptions<DataContext> options) : base(options) { }

        public DbSet<Address> Addresses { get; set; }
        public DbSet<Customer> Customers { get; set; }
        public DbSet<Person> People { get; set; }
        public DbSet<Tenant> Tenants { get; set; }
    }
}

文件路径:Controllers\CustomersController.cs

using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Bookings_Server.EF;
using Bookings_Server.OData.Models;
using Microsoft.AspNet.OData;


namespace Bookings_Server.OData.Controllers
{
    [Produces("application/json")]
    public class CustomersController : ODataController
    {
        private readonly DataContext _context;

        public CustomersController(DataContext context)
        {
            _context = context;
        }

        // GET: odata/customers
        [EnableQuery(PageSize = 20)]       
        public IQueryable<Customer> Get() => _context.Customers.AsQueryable();

        /*
        public IActionResult Get()
        {
            return Ok(_context.Customers.AsQueryable());
        }
        */
    }
}

文件路径:startup.cs

using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNet.OData.Extensions;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace Bookings_Server
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }


        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, BookingsModelBuilder BookingsModelBuilder)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseCors("cors");
            // app.UseMvc();

            // Added for Odata config
            app.UseMvc(routeBuilder =>
            {
                routeBuilder.MapODataServiceRoute("ODataRoutes", "odata", BookingsModelBuilder.GetEdmModel(app.ApplicationServices));
            });

        }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors(options => options.AddPolicy("cors", builder =>
            {
                builder
                .AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader();
            }

            ));
            var connection = @"Server=(localdb)\mssqllocaldb;Database=BookingsDB;Trusted_Connection=True;";
            services.AddDbContext<EF.DataContext>(options => options.UseSqlServer(connection));

            // Add OData configuration
            services.AddOData();
            services.AddTransient<BookingsModelBuilder>();

            services.AddMvc().AddJsonOptions(opt =>
            {
                opt.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                opt.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
            });

        }
    }
}

【问题讨论】:

  • 1.请移除除 Startup 和控制器之外的所有模型。 (太多的代码吓跑了用户) 2. 您需要添加 OData routeBuilder.Count().Filter().OrderBy().Expand().Select().MaxTop(null); 允许的设置 3. 我遇到了同样的问题,您可以在另一个问题中看到解决方法我 asked 看看我的控制器
  • 感谢您的反馈。我会编辑和清理(如果需要,可以添加回来)。也许我做得不对,但是 Odata 设置是在顶部的 BookingsModelBuilder 中定义的,并通过 Startup.cs 调用
  • 我会看看这是否可行,我想我曾经尝试过,但我仍然能够通过扩展其他实体来访问它们

标签: c# entity-framework odata asp.net-core-webapi


【解决方案1】:

好的。解决了这个问题。到头来还是有些傻。我错过了 CustomerContoller.cs 上的装饰器

[ODataRoute("customers")] 

和命名空间:

using Microsoft.AspNet.OData.Routing; 

之后一切都开始正常了。

// GET: odata/customers
[ODataRoute("customers")]
[EnableQuery(PageSize = 20)]       
public IQueryable<Customer> Get() => _context.Customers.AsQueryable();

附加信息:http://odata.github.io/WebApi/03-03-attrribute-routing/

【讨论】:

    【解决方案2】:

    作为一种解决方法,您可以将更改直接应用到现有控制器,此代码可以轻松地进行通用化并添加到基本控制器,这将适用于现有控制器:

    [HttpGet]
    [EnableQuery]
    public async Task<Skill[]> GetFilteredODataList(ODataQueryOptions<Skill> q)
    {
        var skillsQuery = this._context.Skills.AsQueryable();
        if (q?.Filter != null)
        {
            skillsQuery = q.Filter.ApplyTo(skillsQuery, new ODataQuerySettings()) as IQueryable<Skill>;
        }
    
        return await skillsQuery.ToArrayAsync();
    }
    

    【讨论】:

    • 感谢 Johnny5。重构了我的一个控制器以反映您的上述功能,但是我仍然遇到同样的问题(未找到 404 页面)。
    • 去掉 odata 前缀,像普通控制器方法一样点击它。
    • 如果您仍然无法在评论中发布 http url
    • 好的。解决了这个问题。到头来还是有些傻。我缺少装饰器 [ODataRoute("customers")] 和命名空间: using Microsoft.AspNet.OData.Routing;之后一切都开始正常工作。附加信息:odata.github.io/WebApi/03-03-attrribute-routing
    • @leadfollowmove 请发布答案。我会支持它,它将在未来帮助社区中的其他人
    猜你喜欢
    • 1970-01-01
    • 2017-12-02
    • 1970-01-01
    • 2020-07-14
    • 1970-01-01
    • 2019-05-15
    • 2021-11-22
    • 2017-06-30
    • 1970-01-01
    相关资源
    最近更新 更多