I have been struggling with this problems for days. I have a controller that need to have multiple GET and POST methods. Somehow I managed to achieve multiple GET methods in the controller. At that time there was only one POST method. Everything was running fine until I introduced one more POST method. Whenever I use POST method from client side using ExtJS, only the first POST method gets called. Here are the methods in my controller:
[AllowAnonymous]
[ActionName("userlist")]
[HttpGet]
public List<MyApp.Entity.Models.usermaster> Get(bool isActive)
{
//My code
}
[AllowAnonymous]
[ActionName("alluserlist")]
[HttpGet]
public List<MyApp.Entity.Models.usermaster> Get()
{
//My code
}
[AllowAnonymous]
[ActionName("updateuser")]
[HttpPost]
public string UpdateUser(JObject userData)
{
//My code
}
[AllowAnonymous]
[ActionName("adduser")]
[HttpPost]
public string AddUser(JObject newUserData)
{
//My code
}
I also have two route config files. The first one has the following configuration:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Another file has the following configuration:
public static void Register(HttpConfiguration config)
{
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "ControllersWithAction",
routeTemplate: "api/{controller}/{action}");
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional });
}
This is how the ajax call is made to the api:
Ext.Ajax.request({
url: 'localhost/myapp/api/users/adduser',
mode: 'POST',
params: {
userName: 'user',
password: 'password'
},
success: function (resp) {
var respObj = Ext.decode(resp.responseText);
if (respObj == 'added') {
Ext.Msg.alert('Success', 'User added.');
}
else {
Ext.Msg.alert('Error', respObj);
}
},
failure: function (resp) {
Ext.Msg.alert('Error', 'There was an error.');
}
});
Can anyone point out the mistake? Alternatively, any example with multiple GET and POST methods in side one controller with route config would be very helpful.
why don't you use PUT method for UpdateUser ?
[AllowAnonymous]
[HttpPut]
public string UpdateUser(JObject userData)
{
//My code
}
update:
you can use multiple POST but then you should either use ActionNames that works but is not restful or stop using Complex Types as parameters. because Web API ignores Complex Types when it tries to select most appropriate Action . check these :
Multiple actions for the same HttpVerb
http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-and-action-selection
You could try this
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "ApiById",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: new { id = #"^[0-9]+$" }
);
config.Routes.MapHttpRoute(
name: "ApiByName",
routeTemplate: "api/{controller}/{action}/{name}",
defaults: null,
constraints: new { name = #"^[a-z]+$" }
);
config.Routes.MapHttpRoute(
name: "ApiByAction",
routeTemplate: "api/{controller}/{action}",
defaults: new { action = "Get" }
);
}
}
you can use ActionName for your method as well
[AllowAnonymous]
[HttpPost]
[ActionName("userlist")]
public string UpdateUser(JObject userData)
{
//My code
}
[AllowAnonymous]
[HttpPost]
[ActionName("alluserlist")]
public string AddUser(JObject newUserData)
{
//My code
}
Also, you have to use ActionName in your URL for API, when you call your post method.
Make sure your route Config have {action} in WebApiConfig.
for custom binding in web API you can refer following link
https://blogs.msdn.microsoft.com/jmstall/2012/04/16/how-webapi-does-parameter-binding/
Related
Did a lot of reading around this but no existing fixes work for me.
I am trying to hit an api endpoint from a apiClient project but I keep getting the error message: No action was found on the controller 'UserApi' that matches the request.
I'm able to debug into the api controller but it just won't hit the method.
Client:
public async Task<bool> UserExists(UserDto dto)
{
var postUrl = $"{BaseUri}UserApi/user-exists";
var json = await PostAsync(new Uri(postUrl), dto);
return JsonConvert.DeserializeObject<bool>(json);
}
Api controller:
[Route("api/UserApi")]
public class UserApiController : ApiController
{
public UserApiController()
{
}
[HttpPost]
[Route("user-exists")]
public async Task<bool> UserExists([FromBody]UserDto dto)
{
return true;
}
Route config:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapHttpRoute(
name: "ApiAction",
routeTemplate: "api/{controller}/{action}/{dto}",
defaults: new { dto = UrlParameter.Optional }
);
}
The bottom routing configuration is the one I'm trying to use. Any help is appreciated
the first comment on the original post solved half my issue - I was trying to configure routing two different ways. I removed all my code from RegisterRoutes and used
config.MapHttpAttributeRoutes();
in WebApiConfig.
I also needed to use the RoutePrefix attribute on the api controller instead of just Route - which is to be used on the controller methods. working now
1.In Global.asax.cs just comment
//RouteConfig.RegisterRoutes(RouteTable.Routes);
As you are using web api no need of this route configuration
2.In WebApiConfig.cs use below line only
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
In ASP.NET MVC WebAPI project by default we have created following controller
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
public string Get(int id)
{
return "value";
}
// POST api/values
public void Post([FromBody]string value)
{
}
// PUT api/values/5
public void Put(int id, [FromBody]string value)
{
}
// DELETE api/values/5
public void Delete(int id)
{
}
}
But is possible to add here any custom methods so they can support get/post as well?
Thank you!
You can use attributes such as the RoutePrefix with the Http type.
[Route("ChangePassword")]
[HttpPost] // There are HttpGet, HttpPost, HttpPut, HttpDelete.
public async Task<IHttpActionResult> ChangePassword(ChangePasswordModel model)
{
}
The http type will map it back to its correct method in combination with the Route name.
I am not sure I follow as you have GET and POST right there in your code, but in any case you have other options:
Option 1
First, you can configure your custom Routes in the App_Start folder in the WebApiConfig.cs file. Here is what I normally use:
// GET /api/{resource}/{action}
config.Routes.MapHttpRoute(
name: "Web API RPC",
routeTemplate: "{controller}/{action}",
defaults: new { },
constraints: new { action = #"[A-Za-z]+", httpMethod = new HttpMethodConstraint("GET") }
);
// GET|PUT|DELETE /api/{resource}/{id}/{code}
config.Routes.MapHttpRoute(
name: "Web API Resource",
routeTemplate: "{controller}/{id}/{code}",
defaults: new { code = RouteParameter.Optional },
constraints: new { id = #"\d+" }
);
// GET /api/{resource}
config.Routes.MapHttpRoute(
name: "Web API Get All",
routeTemplate: "{controller}",
defaults: new { action = "Get" },
constraints: new { httpMethod = new HttpMethodConstraint("GET") }
);
// PUT /api/{resource}
config.Routes.MapHttpRoute(
name: "Web API Update",
routeTemplate: "{controller}",
defaults: new { action = "Put" },
constraints: new { httpMethod = new HttpMethodConstraint("PUT") }
);
// POST /api/{resource}
config.Routes.MapHttpRoute(
name: "Web API Post",
routeTemplate: "{controller}",
defaults: new { action = "Post" },
constraints: new { httpMethod = new HttpMethodConstraint("POST") }
);
// POST /api/{resource}/{action}
config.Routes.MapHttpRoute(
name: "Web API RPC Post",
routeTemplate: "{controller}/{action}",
defaults: new { },
constraints: new { action = #"[A-Za-z]+", httpMethod = new HttpMethodConstraint("POST") }
);
I use a combination of RESTful endpoints as well as RPC endpoints. For some purists, this is grounds for a holy war. For me, I use a combination of the two because it is a powerful combination and I can't find any sane reason not to.
Option 2
As the others have pointed out and as I myself am doing more of these days, use attribute routing:
[HttpGet]
[GET("SomeController/SomeUrlSegment/{someParameter}")]
public int SomeUrlSegment(string someParameter)
{
//do stuff
}
I needed a NuGet package for attribute routing to make this work (just search NuGet for "Attribute Routing"), but I think that MVC 5/WebAPI 2 has it natively.
Hope this helps.
You could use attribute routing:
[Route("customers/{customerId}/orders")]
public IEnumerable<Order> GetOrdersByCustomer(int customerId) { ... }
Some documentation to get you started:
http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2
First Put this route to webapiconfig.cs
config.Routes.MapHttpRoute(
name: "ApiWithAction",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Now you can add actions to your controllers like this
[HttpPost]
public void Upload()
{
//Do some thing
}
I decorated upload action with httppost attribute that means this action accept just only post requests , if you want to actions to be GET , you can remove attribute or just decorate to your suite
I can't see the trouble, i have the ApiController with many actions, when i try to do request to one of action i have the following exception. Thanks in advance
//Angular script
var app = angular.module('app');
app.factory('userRepository', function ($http) {
var defaultUrl = 'api/UsersApi';
return {
addUserToRole: function (data) {
return $http({
method: 'POST',
url: defaultUrl + '/' + 'AddUserToRole',
data: {
RoleId: data.RoleId,
UserId: data.User.UserId
}
});
}
}
});
//Api controller
public class UsersApiController : ApiController
{
UserRepository uRep;
RoleRepository rRep;
[Authorize]
[HttpPost]
public HttpResponseMessage AddUserToRole(Int32 RoleId, Int32 UserId)
{
try
{
uRep = new UserRepository();
uRep.AddUserToRole(UserId, RoleId);
}
catch (Exception ex)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return new HttpResponseMessage(HttpStatusCode.OK);
}
}
}
//Route configuration
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi1",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi2",
routeTemplate: "api/{controller}/{action}"
);
}
}
After request i have the result:
This XML file does not appear to have any style information associated with it. The document tree is shown below.
The requested resource does not support http method 'GET'.
if i change HttpPost to HttpGet appears the following error occurs
This XML file does not appear to have any style information associated with it. The document tree is shown below.
No HTTP resource was found that matches the request URI '/api/UsersApi/AddUserToRole'.
No action was found on the controller 'UsersApi' that matches the request.
In your addUserToRole function inside your service, instead of setting data with the post set params:
params: {RoleId: data.RoleId,UserId: data.User.UserId}
Also, check your Web API route config to make sure you're allowing multiple requests with the same HTTP method to one controller, do this by including the action name inside your route config.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
I'm working on mvc4 web api project.
I have created a new controller GroupValuesController and i have following methods
public GroupViewModel Get()
public List<GroupModel> Get(Guid Id)
public List<GroupModel> GetDetails(Guid Id)
First two methods are working fine I'm calling them from a group.cshtml view like following
$.getJSON(
"api/groupvalues",
function (data) {
and
$.getJSON(
"api/groupvalues/" + id,
function (data) {
For third controller method public List<GroupModel> GetDetails(Guid Id) i'm executing that from Details.cshtml view like following but it is not working.
i'm mismatching some calling ?
function getGroupDataById(id, ctrl) {
$.getJSON(
"api/groupvalues/GetDetails/" + id,
function (data) {
Is this related with Route?
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Per the link below, in order to target that action method the way you have, you need to change your routing:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
http://www.codeproject.com/Articles/624180/Routing-Basics-in-ASP-NET-Web-API
It really doesn't matter what you write after Get, it is going to call the first one with same arguments. Web API don't rely on name rather they rely on HTTP verbs.
I have these two routes defined:
routes.MapRoute(
name: "GetVoucherTypesForPartner",
url: "api/Partner/{partnerId}/VoucherType",
defaults: new { controller = "Partner", action = "GetVoucherTypesForPartner"}
);
routes.MapRoute(
name: "Default",
url: "api/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional}
);
In my PartnerProfile controller, I have 2 methods:
public Partner Get(string id)
{ }
public IEnumerable<string> GetVoucherTypesForPartner(string id)
{ }
If I hit the url ~/api/Partner/1234 then, as expected, the Get method is called.
However, if I hit the url ~/api/Partner/1234/VoucherType then the same Get method is called. I am expecting my GetVoucherTypesForPartner to be called instead.
I'm pretty sure something in my route setup is wrong...
You seem to have mapped standard MVC routes, not Web API routes. There's a big difference. The standard routes are used by controllers deriving from the Controller class, but if you are using the ASP.NET Web API and your controllers are deriving from the ApiController type then you should define HTTP routes.
You should do that in your ~/App_Start/WebApiConfig.cs and not inside your ~/App_Start/RouteConfig.cs.
So go ahead:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "GetVoucherTypesForPartner",
routeTemplate: "api/Partner/{partnerId}/VoucherType",
defaults: new { controller = "Partner", action = "GetVoucherTypesForPartner" }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
and then:
public class PartnerController : ApiController
{
public Partner Get(string id)
{
...
}
public IEnumerable<string> GetVoucherTypesForPartner(string partnerId)
{
...
}
}
Things to notice:
We have defined HTTP routes not standard MVC routes
The parameter that the GetVoucherTypesForPartner action takes must be called partnerId instead of id in order to respect your route definition and avoid any confusions