【问题标题】:Is it possible to set the query parameter name in a controller based on attributes of a class?是否可以根据类的属性在控制器中设置查询参数名称?
【发布时间】:2020-12-19 20:58:13
【问题描述】:

我正在创建一个使用泛型的控制器。这个父控制器通过传递它们处理的类的类型以通用方式被其他子控制器继承。父控制器中的操作需要从名为 partitionKey (Cosmos) 的查询参数绑定的参数。现在,与通用控制器一起使用的每个类型参数都具有不同的 partitionKey 属性(尽管都是 Guid,但名称会发生​​变化)。问题是当API使用者看到“partitionKey”作为查询参数的描述时,他们不知道所有类Guid属性中哪个属性是partitionKey。

我想也许有一种方法可以根据与 partitionKey 对应的属性类上设置的属性动态设置查询参数名称。是否可以在基于控制器的类属性属性中设置查询参数名称?还是有更好的方法?

父控制器

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

namespace x.API.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class GenericController<T> : ControllerBase
    {
        [HttpGet("{id}")]
        public async Task<ActionResult<T>> Get(Guid id, Guid partitionKey)
        {
                var item = await GetItemAsync<T>(id, partitionKey);

                return Ok(item);
        }

儿童控制器

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;


namespace x.API.Controllers
{
    public class GameController : GenericController<Game>
    {
    }
}

【问题讨论】:

    标签: c# asp.net-core .net-core asp.net-core-webapi


    【解决方案1】:

    您必须在某些时候指定查询参数的名称,这是毫无疑问的。但是让它动态化真的值得吗?对我来说,这听起来有点矫枉过正,因为仍有其他可用的解决方案可以轻松实现。

    我说解决方案是因为不只有一种方法可以做到这一点。但我的做法是让GenericController&lt;T&gt; 中的Get() 方法受保护并删除[HttpGet] 属性。

    [ApiController]
    [Route("[controller]")]
    public class GenericController<T> : ControllerBase
    {
        private readonly IEntityService _entityService;
    
        public GenericController(IEntityService entityService)
        {
            _entityService = entityService;
        }
    
        protected async Task<ActionResult<T>> GetEntity(Guid id, Guid partitionKey)
        {
            try
            {
                var item = await _entityService.GetItemAsync<T>(id, partitionKey);
    
                return Ok(item);
            }
            catch (EntityNotFoundException ex)
            {
                return NotFound(ex.Message);
            }
        }
    }
    

    GenericController 派生的控制器(这里以Foo 为例)将调用基本Get() 方法。每个派生控制器都可以完全控制方法路径及其查询参数名称。

    public class FooController : GenericController<Foo>
    {
        public FooController(IEntityService entityService) : base(entityService)
        {
    
        }
    
        [HttpGet("{id}")]
        public async Task<ActionResult<Foo>> Get(Guid id, Guid fooKey)
        {
            return await GetEntity(id, fooKey);
        }
    }
    

    示例Foo 实体:

    public class Foo
    {
        public Guid FooKey { get; set; }
    }
    

    【讨论】:

    • 是的,但是按照你说的做,失去了继承的便利,你在每个控制器中创建动作。使用当前的方法,我只需要声明继承即可。端点具有神秘的 partitionKey 参数,这就是我想要解决的问题。我想为类中的属性添加一个属性,即 partitionKey,然后通过反射获取属性名称并将其用于路径或参数,但我不确定这是否可能。
    猜你喜欢
    • 2020-04-20
    • 1970-01-01
    • 2020-01-27
    • 1970-01-01
    • 1970-01-01
    • 2010-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多