1
votes

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 }
    );
}
1
did you check the object returned from db.Data.Find call? It might be having a null value for id field. - Gulzar Nazim
I put in a a break point, its not hitting that new method at all - user979331
route conflict. it is hitting another route that matched the request. Show how you configure your routes setup. and the url being requested - Nkosi
From the stack trace, it looks like it is hitting GetLCPreview(Int32) with a null parameter. - Gulzar Nazim
I'm going to go out on a limb and and assume you are using a GET request to try and hit this method. By default, I believe that any route that doesn't have get in the name (or is marked with an HTTPGet attibute) will default to POST. So you will either need to mark this as a GET request or change your call to a POST - Simon C

1 Answers

1
votes

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/[email protected]/
    [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.