Integrating Visual Studio Code with dnx-watch to develop ASP.NET 5 applications
Visual Studio Code is a great cross platform code editor that is also free. You can get it at code.visualstudio.com for Mac, Windows, or Linux. It's great for web development, and particularly shines with node.js. Since ASP.NET 5 is still in active beta and moving very fast, some of the features I want when VSCode is used with ASP.NET aren't there yet. Fortunately VSCode is very configurable and I was able to get it to do what I wanted in about 10 minutes of messing around.
One of the promises of ASP.NET is the ability to write code, hit Ctrl-S (Save) in your editor and then hit F5 (refresh) in your browser to see the results. Rinse, repeat. Any "build" step should be basically hidden.
After you've got .NET Core and ASP.NET 5 with the DNX (for now, the "dotnet execution engine") you should take a look at the dnx-watcher command. It's a command you can install in one line:
dnu commands install Microsoft.Dnx.Watcher
This convenience command wraps dnx, so when you want to run your app rather than "dnx web" you'll say "dnx-watch web." It will watch your source files directory for changes. When you make a change, be it in VSCode or in Notepad, dnx-watch will kick the process and start it again so you can hit F5 in your browser.
Visual Studio Code doesn't have a Build or Debug menu for ASP.NET today, but I wanted to be able to "Ctrl-Shift-B" and build/start my web application. Specifically I wanted to run dnx-web on the current app.
Here's how you do that today. First, install dnx-watch as above.
This next part with tasks.js is totally optional, but I like it because it makes VSCode and the Ctrl-Shift-B hotkey I'm used to work the way I want.
Make a folder at the top of your project called ".vscode" and put a file called "tasks.json" inside it. This is a special file that lets you tell Visual Studio Code what gulp tasks it should know about.
Here I'm saying there's a task (that we'll create in a second) called "watch" (I decide on the name) and it's the Build command for this project. I could make a Test command if I wanted, as well. I want to see the output.
{
"version": "0.1.0",
"command": "gulp",
"isShellCommand": true,
"tasks": [
{
"taskName": "watch",
"isBuildCommand": true,
"showOutput": "always",
"isWatching": true
}
]
}
Now where does this "watch" task go? Well it goes in my project's gulpfile.js! It's a gulp task like any other.
I want to shell out and run dnx-watch, so I'll have to bring in a small library called gulp-shell by adding it to my package.json, then running npm.install. That will give me the ability to shell out to arbitrary command line apps like dnx-watch. Visual Studio Code will capture and stream the output as seen in the screenshot above.
Then I just add one line to my gulpfile after adding the appropriate require at the top.
gulp.task('watch', shell.task(['dnx-watch web']))
ASIDE: There is the beginnings of a gulp plugin for ASP.NET called "gulp-dnx" that knows about DNX and ASP.NET 5 but since I just wanted this one feature, this was easier. When gulp-dnx knows about dnx-watch, it might be easier, but the general flow would remain the same.
At this point, I can code all I want, press Save and dnx-watch will automatically restart my application. I can put Visual Studio Code side by side with my browser and Save/Refresh over and over.
Now you can always add your own keybindings by editing keybindings.js from File | Preferences | Keyboard Shortcuts. For example, here Ctrl-Q is bound to Terminate Task (that will let me stop dnx-watch). However, because we said "isBuildCommand: true" in the tasks.js file, we've told Visual Studio Code that our "watch" gulp command IS our project's command to build. You could add test commands, make your gulp file more sophisticated; the sky's the limit.
Give it a try!
Sponsor: Many thanks to Atalasoft for sponsoring the feed this week. If your project requires image viewing, format freedom, scanning, or other document-centric workflows, Atalasoft’s document imaging experts can help. Evaluate their developer tools for 30 days with remarkable human support.
About Scott
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
About Newsletter
In the good old days, there was not such a thing as JavaScript compilation/transpilation, just open an html page with JavaScript (even without web server) and it just works. Today you need to be gulp/babel/typescript guru just to get some basic javascript working.
The .net world (surprise surprise) is taking the path of the radical simplification thanks to roslyn. That's really great. For my javascript, I would already be very happy if there was some equivallent of msBuild.
dnx-watch webcrashes with the following:
Error: This application requires DNX version 1.0.0-rc1-15838 or newer to run.Is there something I can do to get it working?
dnvm upgradedoesn't upgrade anything, since beta8 is the latest "stable" release. I ran upgrade just before trying dnx-watch to get up to beta8 from beta7. 1.0.0-rc1-15838 looks like the version number of a nightly build to me.
you can do it by using browser sync plugin, its not as easy as with livereload but it works quite good.
1. VS Code
2. Asp.net project directory tree
3. A .vscode subdirectory
4. Html form in .vscode subdirectory with a few text fields, dropdowns, a compile button, a debug button, a run button, ...
5. A REST service running in node.js
6. JavaScript on the html form in #4 to call the REST service from #5
7. Code in the REST service to do a build, a debug or a run on the asp.net application
It is all just waiting to be built and tagged "inspired by tcl/tk".
Why can't web sites be developed more like assemblies or applications where there is a clean isolation between the source code and output? I'll inject database development into this because it also is busted. If database development actually isolated schema from "data" and the physical database instance abstraction patterns could be used plus could enhance the physical upgrade capabilities and version of the schema tracking.
The only reasons I think of is the carryover from having limited access to spawn http server instances to a compiled output location. IISExpress and the embedded support for asp.net grealy enhance the abilty to build solutions to "build" and execute from the compiled location.
What is the real advantage of running a web site from the same location as your source code?
I am working on a MAC, and it works (or at least executes without errors).
mono --version
Mono JIT compiler version 4.0.4 (Stable 4.0.4.1/5ab4c0d Tue Aug 25 23:11:51 UTC 2015)
dnvm list
Active Version Runtime Architecture OperatingSystem Alias
------ ------- ------- ------------ --------------- -----
1.0.0-beta7 mono linux/osx
* 1.0.0-beta8 mono linux/osx default
And here's what I get:
dnx-watch web
System.NullReferenceException: Object reference not set to an instance of an object
at Microsoft.Dnx.Watcher.Program..ctor () [0x00000] in <filename unknown>:0
at Microsoft.Dnx.Watcher.Program.Main (System.String[] args) [0x00000] in <filename unknown>:0
at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&)
at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <filename unknown>:0
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x00000] in <filename unknown>:0
at Microsoft.Dnx.Runtime.Common.EntryPointExecutor.Execute (System.Reflection.Assembly assembly, System.String[] args, IServiceProvider serviceProvider) [0x00000] in <filename unknown>:0
at Microsoft.Dnx.ApplicationHost.Program.ExecuteMain (Microsoft.Dnx.ApplicationHost.DefaultHost host, System.String applicationName, System.String[] args) [0x00000] in <filename unknown>:0
at Microsoft.Dnx.ApplicationHost.Program.Main (System.String[] args) [0x00000] in <filename unknown>:0
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x00000] in <filename unknown>:0
at Microsoft.Dnx.Runtime.Common.EntryPointExecutor.Execute (System.Reflection.Assembly assembly, System.String[] args, IServiceProvider serviceProvider) [0x00000] in <filename unknown>:0
at Microsoft.Dnx.Host.Bootstrapper.RunAsync (System.Collections.Generic.List`1 args, IRuntimeEnvironment env, System.String appBase, System.Runtime.Versioning.FrameworkName targetFramework) [0x00000] in <filename unknown>:0
To have something cross platform? And then sneak in android and ios builds? Replacing Xamarin?
I feel that adding tasks to gulp that can be directly run by npm is more complex than necessary so instead of using gulp I just added a command to the script section of package.json like so:
{
"scripts": {
"setup": "npm install && bower install && dnu restore && dnu build",
"start": "dnx-watch web"
}
}
Even though this does not give me a task in vs code (easily fixed), it does correspond well to what I'm used to, i.e using npm for web projects and just running
npm run setup
npm start
Comments are closed.
Can't wait til ASP.NET 5 arrives!