Маршрут атрибутов OData не работает должным образом в ASP.NET Core 5 с Microsoft.AspNetCore.OData v8.0.0-preview2

Я работаю над API ASP.NET Core 5 с Entity Framework Core 5, и я использую Microsoft.AspNetCore.Odata v8.0.0-preview2

Я просмотрел блоги Сэма Сюй; Маршрутизация в ASP.NET Core OData 8.0 Preview и ASP.NET Core OData 8.0 Preview для.NET 5

Я выполняю интеграцию с существующей базой данных SQL Server, схему которой я не контролирую, поэтому мне приходится работать с тем, что предоставляется.

В базе данных есть таблица "Организации" и таблица "Местоположение".

Я установил OrganizationsController и OrganizationLocationsController.

Маршрутизация моего OrganizationsController, похоже, работает должным образом, так как я могу выполнить GET, чтобы...

https://{{url}}/odata-v1/organizations

и получить список всех организаций в таблице, и я могу ПОЛУЧИТЬ, чтобы...

https://{{url}}/odata-v1/organizations/'1000'

и вернуть указанную запись организации.

Теперь таблица OrganizationLocations может иметь несколько расположений для данного OrganizationID. Итак, что я хочу сделать, так это получить...

https://{{url}}/odata-v1/organizations('1000')/locations

или, желательно...

https://{{url}}/odata-v1/organizations/'1000'/locations

и вернуть список всех записей OrganizationLocation для указанного OrganizationID.

Однако, когда я пытаюсь выполнить этот вызов в Postman, он возвращает 404 NOT FOUND.

Если я установил точку останова в Startup.cs -> Configure method, в разделе app.Use(next => context => ... в строке

if (endpoint == null)

и проверьте переменную конечной точки, она равна нулю.

Почему значение конечной точки равно нулю? Что мне не хватает?

Вот мой Startup.cs

using System;
using System.Collections;
using System.Collections.Generic;
using CDR.API.Azure.Extensions;
using CDR.API.Data;
using CDR.API.Middleware;
using EII.CDR.Models.ERP.M1;
using MediatR;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.OData;
using Microsoft.AspNetCore.OData.Routing;
using Microsoft.AspNetCore.OData.Routing.Template;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OData.Edm;
using Microsoft.OData.ModelBuilder;
using Microsoft.OpenApi.Models;

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

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            // Add Azure AD OAUTH2.0 Authentication Services
            services.AddAuthentication(sharedOptions =>
                {
                    sharedOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
                })
                .AddAzureAdBearer(options => Configuration.Bind("AzureAd", options));

            // Set up database access
            ConfigureDatabase(services);

            services.AddHttpContextAccessor();
            services.AddRouting();
            services.AddControllers();
            services.AddOData(
                option => option.AddModel("odata-v1", GetV1EdmModel())
                .Select()
                .Expand()
                .Filter()
                .OrderBy()
                .Count());

            services.AddScoped(typeof(IPipelineBehavior<,>), typeof(UserIdPipe<,>));
            services.AddMediatR(typeof(Startup).Assembly);
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseRouting();  // UseRouting should appear before any other middleware.

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseStaticFiles();

                // Middleware for testing endpoint routes
                app.Use(next => context =>
                {
                    var endpoint = context.GetEndpoint();
                    if (endpoint == null)
                    {
                        return next(context);
                    }

                    IEnumerable templates;
                    IODataRoutingMetadata metadata = endpoint.Metadata.GetMetadata<IODataRoutingMetadata>();
                    if (metadata != null)
                    {
                        templates = metadata.Template.GetTemplates();
                    }

                    return next(context); // put a breakpoint here when testing.
                });
            }

            app.UseHttpsRedirection();

            app.UseAuthentication();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }

        protected virtual void ConfigureDatabase(IServiceCollection services)
        {
            var sqlTransientErrors = new List<int>() { 10928, 10929, 10053, 10054, 10060, 40197, 40540, 40613, 40143, 64 };

            services.AddDbContext<M1Context>(options =>
            {
                options.UseSqlServer(
                    Configuration.GetConnectionString("M1DbConnectionString"),
                    sqlOptions =>
                    {
                        sqlOptions.EnableRetryOnFailure(5, TimeSpan.FromSeconds(30), sqlTransientErrors);
                        sqlOptions.CommandTimeout(Convert.ToInt32(Configuration["DbSettings:M1DbCommandTimeout"]));
                    });
            });
        }

        private static IEdmModel GetV1EdmModel()
        {
            var builder = new ODataConventionModelBuilder();
            builder.EntitySet<Organization>("Organizations");
            builder.EntitySet<OrganizationLocation>("OrganizationLocations");
            builder.EntitySet<OrganizationContact>("OrganizationContacts");
            return builder.GetEdmModel();
        }
    }
}

Вот мой OrganizationsController;

using System;
using System.Linq;
using CDR.API.Data;
using CDR.Models.ERP.M1;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Query;
using Microsoft.AspNetCore.OData.Results;
using Microsoft.AspNetCore.OData.Routing.Attributes;
using Microsoft.AspNetCore.OData.Routing.Controllers;

namespace CDR.API.Controllers.V1.ODataControllers
{
    [Authorize]
    [ODataRoutePrefix("organizations")]
    public class OrganizationsController : ODataController
    {
        private readonly M1Context context;

        public OrganizationsController(M1Context context)
        {
            this.context = context ?? throw new ArgumentNullException(nameof(context));
        }

        [EnableQuery(AllowedQueryOptions = AllowedQueryOptions.Supported, PageSize = 2000)]
        public IQueryable<Organization> GetOrganizations()
        {
            return context.Organizations;
        }

        [ODataRoute("{id}")]
        [EnableQuery(AllowedQueryOptions = AllowedQueryOptions.Select)]
        public SingleResult<Organization> GetOrganizationById([FromRoute] string id)
        {
            return new SingleResult<Organization>(context.Organizations.Where(o => o.OrganizationId == id));
        }
    }
}

Вот мой контроллер OrganizationLocations;

using System;
using System.Linq;
using CDR.API.Data;
using CDR.Models.ERP.M1;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.OData.Query;
using Microsoft.AspNetCore.OData.Results;
using Microsoft.AspNetCore.OData.Routing.Attributes;
using Microsoft.AspNetCore.OData.Routing.Controllers;

namespace CDR.API.Controllers.V1.ODataControllers
{
    [Authorize]
    [ODataRoutePrefix("organizations({id})")]
    public class OrganizationLocationsController : ODataController
    {
        private readonly M1Context context;

        public OrganizationLocationsController(M1Context context)
        {
            this.context = context ?? throw new ArgumentNullException(nameof(context));
        }

        [ODataRoute("locations")]
        [EnableQuery(AllowedQueryOptions = AllowedQueryOptions.Supported, PageSize = 2000)]
        public IQueryable<OrganizationLocation> GetOrganizationLocations(string id)
        {
            return context.OrganizationLocations.Where(ol => ol.OrganizationId == id);
        }

        [ODataRoute("locations({locationId})")]
        [EnableQuery(AllowedQueryOptions = AllowedQueryOptions.Select)]
        public SingleResult<OrganizationLocation> GetOrganizationLocationById(string id, string locationId)
        {
            return new SingleResult<OrganizationLocation>(context.OrganizationLocations.Where(ol => ol.OrganizationId == id && ol.LocationId == locationId));
        }
    }
}

0 ответов

Другие вопросы по тегам