Search code examples
c#asp.net-web-api2asp.net-web-api-routing

Receiving "No resource found" when passing an object to a WebApi using HttpClient


Background

Currently have an api which I have created a while back which is a helper api. This api has a controller that receives an object, and then processes it accordingly.

Problem

When I am making a call to this my receiving api I get an error the following error message.

{"Message":"No HTTP resource was found that matches the request URI 'http://appdev.tenant.com/caseware32/api/DataServices/CreateDBF'.","MessageDetail":"No action was found on the controller 'DataServices' that matches the request."}

However, the controller is operational because I can call out another function in the control which can give me all clients. I made sure my route attribute matches my request url but still have no success.

Code

Sending Web Api

public static async Task<bool> CreateDBF(string dPath)
{
    var postObject = (new DBFPostModel
    {
        destinationPath = dPath,
        fileName = "CustomDBF"
    });
    List<string> uniqueID = new List<string>();
    try
    {
        string requestUrl = "http://appdev.tenant.com/caseware32/api/DataServices/CreateDBF";

        HttpClient hc = new HttpClient();

        var method = new HttpMethod("POST");

        var values = new Dictionary<string, string>()
        {
            { "Id", "6"},
            { "Name", "Skis"},
            { "Price", "100"},
            { "Category", "Sports"}
        };

        var content = new FormUrlEncodedContent(values);

        var hrm = await hc.PostAsync(requestUrl, content);
        if (hrm.IsSuccessStatusCode)
        {
            var responseData = await hrm.Content.ReadAsStringAsync();
            return true;
        }
        else
        {
            return false;
        }
    }
    catch (Exception ex)
    {
        // TODO Log 
        return false;
    }
}

Receiving Api

public class IncomingDbfModel
{
    public string Id { get; set; }
    public string Name { get; set; }
    public string Price { get; set; }
    public string Catergory { get; set; }
}

public class DataServicesController : ApiController
{
      [Route("api/DataServices/CreateDBF")]
    public IHttpActionResult CreateDBF(IncomingDbfModel postParam)
    {
        DatabaseServices dbServices = new DatabaseServices();
        bool success = dbServices.InsertDataIntoDBF(postParam);
        return Ok(success);
    }
}

Error

HTTP/1.1 404 Not Found
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Thu, 30 Mar 2017 15:17:38 GMT
Content-Length: 232

{"Message":"No HTTP resource was found that matches the request URI 'http://appdev.tenant.com/caseware32/api/DataServices/CreateDBF'.","MessageDetail":"No action was found on the controller 'DataServices' that matches the request."}

Routing Config

 public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
        config.EnableCors();

        log4net.Config.XmlConfigurator.Configure();

        // Web API routes
        config.MapHttpAttributeRoutes();

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

Solution

  • By default the convention-based route template for web api excludes the action name in the URL template "api/{controller}/{id}". The example above includes the action name in the requestUrl = "http://appdev.tenant.com/caseware32/api/DataServices/CreateDBF" with matches the attribute route. [Route("api/DataServices/CreateDBF")]

    So the assumption is that you meant to use attribute routing.

    Apply HttpPost attribute to the action so that route knows how to handle the POST request

    public class DataServicesController : ApiController {
        //POST api/DataServices/CreateDBF
        [HttpPost]
        [Route("api/DataServices/CreateDBF")]
        public IHttpActionResult CreateDBF(IncomingDbfModel postParam) {
            DatabaseServices dbServices = new DatabaseServices();
            bool success = dbServices.InsertDataIntoDBF(postParam);
            return Ok(success);
        }
    }
    

    Source: Attribute Routing in ASP.NET Web API 2 - HTTP Methods

    Web API also selects actions based on the HTTP method of the request (GET, POST, etc). By default, Web API looks for a case-insensitive match with the start of the controller method name.

    You can override this convention by decorating the mathod with any the following attributes:

    [HttpDelete]
    [HttpGet]
    [HttpHead]
    [HttpOptions]
    [HttpPatch]
    [HttpPost]
    [HttpPut]