Home > Mobile >  C# Controller behavior changes based on variable name
C# Controller behavior changes based on variable name

Time:11-10

I don't know enough about C#, .NET, or the MVC pattern to know exactly what is relevant to include here, but I'm pulling my hair out with a very simple change I'm working on.

I have a controller with a Search action (method?) that looks like:

public string Search(int id)
{
    return $"The id was {id}";
}

and when I hit the route I get the expected response, e.g.

$ curl https://localhost:7180/Players/Search/1
The id was 1

expected behavior when visiting route

but when I change the variable name from id to anything else, the behavior changes and the value goes to 0 for some reason.

public string Search(int thing)
{
    return $"The thing was {thing}";
}
$ curl https://localhost:7180/Players/Search/1
The thing was 0

unexpected behavior when visiting route

I thought maybe it had to do with the Model itself, because the model code at least has an Id attribute

    public class Player
    {
        public int Id { get; set; }
        public string? Name { get; set; }
    }

but renaming that variable to name (which seems analogous) also doesn't help.

So what concept am I missing here? Why can't I just rename that variable to whatever I want? Thanks in advance!

(I don't know how better to communicate all the different aspects of the code, so here is a link to the line in question, inside the project)

CodePudding user response:

By default MVC registers (see either Program or Startup) next default route, so it can bind id parameter of method as positional part of path:

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

You can change the parameter name for example using attribute routing:

[Route("[controller]/search/{thing}")] 
public string Search(int thing)
{
    return $"The thing was {thing}";
}

Or using HTTP verb templates:

[HttpGet("[controller]/search/{thing}")] 
public string Search(int thing)
{
    return $"The thing was {thing}";
}

Check the linked docs for other options/details.

CodePudding user response:

You can decorate the method and define the parameter.

    // GET api/values/5
    [HttpGet("{id}")]
    public virtual async Task<ActionResult<IEntity>> Get(string id)
    {
        var entity = await Repository.GetEntity(x => x.Id == id);
        if (entity == null) return NotFound();

        return Ok(entity);
    }

CodePudding user response:

I believe this has to do with the way you've defined your route in Program.cs:

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

You'll want to add a new definition like this:

app.MapControllerRoute(
    name: "default",
    pattern: "Players/Search/{thing?}");

alternatively, you could use attribute-based route definitions to move the route pattern definition closer to the actual code. See the MSFT docs for details. Basically, add app.MapControllers(); to Program.cs, then for your individual routes, do something like this:

[Route("Player/Search/{thing}")
public string Search(int thing)
{
    return $"The thing was {thing}";
}
  • Related