Search code examples
restodataguid

OData V4 REST using GUID primary key


all! I am using OData v4 building REST services. My tables have a GUID primary key.

My GET and POST requests are working fine. But the PUT, PATCH, and DELETE requests fail with 404.

I am not sure what the url should look like. I've tried these in Fiddler, all getting the 404. I have googled this quite a bit with no luck.

http://localhost/ershubrest/AppVersions/guid'00000000-e90f-4938-b8f6-000000000000'

http://localhost/ershubrest/AppVersions/'00000000-e90f-4938-b8f6-000000000000'

http://localhost/ershubrest/AppVersions/00000000-e90f-4938-b8f6-000000000000

Here is the code for my controller...

using ERSHubRest.Models;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.OData;
using System.Web.OData.Query; 
using System.Web.OData.Routing;

namespace ERSHubRest.controllers
{
[ODataRoutePrefix("AppVersions")]
public class AppVersionsController : ODataController
{
    HubModel db = new HubModel();

    private bool AppVersionsExists(System.Guid key)
    {
        return db.AppVersions.Any(p => p.AppVersionId == key);
    }

    // http GET for select queries

    [ODataRoute]
    [EnableQuery]
    public IQueryable<AppVersions> Get()
    {
        return db.AppVersions;
    }

    [ODataRoute("({key})")]
    [EnableQuery]
    public IHttpActionResult Get([FromODataUri] System.Guid key)
    {
        IQueryable<AppVersions> result = db.AppVersions.Where(p => p.BusinessId == key);

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

        return Ok(result);
    }

    // http POST for insert

    [ODataRoute()]
    [HttpPost]
    [EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
    public async Task<IHttpActionResult> Post(AppVersions appVersions)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }
        db.AppVersions.Add(appVersions);
        await db.SaveChangesAsync();
        return Created(appVersions);
    }

    // http PUT and PATCH for updates

    [ODataRoute()]
    [HttpPatch]
    [EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
    public async Task<IHttpActionResult> Patch([FromODataUri] System.Guid key, Delta<AppVersions> appVersions)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }
        var entity = await db.AppVersions.FindAsync(key);
        if (entity == null)
        {
            return NotFound();
        }
        appVersions.Patch(entity);
        try
        {
            await db.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!AppVersionsExists(key) )
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
        return Updated(entity);
    }

    [ODataRoute()]
    [HttpPut]
    [EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
    public async Task<IHttpActionResult> Put([FromODataUri] System.Guid key, AppVersions update)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }
        if ( ! key.Equals( update.BusinessId ))
        {
            return BadRequest();
        }
        if (!AppVersionsExists(key))
        {
            return BadRequest();
        }
        db.Entry(update).State = EntityState.Modified;
        try
        {
            await db.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if ( ! AppVersionsExists(key))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
        return Updated(update);
    }

    // last is Delete

    [ODataRoute()]
    [HttpDelete]
    [EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
    public async Task<IHttpActionResult> Delete([FromODataUri] System.Guid key)
    {
        var appVersions = await db.AppVersions.FindAsync(key);
        if (appVersions == null)
        {
            return NotFound();
        }
        db.AppVersions.Remove(appVersions);
        await db.SaveChangesAsync();
        return StatusCode(HttpStatusCode.NoContent);
    }

    // clean up 

    protected override void Dispose(bool disposing)
    {
        db.Dispose();
        base.Dispose(disposing);
    }
}
}

Solution

  • The request URL for PATCH, PUT and DELETE should be:

    http://localhost/ershubrest/AppVersions(00000000-e90f-4938-b8f6-000000000000)
    

    OData is using parenthesizes for addressing single entities using keys.

    For more URL conventions, the OData V4 URL convention spec can be referred to: http://docs.oasis-open.org/odata/odata/v4.0/os/part2-url-conventions/odata-v4.0-os-part2-url-conventions.html