0

I have an ODataController with 2 methods:

[EnableQuery]
public SingleResult<item> Getitem([FromODataUri] System.Guid key)
{
    return SingleResult.Create(db.items.Where(item=> item.guid == key));
}

public async Task<IHttpActionResult> Postitem([FromODataUri] System.Guid key, [FromBody] double itemId)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    //Find the correct account
    item i = await db.items.FirstAsync(item=> item.guid == key);

    if (i == null)
    {
        return NotFound();
    }

    //Update the account field we are using for id
    i.itemId = itemId;

    //Save the changes
    try
    {
        await db.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        if (!itemExists(key))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }

    return Updated(i);
}

private bool itemExists(System.Guid key)
{
    return db.items.Count(e => e.guid == key) > 0;
}

With the standard WebApiConfig:

GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;

config.EnableCors();
// Web API configuration and services

// Web API routes
config.MapHttpAttributeRoutes();

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

ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<item>("items");
config.Routes.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());

And I can type mydomain.com/odata/items(guid'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX') in the url bar and get the database object as json just fine.

But when I try the following client code:

var itemGuid = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX";
var itemId = "55555";

using (WebClient wc = new WebClient())
{
    wc.UseDefaultCredentials = true;

    var domain = "mydomain.com";

    var url = domain + "/odata/items(guid'" + itemGuid + "')";

    var data = new NameValueCollection();
    data["itemId"] = itemId;

    byte[] temp = wc.UploadValues(url, "POST", data);
    context.Response.Write(Encoding.UTF8.GetString(temp));
}

I get The remote server returned an error: (404) Not Found.

I know it's probably some simple mistake, but been messing around with it too long and I'm new to asp.net.

Boghyon Hoffmann
  • 17,103
  • 12
  • 72
  • 170
  • you put a breakpoint on your endpoint? Did it hit it? – Steve's a D Jul 05 '16 at 16:47
  • well, since you aren't responding, i'll say this: Your endpoint returns 404's depending on specific circumstances. How do we know if the URL is what is causing the 404, or one of your special circumstances that returns not found? You should put a break point on your end point, see if it hits the endpoint. If it hits the endpoint, then you know it's how you construct / pass `itemId` on the client. If it doesn't hit the endpoint, then you know it's how you're constructing your URL on the client. Debug to narrow it down, and then work from there. – Steve's a D Jul 05 '16 at 18:14
  • Also, if you're using both a `Web Api` / `MVC` controller, and an `OData` controller with the same routes, then `post`s need to be explicitly set in `WebApiConfig`. – Steve's a D Jul 05 '16 at 18:16
  • Sorry I have been trying to get debugging working and finally did. My breakpoint in the web api never gets it from what I see. I get a WebException in the WebClient call. I'm looking into it more, but figured I would post what I found. – MusicMonkey5555 Jul 05 '16 at 21:02
  • My biggest hope is someone would know if I was messing up the function formatting in my controller or something. – MusicMonkey5555 Jul 05 '16 at 21:06
  • Based on what I'm seeing I really see it being an issue with how the controller method is getting translated into a route. Is there an easy way to just view all the routes for a controller? – MusicMonkey5555 Jul 05 '16 at 21:13
  • I meant constructing the url from the C# client. If you can hit the endpoint via restconsole or something similar, but not through the client, then you know it's how you're constructing / passing the endpoint url in the client. (It usually works best if you test the endpoint separately with something like restconsole or integration tests, then once you get that working, hook up a client via code) – Steve's a D Jul 06 '16 at 12:57
  • Yeah and the issue with that is I couldn't find a good tool that would work with iis/windows authentication/NTLM. Otherwise that is what I was going to do is just use a separate tool to test my api. – MusicMonkey5555 Jul 18 '16 at 16:05

1 Answers1

0

I think I may have figured it out and it makes sense. So if you create an OdataController you sorta just have your default Post to create a new item, Patch to change/update an update, Put to replace an item with a new one...

Then if you want custom api calls you need to use actions: http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-v3/odata-actions

So I was just doing it all wrong. I just assumed you could put Post in front of some function name and it would be a Post opperation with custom arguments.