Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

call web api by passing simple and complex parameter

Getting an error message of no http resource or action found in controller. In a web api I have a from body and from uri parameter.

[HttpPost]        
public IHttpActionResult processfields(
    [FromUri]string field1,
    [FromUri]string field2, 
    [FromBody] string field3, 
    [FromUri]string field4
){...}

In the client I want to call the web api by doing--

using (var client = new HttpClient())
{
    //set up client
    client.BaseAddress = new Uri(Baseurl);
    client.DefaultRequestHeaders.Clear();
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));


     var values = new Dictionary<string, string>();
     values.Add("field1", field1);
     values.Add("field2", field2);
     values.Add("field3", field3);
     values.Add("field4", filed4);


     var jsonString = JsonConvert.SerializeObject(values);
     try
     {

         HttpResponseMessage Res = client.PostAsync("api/home/processfields", new StringContent(jsonString, Encoding.UTF8, "application/json")).Result;
         var result = Res.Content.ReadAsStringAsync();
     }
}

While debugging, it executes the last line above but nothing happens and error message says--

{"Message":"No HTTP resource was found that matches the request URI 'http://xxx.xxx.xx.xx:1234/api/home/processfields'.","MessageDetail":"No action was found on the controller 'home' that matches the request."}

my webapi.config has

// Web API routes
config.MapHttpAttributeRoutes();


config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{action}/{id}",
    defaults: new { id = RouteParameter.Optional }
);
like image 624
santa029 Avatar asked Jul 12 '26 09:07

santa029


2 Answers

field1, field2 and field4 parameters are expected in the Url, not in the request body. That's why the request Url should look like: http://xxx.xxx.xx.xx:1234/api/home/processfields?field1=value1&field2=value2&field4=value4

field3 is deserialized from the body. However as it is string parameter, request body should be built not as JSON object:

{
  "field3": "value3"
}

but as JSON string:

"value3"

Here is adjusted client code that should work:

using (var client = new HttpClient())
{
    //set up client
    client.BaseAddress = new Uri(Baseurl);
    client.DefaultRequestHeaders.Clear();
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    var requestUri = new Uri($"api/home/processfields?field1={HttpUtility.UrlEncode(field1)}&field2={HttpUtility.UrlEncode(field2)}&field4={HttpUtility.UrlEncode(field4)}", UriKind.Relative);
    var content = new StringContent($"\"{field3}\"", Encoding.UTF8, "application/json");
    var response = await client.PostAsync(requestUri, content);
    var result = await response.Content.ReadAsStringAsync();
}
like image 177
CodeFuller Avatar answered Jul 14 '26 22:07

CodeFuller


First, looking at the Web API method signature, I don't think there's any JSON involved here at all. So I think you can skip setting the Accept header. (If the [FromBody] parameter were a complex object rather than a string, then JSON serialization would likely come into play.)

Second, never use .Result with HttpClient. It is an async-only API and you should be using async / await, otherwise you're just inviting deadlocks.

Finally, as others have pointed out, field1, field2, and field4 go in the query string, not the body. If you want a more structured way to do this, and with less ceremony overall, consider using Flurl (disclaimer: I'm the author), which uses HttpClient under the hood:

using Flurl.Http;

var result = await BaseUrl
    .AppendPathSegment("api/home/processfields")
    .SetQueryParams(new { field1, field2, field4 })
    .PostStringAsync(field3)
    .ReceiveString();
like image 34
Todd Menier Avatar answered Jul 14 '26 23:07

Todd Menier



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!