How to pass multiple parameters to WebAPI Action using HttpClient.PostAsJsonAsync method? - asp.net-web-api

I have a Web API action as following:
[HttpPost]
public List<FavoriteDTO> GetFavoritesPaged(long userId, PagingInfo pagingInfo)
{
var result = _userService.GetFavoritesPaged(fav => fav.UserId == userId, pagingInfo);
var favDTOs = ConvertToDTOs(result.Source);
return favDTOs;
}
I need to call it using HttpClient and I am trying it as following:
paging info needs to be passed to the get method.
var pagingInfo = new PagingInfo()
{
PageIndex = 1,
PageSize = 10,
OrderBy = "URL",
OrderDirection = OrderDirection.Desc
};
where OrderDirection is an enum:
public enum OrderDirection
{
Asc,
Desc
}
var detailURI = "Favorites/GetFavoritesPaged?userId="+34;
HttpClient client = new HttpClient()
client.BaseAddress="mywebApiAddress";
var response = client.PostAsJsonAsync(detailURI, pagingInfo).Result;
response.EnsureSuccessCode();
var result = JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().Result,
tyepof(FavoritesDTO));
But, its not working. It says internal server error, what I am missing here; is the enum causing problem or something else? I have other WebAPIs working just fine; none of them has more than one parameter like this.
Here is my routConfig:
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
Is it the right way to call the WebAPI with multiple parameters or is there a better way, please suggest?
EDIT-1:
changed this:
var detailURI = "Favorites/GetFavoritesPaged?userId?"+34;
to:
var detailURI = "Favorites/GetFavoritesPaged?userId="+34;
All it was a typo :)
EDIT-2:
With EDIT-1 the request goes to follwing WebAPI method (which is wrong):
[HttpPost]
public FavoriteDTO AddToFavorites(FavoriteDTO favoriteDTO)
{
------code to add to db------
}
But, when I edited the routeConfig to the following:
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
Then I started getting the following exception:
ReasonPhrase: Not Found
Request: {Method: POST, RequestUri: 'http://localhost:60208/api/Favorite/GetPagedFavorites?user=1', Version: 1.1, Content: System.Net.Http.ObjectContent`1[[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], Headers:{ Content-Type: application/json; charset=utf-8 Content-Length: 44}}

You could try putting an ActionName attribute on the controller method. Then append the ActionName to your query string.
/ActionName?param=value

Your url is wrong. Try like this:
var detailURI = "Favorites/GetFavoritesPaged?userId=34";
or use the {id} route:
var detailURI = "Favorites/GetFavoritesPaged/34";
But you're gonna have to modify your parameter name:
public List<FavoriteDTO> GetFavoritesPaged(long id, PagingInfo pagingInfo)

Another approach is to post an anonymous type, and have the Controller accept a dynamic.
var response = client.PostAsJsonAsync(new { detailURI, pagingInfo }).Result;
[HttpPost]
public List<FavoriteDTO> GetFavoritesPaged([FromBody]dynamic model)
{
PagingInfo pagingInfo = (PagingInfo)model.pagingInfo;
long userid = (long)model.userId;
...
}

Related

OData Action Parameters is null in run time

I was trying to define a Post OData Web API action.The parameter is a number.
I found an article
And I followed as the article described, here is the source code:
WebApiConfig.cs
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.MapODataServiceRoute("odata", "odata", model: GetModel());
}
private static Microsoft.OData.Edm.IEdmModel GetModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<ThumbnailQueue>("ThumbnailQueues");
builder.EntitySet<Document>("Documents");
EntitySetConfiguration<ThumbnailQueue> thumbnailQueue = builder.EntitySet<ThumbnailQueue>("ThumbnailQueues");
var action = thumbnailQueue.EntityType.Action("PostThumbnailQueue");
action.Parameter<long>("DocumentSN");
var postThumbnailQueue = thumbnailQueue.EntityType.Collection.Action("PostThumbnailQueue");
postThumbnailQueue.Parameter<long>("DocumentSN");
return builder.GetEdmModel();
}
}
Web API
public class ThumbnailQueuesController : ODataController
{
private MarketingEntities db = new MarketingEntities();
// POST: odata/ThumbnailQueues
[HttpPost]
public IHttpActionResult PostThumbnailQueue(ODataActionParameters parameters)
{
if (parameters == null) return BadRequest();
var documentSN = (long)parameters["DocumentSN"];
if (db.ThumbnailQueues.Any(t => t.DocumentSN == documentSN))
{
return BadRequest("Record already exists");
}
var myThumbnailQueue = new ThumbnailQueue();
myThumbnailQueue.DocumentSN = documentSN;
myThumbnailQueue.Status = 1;
db.ThumbnailQueues.Add(myThumbnailQueue);
db.SaveChanges();
return Ok();
}
I used Postman to test the function
But in the run time, the parameter is null, so I can not get documentSN from the parameter. I have troubleshoot this porblem for hours, could anybody help me to fix this problem? Many thanks~
You need to use the following route for that: http://localhost:10076/odata/ThumbnailQueues/Default.PostThumbnailQueue
ThumbnailQueues - entity set
Default - default namespace
PostThumbnailQueue - action

How do I set Route attribute in this scenario?

In MVC WEB API using C# and .Net framework 4.5.1 I have a controller name MonitoringController as bellow:
public class MonitoringController : ApiController
{
[HttpGet]
[ActionName("list")]
public IEnumerable<string> List(string collection)
{
return new String[] { "test 1", "test 2" };
}
}
and my routing config is like this:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.MapHttpAttributeRoutes();
config.EnsureInitialized();
The api works fine on get requests e.g. http://localhost/api/monitoring/list?collection=test
How do I apply Route attribute to make sure it works on http://localhost/api/monitoring/channels/list?collection=test
What I thought I should do was :
[RoutePrefix("api/monitoring")]
public class MonitoringController : ApiController
{
[HttpGet]
[Route("channels")]
[ActionName("list")]
public IEnumerable<string> List(string collection)
{
return new String[] { "test 1", "test 2" };
}
}
I cannot get http://localhost/api/monitoring/channels/list?collection=test working! What have I done wrong?
I want to be able to have the following routes defined in the controller:
/api/monitoring/channels/list
/api/monitoring/windows/list
/api/monitoring/doors/list
Thanks for your help
Try flipping the order in which you register the routes:
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
And also change [Route("channels")] to [Route("channels/list")] and dump the ActionName attribute.
Better still, don't mix the two approaches and go attribute routing throughout.
If you want the collection to be part of the route use a route parameter.
[Route("{collection}/list")]
See http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2

how to route this in mvc web api?

I have this requirement to map the url
api/v1/Contact/12/tags
in the above url the Contact is the controller, and 12 is the contactId and tags is the action is want to be called.
The method is like this
[HttpGet]
public List<TagModel> Tags([FromUri]int contactId)
I have did like this
config.Routes.MapHttpRoute(
name: "RouteForHandlingTags",
routeTemplate: "api/v1/{controller}/{id}/{action}",
defaults: new { },
constraints: new { id = #"\d+" }
);
I am getting the error "No HTTP resource was found that matches the request URI http://localhost:4837/api/v1/contact/12/tags"
I have tried
[HttpGet]
public List<TagModel> Tags(int contactId)
and
config.Routes.MapHttpRoute(
name: "RouteForHandlingTags",
routeTemplate: "api/v1/{controller}/{id}/{action}"
);
But all are giving the same error. But when I do a call like this
api/v1/Contact/12/tags?contactid=12
everything works fine. But this is not what I want. The contactId is specified after contact. Can anyone please tell me how to route this?
The parameter names in your action and route must match.
You can either change your action to:
[HttpGet]
public List<TagModel> Tags(int id)
Or change your route to:
config.Routes.MapHttpRoute(
name: "RouteForHandlingTags",
routeTemplate: "api/v1/{controller}/{contactId}/{action}",
defaults: new { },
constraints: new { id = #"\d+" }
);
Note: you do not need [FromUri] with a primitive type like an int.

Asp.Net Mvc Web Api Routing 404

I try to something on Web Api. First I will share my WebApiConfig
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: new { id = #"^[0-9]+$" }
);
config.Routes.MapHttpRoute(
name: "ApiCategory",
routeTemplate: "api/tales/{category}/{id}",
defaults: new { controller = "Tales", id = RouteParameter.Optional},
constraints: new { category = #"^[a-z]+$" }
);
I read this issue and I fix my apiconfig file. My purpose like this:
List GetAllTales() = api/tales/ -> 404 Not Found
Tale GetTale(int id) = api/tales/1 -> Ok!
List GetAllTalesByCategory(string categoryName) = api/tales/kids -> Ok!
Tale GetTalesByCategoryAndId(string categoryName, int id) = api/tales/kids/1 -> Ok!
İf u wonder my ApiController
[HttpGet]
public Tale GetAllTalesByCategoryAndId(string category, int id){}
[HttpGet]
public IEnumerable<Tale> GetAllTalesByCategory(string category){}
[HttpGet]
public IEnumerable<Tale> GetAllTales(){}
[HttpGet]
public Tale GetTale(int id){}
Thanks for all replies.
You need to switch the route order. Default route will handle the request when you don't specify an id (api/tales) so you need to place your custom route before that.
config.Routes.MapHttpRoute(
name: "ApiCategory",
routeTemplate: "api/tales/{category}/{id}",
defaults: new { controller = "Tales",
id = RouteParameter.Optional,
category = RouteParameter.Optional});
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: new { id = #"^[0-9]+$" }
);

UriPathExtensionMapping to control response format in WebAPI

I'm having a problem getting UriPathExtensionMapping working in ASP.NET WebAPI. My setup is as follows:
My routes are:
config.Routes.MapHttpRoute(
name: "Api UriPathExtension",
routeTemplate: "api/{controller}.{extension}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "Api UriPathExtension ID",
routeTemplate: "api/{controller}/{id}.{extension}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
My Global ASAX file is:
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
My Controller is:
public IEnumerable<string> Get()
{
return new string[] { "Box", "Rectangle" };
}
// GET /api/values/5
public string Get(int id)
{
return "Box";
}
// POST /api/values
public void Post(string value)
{
}
// PUT /api/values/5
public void Put(int id, string value)
{
}
// DELETE /api/values/5
public void Delete(int id)
{
}
When making requests using curl, JSON is the default response, even when I explicitly request XML I still get JSON:
curl http://localhost/eco/api/products/5.xml
Returns:
"http://www.google.com"
Can anyone see the problem with my setup?
The following code maps the extensions in the Global.asax file after the routes have been configured:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.
MediaTypeMappings.Add(
new UriPathExtensionMapping(
"json", "application/json"
)
);
GlobalConfiguration.Configuration.Formatters.XmlFormatter.
MediaTypeMappings.Add(
new UriPathExtensionMapping(
"xml", "application/xml"
)
);
Do you need to register the extension mapping like so:
config.Formatters.JsonFormatter.MediaTypeMappings.Add(new UriPathExtensionMapping("json", "application/json"));
config.Formatters.XmlFormatter.MediaTypeMappings.Add(new UriPathExtensionMapping("xml", "application/xml"));
Example was found here.
Update
If you look at the code for UriPathExtensionMapping the placeholder for the extension is
/// <summary>
/// The <see cref="T:System.Uri"/> path extension key.
/// </summary>
public static readonly string UriPathExtensionKey = "ext";
So your routes would need to be changed to ({ext} not {extension}):
config.Routes.MapHttpRoute(
name: "Api UriPathExtension",
routeTemplate: "api/{controller}.{ext}/{id}",
defaults: new { id = RouteParameter.Optional }
);
As an addendum to this answer, because I can't comment yet, you should also make sure your web.config contains the line
<modules runAllManagedModulesForAllRequests="true" />
inside the <system.webServer> section.
Mine didn't and this example didn't work for me until I added that line.

Resources