1
votes

I'm creating a project which will have an Angular frontend that talks to a .net core Web Api project, using OData to provide rich querying. I've added the OData Nuget package to my angular project.

I've followed the following tutorial: https://devblogs.microsoft.com/odata/simplifying-edm-with-odata/

In my 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");
                }
            });
}

In my API Controller class (called 'Assets' here)

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();
      }
}

Problem 1

If I remove the ApiController attribute from my Web API Controller class, the url http://localhost:xxxx/api/Assets/All simply renders my SPA again.

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

Problem 2

If I add this code again to my class, the following happens:

Calling http://localhost:xxxx/api/Assets?$count=true should return a list like this:

{
  "@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",
    }
  ]
}

but instead this endpoint returns :

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

Does anyone have any ideas what is happening or what I am doing wrong?

2

2 Answers

0
votes

Try removing this line:

routes.EnableDependencyInjection();
0
votes

What I'm seeing in your code is that you're getting all assets using a service, but that's not your context is it? The OData endpoints need to return a context to work against using some black magic.

I don't like it, but I believe you need to inject your context into your controller if you want to use OData the way you're trying to