Search code examples
c#asp.net-mvcentity-frameworkasp.net-web-apiasp.net-web-api-routing

ASP.NET Entity Framework API Controller Add method not working


I have a Entity Framework API Controller that was generated, I am now trying to add a new method to it:

[ResponseType(typeof(LCPreview))]
public IHttpActionResult ValidateEmail(string email)
{
    LCPreview lCPreview = db.Data.Find(5);
    if (lCPreview == null)
    {
        return NotFound();
    }

    return Ok(lCPreview);
}

but when I run this, I get this error:

The request is invalid. The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'System.Web.Http.IHttpActionResult GetLCPreview(Int32)' in 'Astoria.Controllers.PreviewLCAPIController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.

public static void Register(HttpConfiguration config)
{
    config.MapHttpAttributeRoutes();

    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );
}

Solution

  • via convention-based routing the route table is unable to differentiate between the two actions and is selecting the GetLCPreview action based on Get prefix convention.

    Given that your route configuration is already enabling attribute routing this means that paramater constraints can be used to help differentiate the routes.

    [RoutePrefix("api/PreviewLCAPI")]
    public class PreviewLCAPIController : ApiController {
    
        //GET api/PreviewLCAPI/5 <- only when the value is an int will it match.
        [Route("{id:int}")]
        [HttpGet]
        public IHttpActionResult GetLCPreview(int id) { ... }
    
        //GET api/PreviewLCAPI/someone@email.com/
        [Route("{email}"]
        [HttpGet]
        [ResponseType(typeof(LCPreview))]
        public IHttpActionResult ValidateEmail(string email) { ... }
    }
    

    Note that the dot (.) in the email will cause you some issues if entered without the slash (/) at the end. The framework will think it's looking for a file and error out.

    If the intention was to send the email address then use POST and include email in the body.

    //POST api/PreviewLCAPI
    [Route("")]
    [HttpPost]
    [ResponseType(typeof(LCPreview))]
    public IHttpActionResult ValidateEmail([FromBody] string email) { ... }
    

    sending it in the request body avoid any issues with the email format in the url.