title: OData attribute routing for deleting relationship between m:m entities
body: <p>The scenario is an application that uses OData v4, server-side API based on an Entity Framework model using ODataLib, client-side using the OData client code generator extension for Visual Studio</p>
  
  <p>I'm failing to get OData attribute routing working for deleting relationships for entities in m:m relationships, for which the client generates DELETE requests in the form:</p>
  
  <pre><code>http://developer4:8080/odata/tblTestRestaurant(241)/tblTestDishes/$ref?$id=http://developer4:8080/odata/tblTestDish(1)
  </code></pre>
  
  <p>Attribute routing for POST for creating a link works just fine - the related entity identifier is encoded in the body, and the following controller action method declaration works (the controller itself has <code>[ODataRoutePrefix("tblTestRestaurant")]</code>):</p>
  
  <pre><code>    [ODataRoute("({pRestaurantID})/tblTestDishes/$ref")]
      [HttpPost]
      [EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
      public async Task&lt;IHttpActionResult&gt; PostAttachtblTestDishes([FromODataUri] int pRestaurantID,
          [FromBody] Uri uri) { ... }
  </code></pre>
  
  <p>But I can't get something similar working for DELETE where the ID of the related entity is specified using the <code>$ref?id=...</code> syntax in the URL.</p>
  
  <p>I have tried the following using the ODataRoute attribute:</p>
  
  <pre><code>    [ODataRoute("({pRestaurantID})/tblTestDishes/$ref")]
      [HttpDelete]
      public async Task&lt;IHttpActionResult&gt; TestRemoveRef1([FromODataUri] int pRestaurantID,
          [FromODataUri] Uri relatedUri)
      {
          throw new NotImplementedException();
      }
      [ODataRoute("({pRestaurantID})/tblTestDishes/$ref")]
      [HttpDelete]
      public async Task&lt;IHttpActionResult&gt; TestRemoveRef2([FromODataUri] int pRestaurantID,
          [FromODataUri] string relatedUri)
      {
          throw new NotImplementedException();
      }
      [ODataRoute("({pRestaurantID})/tblTestDishes/$ref?$id={pRelated}")]
      [HttpDelete]
      public async Task&lt;IHttpActionResult&gt; TestRemoveRef3([FromODataUri] int pRestaurantID,
          [FromODataUri] string pRelated)
      {
          throw new NotImplementedException();
      }
      [ODataRoute("({pRestaurantID})/tblTestDishes/$ref?$id={pRelated}")]
      [HttpDelete]
      public async Task&lt;IHttpActionResult&gt; TestRemoveRef4([FromODataUri] int pRestaurantID,
          [FromODataUri] Uri pRelated)
      {
          throw new NotImplementedException();
      }
  </code></pre>
  
  <p>But none of the above controller actions get hit in response to a DELETE request to <code>http://developer4:8080/odata/tblTestRestaurant(241)/tblTestDishes/$ref?$id=http://developer4:8080/odata/tblTestDish(1)</code>.</p>
  
  <p>The only way I can get it working is not to use attribute routing but instead to rely on the OData routing conventions, ie</p>
  
  <pre><code>    [HttpDelete]
      public async Task&lt;IHttpActionResult&gt; DeleteRef([FromODataUri] int key,
          [FromODataUri] string relatedKey, string navigationProperty)
      {
          throw new NotImplementedException();
      }
  </code></pre>
  
  <p>This method relies on testing the string navigationProperty to work out which collection navigation property on the entity to modify - instead I would prefer to use attribute routing and have a separate action method in my controller for each collection navigation property.</p>
  
  <p>I've used a number of tutorials and documentation in particular  <a href="https://damienbod.wordpress.com/2014/06/10/getting-started-with-web-api-and-odata-v4/" rel="nofollow">https://damienbod.wordpress.com/2014/06/10/getting-started-with-web-api-and-odata-v4/</a></p>
  
  <p>I have also been through some of the OData WebApi test cases, particularly <a href="https://github.com/OData/WebApi/blob/41b457a981b95545970b9ebf5a99bc517e66cff1/OData/test/E2ETest/WebStack.QA.Test.OData/Containment/ContainmentControllers.csd" rel="nofollow">this one</a> which uses a mixture of attribute routing and OData routing conventions - but doesn't contain an example for attribute routing for deleting links. </p>
  
  <p>So my question is - what ODataRoute attribute syntax and method parameters should I be using, assuming that the ODataRoute attribute does support this ...$ref?id=... syntax in the URL for deletes; and if it doesn't then what alternatives are there?</p>