WebApi icon indicating copy to clipboard operation
WebApi copied to clipboard

ODataRoute template is not working in .Net Core

Open komdil opened this issue 4 years ago • 9 comments

I was using ODataRoute with a template in .Net. I was working fine. Now, I am trying to migrate to .Net Core, but it is not working.

Assemblies affected

I am using Microsoft.AspNetCore.OData

Reproduce steps

My ConfigureServices:

 public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services.AddOData();
            services.AddRouting();
            services.AddMvc();
        }

Configuration:

 public static void Configure(object appBuilder)
        {
            var app = appBuilder as IApplicationBuilder;
            var builder = new ODataConventionModelBuilder(app.ApplicationServices);
            app.UseHttpsRedirection();
            app.UseRouting();
            app.UseAuthorization();
            app.UseODataBatching();
            var edmModel = GetEdmModel(builder);
            app.UseDeveloperExceptionPage();
            app.UseEndpoints(routeBuilder =>
            {
                routeBuilder.EnableDependencyInjection();
                routeBuilder.Select().Filter().Expand();
                routeBuilder.MapODataRoute("OData", "odata", b =>
                {
                    b.AddService(Microsoft.OData.ServiceLifetime.Singleton, sp => edmModel);
                    var customRoutingConvention = new ODataCustomRoutingConvention();
                    var conventions = ODataRoutingConventions.CreateDefault();
                    //Workaround for https://github.com/OData/WebApi/issues/1622
                    conventions.Insert(0, new AttributeRoutingConvention("OData", app.ApplicationServices, new DefaultODataPathHandler()));
                    //Custom Convention
                    conventions.Insert(0, customRoutingConvention);
                    b.AddService<IEnumerable<IODataRoutingConvention>>(Microsoft.OData.ServiceLifetime.Singleton, a => conventions);
                });
            });
        }

        static IEdmModel GetEdmModel(ODataConventionModelBuilder builder)
        {
            builder.EntityType<Student>().HasKey(a => a.Id);
            builder.EntitySet<Student>("Student");
            return builder.GetEdmModel();
        }

Controller:

    public class StudentController : BaseController<Student>
    {
        [EnableQuery]
        [ODataRoute("Student(Id={key})")]
        public override IActionResult Get(string key)
        {
            return Get("Id", key);
        }
    }

Expected result

Get method should work when I send query: https://localhost:44383/odata/Student(Id='DBS')*

Actual result

It is returning 404 when I send query https://localhost:44383/odata/Student(Id='DBS')*

Additional detail

It was working on .Net. Maybe it is happening because of workaround of https://github.com/OData/WebApi/issues/1622*

komdil avatar Jul 11 '20 05:07 komdil

@komdil Can https://localhost:44383/odata/Student('DBS') works at your side?

xuzhg avatar Jul 14 '20 18:07 xuzhg

@xuzhg

@komdil Can https://localhost:44383/odata/Student('DBS') works at your side?

I tried, but I didn't work. Also, putting ODataRoutePrefix is not affecting to my controllers. I researched, but I couldn't find solution

komdil avatar Jul 15 '20 09:07 komdil

@komdil, please note that your controllers should inherit from ODataController. In your case you're inheriting from BaseController (should it be ControllerBase?).

While you can certainly use the ODataRoute attribute, keep in mind that it's not necessary for Get(int key) as it will map to Student({key}) automatically.

habbes avatar Jul 15 '20 09:07 habbes

@komdil, please note that your controllers should inherit from ODataController. In your case you're inheriting from BaseController (should it be ControllerBase?).

While you can certainly use the ODataRoute attribute, keep in mind that it's not necessary for Get(int key) as it will map to Student({key}) automatically.

@habbes Here is my BaseController class. It is inherited from ODataController:

` [ODataRoutePrefix("{contextToken}/[controller]")]
    [ODataRoutePrefix("[controller]")]
    public class BaseController<TEntity> : ODataController where TEntity : class
    {
        public IActionResult Get(ODataQueryOptions<TEntity> queryOptions, CancellationToken cancellationToken)
        {
            var list = new List<Student>
            {
                CreateNewStudent("Cody Allen", 130),
                CreateNewStudent("Todd Ostermeier", 160),
                CreateNewStudent("Viral Pandya", 140)
            };
            return Ok(list);
        }

    public virtual IActionResult Get(string key)
    {
        var list = new List<Student>
        {
            CreateNewStudent("Cody Allen", 130),
            CreateNewStudent("Todd Ostermeier", 160),
            CreateNewStudent("Viral Pandya", 140)
        };
        return Ok(list);
    }
    private static Student CreateNewStudent(string name, int score)
    {
        return new Student
        {
            Id = Guid.NewGuid(),
            Name = name,
            Score = score
        };
    }
}`

The purpose of putting [ODataRoutePrefix("{contextToken}/[controller]")] is I want to work with specific DB context by Guid. I am getting this token from Request.RouteValues["contextToken"]. I tried to do it in ASP.Net Core and it is working when I put [Route("{contextToken}/[controller]")] [Route("[controller]")] in controller. But ODataRoutePrefix is not afffecting on my controller

komdil avatar Jul 15 '20 09:07 komdil

I had an issue, that an odata function with [ODataRoute] was not found (got 404). So I played around with MapODataRoute and in my opinion I experienced a pretty strange behavior.

You can see my experiments here: https://github.com/manureini/OData3.1WithSwagger/commit/3bb3d9e7196de49dbbeba98338a2413f971def3c

For me the routing only works when I use the magicFunc variable. - I don't understand, why this is working 😕

manureini avatar Aug 18 '20 14:08 manureini

@komdil could you share repro of your scenario. I'm curious about what your CustomODataRoutingConvention() is doing. Could it be that it overrides the attribute routing convention?

habbes avatar Aug 25 '20 15:08 habbes

I have the same issue with newest version Version="8.0.0-preview3" : https://stackoverflow.com/questions/65551331/using-odatarouteprefix-and-odataroute-for-odata-attributerouting-is-not-working

navidzehi avatar Jan 06 '21 11:01 navidzehi

@komdil Was this issue resolved?

KenitoInc avatar May 18 '22 08:05 KenitoInc

@komdil Was this issue resolved?

I don't know. Did you check the steps?

komdil avatar May 18 '22 09:05 komdil

Closing this issue due to inactivity. If this issue still persists, feel free to create a new issue.

KenitoInc avatar Feb 10 '23 08:02 KenitoInc