GET requests work but POST requests 404 in Web API 2 - c#

I've got a project which uses MVC 5 and Web API 2. Locally, both HTTP GET and POST requests to the Web API controller are working. When the website is published and deployed to an external environment, the GET requests still work, but the POST requests result in a 404.
Here's my API controller:
public class ExampleApiController : ApiController
{
[HttpPost]
[Route("GetRoles")]
public IHttpActionResult GetRoles([FromBody] string userName)
{
// ...
return Json(response);
}
[HttpGet]
[Route("GetUsers")]
public HttpResponseMessage GetUsers()
{
HttpResponseMessage response;
// ...
return response;
}
}
Here's my WebApiConfig.cs file:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
config.Routes.MapHttpRoute(
name: "Web API default route",
routeTemplate: "api/{controller}/{action}",
defaults: null
);
}
}
Here's my Global.asax file:
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);
}
}
Some other notes:
I've verified that the POST request that the client is making is formatted correctly.
I added the following code to the Web.config:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
</system.webServer>
The environment I'm deploying my application out to has a subdomain which requires authentication (e.g. the URL looks something like http://qa.example.com). I am testing using (for instance) http://username:password#qa.example.com/GetUsers.
My controller is not using the RoutePrefix attribute.
Any ideas?

The issue was resolved - not super helpful for future readers, but the issue was related to a third-party security client on the server-side specifically blocking the request. Juliano's comment helped me in that direction of realizing this.

I would suggest use web API documentation (help page) or swagger to check your web api method actual url and parameter. you must missing something.
few day back I've face similar problem (post method working on local but not working on QA env.) but that time I was getting 405 error

Related

Using RouteAttribute and IIS Application gives 404 error

I have created a webAPI project and I would like to start hosting it in IIS.
The method in the controller looks like this:
[TokenAuthentication]
[HttpGet]
[Authorize(Roles=Roles.PING)]
[Route("~/Ping")]
public DateTime Ping()
{
return DateTime.UtcNow;
}
My WebApiConfig looks like this:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
config.MapHttpAttributeRoutes();
GlobalConfiguration.Configuration.Filters.Add(new ValidateModelAttribute());
//config.Routes.MapHttpRoute(
// name: "DefaultApi",
// routeTemplate: "{controller}/{id}",
// defaults: new { id = RouteParameter.Optional }
//);
}
}
When I run the project via visual studio, and go to the link http://localhost:53722/ping I get an unauthorized response which is what I expect.
When I put the website on IIS in an applicaion with the virtual path "/Account" I get a 404 response and it is trying to use the StaticFile Handler.
Through searching online I have runAllManagedModulesForAllRequests set to true. I have also found Configure ASP.NET Web API application as a Virtual Directory under ASP.NET MVC application which seems like the "/Account/" should not be interfering with the route.
I can not put the API at the route directory because I will be running multiple microservices under the same site.
How would I get the route to work using the virtual directory?
Thanks,
Steven
Each site should be running as an Application and not a Virtual Directory (and ideally with each having its own application pool).
Out of the box you would normally go for
[Route("ping")]
This would give you a url of http://blah.com/ping
If you are running this api in a sub folder/application then it maybe something like http://blah.com/subapp/ping
This is all i have...

Web Api 2 Routing Issue: "No action was found on the controller..."

I am having the issue of getting a 404 on my web api routing. Although there are many posts about this issue, they mainly seem to be about changing the order of the routes so that the MVC routes don't override the api routes.
I have tried all of the solution I have come across yet nothing seems to fix my issue.
Here is my controller:
[RoutePrefix("api/paving-designer")]
public class PavingDesignerController : ApiController
{
[HttpGet]
[Route("get-forms/{userId}")]
public IHttpActionResult GetForms(Guid userId)
{
ICollection<PavingDesignerFlatForm> forms = _helper.GetForms(userId);
if (forms != null)
{
return Ok(forms);
}
else
{
return NotFound();
}
}
}
And this is my Web Api Config
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new
{
id = RouteParameter.Optional
});
}
}
and this is my global asax
private void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
// RouteConfig.RegisterRoutes(RouteTable.Routes);
// Initialize Castle & install application components
_bootstrapper = CastleInitialiser.Initialise();
}
As you can see I have even tried to comment out the mvc routes to see if that made a difference
If I browse to http://localhost/api/paving-designer/get-forms/c6c489a7-46c6-420e-9e39-56797c8094cf
I get the following error:
No type was found that matches the controller named 'paving-designer'.
I have tried changing the route prefix to the following but to no avail
/api/paving-designer
/paving-designer
paving-designer
And if I browse to http://localhost/api/pavingdesigner/get-forms/c6c489a7-46c6-420e-9e39-56797c8094cf
I get the following error:
Multiple types were found that match the controller named 'pavingdesigner'. This can happen if the route that services this request ('api/{controller}/{action}/{id}') found multiple controllers defined with the same name but differing namespaces
I don't see how I can have multiple controllers as this is the only one I have.
Can anyone see where I am going wrong?
You are using both routing types.
Using attribute routing defined next route:
/api/paving-designer/get-forms/{userId}
Using default routing there is other route:
/api/{controller}/{action}/{id}
These routes are have the same template.
But using the first of them - ControllerSelector can not find paving-designerController.
Using the second - there is no action named get-forms. There are GetForms
If you remove one of them - it should work.
Ok in my particular case, the error was being caused as my IoC was registering the controller twice.
This was causing the duplicate entries, which in turn made the attribute routing fail.

WebAPI MapHttpRoute doesn't work, but AttributeRouting does

I have a case where I can't get a default route to work via Config.Routes.MapHttpRoute(), but if I put the route as a route attribute in the controller it works fine.
Global.asax
protected void Application_Start() {
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
//RouteConfig.RegisterRoutes(RouteTable.Routes);
//BundleConfig.RegisterBundles(BundleTable.Bundles);
}
(removed last two as they're non-WebAPI requirements (right?) same result even if I leave them in)
WebApiConfig.cs
public static void Register(HttpConfiguration config) {
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "v1/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
Controller
public class ErrorsController : ApiController
{
[HttpGet]
[Route("v1/Errors/Get")]
public IHttpActionResult Get(int id) {
return Ok();
}
[HttpPost]
[Route("v1/Errors/Submit")]
public IHttpActionResult Submit()
{
// do stuff
return Ok();
}
}
If I have the attribute routes in there, everything works fine. If I don't, I get 404s. For example, the following two report a 404 error:
localhost:myport/v1/Errors/Get?id=5
localhost:myport/v1/Errors/Submit
Yet, if I submit this:
localhost:myport/v1/Errors
I get the following response:
No HTTP resource was found that matches the request URI
'http://localhost:59498/v1/Errors/'.
No type was found that matches the controller named 'v1'.
Obviously my route configuration isn't kicking in, but for the life of my I can't tell why. I even tried changing the route name to Default instead of DefaultApi, thinking that perhaps Default had some internal significance.
"Normal" routing doesn't support this kind of routes with prefix "v1" in it. In a way or another this kind of rounting follows the old MVC routing, where the first part of the address must be the controller; so when you set the address localhost:myport/v1/Errors the system is currently looking for a controller named "v1".
If you want to use a route with a prefix before you have to stick with the attribute routing; that's why it works perfectly with attributes and it doesn't without.
May I suggest you to use a "global" prefix for the v1 thing? That would allow you to avoid repeating the same part of the URL over and over again on different resources. I suggest you to check this article for a couple of implementation details.

C# web api route for a webservice

I am coding a web api in c# and I have a question in regards to the correct route to access a function called test.
Here is the class definition:
[RoutePrefix("api")]
public class ItemsWebApiController : ApiController
I have a RoutePrefix as follows:
[Route("test")]
Here is the function called test:
[Route("test")]
[System.Web.Http.AcceptVerbs("GET")]
[System.Web.Http.HttpGet]
public String test()
{
return "test";
}
I am trying to access the following url:
http://localhost/api/test
The above url is displaying the following exception:
Server Error in '/' Application.
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its
dependencies) could have been removed, had its name changed, or is
temporarily unavailable. Please review the following URL and make
sure that it is spelled correctly.
Requested URL: /api/test
How can I access the test function, such that the string "test" is displayed in my browser?
EDIT
I have deployed to my local IIS, and the database connection strings are working correctly.
The address for the local IIS is http://localhost/
These are the urls that I have tried:
http://localhost/test
http://localhost/api/test
http://localhost/api/test/test
http://localhost/ItemsWebApiController/test
http://localhost/ItemsWebApi/test
All of the above return the error page.
Thanks
If you a putting [Route("test")] your url will be http://address/test
if you need url like http://address/api/test, change your route like [Route("api/test")]
Note: you need to add [HttpGet] as well
You have to activate Attribute Routing in WebAPI Controllers
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 }
);
}
}
and in your application start
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
}
And then your URL is http://localhost/test, because the default route would not match here.
The route based on your configuration will be: http://address/api/test/test
the first test is the route prefix from the attribute [Route("test")];
the scond test is the action in the controller from the attribute defined on the method
[Route("test")]
public String test()
{
Web api infers the http method based on your action name. It won't know from "Test" what to use.
See the docs
HTTP Methods
Web API also selects actions based on the HTTP method of the request (GET, POST, etc). By default, Web API looks for a case-insensitive match with the start of the controller method name. For example, a controller method named PutCustomers matches an HTTP PUT request.
You can override this convention by decorating the mathod with any the following attributes:
[HttpDelete]
[HttpGet]
[HttpHead]
[HttpOptions]
[HttpPatch]
[HttpPost]
[HttpPut]
The following example maps the CreateBook method to HTTP POST requests.
[Route("api/books")]
[HttpPost]
public HttpResponseMessage CreateBook(Book book) { ... }

Web Api 2 route configuration with legacy asmx services in api folder

I'm trying to add the Web Api functionality to an existing ASP.NET application. This should be something simple but I'v been stuck on this for hours. I've tried a bunch of things but no luck so far.
The app has several asmx services in "/api" folder. This somehow interferes with the web api routing. Ideally, I'd like to keep the existing services in the current place since there are external references to them.
Sample service:
/Api/ApiServ.asmx - I'm able to invoke the initial screen with the method list
The problem is when I try to invoke any method on one of the services e.g. /Api/ApiServ.asmx/ServMethod - I can't invoke this and I'm getting this response: "No HTTP resource was found that matches the request URI 'http://localhost:49415/api/apiserv.asmx/ServMethod'"
Here is what I have:
Global.asax:
public class WebApiApplication : HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
//RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
Sample service:
namespace WebApiTest.Api
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
[ScriptService]
public class ApiServ : WebService
{
[WebMethod]
public string ServMethod()
{
return "Test";
}
}
}
Web Api Config:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.IgnoreRoute("asmx", "api/{resource}.asmx/{*pathInfo}");
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Strangely enough, when I use a route debbuger it actually matches the asmx ignore route but the service method is not being hit. Any help appreciated!
I didn't actually figure out a proper fix as I ran out of time I had allocated for fixing this but since the solution is temporary and will be moving the asmx services to web api controllers I decided to settle for a workaround.
This is what I did:
1) In the /Api folder I created a /Legacy subfolder and moved all asmx services there
2) In global.asax Application_BeginRequest:
private void Application_BeginRequest(object sender, EventArgs e)
{
string url = Request.Url.AbsolutePath.ToLower();
if (url.StartsWith("/api") && url.Contains(".asmx") && !url.Contains("/api/legacy/"))
{
url = Request.Url.AbsolutePath.Replace("/api/", "/api/legacy/");
Context.RewritePath(url);
}
}
Note a similar thing could be achieved in a more cultured way such as using the rewrite module but this works for me a temporary solution.
If you do have an mvc portion to your API (web api help pages will add mvc)
you will need to add the following line to your RouteConfig.cs:
routes.IgnoreRoute("{resource}.asmx/{*pathInfo}");
and that will do the trick!

Categories

Resources