This little post is just a reminder that while Model Binding in ASP.NET is very cool, you should be aware of the properties (and semantics of those properties) that your object has, and whether or not your HTML form includes all your properties, or omits some.
OK, that's a complex - and perhaps poorly written - sentence. Let me back up.
Let's say you have this horrible class. Relax, yes, it's horrible. It's an example. It'll make sense in a moment.
public class Person { public int ID { get; set; } public string First { get; set; } public string Last { get; set; } public bool IsAdmin { get; set; } }
Then you've got an HTML Form in your view that lets folks create a Person. That form has text boxes/fields for First, and Last. ID is handled by the database on creation, and IsAdmin is a property that the user doesn't need to know about. Whatever. It's secret and internal. It could be Comment.IsApproved or Product.Discount. You get the idea.
Then you have a PeopleController that takes in a Person via a POST:
[HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Create(Person person) { if (ModelState.IsValid) { _context.Add(person); await _context.SaveChangesAsync(); return RedirectToAction("Index"); } return View(person); }
If a theoretical EvilUser found out that Person had an "IsAdmin" property, they could "overpost" and add a field to the HTTP POST and set IsAdmin=true. There's nothing in the code here to prevent that. ModelBinding makes your code simpler by handling the "left side -> right side" boring code of the past. That was all that code where you did myObject.Prop = Request.Form["something"]. You had lines and lines of code digging around in the QueryString or Form POST.
Model Binding gets rid of that and looks at the properties of the object and lines them up with HTTP Form POST name/value pairs of the same names.
NOTE: Just a friendly reminder that none of this "magic" is magic or is secret. You can even write your own custom model binders if you like.
The point here is that folks need to be aware of the layers of abstraction when you use them. Yes, it's convenient, but it's hiding something from you, so you should know the side effects.
How do we fix the problem? Well, a few ways. You can mark the property as [ReadOnly]. More commonly, you can use a BindAttribute on the method parameters and just include (whitelist) the properties you want to allow for binding:
public async Task<IActionResult> Create([Bind("First,Last")] Person person)
Or, the correct answer. Don't let models that look like this get anywhere near the user. This is the case for ViewModels. Make a model that looks like the View. Then do the work. You can make the work easier with something like AutoMapper.
Some folks find ViewModels to be too cumbersome for basic stuff. That's valid. There are those that are "All ViewModels All The Time," but I'm more practical. Use what works, use what's appropriate, but know what's happening underneath so you don't get some scriptkiddie overposting to your app and a bit getting flipped in your Model as a side effect.
Use ViewModels when possible or reasonable, and when not, always whitelist your binding if the model doesn't line up one to one (1:1) with your HTML Form.
What are your thoughts?
Sponsor: Check out JetBrains Rider: a new cross-platform .NET IDE. Edit, refactor, test, build and debug ASP.NET, .NET Framework, .NET Core, or Unity applications. Learn more and get access to early builds!
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.
While I was getting Ruby on Rails to work nicely under Ubuntu on Windows 10 I took the opportunity to set up my *nix bash environment, which was largely using defaults. Yes, I know I can use zsh or fish or other shells. Yes, I know I can use emacs and screen, but I am using Vim and tmux. Fight me. Anyway, once my post was done, I starting messing around with open source .NET Core on Linux (it runs on Windows, Mac, and Linux, but here I'm running on Linux on Windows. #Inception) and tweeted a pic of my desktop.
Also, for those of you who are DEEPLY NOT INTERESTED in the command line, that's cool. You can stop reading now. Totally OK. I also use Visual Studio AND Visual Studio Code. Sometimes I click and mouse and sometimes I tap and type. There is room for us all.
A number of people asked me how they could set up their WSL (Windows Subsystem for Linux) installs to be something like this, so here's what I did. Note that will I've been using *nix on and off for 20+ years, I am by no means an expert. I am, and have been, Permanently Intermediate in my skills. I do not dream in RegEx, and I am offended that others can bust out an awk script without googling.
So there's a few things going on in this screenshot.
Running .NET Core on Linux (on Windows 10)
Cool VIM theme with >256 colors
Norton Midnight Commander in the corner (thanks Miguel)
Desqview-esque tmux splitter (with mouse support)
Some hotkey remapping, git prompt, completion
Ubuntu Mono font
Nice directory colors (DIRCOLORS/LS_COLORS)
Let's break them down one at a time. And, again, your mileage may vary, no warranty express or implied, any of this may destroy your world, you read this on a blog. Linux is infinitely configurable and the only constant is that my configuration rocks and yours sucks. Until I see something in yours that I can steal.
Running .NET Core on Linux (on Windows 10)
Since Linux on Windows 10 is (today) Ubuntu, you can install .NET Core within it just like any Linux. Here's the Ubuntu instructions for .NET Core's SDK. You may have Ubuntu 14.04 or 16.04 (you can upgrade your Linux on Windows if you like). Make sure you know what you're running by doing a:
~ $ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 16.04.2 LTS Release: 16.04 Codename: xenial ~ $
If you're not on 16.04 you can easily remove and reinstall the whole subsystem with these commands at cmd.exe (note the /full is serious and torches the Linux filesystem):
> lxrun /uninstall /full > lxrun /install
Or if you want you can run this within bash (will take longer but maintain settings).
NOTE that you'll need Windows 10 Creators Edition build 16163 or greater to run Ubuntu 16.04. Type "winver" to check your build.
sudo do-release-upgrade
Know what Ubuntu your Windows 10 has when you install .NET Core within it. The other thing to remember is that now you have two .NET Cores, one Windows and one Ubuntu, on the same (kinda) machine. Since the file systems are separated it's not a big deal. I do my development work within Ubuntu on /mnt/d/github (which is a Windows drive). It's OK for the Linux subsystem to edit files in Linux or Windows, but don't "reach into" the Linux file system from Windows.
Cool Vim theme with >256 colors
That Vim theme is gruvbox and I installed it like this. Thanks to Rich Turner for turning me on to this theme.
$ cd ~/ $ mkdir .vim $ cd .vim $ mkdir colors $ cd colors $ curl -O https://raw.githubusercontent.com/morhetz/gruvbox/master/colors/gruvbox.vim $ cd ~/ $ vim .vimrc
Paste the following (hit āiā for insert and then right click/paste)
set number syntax enable set background=dark colorscheme gruvbox set mouse=a
if &term =~ '256color' " disable Background Color Erase (BCE) so that color schemes " render properly when inside 256-color tmux and GNU screen. " see also http://snk.tuxfamily.org/log/vim-256color-bce.html set t_ut= endif
Then save and exit with Esc, :wq (write and quit). There's a ton of themes out there, so try some for yourself!
Norton Midnight Commander in the corner (thanks Miguel)
Midnight Commander is a wonderful Norton Commander clone that Miguel de Icaza started, that's licensed as part of GNU. I installed it via apt, as I would any Ubuntu software.
$ sudo apt-get install mc
There's mouse support within the Windows conhost (console host) that bash runs within, so you'll even get mouse support within Midnight Commander!
Great stuff.
Desqview-esque tmux splitter (with mouse support)
Tmux is a terminal multiplexer. It's a text-mode windowing environment within which you can run multiple programs. Even better, you can "detach" from a running session and reattached from elsewhere. Because of this, folks love using tmux on servers where they can ssh in, set up an environment, detach, and reattach from elsewhere.
NOTE: The Windows Subsystem for Linux shuts down all background processes when the last console exits. So you can detach and attach tmux sessions happily, but just make sure you don't close every console on your machine.
Here's a nice animated gif of me moving the splitter on tmux on Windows. YES I KNOW YOU CAN USE THE KEYBOARD BUT THIS GIF IS COOL.
Some hotkey remapping, git prompt, completion
I am still learning tmux but here's my .tmux.conf. I've made a few common changes to make the hotkey creation of windows easier.
#remap prefix from 'C-b' to 'C-a' unbind C-b set-option -g prefix C-a bind-key C-a send-prefix
# Enable mouse control (clickable windows, panes, resizable panes) set -g mouse on set -g default-terminal "screen-256color"
I'm using the default Ubuntu .bashrc that includes a check for dircolors (more on this below) but I added this for git-completion.sh and a git prompt, as well as these two alias. I like being able to type "desktop" to jump to my Windows Desktop. And the -x on Midnight Commander helps the mouse support.
alias desktop="cd /mnt/c/Users/scott/Desktop" alias mc="mc -x"
export CLICOLOR=1 source ~/.git-completion.sh PS1='\[\033[37m\]\W\[\033[0m\]$(__git_ps1 " (\[\033[35m\]%s\[\033[0m\])") \$ ' GIT_PS1_SHOWDIRTYSTATE=1 GIT_PS1_SHOWSTASHSTATE=1 GIT_PS1_SHOWUNTRACKEDFILES=1 GIT_PS1_SHOWUPSTREAM="auto"
Git Completion can be installed with:
sudo apt-get install git bash-completion
Ubuntu Mono font
I really like the Ubuntu Mono font, and I like the way it looks when running Ubuntu under Windows. You can download the Ubuntu Font Family free. Right click the downloaded TTF files and right click and "Install," or drag them into C:\windows\fonts. Then click the upper left corner of any Bash console window and change your font to Ubuntu Mono.
Nice directory colors (DIRCOLORS/LS_COLORS)'
If you have a black command prompt background, then default colors for directories will be dark blue on black, which sucks. Fortunately you can get .dircolors files from all over the wep, or set the LS_COLORS (make sure to search for LS_COLORS for Linux, not the other, different LSCOLORS on Mac) environment variable.
I ended up with "dircolors-solarized" from here, downloaded it with wget or curl and put it in ~. Then confirm this is in your .bashrc (it likely is already)
# enable color support of ls and also add handy aliases if [ -x /usr/bin/dircolors ]; then test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)" alias ls='ls --color=auto' alias dir='dir --color=auto' #alias vdir='vdir --color=auto'
alias grep='grep --color=auto' alias fgrep='fgrep --color=auto' alias egrep='egrep --color=auto' fi
Download whatever .dircolors file makes you happy (make sure the filename ends up as ".dircolors," so you may need to cp yoursourcefile ~/.dircolors and then restart your console.
Make a big difference for me, and as I mention, it's totally, gloriously, maddeningly configurable.
Leave YOUR Linux on Windows tips in the comments!
Sponsor: Did you know VSTS can integrate closely with Octopus Deploy? Watch Damian Brady and Brian A. Randell as they show you how to automate deployments from VSTS to Octopus Deploy, and demo the new VSTS Octopus Deploy dashboard widget. Watch now
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.
Running Ruby on Rails on Windows has historically sucked. Most of the Ruby/Rails folks are Mac and Linux users and haven't focused on getting Rails to be usable for daily development on Windows. There have been some heroic efforts by a number of volunteers to get Rails working with projects like RailsInstaller, but native modules and dependencies almost always cause problems. Even more, when you go to deploy your Rails app you're likely using a Linux host so you may run into differences between operating systems.
Fast forward to today and Windows 10 has the Ubuntu-based "Linux Subsystem for Windows" (WSL) and the native bash shell which means you can run real Linux elf binaries on Windows natively without a Virtual Machine...so you should do your Windows-based Rails development in Bash on Windows.
Ruby on Rails development is great on Windows 10 because you've Windows 10 handling the "windows" UI part and bash and Ubuntu handling the shell.
After I set it up I want to git deploy my app to Azure, easily.
Developing on Ruby on Rails on Windows 10 using WSL
Rails and Ruby folks can apt-get update and apt-get install ruby, they can install rbenv or rvm as they like. These days rbenv is preferred.
You will likely also want either PostgresSQL or MySQL or Mongo, or you can use a Cloud DB like Azure DocumentDB.
When you're developing on both Windows and Linux at the same time, you'll likely want to keep your code in one place or the other, not both. I use the automatic mount point that WSL creates at /mnt/c so for this sample I'm at /mnt/c/Users/scott/Desktop/RailsonAzure which maps to a folder on my Windows desktop. You can be anywhere, just be aware of your CR/LF settings and stay in one world.
I did a "rails new ." and got it running locally. Here you can se Visual Studio Code with Ruby Extensions and my project open next to Bash on Windows.
After I've got a Rails app running and I'm able to develop cleanly, jumping between Visual Studio Code on Windows and the Bash prompt within Ubuntu, I want to deploy the app to the web.
Since this is a simple "Hello World" default rails app I can't deploy it somewhere where the Rails Environment is Production. There's no Route in routes.rb (the Yay! You're on Rails message is development-time only) and there's no SECRET_KEY_BASE environment variable set which is used to verify signed cookies. I'll need to add those two things. I'll change routes.rb quickly to just use the default Welcome page for this demo, like this:
Rails.application.routes.draw do
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
get '/' => "rails/welcome#index"
end
And I'll add the SECRET_KEY_BASE in as an App Setting/ENV var in the Azure portal when I make my backend, below.
Deploying Ruby on Rails App to Azure App Service on Linux
NOTE: A few glossary and definition points. Azure App Service is the Azure PaaS (Platform as a Service). You run Web Apps on Azure App Service. An Azure App Service Plan is the underlying Virtual Machine (sall, medium, large, etc.) that hosts n number of App Services/Web Sites. I have 20 App Services/Web Sites running under a App Service Plan with a Small VM. By default this is Windows by can run Php, Python, Node, .NET, etc. In this blog post I'm using an App Service Plan that runs Linux and hosts Docker containers. My Rails app will live inside that App Service and you can find the Dockerfiles and other info here https://github.com/Azure-App-Service/ruby or use your own Docker image.
Here you can see my Azure App Service that I'll now deploy to using Git. I could also FTP.
I went into Deployment OPtions and setup a local (to Azure) git repro. Now I can see that under Overview.
On my local bash I add azure as a remote. This can be set up however your workflow is setup. In this case, Git is FTP for code.
This starts the deployment as the code is pushed to Azure.
IMPORTANT: I will also add "RAILS_ENV= production" and a SECRET_KEY_BASE=to my Azure Application Settings. You can make a new secret with "rake secret."
If I'm having trouble I can turn on Application Logging, Web Server Logging, and Detailed Error Messages under Diagnostic Logs then FTP into the App Service and look at the logs.
This is all in Preview so you'll likely run into issues. They are updating the underlying systems very often. Some gotchas I hit:
Deploying/redeploying requires an explicit site restart, today. I hear that'll be fixed soon.
I had to dig log files out via FTP. They are going to expose logs in the portal.
I used the Kudu "sidecar" site at mysite.scm.azurewebsite.net to get shell access to the Kudu container, but I'd like to be able to ssh into or get to access to the actual running container from the Azure Portal one day.
Sponsor: Did you know VSTS can integrate closely with Octopus Deploy? Watch Damian Brady and Brian A. Randell as they show you how to automate deployments from VSTS to Octopus Deploy, and demo the new VSTS Octopus Deploy dashboard widget. Watch now
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.
However, I've also got this wonderful Nintendo Switch and two JoyCon controllers. Rachel White reminded me that they are BlueTooth! So why not pair them to your machine and map some of their buttons to keystrokes?
Let's do it!
First, hold the round button on the black side of the controller between the SL and SR buttons, then go into Windows Settings and Add Bluetooth Device.
You can add them both if you like! They show up like Game Controllers to Windows:
Ah, but these are Joysticks. We need to map JoyStick Actions to Key Presses. Enter JoyToKey. If you keep using it (even though you can use it free) it's Shareware, you can buy JoyToKey for just $7.
Hold down a button on your Joystick/Joycon to see what it maps to. For example, here I'm clicking in on the stick and I can see that's Button 12.
Map them anyway you like. I mapped left and right to PageUp and PageDown so now I can control PowerPoint!
Sponsor: Did you know VSTS can integrate closely with Octopus Deploy? Watch Damian Brady and Brian A. Randell as they show you how to automate deployments from VSTS to Octopus Deploy, and demo the new VSTS Octopus Deploy dashboard widget. Watch now
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.
Minimize it - "Oh, it's just Cygwin." (It's actually not, it's the actual Ubuntu elf binaries running on a layer that abstracts the Linux kernel.)
Design it - "So it's a docker container? A VM?" (Again, it's a whole subsystem. It does WAY more than you'd think, and it's FASTer than a VM.)
Here's a simple explanation from Andrew Pardoe:
1. The developer/user uses a bash shell. 2. The bash shell runs on an install of Ubuntu 3. The Ubuntu install runs on a Windows subsystem. This subsystem is designed to support Linux.
It's pretty cool. WSL has, frankly, kept me running Windows because I can run cmd, powershell, OR bash (or zsh or Fish). You can run vim, emacs, tmux, and run Javascript/node.js, Ruby, Python, C/C++, C# & F#, Rust, Go, and more. You can also now run sshd, MySQL, Apache, lighttpd as long as you know that when you close your last console the background services will shut down. Bash on Windows is for developers, not background server apps. And of course, you apt-get your way to glory.
Bash on Windows runs Ubuntu user-mode binaries provided by Canonical. This means the command-line utilities are the same as those that run within a native Ubuntu environment.
I wanted to write a Linux Console app in C++ using Visual Studio in Windows. Why? Why not? I like VS.
Setting up Visual Studio 2017 to compile and debug C++ apps on Linux
Then open up /etc/ssh/sshd_config with vi (or nano) like
sudo nano /etc/ssh/sshd_config
and for simplicity's sake, set PasswordAuthentication to yes. Remember that it's not as big a security issue as you'd think as the SSHD daemon closes when your last console does, and because WSL's subsystem has to play well with Windows, it's privy to the Windows Firewall and all its existing rules, plus we're talking localhost also.
Now generate SSH keys and manually start the service:
$ sudo ssh-keygen -A $ sudo service ssh start
Create a Linux app in Visual Studio (or open a Makefile app):
Make sure you know your target (x64, x86, ARM):
In Visual Studio's Cross Platform Connection Manager you can control your SSH connections (and set up ones with private keys, if you like.)
Boom. I'm writing C++ for Linux in Visual Studio on Windows...running, compiling and debugging on the local Linux Subsystem
BTW, for those of you, like me, who love your Raspberry Pi tiny Linux computers...this is a great way to write C++ for those little devices as well. There's even a Blink example in File | New Project to start.
Sponsor: Thanks to Redgate! Track every change to your database! See who made changes, what they did, & why, with SQL Source Control. Get a full version history in your source control system. See how.
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.