I'm trying to put together an OWIN configuration that allows me to serve static files from a directory in my project. I'm also starting pretty much from scratch (from a blank WebAPI project in Visual Studio Community 2015 Update 1). Here is what I have so far:
var options = new FileServerOptions
{
EnableDirectoryBrowsing = true,
EnableDefaultFiles = true,
DefaultFilesOptions = { DefaultFileNames = { "index.html" } },
FileSystem = new PhysicalFileSystem(#".\StaticFiles"),
StaticFileOptions = {
ContentTypeProvider = new FileExtensionContentTypeProvider(new Dictionary<string, string>() {
{ ".html", "text/html" }
})
}
};
app.UseFileServer(options);
Unfortunately this doesn't work. I can browse the directory StaticFiles from the root url (as I would expect) but as soon as I click on a file (Login.html at this point) I get a 404 with the message "The resource you are looking for does not have a handler associated with it.".
To note: The login.html file is included in the build (copy newer), and I have disabled IIS file serving, using the handlers option:
<remove name="StaticFile" />
I am at a loss for where to go from here, obviously I'm missing something. Any suggestions would be appreciated.
Turns out I needed to tell IIS to pass all requests through OWIN:
<add name="Owin" verb="" path="*" type="Microsoft.Owin.Host.SystemWeb.OwinHttpHandler, Microsoft.Owin.Host.SystemWeb"/>
That needed to go in the handlers section.
If anyone has a better/different solution for this, I would still like to hear it.
Related
I have added Workbox to Angular in first production deploy everything works fine, but after updating a module and rebuilding angular and injecting Workbox then visiting the site i see the service worker updates to the new version and refreshes the page, but now trying to use the updated module I get errors
Refused to execute script from 'https://example.com/8-es2015.203674bf0547eff7ff27.js'
because its MIME type ('text/html') is not executable,
and strict MIME type checking is enabled.
main-es2015.45ba4a512f87eefb1b3a.js:1 ERROR Error: Uncaught (in promise): ChunkLoadError:
Loading chunk 8 failed.(error: https://example.com/8-es2015.203674bf0547eff7ff27.js)
ChunkLoadError: Loading chunk 8 failed......
I looked at the network in chrome and I see that the file 8-es2015.203674bf0547eff7ff27.js is being served from the (disk cache) unlike the rest of the files which get served by (ServiceWorker), its content is the index.html file I don't know where it came from its not even part of the new build ? chrome places it in top frame section under scripts
Whats the reason for this Error, in the angular.json I have "outputHashing": "all", I delete everything and rebuild but still this errors, its until I clear the browser cash remove the ServiceWorker and hard refresh that the error stops happening until I reload page and it returns. Do I need to delete all the cache after every update, I thought Workbox does this automatically.Do I add something like so in the sw.js
self.addEventListener('activate', event => event.waitUntil(
caches.keys().then(cacheNames => cacheNames.forEach(name => caches.delete(name)))
)
);
Am using express, so I have set the maxAge on the sw.js to 0 and even change the public route to static files to a deep route but nothing
app.use('/sw.js', express.static(path.resolve('./public/dist/static/sw.js'), {maxAge: 0}));
app.use('/', express.static(path.resolve('./public/dist/static/'), {maxAge: 86400000}));
tools: angular 8.2.4 - workbox 4.3.1
Update
Removed workbox and the app worked, am guessing its cause of their new package workbox-window or the way am trying to use it. I have placed it in module service that is loaded from app.module then the service is called from a AppComponent ngOnInit. This could be the wrong way of initializing it.
code setup:
import {Workbox} from 'workbox-window';
#Injectable()
export class WorkerService {
supportWorker: boolean;
supportPush: boolean;
constructor(#Inject(WINDOW) private window: any, private loggerService: LoggerService) {
this.supportWorker = ('serviceWorker' in navigator);
this.supportPush = (this.supportWorker && 'PushManager' in window);
}
initWorker() {
if (this.supportWorker && environment.production) {
const wb = new Workbox('sw.js');
if (wb) {
wb.addEventListener('installed', event => {
if (event.isUpdate) {
// output a toast translated message to users
this.loggerService.info('App.webWorkerUpdate', 10000);
setTimeout(() => this.window.location.reload(), 10000);
}
});
wb.addEventListener('activated', event => {
if (!event.isUpdate) {
this.loggerService.success('App.webWorkerInit', 10000);
}
});
wb.register();
}
}
}
}
This the app component, i thought it would be best to add it to main.ts after bootstrapModule.then() but I don't know how inject a service in this method
#Component({
selector: 'app-root',
template: '<route-handler></route-handler>'
})
export class AppComponent implements OnInit {
constructor(private ws: WorkerService) {
}
ngOnInit(): void {
this.ws.initWorker();
}
}
After setting up Workbox in a different way it worked, the problem effected even chrome which failed to clear all cache after each build when testing it, had to use incognito to make sure everything works.
Here is the solution thanks to Ralph Schaer article a must read. His method is not to Cache-Bust the chunks angular build generates, also he globs in all the production scripts of workbox used by the app into the build folder and finally in the index.html he calls on workbox-window to register the service-worker.
I've got two angular 2 client apps that I'd like to serve from my loopback backend. I've been able to serve them successfully from subdirectories (www.mysite.com/subdirectory), but I'm trying to serve them from subdomains (www.subdomain.mysite.com).
Loopback doesn't seem to have a built in way to handle subdomain routing through the middleware or anywhere else that I can see. So I'm trying to accomplish the routing by matching the hostname in a url-not-found-handler that is set for final in the middleware.json file as such:
if (req.hostname.match(/subdomain1\./g)) {
console.log('requesting subdomain1 site')
res.sendFile(path.resolve() + '/dist/subdomain1/index.html')
} else if (req.hostname.match(/subdomain2\./g)) {
console.log('requesting subdomain2 site')
res.sendFile(path.resolve() + '/dist/subdomain/index.html')
} else {
next();
}
I've also got the static files in the middleware.json set up as such:
"files": {
"loopback#static": [
{
"name": "subdomain1",
"params": "dist/subdomain1"
},
{
"name": "subdomain2",
"params": "dist/subdomain2"
}
]
}
This seems to work in that it properly matches and sends the correct index.html file. I know it's the right index.html by inspecting in the browser.
But for some reason the actual angular app that gets served ALWAYS is whatever is first in the loopback#static array. If I have subdomain2 first, that will be shown for both subdomain1.mysite.com as well as subdomain2.mysite.com.
How can I fix this issue and serve a different apps based on the subdomain?
So I figured out a solution. Don't think loopback has a built in way of handling this, so got it to work with the following:
Cleared the files section from middleware.json
"files": {}
Used a combination of vhost and serve-static to deliver based on the subdomain
var vhost = require('vhost');
var serveStatic = require('serve-static');
var serveSubdomain1 = serveStatic('dist/subdomain1', {'index': ['index.html']})
var serveSubdomain2 = serveStatic('dist/subdomain2', {'index': ['index.html']})
app.use(vhost('subdomain1.mysite', serveSubdomain1));
app.use(vhost('subdomain2.mysite', serveSubdomain2));
I try to share my code betwen server and client I use following code (app.js):
var io = require('socket.io').listen(8000),
Static = require('socket.io').Static;
io.configure(function () {
var _static = new Static(io);
// some methods to add my custom files
_static.add('\public\test.js');
io.set('static', _static);
});
My file structure looks like this:
root
app.js
public
test.js
When I type "http://localhost:8000/public.test.js" Browser download default file "Welcome to socket.io"
This question is rather old, but here's the current way to do it (for v0.9):
var io = require('socket.io').listen(8000);
io.static.add('/path/for/request.js', {file: 'path/to/file.js'});
Note that the path to the resource is relative to the socket.io path, so the request URI would be something like:
http://localhost:8000/socket.io/path/for/request.js
If you see an error like Protocol version not supported, then that means your request URI probably has an extension that the manager can't support. Here's how to add that support:
io.static.add('/path/for/request.foo', {
mime: {
type: 'application/javascript',
encoding: 'utf8',
gzip: true
},
file: 'path/to/file.js'
});
The documentation points at their own Static library for a working implementation.
I'm new in the world of Node.js
According to this topic: What is Node.js' Connect, Express and “middleware”?
I learned that Connect was part of Express
I dug a little in the code, and I found two very interesting files :
./myProject/node_modules/express/lib/utils.js
and better :
./myProject/node_modules/express/node_modules/connect/lib/utils.js
These two files are full of useful functions and I was wondering how to invoke them correctly.
As far, in the ./myProject/app.js, that's what I do:
var express = require('express')
, resource = require('express-resource')
, mongoose = require('mongoose')
, expresstUtils =
require('./node_modules/express/lib/utils.js');
, connectUtils =
require('./node_modules/express/node_modules/connect/lib/utils.js');
But I found it a little clumsy, and what about my others files?
e.g., here is one of my routes:
myResources = app.resource(
'myresources',
require('./routes/myresources.js'));
and here is the content of myresources.js:
exports.index = function(req, res)
{
res.render('./myresources.jade', { title: 'My Resources' });
};
exports.show = function(req, res)
{
fonction resourceIsWellFormatted(param)
{
// Here is some code to determine whether the resource requested
// match with the required format or not
// return true if the format is ok
// return false if not
}
if (resourceIsWellFormatted(req.params['myresources']))
{
// render the resource
}
else
{
res.send(400); // HEY! what about the nice Connect.badRequest in its utils.js?
}
};
As you can see in the comment after the res.send(400), I ask myself if it is possible to use the badRequest function which is in the utils.js file of the Connect module.
What about the nice md5 function in the same file?
Do I have to place this hugly call at the start of my myresources.js to use them?:
var connectUtils =
require('../node_modules/express/node_modules/connect/lib/utils.js');
or, is there a more elegant solution (even for the app.js)?
Thank you in advance for your help!
the only more elegant way i came up with is (assuming express is inside your root "node_modules" folder):
require("express/node_modules/connect/lib/utils");
the node installation is on windows, node version 0.8.2
and a bit of extra information:
this way you don't need to know where you are in the path and be forced to use relative paths (./ or ../), this can be done on any file nesting level.
i put all my custom modules inside the root "node_modules" folder (i named my folder "custom_modules") and call them this way at any level of nesting:
require("custom_modules/mymodule/something")
If you want to access connect directly, I suggest you install connect as a dependency of your project, along with express. Then you can var utils = require('connect').utils.
I have a phonegap iOS app that i ported to webos on the touchpad the app works great except for the one iOS plugin that i used. it basically saved the canvas data to the photo roll. From my understanding of webos i will need to create a node.js service and write the data to a buffer and finally to the file system, there is an example for that in the forums. however what i can not figure out is how to call all of this from my phonegap app. I believe i will need to have the following in my index.html file.
<script src="/opt/PalmSDK/Current/share/framework/enyo/1.0/framework/enyo.js" type="text/javascript"></script>
and something like
enyo.create({kind: "Main"}).renderInto(document.body);
my guess i will also have to have all of the "kind" data in a js file. but how do i do the little step from my app's js file to communicate with the service that is created. I looked in the phonegap 1.0.js file and see that they are calling services this way.
this.service = navigator.service.Request('palm://com.palm.applicationManager', {
method: 'launch',
parameters: {
id: 'com.palm.app.camera',
params: {
appId: 'com.palm.app.camera',
name: 'capture',
sublaunch: true,
filename: filename
}
},
onSuccess: successCallback,
onFailure: errorCallback
});
but i also noticed it appears that it is all mojo and what i am doing is enyo, so yes i am pretty confused the moment...
seems it should be easy to call a service in webos, say here is a string of image data and write it to the file system from my existing phonegap app. and not have to do everything in enyo. anyone have a sample of a webos plugin like this or know where to point me?
thanks tim
**Update
I have created a node service now as defined below, i think that works and i am trying to make the call to the service, but it does not get to it. the test app runs on my touchpad, but when i push the button to save the image i do not get into the service. I tried to follow what was done for the camera in the phonegap0.0.1.js file this is a copy of my service, how i defined it and how i am calling it. any ideas what i am doing wrong.
services.json =
"id": "com.tim.pgmojo1.service",
"description": "FileIO Service",
"services": [
{
"name": "com.tim.pgmojo1.service",
"description": "FileIO Service",
"commands": [
{
"name": "writefile",
"assistant": "WriteFileAssistant",
"public": true
}]
}]
}
** service code
var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var fs = IMPORTS.require("fs");
var sys = require('sys');
var WriteFileAssistant = function() {}
WriteFileAssistant.prototype.run = function(future) {
var mypath = this.controller.args.thepath;
var mydata = this.controller.args.thedata;
console.log("in write file");
console.log("path=" + thepath);
console.log("image data=" + thedata);
var data = content.replace(/^data:image\/\w+;base64,/, "");
var buf = new Buffer(data, 'base64');
fs.writeFile('/media/internal/downloads/timimage.png', buf);
}
my call to the service**
this.service = navigator.service.Request('palm://com.tim.pgmojo.service', {
method: 'writefile',
parameters: {
thepath: '/media/internal/downloads/timimage.png',
thedata: canvasData
},
onSuccess: mySuccess,
onFailure: myFailure
});
currently i have this in my index.html file since it is only for testing..
Mojo is still included on the TouchPad. You can use the same service-calling functions as PhoneGap is doing.
In Enyo, access to on-device services is handled by the enyo.PalmService kind. You can see an example of an app that has a node.js service included and how calls are made to this service at https://github.com/palm/txjs-fortunecookie