I've got a C# project using Web API. I've defined my prefix and routing for my controller, but I keep receiving an error when trying to access the "all" route:
{
"message": "No HTTP resource was found that matches the request URI '.../api/InventoryOnHand/all'.",
"messageDetail": "No type was found that matches the controller named 'InventoryOnHand'."
}
Here's my controller:
[RoutePrefix("api/inventoryonhand")]
public class InventoryOnHandController : ApiController
{
public InventoryOnHandController(){}
[HttpGet]
[Route("all")]
[CacheOutput(ClientTimeSpan = 50, MustRevalidate = true)]
public IHttpActionResult GetAllInventoryOnHand()
{
// Do stuff
}
}
My WebApiConfig isn't the issue (I think) because we have other routes working just fine, can't figure out why this one is the odd man out. Our routing in WebApiConfig:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
EDIT Adding the WebApiConfig file:
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// require authenticated users in all controllers/action unless decoratd with "[AllowAnonymous]"
config.Filters.Add(new AuthorizeAttribute());
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
config.Services.Add(typeof(IExceptionLogger), new SerilogExceptionLogger());
ConfigureJsonHandling(config.Formatters.JsonFormatter);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// Web API routes
config.MapHttpAttributeRoutes();
}
private static void ConfigureJsonHandling(JsonMediaTypeFormatter json)
{
//make our json camelCase and not include NULL or default values
json.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
json.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
json.SerializerSettings.DefaultValueHandling = Newtonsoft.Json.DefaultValueHandling.Ignore;
json.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
}
EDIT Adding the Startup file (shortened for brevity):
public void Configuration(IAppBuilder app)
{
LoggingConfig.ConfigureLogger();
HttpConfiguration httpConfiguration = new HttpConfiguration();
var container = IoC.Initialize();
httpConfiguration.DependencyResolver = new StructureMapResolver(container);
ConfigAuth(app);
WebApiConfig.Register(httpConfiguration);
GlobalConfiguration.Configure(WebApiConfig.Register);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(httpConfiguration);
Log.Logger.ForContext<Startup>().Information("======= Starting Owin Application ======");
}
Since you are using attributes, you can't get routing by convention. In your WebApiConfig (where you have the route right now), you need to add a line to config.MapHttpAttributeRoutes() like this:
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
The call to the MapHttpAttributeRoutes extension method is what will pick up the attributes for the route/routeprefix and create a new route to your method.
Attribute Routing in ASP.NET Web API 2
The order in which routes are mapped is important. Attribute route mapping config.MapHttpAttributeRoutes() must be done before convention-based routes because when the framework is matching routes in the route table, the first match wins. If a route is match via convention then it will not reach the attribute routes.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
//..other code removed for brevity
// Attribute routing.
config.MapHttpAttributeRoutes();
// Convention-based routing.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
ApiController
[RoutePrefix("api/inventoryonhand")]
public class InventoryOnHandController : ApiController {
public InventoryOnHandController(){}
//GET api/inventoryonhand
[HttpGet]
[Route("")]
[CacheOutput(ClientTimeSpan = 50, MustRevalidate = true)]
public IHttpActionResult GetAllInventoryOnHand() {
// Do stuff
}
}
Try this in the Startup.
public void Configuration(IAppBuilder app)
{
LoggingConfig.ConfigureLogger();
HttpConfiguration httpConfiguration = GlobalConfiguration.Configuration;
GlobalConfiguration.Configure(WebApiConfig.Register);
var container = IoC.Initialize();
httpConfiguration.DependencyResolver = new StructureMapResolver(container);
ConfigAuth(app);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
Log.Logger.ForContext<Startup>().Information("======= Starting Owin Application ======");
}
Related
I cannot figure out why one my attribute routing isn't working, the first action method works but not the second one.
Here is my setup:
public class ActivMobileController : ApiController
{
[HttpGet]
[Route("api/ActivMobile/Impact/{token}")]
public IHttpActionResult Impact(string token)
{
...
}
[HttpGet]
[Route("api/ActivMobile/Attachments/{id}")]
public IHttpActionResult Attachments(string id)
{
...
}
}
here is my WebApiConfig:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Reference: https://learn.microsoft.com/en-us/aspnet/web-api/overview/security/enabling-cross-origin-requests-in-web-api
config.EnableCors(new EnableCorsAttribute(CloudConfigurationManager.GetSetting("AllowOrigins"), "*", "*"));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Here is the URL im testing and it gives 404 Error
http://localhost:60105/api/ActivMobile/Attachments/39E522838A652508112E9AD1E0E831C7
You're specifying API twice when it's already in your default template
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Remove the redundant Api/activMobile from your routes
[Route("Impact/{token}")]
public IHttpActionResult Impact(string token)
{
...
}
[HttpGet]
[Route("Attachments/{id}")]
public IHttpActionResult Attachments(string id)
{
...
}
In a self hosted webapi console application project, I am not able to hit the SayHello method using http://localhost:9998/api/shri/flows/config.
Error:
{
"Message": "No HTTP resource was found that matches the request URI 'http://localhost:9998/api/shri/flows/config'.",
"MessageDetail": "No route data was found for this request."
}
Controller:
class ConfigController : ApiController
{
[HttpGet, Route("{id}/flows/config")]
public string SayHello([FromUri] string id)
{
return "Hello " + id;
}
}
Startup:
public class Startup
{
// This code configures Web API. The Startup class is specified as a type
// parameter in the WebApp.Start method.
public void Configuration(IAppBuilder appBuilder)
{
// Configure Web API for self-host.
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
appBuilder.UseWebApi(config);
}
}
To keep the self hosted webapi running I have the following:
public class Program
{
static void Main()
{
Uri myUri = new Uri(#"http://localhost:9998/");
// Let have our configurations readY
HttpSelfHostConfiguration config = new HttpSelfHostConfiguration(myUri);
// configure routes
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
HttpSelfHostServer server = new HttpSelfHostServer(config);
// Start listening
server.OpenAsync().Wait();
Console.WriteLine("WebApi hosted on " + myUri.AbsoluteUri + " It can be tested now");
Console.ReadLine();
}
}
What am I missing?
Change route
[HttpGet,Route("api/{id}/flows/config")]
With such routing your action will be accessible by http://localhost:9998/shri/flows/config url (without /api part)
If you want to access that action with http://localhost:9998/api/shri/flows/config url either correct Route attribute for the action:
[HttpGet, Route("api/{id}/flows/config")]
public string SayHello([FromUri] string id)
or add RoutePrefix attribute on controller class:
[RoutePrefix("api")]
public class ConfigController : ApiController
For someone in the future that might be struggling with this, as Nkosi said you need to enable attribute routing.
public class Program
{
static void Main()
{
Uri myUri = new Uri(#"http://localhost:9998/");
// Let have our configurations readY
HttpSelfHostConfiguration config = new HttpSelfHostConfiguration(myUri);
// enables the attribute routing
config.MapHttpAttributeRoutes();
// configure routes
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
HttpSelfHostServer server = new HttpSelfHostServer(config);
// Start listening
server.OpenAsync().Wait();
Console.WriteLine("WebApi hosted on " + myUri.AbsoluteUri + " It can be
tested now");
Console.ReadLine();
}
}
If attribute routing is not configured then it does not matter if your routing is correct, When the request is made to the API it will not get the parameter values from the address itself even if you use [FromBody] or [FromUri].
I hope this helps someone, It was the issue in my case.
I have checked links related to mvc5, webapi2 but not being able to figure out my mistake.
My Problem:
/api/EBanking/CheckLogin is not excuting code of checkLogin method in ebankingcontroller
Links checked:
Custom Routing not working in MVC5
WebAPI2 and MVC5 route config
QueryString with MVC 5 AttributeRouting in Web API 2
App_start Code:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AutoMapperCentralAppConfig.Configure();
}
RouteConfig.cs
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
WebApiConfig.cs
public static string UrlPrefixRelative { get { return "~/api"; } }
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "ActionBased",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
APi Controller:
[RoutePrefix("api/EBanking")]
public class EBankingController : ApiController
{
public EBankingController()
{
//some other code, it runs
}
[HttpGet, HttpPost]
[Route("CheckLogin")]
public IEnumerable<usr06user_role> CheckLogin(string UserName, string Password)
{
//main code which doesn;t runs
}
public IEnumerable<usr06user_role> GetAll()
{
//test code which runs when we call: /api/ebanking/
}
result screenshot:
In your WebApiConfig.cs add another route for action based routing like this:
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "ActionBased",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "Default",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
This "api/{controller}/{action}/{id}" will allow calls to api/ebanking/checklogin
Alternatively you can even add full route in attribute such as:
[Route("api/EBanking/CheckLogin")]
public IEnumerable<usr06user_role> CheckLogin(string UserName, string Password)
{
//main code which doesn;t runs
}
When i am hitting the url:
http://localhost/api/adxxx/getDeals/?input=2
I get the following error:
"Message": "No HTTP resource was found that matches the request URI
'http://localhost/api/adxxx/getDeals/?input=2'.",
"MessageDetail": "No type was found that matches the controller
named 'adxxx'."
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.DependencyResolver = new UnityResolver(UnityBootstrapper.Initialise());
config.EnableCors();
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "xxx.services",
routeTemplate: "webapi/{controller}/{action}"
);
config.Routes.MapHttpRoute(
name: "xxx.services_new",
routeTemplate: "api/{controller}/{action}",
defaults: new { id = RouteParameter.Optional }
);
FluentValidationModelValidatorProvider.Configure(config);
}
}
[Route("api/adxxx/getDeals/")]
public IHttpActionResult GetDeals(int input)
{
//code here
}
How do i resolve this? Very similar apis having different route are working fine.
This happened when i have added fluent validation to my api. That updated my System.Web.Http.dll to v5.2.3.0
Correct your route config for allow parameter
[Route("api/adxxx/getDeals/{input}")]
public IHttpActionResult GetDeals(int input)
{
//code here
}
and then you can request it by
http://localhost/api/adxxx/getDeals/2
I am doing a SPA with web api as the backend and AngularJS as the SPA.
I am using attribute routing in WebApi2. The problem is when I do any http request that matches the following skeleton, it throws me a 404 NOT Found.
Request: http://localhost:63915/api/cab/delete/2
Request:
Error:
WebApiConfig Code:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
RouteDeclaration:
[RoutePrefix("api/driver")]
public class DriverController : ApiController
{
[POST("new")]
public bool NewDriver(DriverModel driver)
{
return new DatabaseService().CreateNewDriver(driver);
}
[GET("all")]
public List<DriverModel> GetAllDrivers()
{
return new DatabaseService().GetDriverList();
}
[DELETE("delete/{id}")]
public bool Delete(int id)
{
return new DatabaseService().DeleteDriver(id);
}
}
If I do something like api/driver/delete?id=2 and change the route to [DELETE("delete")] it works.
Is everything all right with my config ?
I think the problem might be with my config only. Please tell me what I am missing to make the route work.
I added another route to the WebApiConfig and it works!
config.Routes.MapHttpRoute(
name: "ComplexApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);