Using ScriptCS files to extend an existing web app (via Nancy/MEF?)

57 views
Skip to first unread message

Steve Cooper

unread,
Nov 2, 2015, 11:47:16 AM11/2/15
to scriptcs
Hi. I'm trying to write a web app that's a hybrid between a classic C# web app and ScriptCS. I've been trying to take an existing Nancy self-hosted console app, and extend it with ScriptCS scripts, loaded with ScriptCS.MEF, but I've not got very far and I'm hoping someone else has tried to do something like me and has some guidance. 

My web app provides certain core services, and has some stable pages. It's complex enough to warrant using Visual Studio and the full power of the IDE. However, I need to be able to create and hack on new pages quickly. I thought a folder of ScriptCS files would be a great way to extend an existing site without having to rebuild it or change it's core checked-in code. I'm thinking of a development style more like, say, Python, where you just edit a script, save it, and refresh the browser.

If anyone's done this (in any system capable of separating views and logic, like ASP.NET MVC or Nancy) I'd love to hear what you achieved and how you did it. I'm happy to rewrite my app in any common framework that can deal with scripted 'controllers' or modules, some kind of view engine, and the ability to save the script and hit 'refresh' to get the new content. 

I know there's script packs to work the other way (say, a Nancy script pack to spin up a new server) but I've already got the server and I want to include arbitrary scripts.

Here's an outline of the approach I've taken, but I'm very happy to change the approach, including changing the web framework, if there's a better way...

So I've got a /Scripts folder which contains .CSX files like so;

    #r "Nancy.dll"

    [Export(typeof(Nancy.NancyModule))]
    public class Module1 : Nancy.NancyModule
    {
        public Module1() 
        {
            this.ModulePath = "Module1";
    
            this.Get["/"] = _ =>
            {
                return "it worked!";
            };
        }
    }

And I use ScriptCS.MEF to discover these files and load them into the current app domain;

    var catalogOptions = new ScriptCsCatalogOptions { References = new[] { typeof(Nancy.NancyModule) } };
    var scriptCsCatalog = new ScriptCsCatalog(Util.GetApplicationDir("Scripts"), "*.csx", catalogOptions);
    var container = new CompositionContainer(scriptCsCatalog);

That seems to work; I can see that the app domain has that script compiled, and the type (Module1) is loaded into the app domain. So ScriptCS.MEF is working perfectly.

However, when I spin up the Nancy server object, like this;

    using (WebApp.Start<Startup>(url))
    {
        log.InfoFormat("Running on {0}", url);
        log.InfoFormat("Press enter to exit");
        Console.ReadLine();
    }

I get three problems. One, the WebApp.Start now takes 46 seconds on a decent machine. (It takes 2.1s without using ScriptCS/MEF). I don't know but I suspect it's that using ScriptCS.MEF loads some hefty DLLs like the Roslyn compiler into the app domain, so when Nancy auto-discovers modules, it has a lot of work to do. That's guesswork, though.

Second, the module doesn't actually seem to work; visiting /Module1/ on the server fails with a 404. 

Lastly, I don't think this approach will support reloading files after the app has started, since Nancy discovers all modules when you spin up the site.

Any and all thoughts appreciated!
Reply all
Reply to author
Forward
0 new messages