I am facing problem while running "Asp.net WebApi with EntityFramework Identity" and "MVC SPA" in the single application, either of the one runs at a time, below is my code Global.asax > Application_Start where startup configuration is given.
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
GlobalConfiguration.Configure(ODataConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
Which route registration calls first that only application is accessible, in above sequence only WebApis be accessible, if I change the sequence and call Application route first then only Default web application runs.
Any help would be appreciated.
Let me know if you need additional information regarding this.
thanks in advance!!
Edit:
All the configs are given below.
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 }
);
}
WebApiConfig:
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 }
);
}
ODataConfig:
public static void Register(HttpConfiguration config)
{
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Entities.Models.ListaValore>(typeof(Entities.Models.ListaValore).Name);
var model = builder.GetEdmModel();
config.Routes.MapODataRoute("odata", "odata", model);
config.EnableQuerySupport();
}
Related
I want to add a new route to my Web Api, which will read various ids and then filter a bunch of books.
So the final url should read something like http://localhost/api/books/1/1/1/1
Now I have added a route to my RouteConfig as follows :-
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "BookFilter",
url: "api/books/{author}/{title}/{genre}/{isbn}",
defaults: new { controller = "Books", action = "BookFilter" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
I also added the following in my BooksController:-
[HttpGet]
public IQueryable<BookDTO> BookFilter(int authorId, int titleId, int genreId, int isbn)
{
//filter books here
return db.Books.ProjectTo<BookDTO>();
}
However when I try to reach the page, I get a 404.
What do I need to do to reach my page?
Thanks for your help and time
Web API and MVC are independent frameworks which each have separate types. The likely reason your route is not working is that you are confusing the two. Specifically, for it to work as you configured, you would need an MVC controller (that is, a controller that inherits System.Web.Mvc.Controller).
So, assuming you want to go with Web API as your question would indicate, you first need to ensure the correct definition of your controller. It should inherit from System.Web.Http.ApiController.
public class BooksController : ApiController
{
[HttpGet]
public IHttpActionResult BookFilter(string author, string title, string genre, string isbn)
{
return Ok("Successful result");
}
}
Next, you need to put your routing in the WebApiConfig.cs file, not in the RouteConfig.cs file. Don't forget to remove your route from the RouteConfig.cs file.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "BookFilter",
routeTemplate: "api/books/{author}/{title}/{genre}/{isbn}",
defaults: new { controller = "Books", action = "BookFilter" });
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
You also need to ensure that the call to GlobalConfiguration.Configure(WebApiConfig.Register); is in your application startup path (by default in Global.asax).
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
Make sure to use the same parameter name in your action (eg. change author to authorId):
Optionally, you can also specify default values for these parameters at your RouteConfig, as follows:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "BookFilter",
url: "api/books/{authorId}/{titleId}/{genreId}/{isbn}",
defaults: new { controller = "Books", action = "BookFilter", authorId= UrlParameter.Optional, titleId = UrlParameter.Optional, genreId = UrlParameter.Optional, isbn = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Controller:
[HttpGet]
public IQueryable<BookDTO> BookFilter(int authorId, int titleId, int genreId, int isbn)
{
//filter books here
return db.Books.ProjectTo<BookDTO>();
}
By testing and wasting obscene amount of time I have found out that ASP.NET MVC has a bug which prevents using the string "api" in request URL. I wan to access my method with URL like this
www.mysite.com/api/test
This is not an unexpected wish. In fact it an an obvious Url choice.
Is there a workaround to achieve this?
UPDATE
By request routing definition.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// this executes, checked it in debugger
routes.MapRoute(
name: "Test",
url: "api/test",
defaults: new { controller = "Api", action = "Test" }
);
}
ApiController
public class ApiController : Controller
{
public ActionResult Test()
{
return Content("TEST TEST TEST");
}
{
If you have the WebApi packages installed, you'll find a WebApiConfig.cs class in App_Start. Here's what it looks like:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
So, assuming you don't change the default code in Global.asax.cs, this route gets added to the routing table. Hence, why your /api/whatever route doesn't work.
If you're not using WebApi, I would suggest removing the packages. Otherwise, you can simply change the "root" part of the API route to something else:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
/* changed 'api' to 'restsvc' */
routeTemplate: "restsvc/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
I have 2 controllers( and ApiController and a Controller). My ApiController calls a provider to get data from the database while my Controller returns a view. I have created separate route configs for them. However, it seems like it is having problems on identifying which route to use? I'm not really sure
RouteConfig.cs
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("{resource}.aspx/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { id = UrlParameter.Optional }
);
}
}
WebApiConfig.cs
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.EnableSystemDiagnosticsTracing();
}
}
Global.asax.cs
public class WebApiApplication
{
protected void ApplicationStart()
{
WebApiAuthConfig.Register(GlobalConfiguration.Configuration);
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AutoMapperConfig.RegisterMappings();
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
}
}
The routes work fine when accessing within the project. However, when the HttpClient tries to contact the ApiController using the route stated above (Api/../..), it could not contact the controller. It seems like it's confused with the route.
Instead of setting up the standard web routing in the WebApi portion of the code, consider doing it the other way around, setting up WebApi routing in the standard web routing portion of the code. This works in a project I have access to:
public class MvcApplication : HttpApplication {
protected void Application_Start() {
GlobalConfiguration.Configure(WebApiConfig.Register);
RouteConfig.RegisterRoutes(RouteTable.Routes);
...
}
}
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}
);
}
}
public static class WebApiConfig {
public static void Register(HttpConfiguration config) {
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new {id = RouteParameter.Optional}
);
}
}
You might find it better to factor out your API into a separate project. You might then also need to factor out a common data access project that your Web and API projects both depend upon but the resulting rationalized structure will make it easier to resolve config issues of the sort you describe and build failures in one area e.g. API will not stop other projects building.
In WebApiConfig.cs, your routeTemplate should be api/{controller}/{action}/{id}
I have a MVC4 web project with WebAPI enabled.
I want to post data to the API controller but the post is not working, I am getting a 404 every time (breakpoint inside the Add method is not hit)....
Here is the code:
public class IncidentSessionLogController : ApiController
{
[HttpPost]
public void Add(MyInputDTO inputData)
{
}
}
I use action based routing:
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "ControllerAndAction",
routeTemplate: "api/{controller}/{action}");
config.Routes.MapHttpRoute(
name: "ControllerAndActionAndId",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional });
}
I use Fiddler to post the data:
http://localhost:42901/api/IncidentSessionLog/Add
My site is hosted in IIS express for development currently, I add the JSON object literal in the request body in Fiddler.
Fixed it, thanks to my collegue !
The MVC routing(which I forgot to post originally), was interfering with the API routing, so I have to add a constraint to the MVC routing :
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Game", action = "Start", id = UrlParameter.Optional },
constraints: new { controller = #"^((?!(api)).)*$" });
I have an MVC4 project with elmah added. My global.asax's Application_Start() has
WebApiConfig.Register(GlobalConfiguration.Configuration); // #1
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes); // #2
#1 and #2 are as follows
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional } );
}
...
}
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 }
);
}
}
The templates are identical and routing into the controllers works exactly as we want it (from a URI spec perspective). The issue is that the ignore route is added AFTER the WebAPI route is added. So what should be ignored by MVC4s routing and handled by Elmah (eg /elmah.axd/styles) is instead intercepted by WebAPI and the request fails => so I have no CSS in my elmah.axd pages. I tried flipping #1 and #2 in global.asax but that caused all WebAPI routing to fail - FAR worse than CSS not working in Elmah!
I basically need some way to instruct WebAPI's routing to ignore {resource}.axd/{*pathInfo} right as the first route - how can I do that?
This is what worked for us - moving the ignore out of the wrapper and as the first one.
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
//ignore route first
RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
// And taken out of the call below
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
Sounds like you need finer control of the order of the route definitions. Instead of pulling these in from the individual RouteConfig and WebApiConfig classes, you could define these directly in global.asax.cs like so:
RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
GlobalConfiguration.Configuration.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}/{action}/{id}",
defaults: new {id = RouteParameter.Optional});
RouteTable.Routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);