I create an app by create-react-pwa(CRP) tool and I deploy the app to a local IIS root path. Then I open Chrome at localhost. Everything works great, even Service worker makes its job, fetches and caches app bundle and other resources. In dev tool, I click on Add to homescreen button in Application tab and a shortcut is added.
There is a problem when I change the root path to a subfolder (localhost/myapp). Of course, I change CRP settings and edit homepage in the package.json and manifest.json
//package.json
"homepage" : "/myapp"
//manifest.json
"start_url": "/myapp/",
Then I build the app and edit a path to service-worker in index.html
<script>
"serviceWorker" in navigator && window.addEventListener("load", function () {
navigator.serviceWorker.register("/myapp/service-worker.js")
})
</script>
I deploy this build to IIS subfolder named "/myapp" and try to inspect result in Chrome. Everything works well, service-worker works. But when I try to Add to homescreen it fails. Chrome display the error bellow:
Site cannot be installed: no matching service worker detected. You may need to reload the page, or check that the service worker for the current page also controls the start URL from the manifest
Please, has someone idea what is wrong?
Build structure:
/wwwroot
/myapp
/static
/index.html
/manifest.json
/service-worker.js
/ etc...
You seem to have done everything correctly except one thing - not defining the scope of the service worker while registering. So there are two things you can try out:
1.Try explicitly adding the scope of the service worker while registration. Before making bigger efforts as described in option 2, check if this works for you. CODE:
<script>
"serviceWorker" in navigator && window.addEventListener("load", function () {
navigator.serviceWorker.register('/myapp/service-worker.js', { scope : '/myapp/' })
})
</script>
2.A full proof way would be this one. Since you are using IIS, you can make changes to your web.config file to add the Service-Worker-Allowed Http header to the response of your service worker file. CODE:
<location path="/myapp/service-worker.js">
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Service-Worker-Allowed" value="/" />
</customHeaders>
</httpProtocol>
</system.webServer>
</location>
and then just define the scope as {scope : '/'} while registering your service worker. This way irrespective of your project structure or placement of your service worker, it should work. Basically what you are doing now is that you are adding "Service-Worker-Allowed" header in HTTP response to the service worker's script resource request. This answer is inspired from the example 10 in the service worker's spec link above.
We were able to get this running on a tomcat server. We had to ensure that
1) The manifest.json, service-worker.js and the index.html reside in WEB-INF directory.
2) Set up a request mapping like to ensure that the manifest and service-worker are returned from the proper location
#RequestMapping(value = "/manifest.json", method = RequestMethod.GET)
public #ResponseBody InternalResourceView manifest() throws IOException {
return new InternalResourceView("/WEB-INF/manifest.json");
}
#RequestMapping(value = "/service-worker.js", method = RequestMethod.GET)
public #ResponseBody InternalResourceView serviceWorker() throws IOException {
return new InternalResourceView("/WEB-INF/service-worker.js");
}
3) We placed the assets from the build script inside resources/static/ directory and made sure that the resources to cache were supplied with proper names, like so, in the service-worker.js
const BASE_STATIC_URLS = [
'.',
'index.html',
'offline.html',
'/myapp/static/js/0.16823424.chunk.js'
];
I am running an ASP.NET MVC 3 website on IIS. Is there a flag in web.config or something similar that can do this?
As long as you're using IIS 7 or above, it's as simple as adding it to your web.config.
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="X-Content-Type-Options" value="nosniff" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
Or you can add them using the IIS Management GUI, or even command line. Take a look at http://www.iis.net/configreference/system.webserver/httpprotocol/customheaders
This question originates from MVC 3, but as this problem is still relevant in ASP.NET Core, I'll let myself propose a solution for the recent versions:
public static IApplicationBuilder UseNoSniffHeaders(this IApplicationBuilder builder)
{
return builder.Use(async (context, next) =>
{
context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
await next();
});
}
Then simply add this in Startup.cs:
app.UseNoSniffHeaders();
The beauty of this approach is that it makes it independent from your web server and deployment process. At the same time you may need to extend this solution if you want it to apply to static files as well.
In case whenever you deploy new application and its replacing the web.config file. its better to add the configuration IIS site level as below.
Click on site and select the 'HTTP response headers".
Click on 'add' on left side corner and add the name and value as below.
name: X-Content-Type-Options
value: nosniff
The nosniff response header is a way to keep a website more secure. Security researcher Scott Helme describes it like this: “It prevents Google Chrome and Internet Explorer from trying to mime-sniff the content-type of a response away from the one being declared by the server.
I'm trying to get an API Controller to work inside an ASP.NET MVC 4 web app. However, every request results in a 404 and I'm stumped. :/
I have the standard API controller route from the project template defined like:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
The registration is invoked in Global.asax:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
// Register API routes
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
I have a basic API controller like this:
namespace Website.Controllers
{
public class FavoritesController : ApiController
{
// GET api/<controller>
public IEnumerable<string> Get()
{
return new [] { "first", "second" };
}
// PUT api/<controller>/5
public void Put(int id)
{
}
// DELETE api/<controller>/5
public void Delete(int id)
{
}
}
}
Now, when I browse to localhost:59900/api/Favorites I expect the Get method to be invoked, but instead I get a 404 status code and the following response:
<Error>
<Message>
No HTTP resource was found that matches the request URI 'http://localhost:59900/api/Favorites'.
</Message>
<MessageDetail>
No type was found that matches the controller named 'Favorites'.
</MessageDetail>
</Error>
Any help would be greatly appreciated, I'm losing my mind a little bit over here. :) Thanks!
One thing I ran into was having my configurations registered in the wrong order in my GLobal.asax file for instance:
Right Order:
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
Wrong Order:
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
WebApiConfig.Register(GlobalConfiguration.Configuration);
Just saying, this was my problem and changing the order is obvious, but sometimes overlooked and can cause much frustration.
Had essentially the same problem, solved in my case by adding:
<modules runAllManagedModulesForAllRequests="true" />
to the
<system.webServer>
</system.webServer>
section of web.config
I have been working on a problem similar to this and it took me ages to find the problem. It is not the solution for this particular post, but hopefully adding this will save someone some time trying to find the issue when they are searching for why they might be getting a 404 error for their controller.
Basically, I had spelt "Controller" wrong at the end of my class name. Simple as that!
Add following line
GlobalConfiguration.Configure(WebApiConfig.Register);
in Application_Start() function in Global.ascx.cs file.
I had the same problem, then I found out that I had duplicate api controller class names in other project and despite the fact that the "routePrefix" and namespace and project name were different but still they returned 404, I changed the class names and it worked.
Similar problem with an embarrassingly simple solution - make sure your API methods are public. Leaving off any method access modifier will return an HTTP 404 too.
Will return 404:
List<CustomerInvitation> GetInvitations(){
Will execute as expected:
public List<CustomerInvitation> GetInvitations(){
For reasons that aren't clear to me I had declared all of my Methods / Actions as static - apparently if you do this it doesn't work. So just drop the static off
[AllowAnonymous]
[Route()]
public static HttpResponseMessage Get()
{
return new HttpResponseMessage(System.Net.HttpStatusCode.OK);
}
Became:-
[AllowAnonymous]
[Route()]
public HttpResponseMessage Get()
{
return new HttpResponseMessage(System.Net.HttpStatusCode.OK);
}
Create a Route attribute for your method.
example
[Route("api/Get")]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
You can call like these http://localhost/api/Get
Had this problem. Had to uncheck Precompile during publishing.
I'm a bit stumped, not sure if this was due to an HTTP output caching issue.
Anyways, "all of a sudden it started working properly". :/ So, the example above worked without me adding or changing anything.
Guess the code just had to sit and cook overnight... :)
Thanks for helping, guys!
I'm going to add my solution here because I personally hate the ones which edit the web.config without explaining what is going on.
For me it was how the default Handler Mappings are set in IIS. To check this...
Open IIS Manager
Click on the root node of your server (usually the name of the server)
Open "Handler Mappings"
Under Actions in the right pane, click "View ordered list"
This is the order of handlers that process a request. If yours are like mine, the "ExtensionlessUrlHandler-*" handlers are all below the StaticFile handler. Well that isn't going to work because the StaticFile handler has a wildcard of * and will return a 404 before even getting to an extensionless controller.
So rearranging this and moving the "ExtensionlessUrlHandler-*" above the wildcard handlers of TRACE, OPTIONS and StaticFile will then have the Extensionless handler activated first and should allow your controllers, in any website running in the system, to respond correctly.
Note:
This is basically what happens when you remove and add the modules in the web.config but a single place to solve it for everything. And it doesn't require extra code!
Check that if your controller class has the [RoutePrefix("somepath")] attribute, that all controller methods also have a [Route()] attribute set.
I've run into this issue as well and was scratching my head for some time.
WebApiConfig.Register(GlobalConfiguration.Configuration);
Should be first in App_start event. I have tried it at last position in APP_start event, but that did not work.
I found this in a comment here: https://andrewlock.net/when-asp-net-core-cant-find-your-controller-debugging-application-parts/
Add the following to your Program.cs:
app.UseRouting();
app.UseEndpoints(endpoints =>
{
// DP: I don't know the purpose of this, but without it, all controllers report 404
endpoints.MapControllerRoute("default", "WTF is this");
});
For me this is all it took to make it work after hours of trying to find a solution. If this doesnt work for you, try adding
builder.Services.AddControllers();
Add this to <system.webServer> in your web.config:
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0"/>
<remove name="OPTIONSVerbHandler"/>
<remove name="TRACEVerbHandler"/>
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0"/>
</handlers>
Adding <modules runAllManagedModulesForAllRequests="true" /> also works but is not recommended due performance issues.
I have solved similar problem by attaching with debugger to application init. Just start webserver (for example, access localhost), attach to w3wp and see, if app initialization finished correctly. In my case there was exception, and controllers was not registered.
I had the same 404 issue and none of the up-voted solutions here worked. In my case I have a sub application with its own web.config and I had a clear tag inside the parent's httpModules web.config section. In IIS all of the parent's web.config settings applies to sub application.
<system.web>
<httpModules>
<clear/>
</httpModules>
</system.web>
The solution is to remove the 'clear' tag and possibly add inheritInChildApplications="false" in the parent's web.config. The inheritInChildApplications is for IIS to not apply the config settings to the sub application.
<location path="." inheritInChildApplications="false">
<system.web>
....
<system.web>
</location>
I have dozens of installations of my app with different clients which all worked fine and then this one just always returned 404 on all api calls. It turns out that when I created the application pool in IIS for this client it defaulted to .net framework 2.0 instead of 4.0 and I missed it. This caused the 404 error. Seems to me this should have been a 500 error. Very misleading Microsoft!
I had this problem: My Web API 2 project on .NET 4.7.2 was working as expected, then I changed the project properties to use a Specific Page path under the Web tab. When I ran it every time since, it was giving me a 404 error - it didn't even hit the controller.
Solution: I found the .vs hidden folder in my parent directory of my VS solution file (sometimes the same directory), and deleted it. When I opened my VS solution once more, cleaned it, and rebuilt it with the Rebuild option, it ran again. There was a problem with the cached files created by Visual Studio. When these were deleted, and the solution was rebuilt, the files were recreated.
If you manage the IIS and you are the one who have to create new site then check the "Application Pool" and be sure the CLR version must be selected. In my situation, it had been selected "No Managed Code". After changed to v4.0 it started to work.
i try above but not sucess all
add ms webhost and GlobalConfiguration.Configure(WebApiConfig.Register);
I'm trying to understand how RouteExistingFiles works.
So I've created a new MVC 3 internet project (MVC 4 behaves the same way) and put a HTMLPage.html file to the Content folder of my project.
Now I went to the Global.Asax file and edited the RegisterRoutes function so it looks like this:
public static void RegisterRoutes(RouteCollection routes)
{
routes.RouteExistingFiles = true; //Look for routes before looking if a static file exists
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new {controller = "Home", action = "Index", id = UrlParameter.Optional} // Parameter defaults
);
}
Now it should give me an error when I'm requesting a localhost:XXXX/Content/HTMLPage.html since there's no "Content" controller and the request definitely hits the default pattern. But instead I'm seeing my HTMLPage.
What am I doing wrong here?
Update:
I think I'll have to give up.
Even if I'm adding a route like this one:
routes.MapRoute("", "Content/{*anything}", new {controller = "Home", action = "Index"});
it still shows me the content of the HTMLPage.
When I request a url like ~/Content/HTMLPage I'm getting the Index page as expected, but when I add a file extenstion like .html or .txt the content is shown (or a 404 error if the file does not exist).
If anyone can check this in VS2012 please let me know what result you're getting.
Thank you.
To enabling routing for static files you must perform following steps.
In RouteConfig.cs enable routing for existing files
routes.RouteExistingFiles = true;
Add a route for your path ( Make sure specialized path are above generalized paths)
routes.MapRoute(
name: "staticFileRoute",
url: "Public/{file}/",
defaults: new { controller = "Home", action = "SomeAction" }
);
Next configure your application, so that request for static files are handeled by "TransferRequestHandler".In Webconfig under system.webServer>handlers add following entry.
<add name="MyCustomUrlHandler2" path="Public/*" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
The value of 'path' can be more generic or specific depending on your requirement. But i prefer it to be always very specific as per one's need. Keeping it very generic will block serving of other site specific resources such as .js or css files. For example if above is set as path="*", then request for even the css (inside the content folder) which is responsible for how your page would look will also end up in your Controller's action. Something that you will not like.
Visual Studio 2012 uses IIS Express. You need to tell IIS not to intercept requests for disk files before they are passed to the MVC routing system. You need set preCondition attribute to the empty string in config file:
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule"
preCondition="" />
In Win7/8 you can find config file on this path: %userprofile%\Documents\IISExpress\config\applicationhost.config
The RouteExistingFiles doesn't keep files from being viewed if there is no route for them, it just checks the routes before checking if the file exists. If there is no matching route, it will continue to check if there is a matching file.
I am attempting to produce a simple WebDAV server using MVC, and I have finally reached the stage where I need to serve up a requested file to the user.
I have a route set up that deals with traversing the directory structure "webdav/{*path}" which works fine, right up until the point where that path ends in a file name. At this point, it appears that IIS decides that it is a static file, and attempts to serve that file from the disk. As it isn't in the location specified in the URL, it returns a 404 error.
I don't have any freedom to change the url, I basically need it to be in the form, otherwise Windows Explorer can't work with it as a mapped drive:
GET /webdav/Test/Test2.txt
I've set the route to greedily match, as the directory structure can have as many levels. I've also set routes.RouteExistingFiles = true;
This is using IIS Express 8.0 on my development machine.
I've gone as far as setting up a blank MVC project just to test this, and this is the RegisterRoutes method:
routes.RouteExistingFiles = true;
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "WebDAVGet",
url: "webdav/{*path}",
defaults: new { controller = "WebDAV", action = "Get", path = "" });
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index",
id = UrlParameter.Optional }
);
So, going to /webdav/Test/Test2 hits the breakpoint in my controller, but going to /webdav/Test/Test2.txt gives me a 404.
Any suggestions?
I needed to add
<modules runAllManagedModulesForAllRequests="true">
to the web config.
Ah, I've been struggling with this for a few days now, I knew posting here would shift the blockage!
Another option is to add this to the <system.webserver> node in web.config:
<modules>
<remove name="UrlRoutingModule-4.0" />
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" />
</modules>
I can vouch that this works on IIS 7.5.
For the record, I found this solution here.