using ODataRoutePrefix and ODataRoute for OData AttributeRouting is not working

前提是你 提交于 2021-01-25 07:57:42

问题


Note: This is not a duplicate since I'm using a completely new implementation version of OData in AspNetCore.

Based on this confusing article by Microsoft, I'm trying to use AttributeRoutingConvetion and ultimately using ODataRoutePrefix and ODataRoute to route OData requests using Asp.net Core 5 Web API and Microsoft.AspNetCore.OData Version="8.0.0-preview3"(please pay attention to version).

Here is my code :

Startup.cs

 public void ConfigureServices(IServiceCollection services)
        {

            services.AddControllers();
           

            services.TryAddEnumerable(ServiceDescriptor.Transient<IODataControllerActionConvention, AttributeRoutingConvention>());
            services.AddOData(
                opt => opt.AddModel("odata",GetEdmModel()).Select().Count().Filter().OrderBy().SetAttributeRouting(true)
                );
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthorization();

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

        public IEdmModel GetEdmModel()
        {
            var builder = new ODataConventionModelBuilder();
            builder.EntitySet<WeatherForecast>("WeatherForecast2");
            return builder.GetEdmModel();
        }

and here is my controller :

    [ODataRoutePrefix("WFC")]
    public class WeatherForecast2Controller : ODataController
    {
        private static readonly string[] Summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };

        private readonly ILogger<WeatherForecast2Controller> _logger;

        public WeatherForecast2Controller(ILogger<WeatherForecast2Controller> logger)
        {
            _logger = logger;
        }

        [HttpGet]
        [EnableQuery]
        public IEnumerable<WeatherForecast> Get()
        {
            var rng = new Random();
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = rng.Next(-20, 55),
                Summary = Summaries[rng.Next(Summaries.Length)]
            })
            .ToArray();
        }


        [HttpGet]
        [EnableQuery]
        [ODataRoute("AnotherGet")]
        public IEnumerable<WeatherForecast> AnotherGet()
        {
            var rng = new Random();
            return Enumerable.Range(1, 3).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = rng.Next(-20, 55),
                Summary = Summaries[rng.Next(Summaries.Length)]
            })
            .ToArray();
        }
    }

Now what I expect is calling the https://localhost:44346/WFC/AnotherGet return the 3 Weatherforcast result by executing AnotherGet method but I get a 404 error. I have also tried the followings:

~/odata/WeatherForecast2  -  executes Get and returns array of 5 Weatherforcast 
~/odata/WFC/              - 404 not found 
~/odata/WFC/AnotherGet    - 404 not found 
~/WFC/                    - 404 not found 
~/WFC/AnotherGet          - 404 not found 

How can I execute a specific controller and its method ?


回答1:


@nAvid

Thanks for trying ASP.NET Core OData 8.0.

First, in the blog, I mentioned:


 1. ODataRoutePrefixAttribute is an attribute that can, and only can be placed on an OData controller to specify the prefix that will be used for all actions of that controller.
 2. ODataRouteAttribute is an attribute that can, and only can be placed on an action of an OData controller to specify the OData URLs that the action handles.

Second, the path route template defined in the attribute should follow up OData convention spec. That is, the concatenated string from 'ODataRoutePrefixAttribute' and 'ODataRouteAttribute' should pass the OData uri parser.

As an example:

[ODataRoutePrefix("WFC")] 
public class WeatherForecast2Controller : ODataController
{
  ...
   [ODataRoute("AnotherGet")]
   public IEnumerable<WeatherForecast> AnotherGet()
   {
   }
}

The concatenated string for action 'AnotherGet' is "WFC/AnotherGet'. From OData convention URI, WFC/AnotherGet should be a valid OData URI (template). BUT, the Edm model (you built in GetEdmModel) doesn't have anything related "WFC" or "AnotherGet".

So, It's expected that you will get the following response:

  • ~/odata/WFC/ - 404 not found
  • ~/odata/WFC/AnotherGet - 404 not found
  • ~/WFC/ - 404 not found
  • ~/WFC/AnotherGet - 404 not found

For

  • '~/odata/WeatherForecast2 - executes Get and returns array of 5 Weatherforcast ',

that's not OData attribute routing, however it works because it's OData convention routing. The convention routing looks the "EntitySetName" + Controller for the controller. So, public class WeatherForecast2Controller meets that convention. and public IEnumerable<WeatherForecast> Get() meets the query entity set convention routing. So, it works.



来源:https://stackoverflow.com/questions/65551331/using-odatarouteprefix-and-odataroute-for-odata-attributerouting-is-not-working

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!