首页 > 解决方案 > 为 Angular SPA 应用程序结合 OData 和 .NET API

问题描述

我正在创建一个项目,该项目将具有与 .net 核心 Web Api 项目对话的 Angular 前端,使用 OData 提供丰富的查询。我已将 OData Nuget 包添加到我的 Angular 项目中。

我遵循了以下教程: https ://devblogs.microsoft.com/odata/simplifying-edm-with-odata/

在我的Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddSpaStaticFiles(configuration =>
            {
                configuration.RootPath = "ClientApp/dist";
            });

    /* snipped some code about DbContext and AutoMapper, not relevant */
    services.AddMvcCore(action => action.EnableEndpointRouting = false)
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    services.AddOData();
    services.AddODataQueryFilter();
}

private static IEdmModel GetEdmModel()
{
     var builder = new ODataConventionModelBuilder();
     builder.EntitySet<Asset>("Assets");

     return builder.GetEdmModel();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
     app.UseStaticFiles();
     app.UseSpaStaticFiles();

     app.UseMvc(routes =>
     {
         routes.EnableDependencyInjection();

         routes.Select().Filter().OrderBy().Expand().Count().MaxTop(10);
         routes.MapODataServiceRoute("api", "api", GetEdmModel());

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

            app.UseSpa(spa =>
            {
                // To learn more about options for serving an Angular SPA from ASP.NET Core,
                // see https://go.microsoft.com/fwlink/?linkid=864501

                spa.Options.SourcePath = "ClientApp";

                if (env.IsDevelopment())
                {
                    spa.UseAngularCliServer(npmScript: "start");
                }
            });
}

在我的API 控制器类中(这里称为“资产”)

public class AssetsController : ControllerBase
{
      public AssetsController(IAssetService _service)
      {
            this._service = _service;
      }

      [HttpGet("[action]")]
      [EnableQuery()]
      public ActionResult<IEnumerable<Asset>> All()
      {
         var assets = _service.GetAllAssets();
         return assets.ToList();
      }
}

问题 1

如果我从 Web API Controller 类中删除 ApiController 属性,则 URL http://localhost:xxxx/api/Assets/All只会再次呈现我的 SPA。

    [Route("api/[controller]")]
    [ApiController]

问题 2

如果我再次将此代码添加到我的班级,则会发生以下情况:

调用http://localhost:xxxx/api/Assets ?$count=true 应该返回如下列表:

{
  "@odata.context": "https://localhost:44374/api/$metadata#Assets",
  "@odata.count": 2,
  "value": [
    {
      "Id": "9cef40f6-db31-4d4c-997d-8b802156dd4c",
      "Name": "Asset 1",
   },
    {
      "Id": "282be5ea-231b-4a59-8250-1247695f16c3",
      "Name": "Asset 2",
    }
  ]
}

但相反,此端点返回:

[
    {
      "Id": "9cef40f6-db31-4d4c-997d-8b802156dd4c",
      "Name": "Asset 1",
   },
    {
      "Id": "282be5ea-231b-4a59-8250-1247695f16c3",
      "Name": "Asset 2",
    }
]

有谁知道发生了什么或我做错了什么?

标签: angular.net-coreodata

解决方案


我在您的代码中看到的是您正在使用服务获取所有资产,但这不是您的上下文,是吗?OData 端点需要返回一个上下文来对抗使用一些黑魔法。

我不喜欢它,但我相信如果你想以你尝试的方式使用 OData,你需要将你的上下文注入你的控制器


推荐阅读