I try to use Web Api in an ASP.NET MVC4 application.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "ActionIdApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
public class OrganisationApiController : ApiController
{
public List<Direction> GetDirections()
{
List<Direction> res = new List<Direction>();
using (SerializerContext context = new SerializerContext())
{
res = context.DirectionSet.ToList();
}
return res;
}
public List<Departement> GetDepartements(int directionId)
{
List<Departement> res = new List<Departement>();
using (SerializerContext context = new SerializerContext())
{
res = context.DepartementSet.Where(d => d.IdDirection == directionId).ToList();
}
return res;
}
}
Application starts with
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
When I develop I can call all my methods from OrganisationApiController :
http://localhost:5000/api/OrganisationApi => GetDirections is called
http://localhost:5000/api/OrganisationApi/GetDirections => GetDirections is called
http://localhost:5000/api/OrganisationApi/GetDepartements/1 => GetDepartement is called with directionId = 1
But when I deploy on a server with IIS
http://myserver.com:5000/api/OrganisationApi => GetDirections is called
http://myserver.com:5000/api/OrganisationApi/GetDirections => GetDirections is called
http://myserver.com:5000/api/OrganisationApi/GetDepartements/1 => 404 error
What I am missing?
You have a problem with those routes:
config.Routes.MapHttpRoute(
name: "ActionIdApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}",
defaults: new { id = RouteParameter.Optional }
);
The second route is unnecessary (because the first one already handles those requests - id is specified as optional) and it has an error that you specifying that id is optional but the route doesn't contain an id at all.
Either remove the second route and change your action so it receive an optional parameter or replace them with:
config.Routes.MapHttpRoute(
name: "ActionIdApi",
routeTemplate: "api/{controller}/{action}/{id}",
);
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}",
);
By the way your default rote is also very problematic because you are not specifying default controller and action - it supposed to be DEFAULT right...
From what i see here all your routes could be replaced with this one
config.Routes.MapHttpRoute(
name: "ApiDefault",
routeTemplate: "api/{controller}/{action}/{id}",
new { controller = "HomeApi", action="IndexApi" id = RouteParameter.Optional });
Just replace your default values for controller and action.
EDIT:
The problem is in your action:
If you specify in your Route "id" parameter your action should be:
public List<Departement> GetDepartements(int id)
Parameter names must match.
Also you can combine both your actions into one action:
public List<Departement> GetDepartements(int? id)
{
List<Departement> res = new List<Departement>();
using (SerializerContext context = new SerializerContext())
{
if(id.HasValue)
{
res = context.DepartementSet.Where(d => d.IdDirection == directionId).ToList();
}
else
{
res = context.DirectionSet.ToList();
}
}
return res;
}
Related
So I have GET-methods in two different controllers that does not seem to work at the same time. My route config looks like this:
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "GetGroupsFromSection",
routeTemplate: "api/{controller}/{action}/{sectionId}"
);
config.Routes.MapHttpRoute(
name: "ReturnCountForGroup",
routeTemplate: "api/{controller}/{action}/{groupIdCount}"
);
}
With this config, the first route(GetGroupsFromSection) works, but not the other one. If I switch them up so the ReturnCountForGroup is first, then that one works but not the other.
This is the methods
In the GroupController:
[HttpGet]
public IEnumerable<Group> GetGroupsFromSection(int sectionId)
{
var allGroups = groupRepository.SearchFor(s => s.SectionId == sectionId).ToList();
return (IEnumerable<Group>)allGroups;
}
And here is the other one from the ActivationCode-controller:
[HttpGet]
public int ReturnCountForGroup(int groupIdCount)
{
var count = dataContext.ActivationCode.Count(c => c.GroupId == groupIdCount);
return count;
}
GetGroupsFromSection is getting a 200 ok. But the ReturnCountForGroup get this error-message:
"MessageDetail": "No action was found on the controller 'ActivationCode' that matches the request."
There are conflicting routes which need to be made more specific for a route match to be made. Also the order of how routes are added to the route table is important. More generic routes need to be added after more specific/targeted routes.
config.Routes.MapHttpRoute(
name: "GetGroupsFromSection",
routeTemplate: "api/Group/{action}/{sectionId}",
defaults: new { controller = "Group" }
);
config.Routes.MapHttpRoute(
name: "ReturnCountForGroup",
routeTemplate: "api/ActivationCode/{action}/{groupIdCount}",
defaults: new { controller = "ActivationCode" }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
I need to use multiple POST-requests in web API but get an error: "Multiple actions were found that match the request..."
I have 2 POST-requests in my controller:
public void PostStart([FromBody]string value)
{
CookieHeaderValue cookie = Request.Headers.GetCookies("user").FirstOrDefault();
...
}
public void PostLogin([FromBody]string value)
{
CookieHeaderValue cookie = Request.Headers.GetCookies("user").FirstOrDefault();
...
}
My route file looks like this currently:
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "apistart",
routeTemplate: "Home/api/values/start/{id}",
defaults: new { action = "PostStart", id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "apilogin",
routeTemplate: "Home/api/values/login/{id}",
defaults: new { action = "PostLogin", id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
If I remove on of the requests from the controller, everything works fine, so my routes seem valid, but when both of requests are present, router can't find the right one.
Any thoughts?
I've tried alredy to use another default route but it changes nothing:
routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
You can use [HttpPost] attribute to specify request method:
[HttpPost]
public void Start([FromBody]string value)
{
CookieHeaderValue cookie = Request.Headers.GetCookies("user").FirstOrDefault();
...
}
[HttpPost]
public void Login([FromBody]string value)
{
CookieHeaderValue cookie = Request.Headers.GetCookies("user").FirstOrDefault();
...
}
That will allows you to use as many post actions as you want with using default action-based route rule.
routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
You should use RouteAttribute to make it work:
[Route("start")]
public void PostStart([FromBody]string value)
{
CookieHeaderValue cookie = Request.Headers.GetCookies("user").FirstOrDefault();
...
}
[Route("login")]
public void PostLogin([FromBody]string value)
{
CookieHeaderValue cookie = Request.Headers.GetCookies("user").FirstOrDefault();
...
}
WebApi doesn't take into consideration method name, only first word to resolve http method. Thats why you have error which says about "Multiple actions..." - there are two actions which can handle POST request.
I have read almost everything. applied all solutions. still nothing is working.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "ApiWithAction",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.EnableSystemDiagnosticsTracing();
}
}
Web api Sorting.cs file
[ActionName("pcc")]
public IHttpActionResult Post(PccModel pcc)
{
return Ok()
}
[ActionName("sortBy")]
public IHttpActionResult PostSortBy(SortByModel sortByModel)
{
return Ok();
}
}
calling web api from angular controller .js file
call to sortBy...
$http({
method: 'POST',
url: '/api/Sorting/sortBy',
data: sortByModel,
headers: { 'Content-Type': 'application/json' }
})
.success(function () {
}).error(function() {
});
call to pcc
return $http.post('/api/Sorting/pcc', data);
In both call, same multiple action method error comes.
apply
config.Routes.MapHttpRoute(
name: "ApiWithAction",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
before
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
for more info see this
i would like to access below methods but i can not access "http://www.test.com:46707/rpc/RealmStatus/RealmByPopulationName/2/Vindication"
[ActionName("RealmByPopulationName")]
public IEnumerable<MyRealmStatus> GetRealmsByBattleGroupName(int regionid, string battlegroupname)
{
//dosomething...
}
My webApiConfig.cs below
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{regionid}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "GetData",
routeTemplate: "api/{controller}/{regionid}/{id}"
);
config.Routes.MapHttpRoute(
name: "RpcApi",
routeTemplate: "rpc/{controller}/{action}/{regionid}",
defaults: new { action = "Get" }
);
config.Routes.MapHttpRoute(
name: "RpcApi2",
routeTemplate: "rpc/{controller}/{action}/{regionid}/{quality}/",
defaults: new { action = "Get" }
);
config.Routes.MapHttpRoute(
name: "RpcApi3",
routeTemplate: "rpc/{controller}/{action}/{regionid}/{battlegroupname}/",
defaults: new { action = "Get" }
);
}
}
Error occurs i can not access GetRealmsByBattleGroupName
Result of "http://www.test.com:46707/rpc/RealmStatus/RealmByPopulationName/2/Vindication" :
<Error>
No HTTP resource was found that matches the request URI 'http://www.test.com:46707/rpc/RealmStatus/RealmByPopulationName/2/Vindication'.
No action was found on the controller 'RealmStatus' that matches the request.
Your call is going to match this route first:
config.Routes.MapHttpRoute(
name: "RpcApi2",
routeTemplate: "rpc/{controller}/{action}/{regionid}/{quality}/",
defaults: new { action = "Get" }
);
Therefore your API is looking for a method on the RealmStatus controller that matches the following signature:
[ActionName("RealmByPopulationName")]
GetRealmsByBattleGroupName(int regionid, string quality)
If quality is a number you could differentiate the routes by adding the following constraint:
config.Routes.MapHttpRoute(
name: "RpcApi2",
routeTemplate: "rpc/{controller}/{action}/{regionid}/{quality}/",
defaults: new { action = "Get" },
constraints: new { id = #"(^\d+$)" }
);
In my TestController I have the following:
[HttpGet]
public IEnumerable<String> Active()
{
var result = new List<string> { "active1", "active2" };
return result;
}
[HttpGet]
public String Active(int id)
{
var result = new List<string> { "active1", "active2" };
return result[id];
}
In RouteConfig the mapping is:
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { action = "", id = RouteParameter.Optional });
In a browser the following request works:
api/test/active/1
But this returns a Internal Server Error:
api/test/active
What do you have to do to return a action that may or maynot have a parameter in a similar manner to the default Get?
Update 1
As Cuong Le suggested, changing the ordering of routes helped, the routes are now:
routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
I had to remove action = "" from the ActionApi route otherwise the standard Get on the other controllers stopped working (i.e. api/values)
api/test/active is now resolving, but I now get a 500 Internal Server Error for /api/test is it possile to have both resolves, so api/test would return "all" and /test/active only return "some"?
It is probably getting confused since you have two methods named action. Try deleting or renaming one of them and see if that works.
One way to do it is to provide a default value for the parameter,
[HttpGet]
public String Active(int id = 0)
{
var result = new List<string> { "active1", "active2" };
if (id == 0) {
return result;
} else {
return result[id];
}
}