Service Worker in Asp.Net MVC, scope - asp.net-mvc

Does the scope of a service worker have to be root for an asp.net mvc application? It needs to see the controller, it will need scripts, etc. My concern is what happens on a very large application.
If using an Area, you can include scripts in the area so that's one way of narrowing it down, are there any best practices?

You can place the service worker file anywhere you want. Here's how I did it.
Let's assume you setup an area called "Customer". So your file structure would be "/Areas/Customer", "/Areas/Customer/Controllers", "/Areas/Customer/Models", "/Areas/Customer/Views", etc. Assuming you didn't change the routing, the url would be "https://www.somewebsite.com/customer". If you want to make the scope of your service worker "/customer", but not have the service worker javascript file in the root, you would do the following.
I'm going to make another assumption that you created a "scripts" folder in this location "/Areas/Customer/Scripts" to hold your server worker js file.
In the javascript file that registers your service worker, you would do something like this.
if ("serviceWorker" in navigator) {
navigator.serviceWorker.register("/areas/customer/scripts/serviceworker.js", { scope: "/customer" })
.then(registration => {
console.log("Service Worker registered properly.");
})
.catch(error => {
console.log("Service Worker NOT registered properly.");
});
}
If you run the site now, you will receive an error similar to this "The path of the provided scope ('/customer') is not under the max scope allowed ('/areas/customer/scripts/'). Adjust the scope, move the Service Worker script, or use the Service-Worker-Allowed HTTP header to allow the scope."
What you need to do is update your web.config file with the below text in order to send the Service-Worker-Allowed HTTP header. This goes in the "configuration" section of web.config.
<location path="areas/customer/scripts/serviceworker.js">
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Service-Worker-Allowed" value="/customer" />
</customHeaders>
</httpProtocol>
</system.webServer>
</location>
This should now allow you to have your serviceworker.js file in a folder other than the root, but still keep the scope of the service worker to the correct area.

Related

How to solve MVC 5 Update and Delete Error

I have built MVC 5 Web application in .net 4.7.2. It runs fine in my local machine. Update and Delete commands were failing, which I have now sorted out thanks to this post: DELETE/PUT verbs result in 404 Not Found in WebAPI, only when running locally, I added this line to the web.config and all the CRUD now works:
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0
However, when I publish the application to my hosting server it breaks at this line in the web.config.
When I remove the line only Create and Retrieve data works, but Update and Delete fails with the error:
Object reference not set to an instance of an object.
at this line in the Index view: Line 40: #For Each item In Model
I understand this is because the model is null/nothing at this point.
This is my delete function showing where the error starts...
Public Function Delete(ByVal id As Integer) As ActionResult
Dim Client As HttpClient = New HttpClient()
Client.BaseAddress = New Uri(myWeb & "AppMenuCRUD")
Dim APIConsumer = Client.DeleteAsync("AppMenuCRUD/" & id.ToString())
APIConsumer.Wait()
Dim Result = APIConsumer.Result << failure here: Error 404
If Result.IsSuccessStatusCode Then
Return RedirectToAction("Index")
End If
Return View("Index")
End Function
The hosted server is running Windows Server 2016, .Net 4.7.2. I have enabled read/write to the website folder.
This is my IIS Settings in the hosting server:
UPDATES:
Having looked further into this, my hosting server is now updated to .net 4.8 and everything now just fails. I am now not able to even load the index view page. It breaks at the same line 40 as above.
In IIS, my application pool is set to integrated, .net 4.0. I cannot see anything higher from the dropdown list.
In IIS, I have nothing filtered in the list of HTTP Verbs, which I believe means it should accept anything.
UPDATE 2
After the updates to .net 4.8, I am now getting a new error
Lock Violation
I have enabled everything in the IIS, including changing all the ASP Configurations from Read Only to Read/Write.
I'm fearing I may introduce vulnerabilities to the VPS...
Is there anything else I need to do to get this to work?
Sometimes you need to update manually the Web.config when you change the target framework, please double check those lines:
<system.web>
<compilation debug="true" targetFramework="4.8">
<httpRuntime targetFramework="4.8" />
...
So, this is how I finally got it to work:
I am hosted with Plesk as 'control cpanel'. Apparently, Plesk has some lock which I had to unlock here:
Plesk > Tools & Settings > Security > Prohibit the ability to override handlers
Thanks to https://support.plesk.com/hc/en-us/articles/115000287305-Site-shows-500-19-Internal-Server-Error-Config-Error-Lock-violation. I was quite surprised my host could not help with this!
In the gymnastics of enabling everything else in my VPS, I ended up enabling/installing WebDAV. This also apparently does not 'allow' Edit/Delete actions. Instead of uninstalling it, I sorted it out from the web.config like this:
<system.webserver>
...
Thanks to Web API Put Request generates an Http 405 Method Not Allowed error

How to configure create-react-pwa with nested homepage (localhost/app)

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'
];

How can I add “X-Content-Type-Options: nosniff” to all the response headers

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.

how to consume webservices from asp.net mvc application

There is a external web services.
I can invoke it from my winform application, but I cannot invoke it from my asp.net mvc web application.
Error message is like this :
System.ServiceModel.EndpointNotFoundException: There was no endpoint listening at http://ihexds.nist.gov:9080/tf6/services/xdsrepositoryb that could accept the message. This is often caused by an incorrect address or SOAP action.
Is there anything to configure for my mvc web application to consume it?
Edit :
following is my code to invoke web services
WCF.Message msgInput, msgOutput;
msgInput = WCF.Message.CreateMessage(MESSAGE_VERSION, PROVIDEANDREGISTERDOCUMENTSETB_WSAACTION, request);
msgOutput = WCF.Message.CreateMessage(WCF.MessageVersion.Soap12WSAddressing10, "");
string endpointName = GetRepositoryEndPointName();
XDSRepository.XDSRepositoryClient client = new XDSRepository.XDSRepositoryClient(endpointName);
msgOutput = client.ProvideAndRegisterDocumentSet(msgInput);
Judging from your comments, I think your problem is proxy server related. I think you're using a proxy server internal to your company. You have to specify in you web.config file that you want the dotnet code to use the credentials you're logged on with. Add this to your web.config and try again:
<system.net>
<defaultProxy enabled="true" useDefaultCredentials="true" >
</defaultProxy>
</system.net>
It's also possible that you're working with a .pac script. In that case you have to explicitly specify the proxy server like so:
<system.net>
<defaultProxy useDefaultCredentials="true">
<proxy proxyaddress="http://proxyserver:proxyport"/>
</defaultProxy>
</system.net>

IIS Express defaulting to port 44300 for HTTPS when enabling SSL

When you initially set up IIS Express to enable SSL, it defaults the port to 44300. Unfortunately, when I try to access my site in on https://localhost/ it doesn't work unless I use the port number 44300 - https://localhost:44300/.
The links are generated using the following:
<%= Html.ActionLink("Index", "Index", "Home", new { #action = "https://" + Request.Hostname + Url.Action("Index", "Home") }) %>
Although an ugly solution, the #action keyword can override the generated route, but it means that the application would seemingly need to be aware of any non-standard ports (eg 44300).
The problem with that is that I'd be writing something to solve a problem that would only occur in a development environment.
So my question is... How do I change the port to 443 and have IIS Express like it?
Config for my site is below:
<site name="MySite" id="2" serverAutoStart="true">
<application path="/">
<virtualDirectory path="/" physicalPath="C:\Inetpub\MySite" />
</application>
<bindings>
<binding protocol="http" bindingInformation=":80:" />
<binding protocol="https" bindingInformation=":44300:" />
</bindings>
</site>
Many thanks in advance.
Update:
This question has been answered by Divya over on the IIS forums.
This question has been answered by Divya over on the IIS forums.
Once you enable SSL for a website in WebMatrix, it defaults to port 44300 and does all the bindings in the background. I am hoping that you tried to change this port to 443 in the config file. Once that is done and saved, you also need to modify the binding in http.sys. You would need to delete the existing entry for port 44300 and add the entry for port 443.
To do this, you could use httpcfg (WinXp/Win2003) or 'netsh http' (WinVista/Win2K8/Win7).
Here are the commands for netsh:
1) Get the appid and certhash for the existing entry of 44300 (I
assume, you are going to use the same certificate which WebMatrix
installs by default. If you want to change the certificate as well,
get the certificate hash of the certificate from the certificate
store): netsh http show sslcert. In the output search for entry for
port 44300 and copy certhash and appID.
2) Delete the entry for 44300: netsh http delete sslcert ipport=0.0.0.0:44300
3) Add a new entry for port 443 with certhash and appID copied in step
1. netsh http add sslcert ipport=0.0.0.0:443 certhash=<certhash> appid=<appid>
After configuring the entry in http.sys, you need to restart http
service for the changes to take effect.
net stop http
net start http
As noted by others, there are several nice ways of getting your SSL certs.
netsh http show sslcert > output.txt
or (my preferred method):
netsh http show sslcert | clip
Since I have spent much time on this topic , I would like to share my finding. I am reposting segment from my other post minus the code. Some background and explanation:
==========================================
After researching aroud, I was able to solve this issue with IIS Express and an override of the Controller class's OnAuthorization method (Ref#1). I have also gone with the route recommended by Hanselman (Ref#2). However, I was not complete satisfied with these two solutions due to two reasons:
Ref#1's OnAuthorization only works at the action level, not at the controller class level
Ref#2 requires a lot of setup (Win7 SDK for makecert), netsh commands, and, in order to use port 80 and port 443, I need to launch VS2010 as administrator, which I frown upon.
So, I came up with this solution that is quite simplistic with the following conditions:
I want to be able to use the RequireHttps attribute at Controller class or action level
I want MVC to use HTTPS when the RequireHttps attribute is present, and use HTTP if it is absent
I do not want to have to run Visual Studio as administrator
I want to be able to use any HTTP and HTTPS ports that are assigned by IIS Express
I can reuse the self-signed SSL cert of IIS Express, and I do not care if I see the invalid SSL Prompt
=========================================
You can find my solution/code here ==> ASP.NET MVC RequireHttps in Production Only
The port 44300 is sequential: 00 mean that its the first application you have configured as SSL enabled; 01 will be the second one and so on.
Since I also require my website to only work in HTTPS by adding the [RequireHttps] global attribute, I had some trouble debugging. When launched, it was automatically redirecting to https://localhost/
To fix this problem when debugging a web site, I simply create a new RequireHttpsAttribute that specify the port
#if DEBUG
public class RequireHttpsAttribute : System.Web.Mvc.RequireHttpsAttribute
{
protected override void HandleNonHttpsRequest(System.Web.Mvc.AuthorizationContext filterContext)
{
base.HandleNonHttpsRequest(filterContext);
var result = (RedirectResult)filterContext.Result;
var uri = new UriBuilder(result.Url);
uri.Port = 44301;
filterContext.Result = new RedirectResult(uri.ToString());
}
}
#endif
Use this class when debugging only. When deployed to IIS7, you should use Url rewriting to redirect to HTTPS.
Dan answer is right but if you still have problems with configuring IIS Express to serve your website with http and https on standard ports here is nice tutorial that that guide you step by step:
http://www.lansweeper.com/kb/54/How-to-configure-SSL-in-IIS-Express.html
In my case I accidentally deleted IIS Express certificate. I think it is generated the first time you use SSL in Visual Studio (F4 on selected project to get properties window and checking 'SSS Enabled' checkbox). This tutorial guided me how to create certificate and fix it.
Create class
public class RequireSSLAttribute: RequireHttpsAttribute
{
protected override void HandleNonHttpsRequest(AuthorizationContext filterContext)
{
base.HandleNonHttpsRequest(filterContext);
if (filterContext.HttpContext.Request.Url.Host.ToLower().Equals("localhost"))
{
// redirect to HTTPS version of page
string localhostSSLPort = System.Configuration.ConfigurationManager.AppSettings["localhostSSLPort"];
string url = "https://" + filterContext.HttpContext.Request.Url.Host + ":" + localhostSSLPort + filterContext.HttpContext.Request.RawUrl;
filterContext.Result = new RedirectResult(url);
}
}
}
And inside your web config add something like this
<appSettings>
<add key="localhostSSLPort" value="44300"/>
</appSettings>
And then you use it like
[RequireSSL]
public class AdminController : Controller
{
...
}

Resources