An Opinionated Approach to ASP.NET Core - Scott Allen

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
still morning right just barely how are we I hope you're enjoying this NDC event I am so happy that NDC has come to the United States I've been doing NDC events for years in Europe and I always thought they were one of the best conferences around so I was really happy and honored to be part of this event so today's topic is an opinionated opinionated approach to asp.net core this is basically where I sat down after a couple code reviews and said you know we're doing some interesting things in these projects I'd like to jot down some ideas of things that we've done right and things that we've done wrong and I came up with a list of something like 61 items and I thought well if I can cut it down to an even 50 maybe I could make a conference talk out of it so that's what you're going to hear today we're going to cover topics like mmm organizing your solutions and projects organizing your startup code working with controllers working with Razer pages also how to organize client code a couple tips for writing c-sharp code in the.net core environment and working with views and razor pages so I do assume that you know a little bit about asp.net core maybe you're already working on a project maybe you're planning to start a project and if so I hope that these tips help you so we'll start about solutions from projects first oh also some testing tips some of my personal philosophy and maybe some rants towards the end solutions and projects you know there's this really interesting thing if you go out onto github and you look at project structures how things are laid out inside of a github repository across various technologies across node and across ruby and people that are doing pure spa's and microsoft repositories for dotnet core code you'll start to notice a consistent project structure that i've adopted for my project so if you look at pretty much well if you look at any microsoft repository related to dotnet core or asp.net core your Garant is guaranteed to see a few things at the top level of that project which is you're always going to see a source folder underneath of there I know that all of the CS proj files all of the projects that make up this solution this new get package whatever we're putting together inside of this repo they're all going to live inside of there there's always going to be a test folder where all the unit testing projects live if this repository represents some sort of library that people are going to use there's typically a samples directory that shows you a few different ways to consume this library and work with the api's there's typically some build scripts checked in at the top level there might be some benchmarks if it's a performance sensitive piece and I like this repository structure it's something I've adopted for my projects it takes a little bit of work inside a visual studio I'll give you a tip for that in just a second but if you can mimic that repository structure inside a visual studio when I actually look at the solution inside a visual studio it encourages developers to follow that structure so docks might be another top-level folder that you have for a project of course one challenge to this is that we know that the solution Explorer in Visual Studio is a complete fabrication of what actually exists on disks right the solution Explorer lives it doesn't actually show us the physical file system layout but and what do I mean by that I mean if I come into now don't do this audit advance on me please this is not a pub comp presentation if I come into Visual Studio and I'm looking at the regular solution Explorer view and I tell this to add a new folder that's not adding a folder on my desk where are we here have to back out a little bit adding a new solution folder creates a virtual folder that the solution file understands but it doesn't create something on disk so I can create this new solution folder it's not going to show up on file system it's not going to show up in my repository I can add items into it they're just gonna be dumped into the root of the project however Visual Studio 2017 up here in the action toolbar a visual studio of the solution Explorer there is this little thing to switch over and to a solutions and folders view and when I click on that now I have a view of the file system just like what I would have in Visual Studio code its presenting the truth so if I right-click a folder and I say please add another folder it actually adds something to the file system of that folder so it has some advantages and disadvantages and you might find yourself toggling back and forth between the solution view and the folder view the folder view is great when you want to create a folder on the file system you want to add some files to it so here I have a script folder which I'll talk about just a bit I encourage people to add scripts to their project and check them into the repository but some of the things I lose like if I try to right-click on a project if I like right clicking to manage NuGet packages and right-clicking to do different things with my project all those project options are going because now it's just kind of a folder but you can toggle back and forth depending on what what you want to achieve at the moment so I can right click now and get to manage and you get packages some other things that you might consider checking in include samples and tools so here's the great thing about Microsoft open sourcing things there was never a problem if I wanted to see the Microsoft source code for let's say system about string or something that was built into the dotnet framework there was always decompiler tools that I could use to dig into code that they wrote for asp.net or anything so having that code now be open source on github yes it's an advantage I don't have to work quite as hard to see the code that they wrote the big advantage to me is the other things that you find inside of those github repositories for asp.net core and dotnet core and core FX the samples folder so when I was trying to understand asp.net security and what was happening at a lower level I went into the github repo asp.net slash security and I found the samples folder and lo and behold inside of there were just these somewhat thrown together samples of things you would never do in production but they were very revealing of how this how the middleware and how the services worked for things like asp.net cookie authentication so you dig into the cookie sample and you'll see an example of different configuration options and what the middle way is supposed to do and what it's not supposed to do the other thing that is extremely valuable inside of those github repositories are the unit tests because again you can read through the unit test and find testing tips from Microsoft how do they test stuff like middleware and also you can look at what a service and what a piece of middleware supposed to do by reading the unit test so those are all very valuable and things we didn't have access to before I also like to include development scripts so with that net core we have a command-line interface that can do all sorts of interesting things we can use it to add package references and with the entity framework and it can create migrations of deep databases if you're developing for some sort of cloud platform like an EWS or a sure it's very useful to have scripts checked in so that when developers clone the repository they'll know that there is a script in there to set up a development environment for example we'll go out to Azure and set up an app service and a sequel database and give it some default parameters for them to start working so I always include development scripts oh and one other thing the solution file the dot SLN file it's nice to keep that in the root of the repository that way you can clone a repository and just double click that right away I don't have to go searching for it and I couldn't open up the solution but here's an example of an ad migration script that has checked in so a developer can just say add migration add employee feature or edit invoice feature and what that will do is go over to the data project run EF migrations to add a new migration automatically update my database and then put me back into the folder that I was in before with a pop so it just kind of makes things a little bit easier deployment scripts and templates depending on what cloud environment you're working in there's various different ways to approach the provisioning of a development or QA environment I use Azure quite a bit so one of the things that we'll do is usually check in a script file that you can run that will execute an azure resource manager template which is a Jason file which includes all the configuration information for setting up a resource group in fact in Visual Studio there's resource group projects that you can create they'll automatically generates some PowerShell scripts for you and some templates that you can modify inside of Visual Studio to like set up an app service set up a sequel server set up an azure key ball wire up all the configuration settings they look kind of like this this would be an example of going to the automation script inside of the azure portal and say generate one of me generate for me a resource manager template that I can then check in the source control and that resource manager template describes the resources I have created and all their configuration entries unfortunately they're frustrating to work with any one use resource manager templates a couple yeah it's amazing you can go and do a sure you can set up let's say a virtual machine or an app service you can do these things then you can come to automation script and you can have as your generate the script that is supposed to create that resource and in my experience they only round-trip about 80% of the time sometimes you have to go back in and tweak things and the documentation it's not that good and you get strange error messages but when things are automated and they're working well it's a truly wonderful experience another option for a sure would be the azure CLI that it can create virtual machines and delete virtual machines and sequel servers and app services so we check them and what about builds some of the projects that I create use out there which basically gives me a free build engine for open source projects if I have something out there where I want to create a new get package inside of out there I can tell it where and github is the source code that it should pull down when I do a push or a pull request where is the source code where's the source code live that it should pull down and then I give a build instructions and I can either describe the build instructions in a UI by selecting check boxes and saying do this and do that or I can check in a gamo file so my general recommendation when you use these build systems that try to be GUI driven is to get as much out of the GUI as you can and try to put it into scripts or some sort of configuration file so for example with out there if I check in an app there yeah Moe file into the rudiment repository that gives out there all the instructions it needs to do a build and one of the things I can tell it when it does a build is to use a build script that I also have checked in so build PS one typically dotnet core applications are pretty straightforward to build this would be an example of a PowerShell script that basically does dotnet restore net build dotnet run the tests and then dotnet pack to create the nougat package so the advantage to this is if a build is not working and out there and I don't have a script I'm just relying on that Bayer UI to do things for me it's very difficult for me to debug I can't run the OP Nayyar build locally at least with this I can rub that I can run this PowerShell script locally on my machine and it should produce the same result as when it's inside of a player running same thing goes for vsti so if you use visual studio team services you're probably aware that you can create a build definition and inside of a build definition you can drag and drop these different tasks and arrange them and configure them to do the same things that we just saw on the ps1 script so do it not never store do a dotnet build on a test on that publish publish the artifacts some of those steps are not things that you can easily replicate in a local development environment things like publish the web artifact because that's actually taking a zip file and putting it into VST s somewhere where you can download it later but certainly not never stored not net building a test out not published not necessarily I need something and I don't necessarily need to describe those steps inside of a GUI so an alternative would be to use from the tax catalog a simple PowerShell task or command line tasks or custom tasks that you can get from the V STS marketplace that know how to run build scripts like PI sake or cake cake if you haven't heard of it as a gives you the ability to c-sharp to write build definitions to write build tasks using c-sharp code so it's familiar and you can run that same cake or P sake or command line script on your turbo on the machine and also inside of the STS and that makes your builds a little bit easier to debug as well as source controlling what's actually happening so let's get out of some of the Moonbeam stuff and talk about startup code so and doing code reviews when I open up a project one of the first places I look is inside a startup Nazi ass because we know that for asp.net core that's what defines what services are going to be registered with the asp.net core container that describes what little where's in effect for doing HTTP processing and to me that's all start up top CS should be responsible for it basically describes how is the application going to behave at runtime but when I open up startup CS sometimes I see some some of the most bizarre things that people are doing I've seen people see databases and run database migrations and move files around on the filesystem copy you know make sure their CSS files are copied out of some folder and put into dub-dub-dub root things like that to me there's better places to put that kind of logic if you insist on having that logic inside of your application and we'll talk about where that is but to me there's three responsibilities inside of startup startup not see us there's the constructor you can do some limited work inside of the constructor if you want to inject some services like the hosting environment or I configuration and save that off as a field to use later there's configure services to configure the service provider aka the container inside of asp.net core and there's configure where you can receive an app builder as well as other injected dependencies to define your middleware that's all you want to do so in asp.net core 2.0 if I open our programmer up see us I actually like to get as many things out of the way as possible before we even get to the startup constructor so if you want to configure some logging and things like that that would be best to do inside of the main method in fact if we at a different project here program to see us maybe you know by now but you scaffold out an asp.net core 2.0 application this create default builder does a number of things for you including setting up some default application configuration sources so it goes ahead and registers app settings Jason and app settings dock development Jason as configuration sources and also configures kestrel would also configures a console logger so if anything goes wrong things spit out into the console a lot of the stuff like that logging and so forth is taken care of for you before you even get into startup so to me startup these days is really about two things first of all there's services so inside of configure services I have sometimes seen hundreds of lines of code because people want to use the MVC services but customize them a bit so they'll add some code to do things maybe like this so 10-15 lines of code to customize some of the MVC options to add different conventions to change the locations and so forth but you can imagine if there's this block of code to configure that MVC services and then you add some additional code inside of configure services to configure or entity framework and to configure asp.net identity configure services becomes very cumbersome to look at and try to figure out what's going on so I always encourage people to keep this method flat all I want to see is a list of things that you're doing oh you're adding MVC you're adding some security services you're using mediator you're adding some data stores and if I'm interested in some specific details like what are you doing to customize NBC I can just put the cursor on that line press f12 and I can look at exactly what you're doing but this is a good big picture of you which is what I want to see inside of configure services I don't actually want to see all the little configuration details same thing for configure which is setting up little where although I do believe it's okay to have an elf statement inside of there so I just want to be able to see oh you're in development so we'll use the developer exception page and database err page and browser link which no one uses anymore it's on the slog otherwise we use this exception handler and then they'll probably be a string of a little way of beneath that and and again most pieces of middleware allow you to pass in options to specify some different behaviors for example the static files middleware can pass in options to tell it what physical direct directory to look in and so forth but if I'm going to have any of those options inside of configure again I want to write an extension method for I application builder so I can just see something that says use static files with options right and those options are tucked off as details somewhere else and I can see exactly what middleware is in the project and what order that little wire is executing and then what about all this other stuff so what if you want to run any framework migrations what if you do need to copy files for some strange reason what if you want to seed the database with data well it's really interesting that asp.net core what we're creating is a console application you know if I do a dotnet run I am running a process from the console that standalone and what's interesting about that process is there's this point in time after I've asked the web host builder to build me a host and before I call run which is when it starts opening or listening for socket connections to come in and prompts us HTTP messages there's this period of time right in here where I have a fully configured application all the services and all the configuration options that I've pumped into the application are there we know about our app settings we have our connection strings we know which services were going to use in production and so if I want to execute some code at that point to do something like seed the database then the main method of program dot C S or somewhere inside of program dot C is between build and run that's a good place to call out and do things because I can take advantage of all this knowledge that I have so here's an example I want to process some DB commands looking at the incoming command-line arguments and using my host so that I can get the services and connection strings and things that are configured here's a piece of code that might be easier to come over to visual studio and look at that here's a piece of code that'll basically say okay if someone did a dotnet run on my application and passed in an argument drop dB what we're going to do is use our services to get a DB context and make sure the database is deleted and if they passed in drop DB space migrate DB will also did it get a DB context and tell it to run the current migrations which could even create a database from scratch and if they also typed in C DB we can add some initial data that's tucked away inside of that application somewhere and I just want to point out that all of this is inside of a using statement where we get an I service scoped Factory and tell it to create a scope and that's very important if you're ever going to go directly to the service provider inside of asp.net core and ask it to resolve a service which is what happens down here so dear service provider give me B DB context derived class so I can work worked with the database if you ever do this outside of the scope of an HTTP transaction you have to be very careful that you don't accidentally create a singleton which is what will happen if you don't explicitly get a service scope factory tell it and tell it to create a scope which gives you back a service provider that you can use to resolve services but when you dispose it you can clean everything off make sure that goes away so how would this get used well I could write a little script that a developer can do call execute called recreate DB so when I arrived to the office in the morning and I do a git pull to get the latest source code the people who've checked in I don't know if there's new migrations or new sets of test data or what is it so I'll just do a git pull and then recreate DB and it'll run my application drop it migrate it see the database and then stop it will not listen for sockets at that point so that makes life a little bit easier let's talk about project structure I have an extremely difficult time these days looking at a traditional asp.net MVC project that has like controllers folder and a views folder and a models folder to me it drives me insane let me show you let me try to demonstrate that by let's pretend for a minute so over here I have created a new project web application 35 I'm about to do some work on it you know we just came out of a sprint meeting and someone has told me that the register or the reset password users are not able to reset passwords and I need to go in to go into this application and look at that bug so this application was generated by doing family project asking for an MVC project and setting the authentication options equal to individual authentication so it's using asp.net identity and it spit out a bunch of user interface code that allows users to register and log in and log out change the password reset their password etc etc but now it's my responsibility to work on this feature what everyone else in the company thinks of as a feature to reset a password so hmm let me start with the controller is it in the account controller or the manage controller I don't know but how bad could it be to just look through one of these let's start actually at the very top of this file that line one okay here I can see we're going to login login with two-factor authentication mm-hmm maybe I just should have done a finding files lock out register external login [Music] what's going on confirm email forgot password oh here we go all the way down here at line 392 reset password this must be the area that I went to work in okay so next let me find the model that this is working with because maybe the problem something with the validation with the model I guess that's in the models folder so I have to come over here I apologize if you can't see the solution Explorer but I found the view model okay there's the D model now I have to find the view mmm so we have to jump over to the views folder and fortunately yeah I can see under the account folder there is a recessed reset password view and finally I haven't even got to the unit test yet but finally I might be able to work on this bug where there's a problem with reset password that just drives me insane the model-view-controller design pattern tells us that we should have a separation of concerns between the model the view and the controller the controller receives an HTTP request the controller uses some services to build a model the model doesn't know anything about HTTP doesn't know anything about the use the controller takes that model can hand it off to a view and the view has the logic to render that model so there's a separation of concerned but no one ever said that there had to be a physical separation between the abstractions in that design pattern where we had to put them into three different directories so for the last oh I'd say year and a half I've been using a concept known as feature folders so with feature folders you can organize folders however you want you might even organize it organize them hierarchically like your UI is organized so when I when I go into the application there's an admin link and I click on that and there's a menu open that allows me to manage this and manage that and manage seasons and oh you know now when I'm trying to work on a feature that someone has identified in the application I'm kind of following the same logic when I navigate through these folders and lo lo and behold here's my controller ant in that folder I just open it up there's some views associated with it I can open that up and there are some models and they're all in the same folder still a separation of concern it's just not a physical separation of the abstractions and to me it's it's a much easier way to organize MVC applications and find things and work on things and actually work on features this would be maybe how we could start reorganizing the account controller breaking it out into smaller pieces and maybe having a registry set password controller folder inside of here to do this it's very easy I actually have a nougat package or just OD code feature folders you can install that actually the command you'd probably want to use today is net and package OD code feature folders and then configure services you can just add NBC and feature folders to that service it'll configure your NBC options to use those that being said these days I quite like Ranger pages who's using razor pages who knows about razor pages okay when I first when razor pages first came out I and I think many other people looked at and said oh this is gonna be one of those two simplistic things that Microsoft has come up with that I never want to actually use but then when I actually started digging into it I realized razor pages are exactly what I want when I went to generate HTML so I'm gonna walk you through a couple razor page scenarios just to show you what I think are the advantages but to me if I'm building an API that has to return JSON or XML I'm not generating HTML I'm building an API that's when I use MVC controllers if I'm generating HTML from the server I don't want to controller with the view I want to use a razor page so over here in Visual Studio I just want to show you that as an alternative to web application 35 with all those huge 500 line controllers and controllers and views are in different places I also have web application 36 new an improved version of web application 35 but this one was generated using file new project and selecting asp.net core razor pages and individual authentication so instead of generating huge controllers it has now generated a series of razor pages and now when someone comes to me and says hey there's a bug with the users resetting passwords what are you going to do about it what I will do after I close all these things up here let's not save anything what I will do is say oh let's go into pages I guess that would be under account and let me look through here oh here's a reset password the razor page let me click to open that and here's reset pay password the code-behind or page model for that razor page and tada I now have everything opened that I need to work on that feature so to me razor pages are a lot like folders I don't need to use feature folders if I'm building stuff of features with razor pages so what are they exactly yes a razor page is still just a razor view has a CS HTML extension uses tag helpers uses model binding you can render sections you can use layout pages you start all those things that you usually do with range reviews the difference is it's going to have a page model or code behind file behind it which some people think oh my gosh maybe it's too much like web forms but it's not there's still the separation of concerns there's still dependency injection so you can see when I would need to reset a user password I can have a constructor and ask for dependencies like a user manager or a logger or dbcontext or I hosting environment I can I'm not a big fan of this but I can define my input model I can define input models and output models and have this razor page work with them when a user posts something to my razor page I can tell asp.net core that I want to try to receive posted form values into this property input so that's how I can receive things like the user's email and their password and their confirm password but one get method responds to a get request but one post method responds to a post requests there's no synthetic click events or any funny stuff like that so to me this is just as good as having a controller and using a controller to render a view just things are organized a little bit differently plus razor pages have some some advantages over controllers like one of the features they added to razor pages is that they will automatically validate anti forgery tokens on a forum posts you don't have to worry about developers accidentally forgetting the validate anti forgery token attribute on a controller action they will do that for me because they just assume everything's going to be a forum post when there's a post so razor page is good give them a try controllers I do not allow people inside of start-up t us to say app dot use NBC and then write that little lambda expression that takes a route builder and define routes inside of you know the conventional routes inside of start-up Nazi ass you know the conventional route would be something like controller slash action slash the optional ID parameter when people rely on those routes and inside of start-up CS they build horrible horrible looking api's they don't think about the URLs they don't think about parameter names I want everyone and I encourage everyone to use route parameters because with route parameters develop alert developers are much more likely to say we know actually this this piece of the API it's part of the admin section or the admin feature of our API so let me put a literal admin in front of this so admin / manage something and then some action perhaps and I don't know if you've ever worked on one of those MVC projects where every single action parameter was named ID you ever done that ever had that even if it was something like invoice date right if someone's passing in an invoice date and they'll still call it ID drives me insane so the routing the route attributes also encourage people to think about the parameter names and what they should be called and what they should be mean for the actual action so instead of having an ID because I'm just being lazy and relying on the conventional route to find this out of Starbucks yes I'm actually thinking this is a seasoned ID versus a matchset ID and my actions become a little bit clearer to me so I encourage you to use the route attributes and throw away the other forms of routing this one I'm still I was big one mediator and now I'm backing off for a little bit on that how many people use mediator anyway whew it's a very simple in-memory message boss what it allows me to do is inside of a controller action I can remove pretty much all of my logic inside of a controller action and instead what I want to do is put together either a command or a query so in this case I'm putting together a command command is actually just based on the inputs that the user has typed into a form I'm gonna accept those inputs as a command and I'm going to tell mediator to send this command off somewhere in a system that's actually going to process it and produce some result for me so all of the all of the logic and the services and the things that go into logging in a user are completely removed from the controller there's somewhere in a request handler that I've defined for that specific type login user commune so the good news is that means some logic becomes a lot easier to reuse its packaged away instead of a component that's not coupled to your UI or to a controller at all it's also easy with mediator to introduce things like decorators so if I want this command to flow through a pipeline something that'll log it and something that will validate it and then something that'll actually execute the login that's relatively easy to do with mediator and I can plug and plug things in but that being said there's always downsides right so a lot of people will look at it and say that's just another layer of abstraction and what you're doing is you're making it harder for me to work on the login user feature because I don't know where that goes so you have to decide based on your team and based on the type of application you're building and how much flexibility you need and how much were you usability you need whether it's whether or not to use mediator but it's good for specific scenarios the other thing I tell people is don't build projects anymore that have an API have API endpoints inside of it and also have endpoints that render HTML and take form posts at least don't do it if you're using any form of cookie authentication because as soon as you have cookie authentication you have the risk of a cross-site request forgery and a lot of people don't realize that they have to protect from cross-site request forgeries and they're api's so in order to do that one of the things we have to do is get anti forgery tokens down to our JavaScript so that when we make Ajax calls or use the fetch API we can pass along an HTTP header that includes an anti forgery token and this is just a simple code example of an endpoint you could build that javascript could invoke to get the anti forgery token needs to send along so just inject the int for jury service and what this get request will do is use that service to get in-store tokens it's not obvious but getting stor tokens actually does two things one thing I will do is return a data structure that has the anti forgery token inside of it and also has the header name the JavaScript should use when it sends that token along so we will take that data structure and serialize it back and send it down to JavaScript so it can use that token and write the appropriate header but the other side effect that happens here that's not obvious is that if the anti forgery token cookie has not been set into the browser yet when I call getting stored tokens I ante forgery did the default implementation of III and set forgery will issue that cookie so at that point I could start using follow the anti forgery token on my API endpoints typically not something you want to do if you you know if you can separate them you don't have to worry about that type of thing security policies if you're just coming in to asp.net core and you're wondering how authorization works and how you can write authorization attributes to work with roles and Active Directory groups and things like that excuse me that could be an entire day workshop an entire day of a workshop but basically things boil everything in asp.net core boils down to claims so I can build a claims principle to define a user and add claims to that principle saying this is the first name this is their email address this is a role that they're in like admin or the department that they're in which is sales and once that is there when I went to authorize that user to do something I can look at claims and these again so claimed can represent roles they can represent facts about me they might represent permissions that I have so a claim could be is can edit invoices that could be a claim and the way I evaluate claims the easy way to evaluate those is to use an authorization policy builder and when I have a policy builder there's a fluent API where I can say require this require that and require a claim like it is admin with this value and when I build that policy I can then use it and give it a mean and I could build I could say authorized that authorized attribute is admin or I could wrap it up into a custom attribute user is admin what that'll do is it's basically the authorized attribute saying evaluate the policy is admin which checks for the claim is admin hopefully that's making sense security policies are very easy once you know that they're there and you know everything is working on clean talk about views for a second don't use HTML helpers anymore they're hideous and they were always the worst part with espn/abc use tag helpers if you're not already so things like ESP - for a SP - validation summary those are good but easy to read they're also extensible you can build your own tag helper by deriving from a base class tag helper and implementing a process method they're relatively straightforward for most trivial tag helpers use view components view components are like partial views but they get to render things independently so a view component is like a controller in the sense that you can give it a constructor and you can enjoy inject services into it but it doesn't respond to a request it has to be rendered from some other view so interview I can say actually this way with a tag helper I can say go out and render the view component main menu this main menu is a class with an invoked method so we can have logic in there it can do data access and it can say return of you and that view could be whatever markup you need with whatever model and that's a good way to build composable you is if you need to client-side code so everyone's using some form of angular or typescript or react these days and my favorite tool to build that sort of thing is web pack I'm not going to go into a lot of detail on this since I think there's some other talks this week on web pack but this is an example web pack configuration file ah so the thing I wanted to point out about webpack as I've seen a lot of developers struggle with that webpack configuration file and the trick is don't think of webpack config KS as a typical configuration file it's not a JSON file it's not static inert data it's actually a JavaScript module that webpack the tool will load up an X cube so you can put executable code in there if you need more flexibility so for example if I need web pack to go out and find tight strip files that are kind of scattered across feature folders I can actually write some JavaScript code that gets executed inside a node to say let's go out and lob up all the TS files spec TS files so these are unit test specifications grab them from all the feature folders and put them into an array for me as well as all the specs that are in this client folder I'm not gonna talk about JavaScript services that much that was another Steve Sanderson creation though but that basically allows you to use webpack hot reloads integrated into asp.net core middleware so that when you send a request to your asp.net core application asp.net core can work with web pack to compile all your typescript files bundle them into a JavaScript file put them in the browser and then as you make changes to your JavaScript and save it those changes can be compiled and automatically swapped into the browser for you the hot module replacement I'm a big fan of con emu anyone use con Meo or commander so once you start working with some of these command line tools when you're writing some command line scripts you'll know you'll realize the basic Windows command line is sometimes a little bit deficient so I use con mu so a couple different things I can do here one is I can right click and say create another console for me and have it's hard to save it here but let me look down here at the bottom tab consoles which is very useful when you have a long-running task in one I can also do things like this see if I have a setup to work today where are we github you release rips yeah so I just typed J s command because inside of this project there's a bunch of things that happen to have to happen with JX and things aren't quite configured correctly but ideally on the left hand side here I think I just ran it from the wrong folder it's all um this would be running web pack watch up here would be running web pack unit test or running unit tests on my app down here would be running a karma integration task and I'd be able to have all three windows open and all those things running at the same time and if I write some typescript code and save the file and it fails a unit test I would see some red scroll by and that would be glorious that does that all happen for me let me try to go to see if I get this working real quick what folder am I in this might be a little bit better yeah over here is the webpack watch over here we're still failing so you get the idea the command that does all that for Connie M you would be to run Connie mu with this following run list in one window I went to run npm run watch then in another window npm run test watch put that in a new window that split horizontally that's SH and then NPN run karma unit test in a new console that split vertically so it takes this side that was split horizontally and splits it vertically and I get that window in the bottom bottom rate fascinating right I'm gonna skip over a few slides here related to client food I do want to point out look Bauer is dead just use NPM or yarn for client-side stuff even if you're just you know if you're not yeah you're not writing a node.js application I understand you're just using bootstrap and jQuery but you know all those front-end dependencies now they're all in NPM so forget about these other package managers in qiyam or yarn will do just fine for you to download those and manage those a new get for anything dotnet related I was not a big fan I tried to like type script for so long and it wasn't until I'd say beginning of 2017 where I thought it really started to mesh well with the way JavaScript programmers wanted to work and I really started to enjoy tight script and now I do encourage people to take a look at it if they haven't looked at it yet type Spirit just finally embrace the node ecosystem you can npm install a typescript compiler the typescript compiler will do things like use the node module resolution strategy in the way it tracks directories and looks around and then it understands the node modules folder so when you npm install other things and inside of typescript you import them it knows to look in there this paths configuration option so this is a typescript config file the pass option is very useful when you want to go and define your own custom sort of modules folder so I don't want I don't want to forced to put my typescript files in a specific folder I want to be able to put them someplace and tell typescript look if something doesn't import through from bar then one of the places where you should look for something called bar is in the client slash script folder so you go into there and look for it and that's what that would do so typescript has come a long way but most projects where I have to do any amount of typescript or JavaScript I'll have the project open in two editors visual sphere for c-sharp code and Visual Studio code for typescript and es2015 it was still by far the best editor for typescript and JavaScript code so if you haven't tried Visual Studio code for JavaScript you really should use Visual Studio code for JavaScript it does a much better job and produces fewer false positives than Visual Studio I think of dub-dub-dub root as my bin folder when I'm using typescript so where do I compile things where do I output them well place them into dub-dub-dub route although bundled and minified stuff it's like so it's like a bin folder for me but for javascript and typescript testing just a quick word on how many test projects should you have so I've worked on projects where there's a web project and a core project and you know some stats calculation project all these things that are separated out and people will say hey we need a test project per production project what to me is crazy because now I have to go looking everywhere for tasks to me a project typically when I want to create a new project is because I want to create a new unit of deployment or I want to deploy that code differently than lock code that's in other projects and to meet unit tests don't have to be deployed you just have to execute them so if you want to put the unit tests for three different projects that are part of a system on the same test project that's fine I like using X unit there's various options now for dotnet core but I still feel that X unit has the is the best test Runner and the best test language for writing unit tests so it's lo ceremony has a good vocabulary and it's my preferred testing framework I try very hard to avoid mom so I'll tell you a little story about how this came around I started trying to do test-driven development around 2004 and I did it the traditional way so write the test before you write the code then you do red green factor and follow all those steps did that for years and then I felt like I got to the point where I was comfortable writing testing code without necessarily writing the test first so yeah I started not following that as religiously and that was fine things still turned out fine but I was still trying to think about unit tests how do you unit test a controller well the only way to unit tests is to make sure you isolate that controller so it's not working with any of your real production services so you're giving it fakes or stubs or mocks to that controller and then you know what's writing a lot of code but it seemed to work pretty decent for c-sharp anyway then first big angularjs project came along and I tried to follow that same philosophy angularjs controller how am I getting unit tested well I'm gonna fake out and mock out all the services that get passed into that controller so me and a couple other people on this team we had this huge huge pile of unit tests for our angular controllers and it was so frustrating because every release something would break unit tests would pass something would break and that's when I realized that trying to mock up things create mock services and write the unit test you're just programming in expectations to your unit test that it should behave the way you think it should which is not really what I went out out of the unit's house so I started using this different approach on that angularjs project and years ago and I said look what if we didn't mock any service except HTTP what if we wrote tasks that called into the controller and if the controller called into the service that called another service that eventually did an HTTP call what if it went the whole way to the HTTP layer and we just mocked out the data at the HTTP layer and what I found was we wrote 30% less test code we actually found bugs when people checked in bugs into the project before they got to production and all of a sudden it just kind of changed my view on a lot that year and I started thinking when I write a test now I'm not necessarily going to think of it as a unit test you know traditionally traditionally at least to me a unit test the reason we wanted to isolate things so if someone checked in a bug out of some low-level system component that it didn't break all 1,000 or 200 or five unit tests that are in the project it only hit you know an isolated area of my unit test that was testing that feature but to me it's not worth it I would rather write let's say ten lines of test code that could fail for any number of reasons inside of the system because to me that's still an effective test it provides a lot of value for me and I only had to write ten lines of code and I didn't have to mock a bunch of stuff up where am I going with this well it turns out with asp.net core there's a couple interesting things you can do one if you look in the Microsoft repositories you'll see they have a nougat specifically when they write unit tests like how do they test middleware or the useless thing called the asp.net core test host the asp.net court éstos kind of like the thing we used to do with web api a few years ago where you could host the web api in memory the asp.net core test host provides me an API where I can say let's create an application with this startup and this middleware and these services and then send requests into it that don't actually travel over the network so everything happens inside of memory and you can find tests inside of the micropyle microsoft repository that look like this let's create a server so behind-the-scenes that's using this test host and we're going to pass in some options for the cookie authentication services that the login password be here we're going to send off HTTP messages to that server they're just really traveling through memory and it's gonna go the whole way through the system it's gonna travel through all my little ware use services that are configured in there and I'm gonna see that it comes out with the status code and this header and so forth another example excuse me down here at the bottom create a server use that server to create a client and use that client to send off a get request here I just want to make sure I get back a status code to me those three lines are beautiful because of those three lines if that test passes successfully I have a higher degree of confidence that the system is going to work versus having 20 tests one that isolates the logger and one that isolates the middleware and so forth but this is my personal philosophy and opinion you can differ so where can you mock things out well again I like mocking things out of the data layer so you have to have the abilities to switch abstractions between let's say something that talks to cosmos DB or MongoDB was something that just holds data in memory and if you're using entity framework and to be framework or actually has this thing called the in-memory provider so it simulates sequel server or simulates a database just by holding data in memory and no it's not going to catch errors like we've tried to insert records with duplicate primary keys it doesn't enforce database constraints but it is a mock or a fake data layer that if I configure that entity framework to be in memory I can use all the rest of my services inside of an application with that test host and fire off request just do something like save this new user or save this invoice or edit something everything happens in memory and I have basically an integration test but it's not an integration test where I have to mess around with the UI it's an integration task that goes through all my middle where all my services exercises everything right up to the actual database layer and to me that means writing a lot less test code and having better bang for the buck for the number of lines of test code that I have so using the EF core in memory provider pretty straightforward just have to say to use an in-memory database and follow a couple constraints when you're instantiating this thing and that's good so more integration tests fewer unit tasks that's kind of my current motto for some scenarios for some scenarios not everywhere but heavy business logic I still like to isolate and test that have specific unit tests for that but to me not having to test a controller in isolation as beautiful because most controllers are let's face it relatively simple I would rather test all the middleware and the controller and everything down to the database layer c-sharp code so one of the things that people are doing with asp.net core of realize if they're taking the advantage that asp.net core can execute on Linux and so when they deploy they picked Linux VMs or Linux app services and they save 20 to 30 percent on that server because they're not paying for the Windows license but there's always a little hiccup some little hiccups so some things that we have run into and I should back up and say if you're gonna do that if you're going so to me one let's talk about docker for a second to me one of the advantages of using docker containers is that I can develop on my machine which is Windows but I'm executing code that is in the production environment which is Linux and there's a big advantage to that because I can catch problems sooner so I think in some sense problems like this so just the littlest things bite you and c-sharp code you hard code new lines into an application but new lines are really different on Linux and Mac versus Windows so instead of hard-coding / r / r / n use environment new line it's amazing how many people hard code paths right so I need to build the path to slash users slash temp slash and then I have the filename or I have some base holder name that's configurable and then I have my file name how do I put them together well I could just use this string plus slash the string except that slash right it's different on Linux vs. Windows the proper way to do that use path not combine also be aware that environment variable names can be different between the two environments so those are the types of little things that you can catch if you're using docker to actually develop on Linux and then finally me personally I despise the async suffix on methods I think having the word async here and having that word async here is just too much icing so even though the Microsoft recommendation is that async Russia methods should have the async suffix I don't do that and to me I felt justified when I read this quote from the inventor of C++ he said for new features people insist on loud explicit scent I said yeah when a sink first came around it was scary so we're just gonna use the async word everywhere make sure people are aware this is a sink but now it's an established feature people want a terse notation and I think I I personally have reached that point I wish we could just have everything be a sync by default and not even have those key words there but that's pipe dream so I think it's fine that's used at you sink suffix but you can differ with me and that's all I have for you I thank you for attending this is my email address if you have some questions I think we're out of time I'll hang out and answer questions have a good afternoon thank you [Applause]
Info
Channel: NDC Conferences
Views: 7,411
Rating: undefined out of 5
Keywords: NDC, NDC Minnesota, 2018, Scott Allen, ASP.NET, Web, MVC Design, Code, .NET
Id: WMdBoeQtxUY
Channel Id: undefined
Length: 56min 33sec (3393 seconds)
Published: Tue May 29 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.