brk
brk

Reputation: 1456

C# WebApi with EF cannot call method

I've created a MVC 4 WebApi application with some POCO classes and used EF to create a quick default controller with read/write etc.

Now for some reason I cannot have these two methods working together, however the first one works which is the one that EF created. In short I'd like to find users by Id and by username.

    // GET api/xxx
    public User GetUser(string id)
    {
        User user = db.Users.Find(id);
        if (user == null)
        {
            throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
        }
        return user;
    }

The above works. This does not work.

    // GET api/xxx
    public User GetUserByUsername(string username)
    {
        var user = db.Users.First(s => s.Username == username);
        if (user == null)
        {
            throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
        }

        return user;
    }

But by changing it a bit to the following and adding some to the webapi config then the following works:

    // GET api/xxx
    [HttpGet]
    [ActionName("username")]
    public User GetUserByUsername(string id)
    {
        var user = db.Users.First(s => s.Username == id);
        if (user == null)
        {
            throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
        }

        return user;
    }

And changing the WebApiConfig to this:

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

I would like to know why the previous methods does not work together (the 1st and 2nd one) and what I can do to make it work if possible. I'm pretty sure there's something to it, since it would seem a bit strange not being able to create similar methods.

Upvotes: 3

Views: 1194

Answers (3)

brk
brk

Reputation: 1456

Made it work by adding a new routing rule after the DefaultApi,

// Routing by Action-name
config.Routes.MapHttpRoute(
    name: "ActionApi",
    routeTemplate: "api/{controller}/{action}/{username}",
    defaults: new { username = RouteParameter.Optional }
);

and changing the method to the following:

// GET api/xxx/username
[ActionName("username")]
public User GetUserByUsername(string username)
{
    var user = db.Users.FirstOrDefault(s => s.Username == username);
    if (user == null)
    {
        throw new HttpResponseException(
            Request.CreateResponse(HttpStatusCode.NotFound));
    }

    return user;
}

I think I tried too much and was being silly, but now it seems pretty clear.

By adding a new routing where I apply {action} to the routeTemplate makes sense as I then can add an attribute [ActionName("username")]. Then I can browse localhost:xxxxx/api/xxx/2 AND localhost:xxxxx/api/xxx/username/bob which makes both GET methods work because the second routing rule accepts an action.

@Rob, thanks for the link and hint though, appreciated!

Upvotes: 0

Rob
Rob

Reputation: 5588

Because Web API only looks for the fact that the method is "GET" and looks for a "get" word in the method name. Since both your methods have "get" and both accept a single string parameter, the controller is probably resolving to the first one it finds, and since "id" is part of the default route it is coming back with your GetUser method.

You can also try adding a route for the "username":

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

EDIT: Try taking a look at these articles to see how routing works with Web API. It's different than regular MVC controllers.

http://www.asp.net/web-api/overview/web-api-routing-and-actions

Upvotes: 3

D.Rosado
D.Rosado

Reputation: 5773

This:

var user = db.Users.First(s => s.Username == id);

will cause an exception if no user with that id is found

But this:

This:

var user = db.Users.FirstOrDefault(s => s.Username == id);

will return null instead.

Upvotes: 0

Related Questions