Scott Hanselman

Publishing an ASP.NET Core website to a cheap Linux VM host

September 1, '16 Comments [2] Posted in DotNetCore | Linux | Open Source
Sponsored By

A little Linux VM on Azure is like $13 a month. You can get little Linux machines all over for between $10-15 a month. On Linode they are about $10 a month so I figured it would be interesting to setup an ASP.NET Core website running on .NET Core. As you may know, .NET Core is free, open source, cross platform and runs basically everywhere.

Step 0 - Get a cheap host

I went to Linode (or anywhere) and got the cheapest Linux machine they offered. In this case it's an Ubuntu 14.04 LTS Profile, 640bit, 4.6.5 Kernel.

I signed up for a tiny VM at Linode

Since I'm on Windows but I want to SSH into this Linux machine I'll need a SSH client. There's a bunch of options.

Step 0.5 - Setup a user that isn't root

It's always a good idea to avoid being root. After logging into the system as root, I made a new user and give them sudo (super user do):

adduser scott
usermod -aG sudo scott

Then I'll logout and go back in as scott.

Step 1 - Get .NET Core on your Linux Machine

Head over to http://dot.net to get .NET Core and follow the instructions. There's at least 8 Linuxes supported in 6 flavors so you should have no trouble. I followed the Ubuntu instructions.

To make sure it works after you've set it up, make a quick console app like this and run it.

mkdir testapp
cd testapp
dotnet new
dotnet restore
dotnet run

If it runs, then you've got .NET Core installed and you can move on to making a web app and exposing it to the internet.

NOTE: If "dotnet restore" fails with a segmentation fault, you may be running into this issue with some 64-bit Linux Kernels. Here's commands to fix it that worked for me on Ubuntu 14.04 when I hit this. The fix has been released as a NuGet now but it will be included with the next minor release of .NET Core, but if you ever need to manually update the CoreCLR you can.

Step 2 - Make an ASP.NET Core website

You can make an ASP.NET Core website that is very basic and very empty and that's OK. You can also get Yeoman and use the ASP.NET yeoman-based generators to get more choices. There is also the great ASP.NET MVC Boilerplate project for Visual Studio.

Or you can just start with:

dotnet new -t web

Today, this default site uses npm, gulp, and bower to manage JavaScript and CSS dependencies. In the future there will be options that don't require as much extra stuff but for now, in order to dotnet restore this site I'll need npm and what not so I'll do this to get node, npm, etc.

sudo install npm
sudo npm install gulp
sudo npm install bower

Now I can dotnet restore easily and run my web app to test. It will startup on localhost:5000 usually.

$ dotnet restore
$ dotnet run
scott@ubuntu:~/dotnettest$ dotnet run
Project dotnettest (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.
info: Microsoft.Extensions.DependencyInjection.DataProtectionServices[0]
User profile is available. Using '/home/scott/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest.
Hosting environment: Production
Content root path: /home/scott/dotnettest
Now listening on: http://localhost:5000

Of course, having something startup on localhost:5000 doesn't help me as I'm over here at home so I can't test a local website like this. I want to expose this site (via a port) to the outside world. I want something like http://mysupermachine -> inside my machine -> localhost:5000.

Step 3 - Expose your web app to the outside.

I could tell Kestrel - that's the .NET Web Server - to expose itself to Port 80, although you usually want to have another process between you and the outside world.

You can do this a few ways. You can open open Program.cs with a editor like "pico" and add a .UseUrls() call to the WebHostBuilder like this.

var host = new WebHostBuilder()
.UseKestrel()
.UseUrls("http://*:80")
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.Build();

Here the * binds to all the network adapters and it listens on Port 80. Putting http://0.0.0.0:80 also works.

You might have permission issues doing this and need to elevate the dotnet process and webserver which is also a problem so let's just keep it at a high internal port and reverse proxy the traffic with something like Nginx or Apache. We'll pull out the hard-coded port from the code and change the Program.cs to use a .json config file.

public static void Main(string[] args)
{
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("hosting.json", optional: true)
.Build();

var host = new WebHostBuilder()
.UseKestrel()
.UseConfiguration(config)
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.Build();

host.Run();
}

The hosting.json file is just this:

{
"server.urls": "http://localhost:5123"
}

We can also use "AddCommandLine(args) instead of "AddJsonFile()" and pass in --server.urls=http://*:5123 on the command line. It's up to you. You can also use the ASPNETCORE_URLS environment variable.

NOTE: I'm doing this work a folder under my home folder ~ or now. I'll later compile and "publish" this website to something like /var/dotnettest when I want it seen.

Step 4 - Setup a Reverse Proxy like Nginx

I'm following the detailed instructions at the ASP.NET Core Docs site called "Publish to a Linux Production Environment." (All the docs are on GitHub as well)

I'm going to bring in Nginx and start it.

sudo apt-get install nginx
sudo service nginx start

I'm going to change the default Nginx site to point to my (future) running ASP.NET Core web app. I'll open and change /etc/nginx/sites-available/default and make it look like this. Note the port number. Nginx is a LOT more complex than this and has a lot of nuance, so when you are ready to go into Super Official Production, be sure to explore what the perfect Nginx Config File looks like and change it to your needs.

server {
listen 80;
location / {
proxy_pass http://localhost:5123;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}

Then we'll check it and reload the config.

sudo nginx -t 
sudo nginx -s reload

Step 5 - Keep your website running

The website isn't up and running on localhost:5123 yet (unless you've run it yourself and kept it running!) so we'll need an app or a monitor to run it and keep it running. There's an app called Supervisor that is good at that so I'll add it.

sudo apt-get install supervisor

Here is where you/we/I/errbody needs to get the paths and names right, so be aware. I'm over in ~/testapp or something. I need to publish my site into a final location so I'm going to run dotnet publish, then copy the reuslts into /var/dotnettest where it will live.

dotnet publish
publish: Published to /home/scott/dotnettest/bin/Debug/netcoreapp1.0/publish
sudo cp -a /home/scott/dotnettest/bin/Debug/netcoreapp1.0/publish /var/dotnettest

Now I'm going to make a file (again, I use pico because I'm not as awesome as emacs or vim) called /src/supervisor/conf.d/dotnettest.conf to start my app and keep it running:

[program:dotnettest]
command=/usr/bin/dotnet /var/dotnettest/dotnettest.dll --server.urls:http://*:5123
directory=/var/dotnettest/
autostart=true
autorestart=true
stderr_logfile=/var/log/dotnettest.err.log
stdout_logfile=/var/log/dotnettest.out.log
environment=ASPNETCORE_ENVIRONMENT=Production
user=www-data
stopsignal=INT

Now we start and stop Supervisor and watch/tail its logs to see our app startup!

sudo service supervisor stop
sudo service supervisor start
sudo tail -f /var/log/supervisor/supervisord.log
#and the application logs if you like
sudo tail -f /var/log/dotnettest.out.log

If all worked out (if it didn't, it'll be a name or a path so keep trying!) you'll see the supervisor log with dotnet starting up, running your app.

Hey it's dotnet on linux

Remember the relationships.

  • Dotnet - runs your website
  • Nginx or Apache - Listens on Port 80 and forwards HTTP calls to your website
  • Supervisor - Keeps your app running

Next, I might want to setup a continuous integration build, or SCP/SFTP to handle deployment of my app. That way I can develop locally and push up to my Linux machine.

Hey it's my ASP.NET Core app on Linux

Of course, there are a dozen other ways to publish an ASP.NET Core site, not to mention Docker. I'll post about Docker another time, but for now, I was able to get my ASP.NET Core website published to a cheap $10 host in less than an hour. You can use the same tools to manage a .NET Core site that you use to manage any site be it PHP, nodejs, Ruby, or whatever makes you happy.


Sponsor: Aspose makes programming APIs for working with files, like: DOC, XLS, PPT, PDF and countless more.  Developers can use their products to create, convert, modify, or manage files in almost any way.  Aspose is a good company and they offer solid products.  Check them out, and download a free evaluation.

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.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web

What is Serverless Computing? Exploring Azure Functions

August 27, '16 Comments [37] Posted in Azure | nodejs
Sponsored By

There's a lot of confusing terms in the Cloud space. And that's not counting the term "Cloud." ;)

  • IaaS (Infrastructure as a Services) - Virtual Machines and stuff on demand.
  • PaaS (Platform as a Service) - You deploy your apps but try not to think about the Virtual Machines underneath. They exist, but we pretend they don't until forced.
  • SaaS (Software as a Service) - Stuff like Office 365 and Gmail. You pay a subscription and you get email/whatever as a service. It Just Works.

"Serverless Computing" doesn't really mean there's no server. Serverless means there's no server you need to worry about. That might sound like PaaS, but it's higher level that than.

Serverless Computing is like this - Your code, a slider bar, and your credit card. You just have your function out there and it will scale as long as you can pay for it. It's as close to "cloudy" as The Cloud can get.

Serverless Computing is like this. Your code, a slider bar, and your credit card.

With Platform as a Service, you might make a Node or C# app, check it into Git, deploy it to a Web Site/Application, and then you've got an endpoint. You might scale it up (get more CPU/Memory/Disk) or out (have 1, 2, n instances of the Web App) but it's not seamless. It's totally cool, to be clear, but you're always aware of the servers.

New cloud systems like Amazon Lambda and Azure Functions have you upload some code and it's running seconds later. You can have continuous jobs, functions that run on a triggered event, or make Web APIs or Webhooks that are just a function with a URL.

I'm going to see how quickly I can make a Web API with Serverless Computing.

I'll go to http://functions.azure.com and make a new function. If you don't have an account you can sign up free.

Getting started with Azure Functions

You can make a function in JavaScript or C#.

Getting started with Azure Functions - Create This Function

Once you're into the Azure Function Editor, click "New Function" and you've got dozens of templates and code examples for things like:

  • Find a face in an image and store the rectangle of where the face is.
  • Run a function and comment on a GitHub issue when a GitHub webhook is triggered
  • Update a storage blob when an HTTP Request comes in
  • Load entities from a database or storage table

I figured I'd change the first example. It is a trigger that sees an image in storage, calls a cognitive services API to get the location of the face, then stores the data. I wanted to change it to:

  • Take an image as input from an HTTP Post
  • Draw a rectangle around the face
  • Return the new image

You can do this work from Git/GitHub but for easy stuff I'm literally doing it all in the browser. Here's what it looks like.

Azure Functions can be done in the browser

I code and iterate and save and fail fast, fail often. Here's the starter code I based it on. Remember, that this is a starter function that runs on a triggered event, so note its Run()...I'm going to change this.

#r "Microsoft.WindowsAzure.Storage"
#r "Newtonsoft.Json"

using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using Newtonsoft.Json;
using Microsoft.WindowsAzure.Storage.Table;
using System.IO; 

public static async Task Run(Stream image, string name, IAsyncCollector<FaceRectangle> outTable, TraceWriter log)
{
    var image = await req.Content.ReadAsStreamAsync();
    
    string result = await CallVisionAPI(image); //STREAM
    log.Info(result); 

    if (String.IsNullOrEmpty(result))
    {
        return req.CreateResponse(HttpStatusCode.BadRequest);
    }

    ImageData imageData = JsonConvert.DeserializeObject<ImageData>(result);
    foreach (Face face in imageData.Faces)
    {
        var faceRectangle = face.FaceRectangle;
        faceRectangle.RowKey = Guid.NewGuid().ToString();
        faceRectangle.PartitionKey = "Functions";
        faceRectangle.ImageFile = name + ".jpg";
        await outTable.AddAsync(faceRectangle); 
    }
    return req.CreateResponse(HttpStatusCode.OK, "Nice Job");  
}

static async Task<string> CallVisionAPI(Stream image)
{
    using (var client = new HttpClient())
    {
        var content = new StreamContent(image);
        var url = "https://api.projectoxford.ai/vision/v1.0/analyze?visualFeatures=Faces";
        client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", Environment.GetEnvironmentVariable("Vision_API_Subscription_Key"));
        content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
        var httpResponse = await client.PostAsync(url, content);

        if (httpResponse.StatusCode == HttpStatusCode.OK){
            return await httpResponse.Content.ReadAsStringAsync();
        }
    }
    return null;
}

public class ImageData {
    public List<Face> Faces { get; set; }
}

public class Face {
    public int Age { get; set; }
    public string Gender { get; set; }
    public FaceRectangle FaceRectangle { get; set; }
}

public class FaceRectangle : TableEntity {
    public string ImageFile { get; set; }
    public int Left { get; set; }
    public int Top { get; set; }
    public int Width { get; set; }
    public int Height { get; set; }
}

GOAL: I'll change this Run() and make this listen for an HTTP request that contains an image, read the image that's POSTed in (ya, I know, no validation), draw rectangle around detected faces, then return a new image.

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log) {
var image = await req.Content.ReadAsStreamAsync();

As for the body of this function, I'm 20% sure I'm using too many MemoryStreams but they are getting disposed so take this code as a initial proof of concept. However, I DO need at least the two I have. Regardless, happy to chat with those who know more, but it's more subtle than even I thought. That said, basically call out to the API, get back some face data that looks like this:

2016-08-26T23:59:26.741 {"requestId":"8be222ff-98cc-4019-8038-c22eeffa63ed","metadata":{"width":2808,"height":1872,"format":"Jpeg"},"faces":[{"age":41,"gender":"Male","faceRectangle":{"left":1059,"top":671,"width":466,"height":466}},{"age":41,"gender":"Male","faceRectangle":{"left":1916,"top":702,"width":448,"height":448}}]}

Then take that data and DRAW a Rectangle over the faces detected.

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
    var image = await req.Content.ReadAsStreamAsync();

    MemoryStream mem = new MemoryStream();
    image.CopyTo(mem); //make a copy since one gets destroy in the other API. Lame, I know.
    image.Position = 0;
    mem.Position = 0;
    
    string result = await CallVisionAPI(image); 
    log.Info(result); 

    if (String.IsNullOrEmpty(result)) {
        return req.CreateResponse(HttpStatusCode.BadRequest);
    }
    
    ImageData imageData = JsonConvert.DeserializeObject<ImageData>(result);

    MemoryStream outputStream = new MemoryStream();
    using(Image maybeFace = Image.FromStream(mem, true))
    {
        using (Graphics g = Graphics.FromImage(maybeFace))
        {
            Pen yellowPen = new Pen(Color.Yellow, 4);
            foreach (Face face in imageData.Faces)
            {
                var faceRectangle = face.FaceRectangle;
                g.DrawRectangle(yellowPen, 
                    faceRectangle.Left, faceRectangle.Top, 
                    faceRectangle.Width, faceRectangle.Height);
            }
        }
        maybeFace.Save(outputStream, ImageFormat.Jpeg);
    }
    
    var response = new HttpResponseMessage()
    {
        Content = new ByteArrayContent(outputStream.ToArray()),
        StatusCode = HttpStatusCode.OK,
    };
    response.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
    return response;
}

I also added a reference to System. Drawing using this syntax at the top of the file and added a few namespaces with usings like System.Drawing and System.Drawing.Imaging. I also changed the input in the Integrate tab to "HTTP" as my input.

#r "System.Drawing

Now I go into Postman and POST an image to my new Azure Function endpoint. Here I uploaded a flattering picture of me and unflattering picture of The Oatmeal. He's pretty in real life just NOT HERE. ;)

Image Recognition with Azure Functions

So in just about 15 min with no idea and armed with just my browser, Postman (also my browser), Google/StackOverflow, and Azure Functions I've got a backend proof of concept.

Azure Functions supports Node.js, C#, F#, Python, PHP *and* Batch, Bash, and PowerShell, which really opens it up to basically anyone. You can use them for anything when you just want a function (or more) out there on the web. Send stuff to Slack, automate your house, update GitHub issues, act as a Webhook, etc. There's some great 3d party Azure Functions sample code in this GitHub repo as well. Inputs can be from basically anywhere and outputs can be basically anywhere. If those anywheres are also cloud services like Tables or Storage, you've got a "serverless backed" that is easy to scale.

I'm still learning, but I can see when I'd want a VM (total control) vs a Web App (near total control) vs a "Serverless" Azure Function (less control but I didn't need it anyway, just wanted a function in the cloud.)


Sponsor: Aspose makes programming APIs for working with files, like: DOC, XLS, PPT, PDF and countless more.  Developers can use their products to create, convert, modify, or manage files in almost any way.  Aspose is a good company and they offer solid products.  Check them out, and download a free evaluation.

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.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web

Psychic Weight - Dealing with the things that press on your mind

August 24, '16 Comments [39] Posted in Musings
Sponsored By
Close up view of man on his phone 

I was really stressed out ten years ago. I felt that familiar pressure between my eyes and felt like all the things that remained undone were pressing on me. I called it "psychic weight." I have since then collected my Productivity Tips and written extensively on the topic of productivity and getting things done. I'm going to continue to remind YOU that Self-Care Matters in between my technical and coding topics. The essence of what I learned was to let go.

The Serenity Prayer:

God, grant me the serenity to accept the things I cannot change,
Courage to change the things I can,
And wisdom to know the difference.

Everyone has stress and everyone has pressure. There's no magic fix or silver bullet for stress, but I have found that some stressors have a common root cause. Things that stress me are things I think I need to do, handle, watch, take care of, worry about, sweat, deal with, or manage. These things press on me - right between my eyes - and the resulting feeling is what I call psychic weight.

For example: When the DVR (Digital Video Recorder) came out it was a gift from on high. What? A smart VCR that would just tape and hold all the TV Shows that I love? I don't have to watch shows when the time and day the shows come on? Sign me up. What a time saver!

Fast forward a few years and the magical DVR is now an infinite todo list of TV shows. It's a guilt pile. A failure queue. I still haven't watched The Wire. (I know.) It presses on me. I've actually had conversations with my wife like "ok, if we bang out the first season by staying up tonight until 4am, we should be all ready when Season 2 drops next week." Seriously. Yes, I know, Unwatched TV is a silly example. But you've binge-watched Netflix when you should have been working/reading/working out so you can likely relate.

But I'm letting go. I'll watch The Wire another time. I'll delete it from my DVR. I'm never going to watch the second season of Empire. (Sorry, Cookie. I love you Taraji!) I'm not going to read that pile of technical books on my desk. So I'm going to declare that to the universe and I'm going to remove the pile of books that's staring at me. This book stack, this failure pile is no more. And I'm not even mad. I'm OK with it.

Every deletion like this from your life opens up your time - and your mind -for the more important things you need to focus on.

What are your goals? What can you delete from your list (and I mean, DROP, not just postpone) that will free up your internal resources so you can focus on your goal?

Delete those emails. Declare email bankruptcy. They'll likely email you again. Delete a few seasons of shows you won't watch. Delete Pokemon Go. Make that stack of technical books on your desk shorter. Now, what positive thing will you fill those gaps with?

You deserve it. Remove psychic weight and lighten up. Then sound off in the comments!

* Image Copyright Shea Parikh / used under license from getcolorstock.com


Sponsor: Aspose makes programming APIs for working with files, like: DOC, XLS, PPT, PDF and countless more.  Developers can use their products to create, convert, modify, or manage files in almost any way.  Aspose is a good company and they offer solid products.  Check them out, and download a free evaluation.

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.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web

Announcing PowerShell on Linux - PowerShell is Open Source!

August 18, '16 Comments [39] Posted in Open Source | PowerShell
Sponsored By

I started doing PowerShell almost 10 years ago. Check out this video from 2007 of me learning about PowerShell from Jeffrey Snover! I worked in PowerShell for many years and blogged extensively,  ultimately using PowerShell to script the automation and creation of a number of large systems in Retail Online Banks around the world.

Fast forward to today and Microsoft is announcing PowerShell on Linux powered by .NET Core and it's all open source and hosted at http://GitHub.com/PowerShell/PowerShell.

Holy crap PowerShell on Linux

Jeffrey Snover predicted internally in 2014 that PowerShell would eventually be open sourced but it was the advent of .NET Core and getting .NET Core working on multiple Linux distros that kickstarted the process. If you were paying attention it's possible you could have predicted this move yourself. Parts of PowerShell have been showing up as open source:

Get PowerShell everywhere

Ok, but where do you GET IT? http://microsoft.com/powershell is the homepage for PowerShell and everything can be found starting from there.

The PowerShell open source project is at https://github.com/PowerShell/PowerShell and there are alphas for Ubuntu 14.04/16.04, CentOS 7.1, and Mac OS X 10.11.

To be clear, I'm told this is are alpha quality builds as work continues with community support. An official Microsoft-supported "release" will come sometime later.

What's Possible?

This is my opinion and somewhat educated speculation, but it seems to me that they want to make it so you can manage anything from anywhere. Maybe you're a Unix person who has some Windows machines (either local or in Azure) that you need to manage. You can use PowerShell from Linux to do that. Maybe you've got some bash scripts at your company AND some PowerShell scripts. Use them both, interchangeably.

If you know PowerShell, you'll be able to use those skills on Linux as well. If you manage a hybrid environment, PowerShell isn't a replacement for bash but rather another tool in your toolkit. There are lots of shells (not just bash, zsh, but also ruby, python, etc) in the *nix world so PowerShell will be in excellent company.

PowerShell on Windows

Related Links

Be sure to check out the coverage from around the web and lots of blog posts from different perspectives!

Have fun! This open source thing is kind of catching on at Microsoft isn't it?


Sponsor: Do you deploy the same application multiple times for each of your end customers? The team at Octopus have been trying to take the pain out of multi-tenant deployments. Check out their 3.4 beta release.

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.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web

Visual Studio's most useful (and underused) tips

August 17, '16 Comments [99] Posted in VS2015
Sponsored By

There was a cool comment in my last blog post (one of many, as always, the comments > the content).

Btw, "until I realized that the Solution Explorer tree nodes are searchable." This one is a saver!

The commenter, Sam, noticed a throwaway bit in the middle of the post where I noted that the Solution Explorer was text-searchable. There's a lot of little tricks like this in Visual Studio that even the most seasoned developers sometimes miss. This phenomenon isn't limited to Visual Studio, of course. It's all software! Folks find non-obvious UX all the time in Windows, OSX, iPhone, everyday. If UX were easy then everything would be intuitive but it's not so it ain't. ;)

There's an old joke about Microsoft Office, which is known for having a zillion features.

"Most of the exciting new Office features you discover have always been in Office." - Me and Everyone Else

Here's some exceedingly useful stuff in Visual Studio (It's free to download and use, BTW) that folks often miss.

Search Solution Explorer with Ctrl+;

You can just click the text box above the Solution Explorer to search all the the nodes - visible or hidden. Or, press "Ctrl + ;"

Ctrl ; will filter the Solution Explorer

Even stuff that's DEEP in the beast. The resulting view is filtered and will remain that way until you clear the search.

Ctrl ; will filter the Solution Explorer and open subnodes

Quick Launch - Ctrl+Q

If there is one feature that no one uses and everyone should use, it's Quick Launch. Someone told me the internal telemetry numbers show that usage of Quick Launch in the single digits or lower.

Do you know that you (we) are constantly digging around in the menus for stuff? Most of you use the mouse and go Tools...Options...and stare.

Just press Ctrl+Q and type. Need to change the Font Size?

Find the Fonts Dialog quickly

Want to Compare Files? Did you know VS had that?

Compare Files

What about finding a NuGet package faster than using the NuGet Dialog?

image

Promise me you'll Ctrl+Q for a few days and see if you can make it a habit. You'll thank yourself.

Map Mode for the Scroll Bar

I love showing people features that totally surprise them. Like "I had NO IDEA that was there" type features. Try "map mode" in the Quick Launch and turn it on...then check out your scroll bar in a large file.

Map Mode for the Scroll Bar

Your scrollbar will turn into a thumbnail that you can hover over and use to navigate your file!

Map Mode turns your Scrollbar into a Scroll Thumbnail

Tab Management

Most folks manage their tabs like this.

  • Open Tab
  • Repeat
  • Declare Tab Bankruptcy
  • Close All Tabs
  • Goto 0

But you DO have both "pinned tabs" and "preview tabs" available.

Pin things you want to keep open

If you pin useful tabs, just like in your browser those tabs will stay to the left and stay open. You can not just "close all" and "close all but this" on a right click, but you can also "close all but pinned."

image

Additionally, you don't always have to double-click in the Solution Explorer to see what's in a file. That just creates a new tab that you're likely going to close anyway. Try just single clicking, or better yet, use your keyboard. You'll get a preview tab on the far right side. You'll never have more than one and preview tabs won't litter your tab list...unless you promote them.

Navigate To - Ctrl+, (Control+Comma)

Absolutely high on the list of useful things is Ctrl+, for NavigateTo. Why click around with your mouse to open a file or find a specific member or function? Press Ctrl+, and start typing. It searches files, members, type...everything. And you can navigate around with your keyboard before you hit enter.

There's basically no reason to poke around in the Solution Explorer if you already know the name of the item you want to see. Ctrl+, is very fast.

image

Move Lines with your keyboard

Yes I realize that Visual Studio isn't Emacs or VIM (unless you want it to be VsVim) but it does have a few tiny tricks that most VS users don't use.

You can move lines just by pressing Alt-up/down arrows. I've never seen anyone do this in the wild but me. You can also Shift-Select a bunch of lines and then Alt-Arrow them around as a group.

Move those lines with ALT-ARROW

You can also do Square Selection with Alt and Drag...and drag yourself a nice rectangle...then start typing to type on a dozen lines at once.

Perhaps you knew these, maybe you learned a few things. I think the larger point is to have the five to ten most useful features right there in your mind ready to go. These are mine. What are your tips?


Sponsor: Do you deploy the same application multiple times for each of your end customers? The team at Octopus have been trying to take the pain out of multi-tenant deployments. Check out their 3.4 beta release.

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.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.