0

I have no idea where to start with this. I asked a question previously, and someone suggested I look at attribute routing. I read up on it, and while it helped me to create the below code, I'm still not sure how to limit it like I want to.

public class ReviewController : ApiController
{
    private Review db = new Review();
    ////This GET works. It was auto-generated by Visual Studio. 
    // GET: api/Review
    public IQueryable<Review> GetReview()
    {
        return db.Review;
    }

    ////This is the GET that I'm trying to write, but don't know what to do
    // GET: api
    [Route("api/review/site")]
    [HttpGet]
    public IEnumerable<Review> FindStoreBySite(int SiteID)
    {
         return db.Review
    }

    ////This GET also works and was generated by VS. 
    // GET: api/Review/5
    [ResponseType(typeof(Review))]
    public IHttpActionResult GetReview(int id)
    {
        Review review = db.Review.Find(id);
        if (review == null)
        {
            return NotFound();
        }

        return Ok(review);
    }

Essentially what I'm aiming to do is to limit what's returned by the API to only the results where the SiteID is equal to whatever value is passed into the URL. I'm not even sure where to get started with this, and googling/searching stack overflow for "what to put in web api return" has been fruitless.

How do I tell the API what I want to have returned based off a parameter besides ReviewID?

Edit: I've updated the code per the suggestions in the answer below, but now I'm getting a new error.

Here's the current code:

    private ReviewAPIModel db = new ReviewAPIModel();

    // GET: api/Review
    [Route("api/Review")]
    [HttpGet]
    public IQueryable<Review> GetReview()
    {
        return db.Review;
    }

    // GET: api
    [Route("api/Review/site/{siteid}")]
    [HttpGet]
    public IEnumerable<Review> FindStoreBySite(int siteid)
    {
        return db.Review.Where(Review => Review.SiteID == siteid);
    }

    // GET: api/Review/5
    [ResponseType(typeof(Review))]
    public IHttpActionResult GetReview(int id)
    {
        Review review = db.Review.Find(id);
        if (review == null)
        {
            return NotFound();
        }

        return Ok(review);
    }
}

Here's the error that I get:

Multiple actions were found that match the request

When I google it, it takes me to this question: Multiple actions were found that match the request in Web Api

However, I've tried the answers there (I've confirmed that I'm using Web API V2, and my webapiconfig.cs file includes the config.MapHttpAttributeRoutes(); line.

In addition, as you can see in my code above, I've included the appropriate routing. However, I'm still getting an error telling me that it's returning two conflicting API calls.

phroureo
  • 377
  • 3
  • 16

2 Answers2

1

if you want to get parameters for GET, it's like a simple overload, but if it's done, POST is with [fromBody], because the URL is in the tag [Route ("/abc/123/{id}")]

example

code

[Route ("/abc/123/{idSite}")]
[HttpGet]
public HttpResponseMessage ControllerIdSite(int IdSite){
   //CODE . . .
   return Request.CreateResponse<int>(HttpStatusCode.OK, IdSite);  
}

call

  /abc/123/17

return

  17

OR

[Route ("/abc/123")]
[HttpGet]
public HttpResponseMessage ControllerIdSite(int IdSite){
       //CODE . . .
       return Request.CreateResponse<int>(HttpStatusCode.OK, IdSite);  
}

call

  /abc/123?IdSite=17

return

  17
  • Sorry, your answer isn't entirely clear to me. What would I put in your code so that it would know to look in the `Review` controller for reviews where the `SiteID` matches the parameter? – phroureo Aug 27 '18 at 21:09
1

To pass parameters to a WebApi controller you need to add a [Route()] attribute to that controller and mark the part of the link that's used as the attribute with this {}.

To return reviews that only match the passed in parameter you need to use LINQ to filter the data.

Here is an example:

[Route("api/getFoo/{id}")]
public IHttpActionResult GetFoo(int id)
{
    return db.Foo.Where(x => x.Id == id);
}

The {id} part of the string represents the id that will be in the url in your browser: http://localhost:51361/api/getFoo/2. The "2" in the url IS the {id} property that you marked in your [Route("api/getFoo/{id}")] attribute.

I also modified your code:

public class ReviewController : ApiController
{
    ...


    [Route("api/review/site/{siteId}")]
    [HttpGet]
    public IEnumerable<Review> FindStoreBySite(int SiteID)
    {
         return db.Review.Where(review => review.Id == SiteID);
    }

    ...

Your request url should look somewhat like this: http://localhost:51361/api/review/site?SiteID=2


This can be difficult to wrap your head around at first but you'll get used to it eventually. It's how arguments are passed to Controller Action parameters.

bezbos.
  • 1,551
  • 2
  • 18
  • 33
  • Right, that's exactly what I have in my sample code. I'm just not sure what goes in your `...` in between the `{ }`s. I have a working API that will return all reviews, and also an API that can limit reviews based off of review ID. I'm struggling to get it to return all reviews based off of `SiteID` instead of the "key" from the model class. – phroureo Aug 27 '18 at 22:14
  • @phroureo I updated my answer. Basically you need to use LINQ to specify that you only want reviews whose `Id` property equals the passed in `siteId` property. You can do that by doing `db.Reviews.Where(review => review.Id == siteId)` – bezbos. Aug 27 '18 at 22:20
  • Thanks! That's what I was looking for. :) – phroureo Aug 27 '18 at 22:27
  • @phroureo I'm glad to hear that. Thanks for the upvote and selected answer! – bezbos. Aug 27 '18 at 22:29
  • Okay, I lied. For some reason, `.../api/review/site?id=1` is returning the same thing as `/api/review/1`. It's not looking at the `siteID` at all. – phroureo Aug 27 '18 at 22:45
  • @phroureo It needs to say `.../api/review/site?SiteID=1`. – bezbos. Aug 27 '18 at 22:47
  • If I do that then I get the error `The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method`. When I looked that one up, it told me that I need to populate an ID but I'm not sure why that would be. – phroureo Aug 27 '18 at 22:50
  • @phroureo public `IEnumerable FindStoreBySite(int? SiteID)` your `SiteID` needs to be nullable then. – bezbos. Aug 28 '18 at 07:45
  • I've added an edit to the question with my NEW error and what I've tried. Do you mind taking a look again. :) – phroureo Aug 28 '18 at 22:49
  • @phroureo Have you tried renaming your API Action? To something like `GetReviewById`. – bezbos. Aug 29 '18 at 08:48
  • @phroureo I'm sorry but I really don't know what could it be other that what we've already discussed. Keep at it and you'll solve it eventually! – bezbos. Aug 29 '18 at 18:25