WebAPI returning 404s in production - c#

I know this question has plenty of other questions that on the face of it may seem the same but I'm fairly sure my case is slightly different. I'm getting 404 errors on our production environment for an API call and I have tried all of the following:
<remove name="UrlRoutingModule-4.0"/>
<add name="UrlRoutingModule-4.0" path="*" verb="*" type="System.Web.Routing.UrlRoutingModule" preCondition=""/>
<modules runAllManagedModulesForAllRequests="true">
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
Having looked at most of the potential solutions online, I found that most peoples error messages were this:
Where mine differs is the Handler part in the left column. Mine instead mentions the System.Web.Http.WebHost.HttpControllerHandler which suggests its hitting something relating to the API.
The URL I'm trying to hit is https://website.com/api/discounts/validate and my routes are configured as so:
public class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "ApiDefault",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional });
}
}
And Register is called from my Global.asax.cs at the very end of the Application_Start method. Again, this all works in our development and QA environments.

Related

How to return 404 by default in Asp Net Web Api

I have a simple Asp Net Web Api, with one endpoint, and it works well. But I want, when you call root server (loclahost:8001/) in my case it returns 404 to me, instead of HTTP Error 403.14 - Forbidden. I'm new to ASP NET MVC and got used to asp net core. Please, how can I return 404 here?
Maybe the route config will help:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{id}",
defaults: new { controller = "GPayController"}
);
}
}
Add this configuration under your <system.webServer> section within your web.config file:
<system.webServer>
<handlers>
<add name="StopDirectoryBrowsing" path="*." resourceType="Directory" verb="*"
preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
</handlers>
<system.webServer>

Catch all routes not working after update Asp.Net WebApi 5.2.2 to 5.2.7

Consider the following route
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute(
"myApi",
baseRoute + "myApi/file/{param1}/{*param2}",
new {controller = "File"}
);
This catch-all route triggers the FileController
[HttpGet]
public object Get(string param1, string param2)
{
//...
}
With WebApi 5.2.2 the controller is triggered with urls
http://www.something/myApi/a/b
http://www.something/myApi/a/b/c/d/e
The second case results in param2 = "b/c/d/e" which is how this catch-all route works (at least for version 5.2.2).
The problem now is that for version 5.2.7 the second case does not work any more. I could not see anything relevant in the release notes. Does anybody have an idea what is the problem?
EDIT
I generalized the problem to much in my question. I have a problem with
http://www.something/myApi/a/b/c/d/e.f
The dot character is causing a problem it seems.
The solutuion in my case was the following. I had to add an addtional extenstionless url handler.
So additionally to
<add name="ExtensionlessUrlHandler-Integrated-4.0_1a" path="*" verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
I needed
<add name="ExtensionlessUrlHandler-Integrated-4.0_1a" path="*.*" verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />

ASP.NET MVC5 refuses to map a route which matches a physical path

When I debug/run, using IIS Express, and browse to http://localhost:1234/People, IIS Express tries to browse the People directory instead of executing the People route, and I get a 403.14 HTTP error. So I disabled the StaticFile handler in the Web.config and refreshed. Now I get a 404.4 HTTP error:
I know that the route works because if I rename the RoutePrefix, e.g. PeopleTest, then the route is executed and I get the response I expect.
How can I convince IIS/Express to prefer MVC routes over static files/directories?
I am using attribute routing; the relevant code is below:
Web.config
<system.webServer>
<modules>
<remove name="FormsAuthentication" />
</modules>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<remove name="StaticFile"/>
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
Global.asax
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AutofacConfig.Configure();
Startup\WebApiConfig
namespace MyApi.Startup {
public static class WebApiConfig {
public static void Register(HttpConfiguration config) {
config.MapHttpAttributeRoutes();
}
}
}
People\PeopleController
namespace MyApi.People {
[RoutePrefix("People")]
public partial class PagesController : BaseController {
[Route]
[HttpGet]
[ResponseType(typeof(IEnumerable<Person>))]
public IHttpActionResult Get() { ... }
}
}
Note that since I'm using attribute routing, I am using a non-standard folder structure. E.g. I don't have the Controllers/Models/Views folders, instead I have root folders for each business area (e.g. ~\People contains the controllers/models/etc. for the "People" business area).
What I've Tried
Setting RAMMFAR.
Removing and re-adding ExtensionlessUrlHandler-Integrated-4.0.
Fixed by adding setting RouteExistingFiles = true:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.RouteExistingFiles = true;
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
}
}
So that ASP.NET routing will handle all routes: https://msdn.microsoft.com/en-us/library/system.web.routing.routecollection.routeexistingfiles(v=vs.110).aspx

Dot character '.' in MVC Web API 2 for request such as api/people/STAFF.45287

The URL I'm trying to let work is one in the style of: http://somedomain.com/api/people/staff.33311 (just like sites as LAST.FM allow all sort of signs in their RESTFul & WebPage urls, for example "http://www.last.fm/artist/psy'aviah" is a valid url for LAST.FM).
What works are following scenarios:
- http://somedomain.com/api/people/ - which returns all people
- http://somedomain.com/api/people/staff33311 - would work as well, but it's not what I'm after
I'd want the url to accept a "dot", like the example below
- http://somedomain.com/api/people/staff.33311 - but this gives me a
HTTP Error 404.0 - Not Found
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
I've set up following things:
The controller "PeopleController"
public IEnumerable<Person> GetAllPeople()
{
return _people;
}
public IHttpActionResult GetPerson(string id)
{
var person = _people.FirstOrDefault(p => p.Id.ToLower().Equals(id.ToLower()));
if (person == null)
return NotFound();
return Ok(person);
}
The 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 }
);
}
I already tried following all the tips of this blogpost http://www.hanselman.com/blog/ExperimentsInWackinessAllowingPercentsAnglebracketsAndOtherNaughtyThingsInTheASPNETIISRequestURL.aspx but it still won't work.. I also think it's quite tedious and I wonder if there isn't another, better and more secure way.
We have our Id's internally like this, so we're going to have to find a solution to fit the dot in one way or another, preferably in the style of "." but I'm open to alternative suggestions for urls if need be...
Suffix the URL with a slash e.g. http://somedomain.com/api/people/staff.33311/ instead of http://somedomain.com/api/people/staff.33311.
Following setting in your web.config file should fix your issue:
<configuration>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
I've found that adding the following before the standard ExtensionlessUrlHandler solves the issue for me:
<add name="ExtensionlessUrlHandler-Integrated-4.0-ForApi"
path="api/*"
verb="*"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
I don't think the name actually matters all that much except it probably helps if your IDE (Visual Studio in my case) is managing your site configuration.
H/T to https://stackoverflow.com/a/15802305/264628
I don't know what I am doing really, but after playing with the previous answer a bit I came up with another, perhaps more appropriate, solution:
<system.webServer>
<modules>
<remove name="UrlRoutingModule-4.0" />
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" />
</modules>
</system.webServer>
I found that I needed to do more than just set the runAllManagedModulesForAllRequests attribute to true. I also had to ensure that the extensionless URL handler was configured to look at all paths. In addition, there is one more bonus configuration setting you can add which will help in some cases. Here is my working Web.config:
<system.web>
<httpRuntime relaxedUrlToFileSystemMapping="true" />
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<handlers>
<remove name="WebDAV" />
<remove name="OPTIONSVerbHandler" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*" verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
Note, specifically, that the ExtensionlessUrlHandler-Integrated-4.0 has its path attribute set to * as opposed to *. (for instance).
I'd use this in Web.config file:
<add name="ManagedSpecialNames" path="api/people/*" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
before standard "ExtensionlessUrlHandler".
For instance in my case I put it here:
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ManagedFiles" path="api/people/*" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
So you force URLs of such pattern to be managed by you, instead of standard management as files in application directory tree.
I got stuck in this situation but appending /
at the end of URL wasn't look clean for me.
so just add below in web.config handlers tag
and you will be good to go.
<add name="Nancy" path="api" verb="*" type="Nancy.Hosting.Aspnet.NancyHttpRequestHandler" allowPathInfo="true" />
I found that both way works for me: either setting runAllManagedModulesForAllRequests to true or add ExtentionlessUrlHandler as following. Finally i choose to add extensionUrLHandler since runAllManagedModulesForAllRequests do have performance impact to the site.
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<remove name="WebDAV" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*" verb="*"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
I also faced this issue. I was under a circumstance where I was not supposed to play with IIS and website config related settings. So I had to make it working by making changes at the code level only.
The point is that the most common case where you would end up having dot character in the URL is when you get some input from the user and pass it as a query string or url fragment to pass some argument to the parameters in the action method of your controller.
public class GetuserdetailsbyuseridController : ApiController
{
string getuserdetailsbyuserid(string userId)
{
//some code to get user details
}
}
Have a look at below URL where user enters his user id to get his personal details:
http://mywebsite:8080/getuserdetailsbyuserid/foo.bar
Since you have to fetch some data from the server we use http GET verb. While using GET calls any input parameters can be passed only in the URL fragments.
So to solve my problem I changed the http verb of my action to POST. Http POST verb has the facility of passing any user or non-user input in body also. So I created a JSON data and passed it into the body of the http POST request:
{
"userid" : "foo.bar"
}
Change your method definition as below:
public class GetuserdetailsbyuseridController : ApiController
{
[Post]
string getuserdetailsbyuserid([FromBody] string userId)
{
//some code to get user details
}
}
Note: More on when to use GET verb and when to use POST verb here.

Why is the response from my Web API not formed properly?

I have a very basic Web API example that I constructed using the example code from this tutorial:
Code
Relevant Web.config Section
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<handlers>
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
Route Configuration
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
View Model
public class Survey
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
ApiController
public class SurveysController : ApiController
{
public IEnumerable<Survey> All()
{
using (ITSurveyEntities model = new ITSurveyEntities())
{
return new List<Survey>(
from s in model.Surveys
select new Survey
{
Id = s.Id,
Name = s.Name,
Description = s.Description,
});
}
}
}
and it's leveraging ITSurveyEntities, which was a generated ADO.NET Entity Data Model from the database, which only contains a single table right now, Survey.
In short, I don't think I'm trying to do anything special here.
Current Result
When I try and navigate to the API using something like http://localhost:1681/api/surveys, I get a response, but the file is named surveys with no extension. Further, if I try and Save As and give it say a txt extension, the download just fails.
Expected Result
I would expect that the API would return a file names surveys.json, like the example project does with products, and the browser would ask me to open or save the file.
What I've Tried
Comparing Web.config Files
I have compared the Web.config files between my project and the example code from the tutorial that works.
Comparing Routing
I have compared the routing configuration between my project and the example code from the tutorial that works.
Excluding WebDav
I've tried to exclude WebDav because my searches have indicated that it might be the cause. I did that by modifying the Web.config in a manner that matches what's on this blog.
UPDATE 1
Okay, after the guidance by Joe Enos I found that the issue was that the view model was named Survey also and so it was throwing an error about ambiguity between the CLR type and the EDM type.
I resolved that by renaming the view model to SurveyViewModel, and the request to http://localhost:1681/api/surveys now returns a HTTP 200 and downloads the file as expected.
If you take a look at the raw request and response using Fiddler or your browser's dev tools, you should find some clues as to the problem.
The response type (xml, json, etc) will be dictated by the accepts header in your request. You didn't mention what browser you were using to call the service but I believe there is difference in the default accept header between browsers. If you only want to return only Json data from webapi try adding the following to the Global.Asax:
GlobalConfiguration.Configuration.Formatters.Clear();
GlobalConfiguration.Configuration.Formatters.Insert(0,new JsonMediaTypeFormatter());
Media Formatters are essentially how the data from the Webapi method are serialized for the browser.

Categories