通用O数据控制器未返回预期结果

时间:2019-07-18 14:32:38

标签: asp.net odata core

我正在尝试创建一个通用的OData控制器。我是根据 this链接。

一切正常;但是http://localhost:65465/odata/Book返回的数据类似

[
        {
            "Id": 999,
            "Title": null,
            "Author": "Author 999"
        }
]

代替

{
    "@odata.context": "http://localhost:65465/odata/$metadata#Book",
    "value": [
        {
            "Id": 999,
            "Title": null,
            "Author": "Author 999"
        }]
}

在进一步调查中,我发现在通用控制器的get内未在请求对象上设置edm模型。似乎正在使用非OData路由;尽管所有OData过滤器都选择,但orderby仍按预期工作。

请让我知道我所缺少的是,它没有在请求上设置edm模型。

谢谢! 阿西夫

[Route("odata/[controller]")]
        [Produces("application/json")]
        public class CustomODataController<T> : ODataController where T : class, 
         ICustomEntity
        {

            [HttpGet]
            [EnableQuery]
            public IActionResult Get()
            {
                IEdmModel edmModel = Request.GetModel();
                return Ok(_storage.GetAll().AsQueryable());

            }
        }

        public class GenericTypeControllerFeatureProvider :IApplicationFeatureProvider<ControllerFeature>
        {
            public void PopulateFeature(IEnumerable<ApplicationPart> parts, ControllerFeature feature)
            {
                var currentAssembly = typeof(GenericTypeControllerFeatureProvider).Assembly;
                var candidates = currentAssembly.GetExportedTypes().Where(x => x.GetCustomAttributes<GeneratedControllerAttribute>().Any());

                foreach (var candidate in candidates)
                {

                    feature.Controllers.Add(typeof(CustomODataController<>).MakeGenericType(candidate).GetTypeInfo());

                }
            }
        }

        var mvcBuilder = services.AddMvc();
        mvcBuilder.AddMvcOptions(o => o.Conventions.Add(new GenericControllerRouteConvention()));
        mvcBuilder.ConfigureApplicationPartManager(c =>
        {
            c.FeatureProviders.Add(new GenericTypeControllerFeatureProvider());
        });

        app.UseMvc(b =>
        {
            GetEdmModel(), new DefaultODataPathHandler(), 
            routingConventions);
            b.MapODataServiceRoute("ODataRoutes", "odata", GetEdmModel());
            b.Expand().Select().Count().OrderBy().Filter();
            b.EnableDependencyInjection();
        });

        private IEdmModel GetEdmModel()
        {
            ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
            builder.EntitySet<Book>(nameof(Book)).EntityType.Filter().OrderBy().Select();
            var edmModel =   builder.GetEdmModel();
            return edmModel;
        }


        public class GenericControllerRouteConvention : IControllerModelConvention
        {
            public void Apply(ControllerModel controller)
            {
                if (controller.ControllerType.IsGenericType)
                {
                    var genericType = controller.ControllerType.GenericTypeArguments[0];

                    controller.Selectors.Add(new SelectorModel
                    {
                        AttributeRouteModel = new AttributeRouteModel(new RouteAttribute($"odata/{genericType.Name}"))

                    });

                }
            }
        }

1 个答案:

答案 0 :(得分:0)

我使用不同的选项进行播放,最后能够使用通用控制器上的属性使它正常工作

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
    public class GenericControllerNameConventionAttribute : Attribute, IControllerModelConvention
    {
        public void Apply(ControllerModel controller)
        {
            if (controller.ControllerType.GetGenericTypeDefinition() !=
                typeof(CustomODataController<>))
            {
                // Not a GenericController, ignore.
                return;
            }

            var entityType = controller.ControllerType.GenericTypeArguments[0];
            controller.ControllerName = entityType.Name;
        }
    }


    [Produces("application/json")]
    [GenericControllerNameConvention]

    public class CustomODataController<T> : ODataController where T : class, IDataEntity
    {
        private Storage<T> _storage;

        public CustomODataController(Storage<T> storage)
        {
            _storage = storage;

        }

        [HttpGet]
        [EnableQuery]
        public IActionResult Get()
        {
            return Ok(_storage.GetAll().AsQueryable());

        }


        [EnableQuery]
        public SingleResult<T> Get([FromODataUri] int key)
        {
            return SingleResult.Create(_storage.GetAll().Where( n => n.Id == key).AsQueryable());
        }

        [HttpPost]
        [EnableQuery]
        public IActionResult Post([FromBody]T value)
        {
            _storage.AddOrUpdate(value.Id, value);
            return Created(value);
        }


        [HttpPut]
        [EnableQuery]
        public IActionResult Put([FromODataUri] int key, [FromBody]T value)
        {
            _storage.AddOrUpdate(key, value);
            return Updated(value);
        }


        [HttpPatch]
        [EnableQuery]
        public IActionResult Patch([FromODataUri] int key, [FromBody] Delta<T> value)
        {
            var existing = _storage.GetById(key);
            if (existing == null)
            {
                return NotFound();
            }
            value.Patch(existing);
            _storage.AddOrUpdate(key, existing);
            return Updated(existing);
        }


        [HttpDelete]
        [EnableQuery]
        public IActionResult Delete([FromODataUri] int key)
        {
            _storage.Delete(key);
            return NoContent();
        }



    }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton(typeof(Storage<>));
        services.AddOData();

        var mvcBuilder = services.AddMvc();

        mvcBuilder.ConfigureApplicationPartManager(c =>
        {
            c.FeatureProviders.Add(new GenericTypeControllerFeatureProvider());
        });

        mvcBuilder.AddJsonOptions(opt =>
            {
                opt.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                opt.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
            });



    }