Reputation: 4527
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
Upvotes: 1
Views: 848
Reputation: 964
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 }
);
}
Upvotes: 1
Reputation: 119166
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.
Upvotes: 1