Asp.Net 核心 MVC 应用程序中的 OData 控制器

OData Controller withing Asp.Net Core MVC application

我正在 ASP .NET Core 3.1 MVC 中开发一个项目,现在我想添加一些 API 控制器 到 return 对象列表。 为此,我想使用 OData Controller 8.0.0 版,这样我就可以获得 quarriable 数据以提高大型数据表的性能

我是 ASP .NET Core 和 OData 的新手。任何人都可以解释如何配置我的项目的启动文件,以便我可以同时 运行 MVC 和 OData 控制器。 请分享一些示例代码

首先,您有一个 MVC 项目,因为 MVC 项目也可以公开 API,所以 OData 也应该适用于 MVC 项目。首先,假设您已经集成了 ef core 并且在我的解决方法中,我按照 this document 为模型创建数据库和数据管理视图。

然后让我们添加OData。安装这个 nuget 包:Microsoft.AspNetCore.OData,修改你的 startup.cs 文件,请参阅 ConfigurationGetEdmModel 方法。

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.EntityFrameworkCore;
using WebMvcNet5.Data;
using WebMvcNet5.Models;
using Microsoft.OData.ModelBuilder;
using Microsoft.AspNetCore.OData;
using Microsoft.OData.Edm;

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

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();

            services.AddControllers().AddOData(opt => opt.EnableQueryFeatures().AddRouteComponents("odata", GetEdmModel()));
            services.AddDbContext<WebMvcNet5Context>(options =>
                    options.UseSqlServer(Configuration.GetConnectionString("WebMvcNet5Context")));
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }
            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseRouting();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
        }

        private static IEdmModel GetEdmModel()
        {
            ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
            //My model is Movie, and what I set "GetMovie" here means I need to create a controller named "GetMovieController"
            builder.EntitySet<Movie>("GetMovie");
            return builder.GetEdmModel();
        }
    }
}

那么这是我的控制器:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Query;
using WebMvcNet5.Data;

namespace WebMvcNet5.Controllers
{
    [Route("odata/[Controller]")]
    public class GetMovieController : Controller
    {
        private readonly WebMvcNet5Context _context;

        public GetMovieController(WebMvcNet5Context context)
        {
            _context = context;
        }

        [EnableQuery]
        public IActionResult Get()
        {
            return Ok(_context.Movie);
        }
    }
}

我的测试结果:

我已设法解决 运行 公开 OData API 的 Web 应用程序的问题 问题在 Startup.cs 文件

我正在使用 Asp.Net Core 3.1 和 Microsoft.AspNetCore.OData v7.3.0

我的Startup.cs文件代码是:

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

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));


        services.AddIdentity<AppUser, AppRole>(opt =>
        {
            opt.User.RequireUniqueEmail = true;
        })
            //.AddDefaultUI(UIFramework.Bootstrap4)
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();

        //add services
        services.RegisterServices();

        services.AddScoped<ViewRendererService>();

        services.AddMvc()
            .AddMvcOptions(options => options.EnableEndpointRouting = false)
            .AddNewtonsoftJson(options =>
            {
                options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver();
            })
            .SetCompatibilityVersion(CompatibilityVersion.Version_3_0);

        services.AddOData();

        services.AddRouting();
        services.AddControllersWithViews();
        services.AddRazorPages();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ApplicationDbContext dataContext)
    {
        if (env.EnvironmentName == "Development")
        {
            dataContext.Database.Migrate();
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseDeveloperExceptionPage();
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseCookiePolicy();

        app.UseAuthentication();

        app.UseRequestLocalization();

        app.UseMvc(routes =>
        {
            routes.Select().Filter().OrderBy().Expand().Count().SkipToken().MaxTop(null);
            routes.MapODataServiceRoute("odata", "api", GetEdmModel());
            routes.MapRoute(
                name: "areas",
                template: "{area:exists}/{controller=Home}/{action=Index}/{id?}"
            );

            routes.MapRoute(
                name: "Finance",
                template: "{area:exists}/{controller=Account}/{action=Index}/{id?}"
            );

            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });

    }
    private static IEdmModel GetEdmModel()
    {
        var builder = new ODataConventionModelBuilder();
        builder.EntitySet<Product>("ProductApi");
        builder.EntitySet<ProductUOM>("ProductUomApi");

        ActionConfiguration action = builder.EntityType<Product>().Action("GetUOM");
        action.Parameter<long>("id");
        action.ReturnsCollectionFromEntitySet<Product>("Product");

        return builder.GetEdmModel();
    }
}

希望这对其他人有帮助