If you want to clone a GitHub repository, the most common (and documented) way is to browse to it and click that green Clone or download button. In this case, I am cloning the .NET machine learning project:


Typically, I would copy the Git repository path and clone it in a command line window, like so:

git clone https://github.com/dotnet/machinelearning.git

As it turns out, this is a waste of clicks. All you have to do is grab the URL from the address bar of your favorite browser and ignore the .git extension altogether.

Try this:

I was writing some vanilla JavaScript this weekend - it has been quite awhile since I did so. As I've been writing mostly C# code lately, what always gets me with JavaScript isn't its pain points or subtle nuances. It's the different behavior from compiled languages I'm often used to, like C# or Java. No matter how often I work in JS, as long as I'm committed to being a polyglot, it'll trip me up to the point that it's just a little bit of an annoyance.

Take this seemingly simple JavaScript code. What will be output to the browser console?

var myString = 'I am outside the function';
function myFunction() {
    var myString = 'I am inside the function';

Was your guess I'm outside the function? Or was it I'm inside the function? I hate to let you down, but in either case you would be incorrect.

In your favorite browser's developer tools, the console will log undefined. But why?

In JavaScript, functions create brand new scopes. If we condense the example a little:

function myFunction() {
    // new scope, the variable is inaccessible outside the function
    var myString = 'I am inside the function';
console.log(myString); // undefined!

Of course, if you've worked in JavaScript (or basically any programming language) you can't expect to declare a variable without an assignment and expect to get anything back but null or, in JavaScript's case, undefined when I do something like this:

var dave;
console.log(dave); // will log undefined

So, if we look at this again:

var myString = 'I am outside the function';
function myFunction() {
    var myString = 'I am inside the function';

To take all we've learned, we need to be aware of how something called hoisting works. For our purposes just know this: variable declarations in JS are always hoisted to the top of the current scope -- variable assignments are not.

So here, the declaration is hoisted to the top of the scope - or, in our case, the myFunction() function. So before the console.log statement in the function, you can basically envision a var myString in the first line of the function. And, of course, knowing this now it is clear to see why the logging statement will come back as undefined.

Just remember this: always define your variables at the top of the current scope. Always.

The true power with ASP.NET Core is in its flexibility. With a powerful CLI, I can run an app on any platform with just a basic text editor, if I so desire. And speaking of desire: when I write code, I prefer Visual Studio Code. It's fast, responsive, and gives me exactly what I need and nothing more. Of course, I rely on Visual Studio 2017 from time-to-time for advanced debugging and profiling. But when I'm in a code-debug-code workflow, nothing is better.

Visual Studio Code is perfect for ASP.NET Core - allowing me to write front-end and back-end code in one great lightweight environment. Unfortunately, when I talk to ASP.NET Core developers many times Visual Studio Code isn't a consideration. Often, I hear that while Code is a great tool, it only is for those slinging front-end code. And after decades of the full-fledged Visual Studio being the only option to write .NET code, who can blame them?

Let's get started and walk through how you can debug C# code, query databases, and more with .NET Core using Visual Studio Code.

Note: All screenshots and keyboard shortcuts are using Windows 10, but they should be very similar on other operating systems like a Mac.



Before we get started, you'll need to make sure you have the following installed on your platform of choice.

Now that we have everything set up, let's start by creating a new ASP.NET Core web application from the ASP.NET Core command-line interface (CLI).

(back to contents)

Create a new Core project

We're going to create a new Core project first, using the ASP.NET Core CLI.

First, from a terminal window let's get a list of all available templates by adding the -l flag to our dotnet new command:

dotnet new -l

You can see that we can create a new project based on many different project template types. For our purposes, any application will do - let's go ahead and create a new ASP.NET Core MVC App by including the Short Name in the command in your terminal window.

dotnet new mvc

Now that we successfully created our project, we can open our new solution in Visual Studio Code. From the terminal, navigate one folder down to the project directory and enter code . from your terminal window.

(back to contents)

Working with your Core solution in Code

When you first open the C# project, you'll get a warning that Code needs to build required assets to the project.

After you click Yes, you'll see a .vscode folder added to your project, which includes the following:

  • launch.json - where Code keeps debugging configuration information
  • tasks.json - where you can define any tasks that you need run - for example, dotnet build or dotnet run.

For example, here's what my tasks.json looks like out of the box.

    "version": "2.0.0",
    "tasks": [
            "label": "build",
            "command": "dotnet build",
            "type": "shell",
            "group": "build",
            "presentation": {
                "reveal": "silent"
            "problemMatcher": "$msCompile"

This allows me to build my solution without needing to keep entering dotnet build from the command line. In Windows, I can hit Ctrl + Shift + B much like I can in regular Visual Studio. Try it out!

(back to contents)

Debugging C# Code

Now, let's take a look at how C# debugging works in Visual Studio Code. First, set a breakpoint anywhere in the application much like you would do in any other IDE (in a gutter next to the line number). In my case, I'm creating a breakpoint inside the About controller action in Controllers/HomeController.cs.

Now, navigate to the Debug tab in Code and click the Debug button.

Code will launch your application using http://localhost:5000.

Next, trigger your breakpoint - for me, that means clicking the About link in the top menu so that I can enter the About action in the Home controller.

If you go back to the Debug section in Code, you'll see all the debugging options at your disposal: accessing your variables, call stack, all your breakpoints, and even the ability to watch variables or objects.

Now, let's add a watch statement for the ViewData message.

It's null now because I haven't executed that line of code yet. Once I step into the method, you'll see the value of ViewData["Message"].

Now that we've been able to debug C#, let's query a database!

Working with Databases in Code

So, I've created a new C# project and can debug it in Visual Studio Code. Pretty cool, right? But with any server-side application, you'll want to work with a database. You can easily do this in Code - for our purposes, we'll be working with SQL Server.

(Note: If you are working with SQL Server on a Mac, a setup guide is beyond the scope of this post. This piece should be able to assist you.)

Before we get started, we'll need to install Microsoft's own SQL Server extension from Visual Studio Code. Just search for mssql in the Extensions panel and you should have no problem finding it.

Now that you have the extension installed, you'll need to create a connection to your database server (this can be locally or even something hosted in Azure). To start connecting to the database, access the Command menu (Ctrl + Shift + P) and search for sql. You'll see all the commands the extension has provided for you.

Select MS SQL : Connect from the command menu and follow the prompts.

  • Server name - since I am connecting locally, I just entered (localhost)\MSSQLLocalDB. You can do this, or if hosted in Azure the mydb.database.windows.net address, or even a remote IP address.
  • Database name - enter the database you want to use (this is optional).
  • Integrated/SQL Server authentication - pick your authentication method. If you're using a local DB, Integrated will do. For something like Azure, you'll need SQL authentication.
  • Profile name - you can optionally enter a name for the profile.

Now that we're set up and connected, let's set up a database with horror movies. To do this, first create a .sql file in your project.

Create sample database

In your SQL file, create a database. Feel free to copy and paste this syntax, then execute (Ctrl + Shift + E).


Now, if you execute the following you should be able to see the name of your new database.

SELECT Name FROM sys.Databases

Now that we have proof of our created databases, execute the following SQL to inject your database with sample data. You should notice IntelliSense-like completion!

USE MyHorrorDB
CREATE TABLE Movies (MovieId INT, Name NVARCHAR(255), Year INT)
INSERT INTO Movies VALUES (1, 'Halloween', 1978);
INSERT INTO Movies VALUES (2, 'Psycho', 1960);
INSERT INTO Movies VALUES (3, 'The Texas Chainsaw Massacre', 1974);
INSERT INTO Movies VALUES (4, 'The Exorcist', 1973);
INSERT INTO Movies VALUES (5, 'Night of the Living Dead', 1968);

Now, do a blanket SELECT to get all your movies (obviously, a blanket SELECT is not recommended for performance reasons but this is pretty harmless since we're querying five movies).


Now you should your sample data in action!

You can do much more than query databases, though! Take a look at this document for more details.

(back to contents)

Wrapping up

While this is just scratching the surface, I hope this convinces you to give Visual Studio Code a try for developing in ASP.NET Core when you don't need a full-fledged IDE. And, of course, leave me a comment if you want to keep this conversation going!

Thanks to Scott Addie of Microsoft and Chris DeMars for performing a technical review of this post.

This is a short post that might help you.

I wasn't sure how to use anchor links in Markdown. These come in handy when you have a long post and want to link to different sections of a document for easy navigation.

The nice thing about Markdown is that it plays so well with straight HTML - so I was pleased to get it working on the first try.

First, add an anchor as regular HTML in your Markdown element. Here, it is right at a heading.

### <a id="MyHeading"></a>My Heading ###

Now, I can link it using a standard Markdown link.

Where is my [heading](#MyHeading)?

For years, if we wanted to store local data we would look to using HTTP cookies—a convenient way to persist small amounts of data on a user's machine. And we do mean small: cookies are limited to about 4KB apiece. Also, the cookie is passed along with every request and response even if it isn't used, making for heavy HTTP messaging.

Enter the web storage APIs, a way for you to store key/value paired string values on a user's machine. Local storage provides much more space—modern browsers support a minimum of 5MB, much more than the 4KB for cookies.

When using web storage, we can implement either localStorage or sessionStorage from the Storage object. Let's work through how to accomplish this.

Checking web storage compatibility

Although most browsers support web storage, you still should be a good developer and verify that a user isn't using an unusually old browser like IE6:

function isWebStorageSupported() {
 return 'localStorage' in window;

When to use localStorage or sessionStorage

The localStorage and sessionStorage APIs are nearly identical with one key exception: persistence.

The sessionStorage object is only available for the duration of the browser session, and is deleted automatically when the window is closed. However, it does stick around for page reloads.

Meanwhile, localStorage is persisted until it is explicitly by the site or the user. All changes made to localStorage are available for all current and future visits to the site.

Whatever the case, both localStorage and sessionStorage work well when working with non-sensitive data needed within an application since data stored in localStorage and sessionStorage can easily be read or updated from a user's browser.

Web storage API methods and properties

The following is a list of methods and properties available on global Storage object's localStorage and sessionStorage variables.

  • key(index) - finds a key at a given index. As with finding indexes in other code you write, you should check the length before finding an index to avoid any null or out-of-range exceptions.
  • getItem(key) - retrieve a value by using the associated key.
  • setItem(key, value) - stores a value by using the associated key. Whether you are setting a new value or updating an existing value, the syntax is the same.
  • removeItem(key) - removes a value from local storage.
  • clear() - removes all items from storage.
  • length - a read-only property that gets the number of entries being stored.

Can I store objects?

While you can only have string values in web storage, you can store arrays or even JavaScript objects using the JSON notation and the available utility methods, like in the following example.

var player = { firstName: 'Kris', lastName: 'Bryant' };
localStorage.setItem('kris', JSON.stringify(player));

You can then use the parse() method to deserialize the kris object.

var player = JSON.parse(localStorage.getItem('kris'));

Keeping web storage synchronized

How do you keep everything in sync when a user has multiple tabs or browser instances of your site open concurrently? To solve this problem, the web storage APIs have a storage event that is raised whenever an entry is updated (add/update/removed). Subscribing to this event can provide notifications when something has changed. This works for both localStorage and sessionStorage.

Subscribers receive a StorageEvent object that contains data about what changed. The following properties are accessible from the StorageEvent object. The storage event cannot be canceled from a callback. The event is merely a notification mechanism: it informs subscribers when a change happens.

  • key - gets the key. The key will be null if the event was triggered by clear()
  • oldValue - gets the initial value if the entry was updated or removed. Again, the value will be null if an old value did not previously exist, or if clear() is invoked.
  • newValue - gets the new value for new and updated entries. The value is null if the event was triggered by the removeItem() or clear() methods.
  • url - gets the URL of the page on the storage action
  • storageArea - gets a reference to either the localStorage or sessionStorage object

To begin listening for event notifications, you can add an event handler to the storage event as follows.

function respondToEvent(event) {

window.addEventListener('storage', respondToChange, false);

To trigger this event, perform an operation like the following in a new tab from the same site.

localStorage.setItem('player', 'Kris');

The fine print

While web storage offers many benefits over cookies, it is not the end-all, be-all solution, and comes with serious drawbacks as others have noted.

  • Web storage is synchronous - because web storage runs synchronously, it can block the DOM from rendering while I/O is occurring.
  • No indexing or transactional features - web storage does not have indexing, which may incur performance bottlenecks on large data queries. If a user is modifying the same storage data in multiple browser tabs, one tab could potentially overwrite the value in another.
  • Web storage does I/O on your hard drive - because web storage writes to your hard drive, it can be an expensive operation depending on what your system is currently doing (virus scanning, indexing data, etc.) While you can store a lot more data in local storage, you'll need to be cognizant of performance.
  • Persistence - if a user no longer uses a site and storage is not explicitly deleted, storage is still loaded when you start the browser session
  • First request memory loading - because browsers load data into memory, it could use a lot of memory if many tabs are utilizing web storage mechanisms.

Web storage does offer you a simple, direct way to store user data, with caveats that it can degrade performance if you do not use it wisely thanks to its synchronous, I/O nature. Much like anything else you code, understand its utility and its nuances before using it, and don't be greedy. It very well can bite you in the rear end if you expect too much.