ASP.NET MVC combined with Web API routing - c#

I'm trying to register multiple routes for Web Pages and for Web API. Here's my config's:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Registration Courses SPA",
url: "Registration/Courses",
defaults: new {controller = "Registration", action = "Index"});
routes.MapRoute(
name: "Registration Instructors SPA",
url: "Registration/Instructors",
defaults: new { controller = "Registration", action = "Index" });
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
and
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate:"api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Here's how I register them in Global.asax
RouteConfig.RegisterRoutes(RouteTable.Routes);
GlobalConfiguration.Configure(WebApiConfig.Register);
The problem is that Web API routing not working, I'm getting 404 error, unless I register WebAPI routes first then ASP.NET MVC routes not working and Web API routes working.

Like #ChrFin stated in his comments, if you register the Web API routes first your MVC routes should still work because the default Web API route begins with "api".
I had the same problem but it was because we changed the routeTemplate of the default Web API route to {controller}/{id} because we wanted that to be the default because the purpose of our app is to be an api for other apps. In our Global.asax file the Web API routes are registered before the MVC routes, which is the default for any new Web API application. Because "/anything" matches the default Web API route, route handling stops so our MVC routes never get a chance to get matched.
The key point is that route handling stops if a route gets matched - even if there's no matching controller.
To solve our problem we prefixed our MVC routes with "mvc" and registered our MVC routes before the Web API routes.

Related

Routing not working .net mvc api

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 }
);

Asp .NET Web Api + MVC + Angular 2 - action with two parameters

I have an ASP .NET MVC application with Angular 2. I added a WebApi Controller and try to communicate from angular service with it, but it does not access an action within the WebApi Controller with two parameters.
I think I read all the question regarding that matter. I have my webApi routes registered before the MVC ones. I can access the action, if it does not require any parameters. But if I try to hit it with the parameters I keep getting 404 not found for the Login action - POST localhost:12312/api/userapi/login 404 (Not Found).
I tried every kind of formatting for the WebApiConfig - with optional parameters, without them, with dynamic controller placeholders, with the exact names for action and controller,etc. I tried Routing attribute as well, but with no effect.
I tried to put it as a single parameter "object credentials" and modified the WebApiConfig.cs as well, but the result didn't change.
RouteConfig.cs
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{*anything}",
defaults: new { controller = "Home", action = "Index", id =
UrlParameter.Optional }
);
WebApiConfig.cs
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "api",
routeTemplate: "api/userapi/login/{username}/{password}",
defaults: new { username = RouteParameter.Optional, password =
RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
UserApiController.cs
[HttpPost]
public HttpResponseMessage LogIn(string username, string password)
{
return ToJson(userRep.LogIn(username, password));
}
angular
this.http.post(url, JSON.stringify(credentials), { headers: headers })
.subscribe(res => {
resolve(res.json());
}, (err) => {
reject(err);
});
Am not sure why its not working in your way(using parmas) but i will simply create an model something like
public class LoginModel{
public UserName {get;set;}
public Password {get;set;}
}
then in login mathod
[HttpPost]
public HttpResponseMessage LogIn(LoginModel model)
{
return ToJson(userRep.LogIn(model.username, model.password));
}
No need of custom routing just use default config

Noob in ASP MVC Routing - 404 error

I'm new to API designing with VS2017 and I'm trying to make my simple API work with few SQL objects in a DB.
I have a fairly simple project which looks like this :
WebApiConfig.cs :
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
//config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
Which I believe is stock so should get me where I want to.
I have some controllers based on the same principles, here's one for example :
public class UsersController : Controller
{
private APIContext db = new APIContext();
// GET: Users
public ActionResult Index()
{
return View(db.Users.ToList());
}
// GET: Users/Details/5
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Users users = db.Users.Find(id);
if (users == null)
{
return HttpNotFound();
}
return View(users);
}
}
There are more of them, but everything has been autogenerated so I don't think I have to show them.
The problem is that when I get to localhost/api/users, I get the 404 error page :
No HTTP resource was found that matches the request URI 'http://localhost:myport/api/users'.
Same thing when I'm trying to access a specific id with /api/users/1
Can anyone point me where I should try and change things ?
I'm lost in the jungle of the config files and routes !
Thanks !
EDIT :
After some good answers, here's some more information:
I'm wondering if the issue is not somewhere else. When I'm on the localhost/api, I get a "beautiful" error page but when I try to access the /api/users/index I get an XML response with a 404 message in it. Is that a sign of another problem ?
Something to note is that the Swagger UI shows absolutely nothing.
Your Routing configuration mentions only a Controller in the template without a default Action associated with.
Multiple choices are available to you, however, I would suggest to go for a simple one as in:
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 { action = "index", id = RouteParameter.Optional }
);
}
Now the Action is part of the template, with a default value of index, you will have the following:
http://localhost:myport/api/users redirecting to UsersController.Index
http://localhost:myport/api/users/index redirecting to UsersController.Index
http://localhost:myport/api/users/details redirecting to UsersController.Details
http://localhost:myport/api/users/details/123 redirecting to UsersController.Details
Edit After a second investigation, it appears that you are using an MVC Controller rather than a WebApi Controller. While they both have the same name, they belong to different namespaces and need their own config.
In order to configure your MVC controller route, ensure to have a class as follow in your App_Start folder:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { action = "Index", id = UrlParameter.Optional }
);
}
}
Then, from the Global.asax, in Application_Start method, ensure to have the following call:
RouteConfig.RegisterRoutes(RouteTable.Routes);
as in:
protected void Application_Start()
{
RouteConfig.RegisterRoutes(RouteTable.Routes);
GlobalConfiguration.Configure(WebApiConfig.Register);
}
From this point, you can now access your controller via http://localhost:myport/users.
On the other end, if you want to do an API returning data rather than views, you would need your controller to inherit from ApiController.
Use http://localhost:yourport/users/index" instead.
The URL format is always Controller/Action/Parameters.
Add a new route with {action}
config.Routes.MapHttpRoute(
name: "MyNewRoute",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { type = RouteParameter.Optional }
URL: http://localhost:myport/api/users/details/123456

404 Errors after porting .Net Core application to MVC

For supportability reasons I'm porting an application from .Net Core with ReactJs to .Net MVC.
This also uses Redux for state handling.
This seemed to be going ok but for some reason the WebAPI calls all fail with 404 errors.
I'm pretty sure the routing is correct as per the failing calls but clearly something is getting lost somewhere.
The default MVC controller that was added as an entry point works fine, it's just the ported WebAPI controllers that seem to fail.
I'm not allowed to post the entire code for commercial reasons but this is what the controller and one of the actions in question looks like:
namespace Api.Controllers
{
/// <summary>
/// Account management.
/// </summary>
[Authorize]
[System.Web.Http.RoutePrefix("api/account")]
public class AccountController : ApiController
{
// <snip>
/// <summary>
/// Current logged in account.
/// </summary>
// GET api/Account/UserInfo
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[System.Web.Http.Route("userinfo")]
public async Task<UserInfoViewModel> GetUserInfo()
{
ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);
var userName = User.Identity.GetUserName();
var account = new AccountRepresentation(await _context
.Accounts
.SingleOrDefaultAsync(acc => acc.Email == userName));
return new UserInfoViewModel
{
Account = account,
UserName = User.Identity.GetUserName(),
Email = User.Identity.GetUserName(),
HasRegistered = externalLogin == null,
LoginProvider = externalLogin != null ? externalLogin.LoginProvider : null,
Roles = await UserManager.GetRolesAsync(User.Identity.GetUserName())
};
}
// </snip>
}
}
(snip comments added by me)
Notice the routing attributes - it's a bit over the top as I'm trying everything, but as far as I can tell this should be ok.
However in the browser console I'm seeing this:
Failed to load resource: the server responded with a status of 404
(not found) http://localhost:49690/api/account/userinfo
The port number is correct for the default controller so unless it's different for the other controllers for some reason, this should be ok as well.
I've been playing with the RouteConfig.cs file which currently looks as follows:
namespace Api
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "Api.Controllers" }
).DataTokens.Add("area", "UI");
routes.MapRoute(
name: "api",
url: "api/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "Api.Controllers" }
).DataTokens.Add("area", "UI");
}
}
}
The WebApiConfig file looks as follows:
namespace Api
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// Web API configuration and services
// Web API routes
// config.MapHttpAttributeRoutes();
// Configure Web API to use only bearer token authentication.
// config.SuppressDefaultHostAuthentication();
// config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
//config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
//config.Routes.MapHttpRoute(
// name: "DefaultApi",
// routeTemplate: "api/{controller}/{id}",
// defaults: new { id = RouteParameter.Optional }
//);
}
}
}
Application_Start() is like this:
namespace Api
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
//UnityConfig.RegisterComponents();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
log4net.Config.XmlConfigurator.Configure();
}
}
}
What else could be missing or wrong that is preventing the API actions being found?
(Let me know if any other code would be helpful)
Other details:
Visual Studio version: Enterprise 2015 update 3
.NET version: 4.6.1
In .Net Core, attribute routing is now enabled by default. However, in MVC5, you are need to set it up. In your route config, add this:
routes.MapHttpAttributeRoutes();
Note that for normal MVC (i.e. not WebAPI) you need this command instead:
routes.MapMvcAttributeRoutes();
Note: MapHttpAttributeRoutes is an extension method in System.Web.Http so you will need a using System.Web.Http; statement.
if you Porting .net Core application from .net mvc you have add WebApiConfig file and register in global file. and it should be like this. First use Route Attribute because you have use Attribute routing.
public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}

Creating a WebService inside my MVC project

I know there's another thread about WebapiConfig.cs and RouteConfig.cs, but I can assure this is a different question.
My MVC project was quite developed by the time I found out I would have to create a webservice (in the same domain) where I would grant access to one of my models (both in JSON and XML).
In order to do so, I right clicked over my Controllers and selected "add Web API 2 Controller with actions, using Entity Framework" and selected also my model class and db context.
The template was quite complete and I thought I was ready to go for the following test:
namespace MVC4GMAPS.Controllers
{
public class RestController : ApiController
{
private LocationDBContext db = new LocationDBContext();
// GET api/Rest
public IQueryable<Location> GetLocations()
{
return db.Locations;
}
etc...
Unfortunately, when I tried to access to https://localhost:44300/api/Rest I've got a 404. However, localhost:44300/Home/Index keeps working great.
I believe the problem relies on my RouteConfig.cs, because it is expecting an {action} and my RestController doesn't have any actions:
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 }
);
etc...
What can I do? Can I create simultaneously a WebapiConfig.cs file? I believe not. I hope you can help me!
Do you also have a WebApiConfig.cs? In a project which was "Web API from the start" I have this in it:
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 }
);
}
}
This, like the other configs, is called from Global.asax.cs:
GlobalConfiguration.Configure(WebApiConfig.Register);
That should get the routing pointed to the API controller. Otherwise, as you say, the route defined from MVC by default would be looking for an action called Rest on a controller called api which doesn't exist.

Categories