I am trying to create an Asp.net WebApi / Single Page Application. I would like my server to dispense index.html if no route is given. I would like it to use a controller when one is specified in the normal "{controller}/{id}" fashion.
I realized that I can visit my index page by using http://localhost:555/index.html. How do I do the same by visiting http://localhost:555 ?
Just add a route to your WebApiConfig file for index page. Your method should look like this:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Attribute routing
config.MapHttpAttributeRoutes();
// Route to index.html
config.Routes.MapHttpRoute(
name: "Index",
routeTemplate: "{id}.html",
defaults: new {id = "index"});
// Default route
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
The solution was to create an empty DefaultRoute.
// I think this passes control through before trying to use a Controller
routes.MapHttpRoute(
"DefaultRoute", "");
routes.MapHttpRoute(
"DefaultAPI",
"{controller}/{id}",
new { Controller = "Home", Id = RouteParameter.Optional });
Another solution was to prefix my WebApi with 'api', which is not entirely what I wanted, but is a suitable solution. This was shown in Herman Guzman's answer, but is not his answer.
// Default route
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
Related
I've got a simple web API that registers on one route. At the moment I've got two because only one of them does what I need.
My application only has one controller and one Post method in that Controller. I've registered a single Route which always returns a 405 (method not allowed)
The two routes are configured in the RouteConfig.cs:
routes.MapHttpRoute(
name: "app-events",
routeTemplate: "events",
defaults: new { controller = "Events" },
handler: new GZipToJsonHandler(GlobalConfiguration.Configuration),
constraints: null
);
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
The Controller method is essentially this...
public class EventsController : ApiController
{
public EventsController()
{
_sender = new EventHubSender();
}
public async Task<HttpResponseMessage> Post(HttpRequestMessage requestMessage)
{
// doing fun stuff here…
return new HttpResponseMessage(HttpStatusCode.OK);
}
}
If I only configure the first route and post a request to http://devbox/events I will get a 405. However, if I add the second, default, route, and post to http://devbox/api/events I get back my expected 201.
With both routes configured at the same time, the same pattern, the route explicitly bound to the Controller receives a post request and fails with a 405, but the other URL will work.
I've spent a long time looking around before conceding to ask the question. Most things I read have a lot to do with Webdav and I think I've followed every one of them to fix the issue. I am not very experienced with this stack, so nothing is very obvious to me.
You mentioned RouteConfig File. This is used for configuring the MVC routes not Web API routes.
So it would appear you are configuring the wrong file which would explain why the api/... path works as it is probably mapping to the default configuration in WebApiConfig.Register, which would look like
public static class WebApiConfig {
public static void Register(HttpConfiguration config) {
// Convention-based routing.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
You would need to update that file with the other desired route
public static class WebApiConfig {
public static void Register(HttpConfiguration config) {
// Convention-based routing.
config.Routes.MapHttpRoute(
name: "app-events",
routeTemplate: "events",
defaults: new { controller = "Events" },
handler: new GZipToJsonHandler(GlobalConfiguration.Configuration),
constraints: null
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Web API routes are usually registered before MVC routes which explains why it was not working with your original configuration.
You should also adorn the action with the respective Http{Verb} attribute.
In this case HttpPost so that the route table knows how to handle POST requests that match the route template.
[HttpPost]
public async Task<IHttpActionResult> Post() {
var requestMessage = this.Request;
// async doing fun stuff here….
return OK();
}
I have two action methods in my Products controller. This is my RouteConfig.
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
These are the two actions and their working urls.
[HttpGet]
//uri:http://localhost:49964/api/products/product?strKey=1
public IHttpActionResult Product(string strKey)
[HttpPost]
//uri:http://localhost:49964/api/products/product
public IHttpActionResult Product([FromBody] Product product)
But I also want to use the below url for GET.
http://localhost:49964/api/products/product/1
But web api responds with,
The requested resource does not support http method 'GET'.
Change strKey to id or do the reverse if you want to keep strKey.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{strKey}",
defaults: new { strKey = RouteParameter.Optional }
);
The route template needs to match up to the action for mapping to work as intended.
//GET api/products/product/1
//GET api/products/product?strKey=1
[HttpGet]
public IHttpActionResult Product(string strKey)
this would however mean that all actions in this route would optionally use strKey as a placeholder
Situation :
I've created controller class that extends ApiController and includes following methods :
// GET api/Posts/5
[ResponseType(typeof(Post))]
public IHttpActionResult GetPost(int id)
{
...
}
// GET api/Posts/ByBoardID/2
[HttpGet]
[ActionName("ByBoardID")]
public IQueryable<Post> GetByBoardID(int boardID)
{
...
}
The idea is to match those method to a given routes (i.e 'api/Posts/ByBoardID/2' to a GetByBoardID(int boardID) method and 'api/Posts/2' to a GetPosts(int id) method).
Here's route config :
config.Routes.MapHttpRoute(
name: "ByParamApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional });
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional });
Problem :
Second route ('api/Posts/ByBoardID/2') cannot be matched - No HTTP resource was found that matches the request URI.
Question :
Whats the best practice to create such 'nested' routes inside controller? I will use many controllers with the same pattern (/{controller}/{id} and /{controller}/bySpecialParam/{id}) so I don't want to 'hardcode' such route that won't be reusable.
Only way I ever got working such combination is by changing this
[ActionName("ByBoardID")]
to
[Route("api/Posts/ByBoardID/{boardID}")]
Never able to figure out how the ActionName attribute works so always preferred to go with Route attribute
This worked:
1) Provide actionName for both the methods in the controller.
[ActionName("DefaultAction")]
[ActionName("ByBoardID")]
2) In the webapiconfig class, add the following routes
config.Routes.MapHttpRoute(
"defaultActionRoute",
"{controller}/{action}/{id}",
null,
new
{
action = "ByBoardId"
});
config.Routes.MapHttpRoute(
"defaultRoute",
"{controller}/{id}",
new
{
action = "DefaultAction"
});
Make sure you have the GlobalConfiguration.Configuration.EnsureInitialized(); at the end of Application_Start() method.
Hi I have customs config.Routes.MapHttpRoute but the API is forcing me to use query string as parameter instead regular parameters separated by / such has this ...api/data/2/23.
If I call my API as ...api/collectdata/1 it does not work but if I call like this it works ...api/collectdata?researchid=1
This what I have in my WebApiConfig
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional });
config.Routes.MapHttpRoute(
name: "CollectDataFromPets",
routeTemplate: "api/collectdata/{researchid}");
And my controller looks like this:
public IHttpActionResult CollectData(int researchId)
{
try
{
service.SaveDataByResearchId(researchId);
return Ok(new { Message = "Data collected and saved" });
}
catch (Exception e)
{
return new CustomError(e.Message,Request);
}
}
Route order matters. Your generic (DefaultApi) route has to be declared last since it's "greedy" - otherwise it will catch all the requests, preventing other routes from kicking in
Your specific route doesn't have a controller defined, you will need to modify it to:
config.Routes.MapHttpRoute(
name: "CollectDataFromPets",
routeTemplate: "api/collectdata/{researchid}",
defaults: new {controller = "CollectData"} //or whatever your controller name is
);
I just merged an existing API project into another existing MVC project. The API controllers have the same name as the MVC controllers but they're in 2 different namespaces (MyApp.Web.MyController and MyApp.API.MyController, respectively).
Now, I don't really know how to configure the routes so that I can access the API controllers :(
I read this post : Mixing Web Api and ASP.Net MVC Pages in One Project and would like the achieve what #Mike Wasson suggested there, but I don't know how to configure the routes.
This is what I currently have in RouteConfig.cs:
public class RouteConfig
{
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 }
);
}
}
It looks like you already have it working, but should you ever wish to use your API controllers in an area, you can enable it simply by adding an additional route.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultAreaApi",
routeTemplate: "api/{area}/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
// Application_Start
GlobalConfiguration.Configure(WebApiConfig.Register);
AreaRegistration.RegisterAllAreas();