0

I am using OData V3 endpoints using asp.net with webapi 2.2. I have successfully implemented CRUD operation with it. Now, I would like to add some custom actions along with CRUD operations. I have followed the article ( http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-v3/odata-actions ) to create the action with OData V3 with web api.

When I type

URI:

http://localhost:55351/odata/Courses(1101)/AlterCredits

it throws following error:

<m:error><m:code/><m:message xml:lang="en-US">No HTTP resource was found that matches the request URI 'http://localhost:55351/odata/Courses(1101)/AlterCredits'.</m:message><m:innererror><m:message>No routing convention was found to select an action for the OData path with template '~/entityset/key/unresolved'.</m:message><m:type/><m:stacktrace/></m:innererror></m:error>

I have also tried adding a custom route convetion for non-bindable actions. (https://aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/OData/v3/ODataActionsSample/ODataActionsSample/App_Start/WebApiConfig.cs ) Not sure if I have to use this.

Here is my code:

WebApiConfig.cs :---

namespace ODataV3Service
{
public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        IList<IODataRoutingConvention> conventions = ODataRoutingConventions.CreateDefault(); //Do I need this?
        //conventions.Insert(0, new NonBindableActionRoutingConvention("NonBindableActions"));

        // Web API routes                        
        config.Routes.MapODataRoute("ODataRoute","odata", GetModel(), new DefaultODataPathHandler(), conventions);
    }

    private static IEdmModel GetModel()
    {
        ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
        modelBuilder.ContainerName = "CollegeContainer";
        modelBuilder.EntitySet<Course>("Courses");
        modelBuilder.EntitySet<Department>("Departments");

        //URI: ~/odata/Course/AlterCredits
        ActionConfiguration atlerCredits = modelBuilder.Entity<Course>().Collection.Action("AlterCredits");
        atlerCredits.Parameter<int>("Credit");
        atlerCredits.Returns<int>();

        return modelBuilder.GetEdmModel();
    }
  }
}

CoursesController.cs:----

[HttpPost]        
    //[ODataRoute("AlterCredits(key={key},credit={credit})")]
    public async Task<IHttpActionResult> AlterCredits([FromODataUri] int key, ODataActionParameters parameters)
    {            
        if (!ModelState.IsValid)
            return BadRequest();

        Course course = await db.Courses.FindAsync(key);
        if (course == null)
        {
            return NotFound();
        }

        int credits = course.Credits + 3;

        return Ok(credits);
    }

Global.asax:----

namespace ODataV3Service
{
 public class WebApiApplication : System.Web.HttpApplication
 {
    protected void Application_Start()
    {
        GlobalConfiguration.Configure(WebApiConfig.Register);
    }
 }
}

I have done research online and found this link. Web API and OData- Pass Multiple Parameters But this one is for OData V4. I am using OData V3 and Action.

Thanks,

1 Answer 1

1

First, your action AlterCredits is defined as:

ActionConfiguration atlerCredits = modelBuilder.Entity<Course>().Collection.Action("AlterCredits");

It means AlterCredits bind to the collection of Course.

Second, your method AlterCredits in your controller is defined as:

public async Task<IHttpActionResult> AlterCredits([FromODataUri] int key, ODataActionParameters parameters)
{
...
}

It means AlterCredits listen to the call on the entity of Course.

Therefore, you got the No HTTP resource was found error message.


Based on your sample code, I create a sample method for your reference:

[HttpPost]
public async Task<IHttpActionResult> AlterCredits(ODataActionParameters parameters)
{
    if (!ModelState.IsValid)
        return BadRequest();

    object value;
    if (parameters.TryGetValue("Credit", out value))
    {
        int credits = (int)value;
        credits = credits + 3;
        return Ok(credits);
    }

    return NotFound();
}

Then, if you send a request:

POST ~/odata/Courses/AlterCredits
Content-Type: application/json;odata=verbose
Content: {"Credit":9}

You can get a response like this:

{
  "d":{
    "AlterCredits":12
  }
}

For your questions:

  1. IList conventions = ODataRoutingConventions.CreateDefault(); //Do I need this?

    Answer: No, you needn't. Just using the default as:

    config.Routes.MapODataServiceRoute("ODataRoute", "odata", GetModel());

  2. //[ODataRoute("AlterCredits(key={key},credit={credit})")]

    Answer: No, you needn't the ODataRouteAttribute for bind action.

Thanks.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.