Search code examples
apiasp.net-coreasp.net-core-mvcasp.net-core-2.1conventions

ApiConvention response types- matching multiple Get methods


I have several controllers within my project which have multiple Get methods:

public async Task<ActionResult<IEnumerable<DModel>>> Get(){}
public async Task<ActionResult<DModel>> Get(int id){}

I am trying to create a convention which matches against these but dependent on the param - so it can tell the difference. So far I have:

        [ProducesResponseType(StatusCodes.Status200OK)]
        [ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)]
        [ProducesDefaultResponseType]
        [ApiConventionNameMatch(ApiConventionNameMatchBehavior.Prefix)]
        public static void Get()
        {
        }

        [ProducesResponseType(StatusCodes.Status200OK)]
        [ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)]
        [ProducesResponseType(StatusCodes.Status404NotFound)]
        [ApiConventionNameMatch(ApiConventionNameMatchBehavior.Prefix)]
        [ProducesDefaultResponseType]
        public static void Get(
            [ApiConventionNameMatch(ApiConventionNameMatchBehavior.Prefix)]
            int id)
        {
        }

This doesn't seem to work and I get an error when I try and start the API:

System.ArgumentException: 'Method name 'Get' is ambiguous for convention type 'P.API.Conventions.PApiConventions'. More than one method found with the name 'Get'. Arg_ParamName_Name'

This shows against the app.UseMvc() in Startup. I understand what happening but can't seem to work the logic to get it to resolve the get methods properly.


Solution

  • I'm not an expert in the Web API conventions but during various tests I noticed that the conventions don't affect routing and model binding. So you still need to explicitly specify HttpMethod attribute for actions

    [HttpGet]
    public async Task<ActionResult<IEnumerable<DModel>>> Get(){}
    
    //parameter name must match string inside curly braces
    //if you leave {id} and update parameter name to idName
    //(which matches prefix name convention)
    //model binder won't bind value to parameter
    //although tools that are using api conventions still will properly read controller info
    [HttpGet("{id}")]
    public async Task<ActionResult<DModel>> Get(int id){}