Unleashing Clean Architecture in .NET 8: Exploring the Solution Template — Jason Taylor
Aug 15, 2023
Unleashing Clean Architecture in .NET 8: Exploring the Solution Template — Jason Taylor
Join us on a captivating exploration of Clean Architecture in the dynamic world of .NET 8. In this session, we dive deep into the Clean Architecture Solution Template, an open-source .NET template that propels solution development to new heights. Discover the seamless integration of Angular or React with ASP.NET Core Minimal API, as we guide you through the creation of a new solution. Delve into the template’s impressive range of features, including built-in support for validation, mapping, Open API, authentication, testing, CI/CD, and even IaC. With this comprehensive toolkit at your fingertips, you’ll gain the ability to build scalable, maintainable, and future-ready applications. Whether you’re a seasoned .NET developer seeking to elevate your skills or an aspiring architect looking to embrace modern software development principles, this talk provides practical insights and hands-on demonstrations. Join us to unlock the true potential of Clean Architecture in .NET 8, revolutionize your workflow, and create remarkable applications that stand the test of time. About Jason: Jason Taylor is a solution architect, trainer, mentor, full stack developer, and Microsoft MVP, with over 20 years of experience. Currently, he specialises in developing, testing, and deploying custom applications to the cloud utilising .NET and Azure. Jason loves a challenge and is skilled at progressing from a simple proposal into a well-defined, coded, and tested solution. Jason on LinkedIn https://au.linkedin.com/in/jasontaylo … Jason on Twitter https://twitter.com/jasontaylordev Jason on GitHub https://github.com/jasontaylordev
Content
2.159 -> foreign
5.66 -> I'm Jason Taylor I'm a solution
8.34 -> architect for increment and a Microsoft
10.92 -> MVP in developer Technologies
14.16 -> for those of you who don't know about
15.599 -> increment increment is a technology
17.94 -> services company that brings together
20.22 -> highly skilled professionals from around
22.68 -> Australia
24.3 -> at increment I help clients to design
27.599 -> develop test and deploy custom solutions
30.18 -> to the cloud if you'd like to learn more
32.22 -> you can jump online and check out
34.219 -> increment.inc or you can ask me some
36.6 -> questions after this presentation
39.18 -> so it's great to be back here at the
40.8 -> brisbane.net user group it's been one
43.26 -> month for me I try to try to get here
44.94 -> most months but I don't always make it
47.12 -> and I'm really excited to be sharing
49.62 -> with you my new presentation unleashing
51.899 -> clean architecture with net eight this
55.559 -> is a show and tell style presentation
57.539 -> I'll be demonstrating the clean
60.059 -> architecture solution template which is
61.739 -> an open source project that I maintain
63.5 -> and I will show you how to prepare your
66.479 -> development environment how to install
68.46 -> the template how to create a new
70.5 -> solution how to build test and deploy
73.439 -> the solution to production and then I'll
75.42 -> tell you about some of the exciting
76.68 -> features that are built into the
77.939 -> template these features are designed to
79.92 -> help you get your next project up and
82.32 -> running quickly and to improve your
85.14 -> productivity as a developer so that you
86.939 -> can focus on delivering value to your
89.939 -> clients
90.84 -> let's get started
94.02 -> so the clean architecture solution
95.64 -> template provides a straightforward and
97.92 -> a pressure a straightforward and
100.2 -> efficient approach to Enterprise
101.88 -> application development with clean
104.1 -> architecture and asp.net core
106.92 -> it's been built using the.net template
109.68 -> in engine and so it's really easy to use
111.96 -> you can create a new solution using.net
114.42 -> new or even through Visual Studio 2022
117.119 -> by selecting the template
119.28 -> uh you can see there I've got a little a
121.619 -> little kind of metric there uh so far
124.439 -> since it was created in October of 2019
126.78 -> I've got 66 000 downloads so I'm hoping
129.899 -> I'm hoping to get that up to 100 000 at
132.239 -> some point in the future thanks Todd uh
135.239 -> so with this template it started out
138.739 -> on.net 3.1 and I've upgraded it through
141.959 -> five six seven and most recently eight
145.08 -> and if you're going to be building a new
147.3 -> solution a new asp.net core solution in
149.22 -> the near future you probably want to
150.9 -> consider.net 8 because it's the long
152.94 -> term support version and I'd say in
155.16 -> about six weeks we'll get that first
157.14 -> production ready license with release
159.66 -> candidate one
162.42 -> all right so with this.net upgrade it
165.78 -> wasn't just about changing the SDK
167.7 -> to.net 8. I started to implement a lot
170.94 -> of the features that people have been
172.56 -> asking for for many years so
174.66 -> traditionally the template was just
176.28 -> angular and asp.net core now it supports
179.459 -> react nasp netcore and you also have a
182.28 -> web API only option
185.36 -> database options not just SQL Server it
188.519 -> also includes sqlite and I'll be looking
190.62 -> at adding postgresql to this very soon
194.819 -> security is now through asp.net core
197.64 -> identity one of the most asked for
199.8 -> features was a simpler security system
202.56 -> so simpler authentication and
204.239 -> authorization I've always taken the lead
206.34 -> from the asp.net core team and how they
208.8 -> built built their Spa templates and so
211.62 -> traditionally this was with identity
213.48 -> server that's been taken out now and so
216 -> the spa templates are using identity
218.519 -> server with cookie based authentication
221.94 -> and the API template is using sorry I
224.879 -> said identity server didn't I asp.net
227.159 -> core identity with cookie based
229.14 -> authentication and the web API template
232.799 -> is identity with token based
236.7 -> I've also built a complete CI CD
239.58 -> Pipeline with infrastructure as code
241.44 -> based on Azure bicep and so that's all
244.62 -> of these things are templated and that
246.959 -> means when you go.net new these things
249.78 -> are produced based on the options that
251.64 -> you've selected and you'll have a custom
254.28 -> CI CD pipeline built on GitHub actions
257.16 -> with custom bicep templates
260.94 -> so this is of course still freely
262.74 -> available and open source on GitHub if
264.96 -> you like it please give it a star that
266.94 -> really helps keep me motivated and so
269.759 -> you can find it at Jason Taylor Dev
271.56 -> forward slash clean architecture
277.44 -> all right so installing the template is
280.08 -> very simple I'm going to demonstrate
281.34 -> this soon but you get to see my nice
283.199 -> animation where I install it so this.net
285.72 -> new install
287.78 -> clean.architecture.solution.template
288.78 -> that'll install the.net 7 version okay
291.479 -> because we're currently running on a
293.699 -> preview version of.net8 and so the
296.22 -> preview version of the template as well
297.9 -> so we need to specify the version and
299.82 -> I'll show you how to do that soon once
302.16 -> the template's installed it's really
303.78 -> easy to use you can use it from the
305.28 -> command line using.net new DOT net new
307.86 -> ca sln it's got a number of options name
311.16 -> and output which come from the net new
314.34 -> command but also client framework so as
317.16 -> I said you can choose between angular or
319.919 -> react and if you specify none it'll just
322.139 -> be a web API Only Solution you can also
325.62 -> specify that you'd like to use SQL Lite
328.08 -> instead of SQL Server so look at
330.18 -> changing some options I add in some
331.74 -> options there to support postgresql so
334.44 -> when you do create a solution and you
336.06 -> say specify I want angular and I want
339 -> sqlite the solution will produce exactly
341.759 -> that so it'll have an angular front end
344.1 -> with an asp.net core backend sqlite set
347.52 -> up with Entity framework call with
349.38 -> migrations already produced for sqlite
351.479 -> so it's ready to go
353.4 -> so that's an example of how you could
355.08 -> create a react solution so that would be
357.32 -> react front end with an asp.net core
360.12 -> back end
362.639 -> all right if you're doing it through
363.84 -> Visual Studio it's even easier just find
366.3 -> the clean architecture solution template
368.039 -> click on it and click next and choose
370.38 -> your options through the IDE
372.66 -> a some of them sometimes that sort of
374.699 -> stuff could be a little bit hard to see
376.86 -> so I might just zoom in a bit Yeah Todd
378.72 -> and you don't have to install anything
380.82 -> yeah yeah you have to install the
383.16 -> template so this is like a nice option
385.74 -> that you get when you install
387.8 -> a.net template through the command line
390.12 -> you can also see it in Visual Studio
392.16 -> it'll used to be a lot harder to to see
394.319 -> your templates in vs
399 -> all right so let's start out with the
400.919 -> demo let's deploy the solution to
402.66 -> production obviously we've got a little
403.8 -> bit of work to do there but it does take
405.84 -> time to deploy to production so I wanted
407.88 -> to kind of kick that off really early
410.639 -> so we're going to set up our development
412.259 -> environment we will create a new
415.02 -> solution build tests and run the
418.139 -> solution locally and then we'll deploy
419.819 -> it to production
421.44 -> so I am let me
425.039 -> bring up my
427.08 -> cheat sheet okay so first thing we want
429.96 -> to do is to make sure that we're running
431.34 -> the latest version of.net so if I go.net
434.6 -> version or we just go.net list sdks we
438.66 -> can see the latest version I have
439.86 -> is.net8 preview six and that's fine now
443.099 -> I'm a running on a Windows machine so if
445.919 -> I wanted to check to see if there was a
449.28 -> new version available and install it I
451.02 -> could go
451.94 -> Microsoft Dot
454.5 -> there it is
457.319 -> SDK preview so I could actually go and
459.18 -> I'm not going to run any of these winget
460.62 -> commands tonight but it's really nice to
462.84 -> be able to run these commands quickly
464.34 -> and efficiently from the command line up
466.8 -> the back can you see this okay it's
468.66 -> pretty good yeah okay good all right so
471 -> I have net installed I'm also going to
472.979 -> be using the GitHub CLI so I could also
476.58 -> install that let me let me grab it here
480 -> so GitHub CLI from the command line we
482.22 -> can get installed github.cli it's really
484.5 -> cool tool okay but I already have the
486.78 -> GitHub CLI installed so the next thing I
489.3 -> want to do is make sure I'm running the
490.56 -> latest version of the template so as I
492.24 -> said it's dotnet new clean architecture
493.979 -> solution template and then the version
495.3 -> so you can see here I've just used a
497.22 -> wild card so
498.979 -> 8.0.0. some preview version whether it's
501.599 -> a release candidate or a preview six or
503.34 -> preview so it doesn't matter so it's
505.319 -> going to go and install that so it says
507.3 -> 7
508.4 -> 6.17 is already installed and now it's
511.319 -> going to install it again for me so make
513.539 -> sure I have the right version
515.279 -> so you can see this is the what's called
518.219 -> a.net project template it's my clean
520.5 -> architecture solution template and this
522.779 -> is a.net item template and so the
526.8 -> project template will create the
528.06 -> solution whereas the item template will
530.64 -> scaffold some code within the solution
532.5 -> and I'll show you that later on so it
534.24 -> makes it easier to create new features
536.88 -> within your application
539.1 -> so I've got the template installed I
541.62 -> want to make sure that I am
543.66 -> authenticated with GitHub so I'll just
546 -> go get what does it get Hub auth status
550.32 -> and it'll say yep we're good to go and I
553.8 -> also want to make sure actually no
556.32 -> that's all we need for right now
558.24 -> so let's use the GitHub CLI to create
562.08 -> ourselves a new repository on GitHub so
564.42 -> we go GitHub repo
566.94 -> create we'll call this one
570.92 -> priz.net and so this interactive way I
574.74 -> can do it if I just press enter there to
576.3 -> give us a bunch of questions and we can
577.98 -> create that repository but I'm just
579.54 -> going to provide options for
582.36 -> um
582.98 -> to make it public was that already there
585.54 -> yeah okay good
587.339 -> um I will create a public repo and I
589.26 -> will clone it and so that means it's
590.7 -> going to create the repo it's going to
592.8 -> clone it locally I can jump straight
594.3 -> into brizz.net and we're ready to go
597 -> with an empty Repository
599.82 -> now I've got the template installed so I
602.459 -> can go Dot net new ca solution and if I
606.779 -> wanted to
607.8 -> learn more
609.54 -> I can go help
610.86 -> okay and so that's going to see some of
613.08 -> the options that we saw in the previous
615.899 -> slide but basically
618.36 -> we now going to create a new solution so
621.18 -> if I go.net new ca solution
624.42 -> I'll give you guys a choice do you want
625.98 -> to do angular or reaction tonight
630.06 -> react
631.26 -> okay and so we'll leave it with SQL
633.779 -> Server uh and it's going to Output into
636.54 -> the current directory so the dotnet
638.339 -> templating engine is going to look at
639.959 -> the current directory and it's going to
641.22 -> say well this directory is called
642.899 -> briz.net and so that means it's going to
645.18 -> create a new solution called briz.net
648 -> and the namespace is inside it are going
650.399 -> to be bris.net so everywhere it finds
652.68 -> clean architecture in this template it's
654.54 -> going to be replaced with briz.net so
656.579 -> that includes the CI CD pipeline it
660.779 -> includes the bicep templates it includes
663.12 -> the source code it includes readmes all
664.86 -> that sort of stuff uh so we're good to
667.56 -> go so why don't I just get this
671.22 -> committed we won't push it yet because
672.72 -> that will trigger the CI CD pipeline
674.579 -> when it's when it's uh ready to go and
677.519 -> we'll go get commit new project like
680.1 -> that
681 -> okay
682.32 -> so I do want to show you how all this
685.019 -> works but before I do that I want to
687.72 -> trigger the CI CD pipeline so that I can
690.36 -> get this deploying through to different
691.74 -> environments
693.18 -> so to do that I need to set up the
697.019 -> GitHub repository there's a few
698.94 -> environments I need to create there's
700.56 -> some variables that I need to create the
702.6 -> secrets that I need to create so it can
704.579 -> communicate with Azure in Azure there's
706.74 -> resource groups that I need to create
708.42 -> there's uh app registrations that I need
711.839 -> to create in Azure ID and so there's a
713.76 -> lot of work so obviously if we were
715.86 -> starting a new solution we had to do all
717.779 -> of this from scratch it would take a
719.64 -> long time but I don't want to do that I
721.92 -> want my solution templates whether it's
723.6 -> the Blazer one or this one to be really
725.88 -> quick to get up and running so that I
727.32 -> can focus on delivering business value
728.76 -> okay and so I've put some scripts into
731.399 -> this template now to do all of that for
733.74 -> me so this script will tell us exactly
736.86 -> what it's going to do when we run it
740.16 -> okay so it says this script automates
742.8 -> the setup of environment resources
744.24 -> credentials for a project hosted on
745.74 -> GitHub and deployed to Azure it creates
747.72 -> workload identities in Azure ID sets up
749.88 -> resource groups and configures
751.079 -> environment specific variables and
752.64 -> secrets in GitHub repository this group
754.98 -> leverages Azure CLI the GitHub CLI and
757.44 -> GitHub apis to perform these tasks it
759.899 -> aims to streamline the process of
761.579 -> setting up and configuring development
763.019 -> staging and production environments for
764.639 -> the project
765.66 -> and this script does have parameters
767.639 -> it's a Powershell script with parameters
769.2 -> but it's done its best to guess
771.6 -> what they might be because we didn't
773.22 -> provide anything and that's where it's
774.899 -> using the GitHub CLI and it's using the
777.959 -> Azure CLI so I need to look at this and
780.36 -> make sure I'm happy with this is this
781.68 -> the right subscription ID
783.48 -> and if I'm not happy with that then I
785.16 -> can go in to the Azure CLI and I can
788.04 -> change it I can say Azure oh sorry AZ
790.74 -> account set subscription
792.779 -> so all of this has been uh gathered for
797.1 -> me now you can see in the environments
799.139 -> it's going to create a development
800.639 -> environment a staging environment and a
802.68 -> production environment and then it's got
804.42 -> a warning it says running the script
806.22 -> will provide various operations in your
807.839 -> GitHub repository and Azure subscription
809.459 -> ensure that you have the necessary
810.779 -> permissions and understand the
812.399 -> consequences so don't run this script
814.26 -> without understanding exactly what it
816.48 -> does okay and in case you didn't see the
818.88 -> warning there's a disclaimer use the
820.74 -> script at your own risk the author and
822.6 -> contributors are not responsible for
824.16 -> loss of data or any unintended side
825.839 -> effects resulting from running the
827.04 -> script so that being said
829.32 -> I will go ahead and run the script the
830.88 -> default option is no
832.62 -> all right but I'm going to run it so
834.48 -> it's going to go away and it's going to
835.74 -> set up a bunch of stuff for me now while
837.899 -> it's doing that I've got a browser handy
841.079 -> let's see
842.639 -> yep I got one here but that one is not
846.48 -> going to be enough because I need to be
848.22 -> signed into GitHub so we'll bring this
849.54 -> one over
851.82 -> I'll hide all my
854.16 -> bookmarks
856.62 -> favorites
859.079 -> uh
860.339 -> never there we go okay so we created a
864.48 -> repo called
866.519 -> british.net
868.74 -> and we just have a couple of manual
870.48 -> things we need to do so that this
872.7 -> pipeline's going to be able to run so
874.8 -> the first thing is we need to give the
877.68 -> workflows
879.66 -> permissions to read and write the GitHub
884.22 -> token so that's used for authorization
886.5 -> whoops so we just set read and write
888.72 -> there and scrolling down we hit save
892.44 -> now the script that's running in the
894.42 -> background
895.86 -> it's finished now the script that's
897.54 -> running in the background created some
899.82 -> environments for us in GitHub so we have
902.339 -> a a development production and staging
904.92 -> environment and it's also created some
906.959 -> Secrets the SQL admin password and three
911.399 -> variables so one thing that I can do is
914.459 -> I can come into an environment and
916.92 -> specify a required reviewer I'm not
919.56 -> going to do that tonight because I
920.94 -> always forget to approve it and then the
922.44 -> pipeline never finishes but but I can
925.5 -> come in here and I can say yep I want to
927.899 -> be one of the required uh reviewers for
931.68 -> this particular pipeline
933.959 -> if I scroll down to secrets and
936 -> variables we can get a bit of a glimpse
937.38 -> at what's in here
939.18 -> so you can see for secrets we have we
942.06 -> have environment specific secrets and
944.22 -> variables now in GitHub actions which is
946.199 -> really nice so I've basically got the
948.3 -> agile SQL administrator sorry the Azure
950.699 -> SQL administrator password for
953.279 -> production staging and development I
955.68 -> don't know what that is that was
956.82 -> generated randomly by that script that
958.92 -> we were on the setup.ps1 script I don't
961.26 -> need to know what it is because it's
962.579 -> going to be passed through to
964.639 -> to the bicep templates and it's going to
967.5 -> end up in key vault as a collection
968.94 -> string so that's fine it's sort of the
971.88 -> variables here
973.019 -> we've got the Azure client ID which is
976.199 -> the app registration which lives in
978.3 -> Azure ID and we also have
981.3 -> the Azure subscription ID the tenant ID
983.88 -> and the project name so this tenant ID
986.94 -> subscription ID and the client ID I used
989.519 -> for GitHub actions to authenticate
991.74 -> against Azure using that app
993.6 -> registration
994.8 -> project name is pretty obvious here we
997.019 -> have the default username for the SQL
999.6 -> administrator and we've got our Resource
1001.699 -> Group names
1003.92 -> so all of this is of course being
1005.48 -> created automatically for us and if we
1007.1 -> go into the Azure portal we can see some
1009.32 -> of the things that have been created in
1010.579 -> there and the focus of this talk is not
1013.459 -> to teach you how to do all of this it's
1016.04 -> to show that when you focus on your
1018.44 -> specialization and you put together the
1020.959 -> right tools Technologies and approach
1023.42 -> you can deploy to production really
1025.579 -> quickly and focus on delivering business
1027.38 -> value we're basically establishing a
1031.22 -> pipeline of value on Day Zero okay and
1034.939 -> so this is my specialization this is the
1037.1 -> way I'd like to do it but you might be
1039.5 -> able to learn from this and Fork it or
1041.66 -> create your own or do something
1042.74 -> completely different
1044.48 -> so you can see here the resource groups
1046.4 -> are all there I'll Zoom that in to 150
1048.799 -> percent so there's our brizz.net
1051.2 -> resource groups and if we went over to
1054.08 -> they're empty at the moment if we went
1056.179 -> over to Azure active directory
1059.12 -> I need a bit more space for that and go
1062.179 -> into app registrations
1065.299 -> we have
1067.46 -> we've got a glimpse of them but then
1068.96 -> they disappeared we've got these app
1071.66 -> registrations representing the
1073.16 -> application running in different
1074.179 -> environments
1075.38 -> and associated with that
1077.96 -> are some credentials so one for an
1082.28 -> environment specific these are these are
1083.84 -> used by GitHub actions to authenticate
1085.76 -> against Azure one that's not environment
1087.559 -> specific and one that is environment
1089.419 -> specific
1090.74 -> okay so with that in place and the
1093.32 -> pipeline set up and the workflow with
1095.539 -> the right permissions all I have to do
1098.059 -> now
1099.799 -> is go get push
1103.16 -> okay normally of course we're going to
1104.9 -> create a feature Branch to a pull
1105.98 -> request all that sort of thing get it
1107.12 -> approved and that sort of thing we don't
1108.26 -> have time it's Thursday night and really
1110.179 -> we want to get some beers soon so we're
1112.94 -> going to skip that
1114.38 -> so come back over here to bris.net and
1117.86 -> go into actions and we can see the
1120.14 -> pipeline has kicked off
1122.419 -> and I'm going to walk you through
1124.34 -> exactly what each step of the pipeline
1126.38 -> does
1127.76 -> but essentially it's going to build the
1130.64 -> project test the project package the
1132.2 -> project deploy it to development staging
1135.26 -> and production and make sure that the
1137.299 -> database which will also be provisioned
1139.72 -> is actually up to date and running the
1142.82 -> latest migrations whatever that might be
1144.32 -> in our solution
1146.72 -> okay so well that's happening
1150.32 -> let's go into this one I'll drop back
1153.46 -> into brizz.net and I just want to give
1156.44 -> you a quick peek at the solution
1158.9 -> so we'll go so the first thing you need
1162.799 -> to know is don't do what I just didn't
1164.12 -> load up visual studio 2022 we've got to
1166.64 -> load up the preview version
1168.34 -> because some of the some of the earlier
1171.38 -> versions of net 8 preview worked in
1173.66 -> Visual Studio 2022 but there's been some
1176.6 -> issues recently that I've run into so
1178.4 -> just use the preview version
1180.799 -> I changed that theme this afternoon to
1183.74 -> do a screenshot it looks so old I'll
1186.5 -> leave it like that for now though
1188.84 -> so if I go file
1191 -> start window clean architecture
1195.559 -> and we'll zoom in
1199.22 -> okay
1201.32 -> so out of the box
1203.66 -> you get your four layers so webbeing
1205.94 -> presentation
1207.7 -> domain and application layers
1209.96 -> representing core and infrastructure all
1212.179 -> of your external concerns such as data
1214.039 -> access
1215.179 -> you also get a bunch of test projects so
1217.7 -> for domain and application there's some
1219.44 -> unit test projects but there's also some
1223.039 -> functional test projects which will
1224.9 -> exercise the they're basically system
1226.94 -> tests so you can run those against a
1229.16 -> live database with live services
1231.32 -> uh for web we have acceptance tests so
1234.32 -> those acceptance tests are running uh
1236.36 -> playwright and spec flow and we also
1240.26 -> have a uh an empty project at the moment
1243.14 -> for infrastructure which is the
1244.94 -> integration tests so you get this out of
1247.1 -> the box something cool that I added
1249.2 -> recently which I kind of kind of like is
1251.539 -> I've also added a default readme uh it's
1254.9 -> not that I'm sorry I I didn't load the
1257.48 -> brizz.net project this is the actual um
1260.78 -> the clean architecture solution template
1263.48 -> we need to load the press.net one
1267.32 -> because when it's generated through
1268.88 -> the.net template in engine it's quite
1270.74 -> quite different
1272.96 -> so here's our readme for our briz.net
1275.78 -> project so it generated a starter readme
1277.84 -> which is going to be great because you
1279.799 -> always need a readme so that everybody
1281.24 -> on the development team's on the same
1282.679 -> page about how to build run tests and
1284.78 -> you know basically deploy the solution
1286.7 -> so that that comes out of the box
1289.34 -> you can see there's an editor config so
1291.62 -> that there's consistent coding code
1293.24 -> Styles and formatting a lot of this I'll
1295.64 -> cover later on in the talk so I think
1297.919 -> you can see the classic structure is
1300.2 -> still in place uh
1302.6 -> and that'll help you get up and running
1303.919 -> really quickly so if I come back over to
1307.1 -> here let's do a quick build so.net build
1314 -> TL
1315.38 -> does anyone has anyone seen this command
1317.179 -> it's really cool
1319.7 -> so I can't remember oh yeah terminal
1322.46 -> build output so don't add you dot net
1324.74 -> build has a new Option and net eight to
1327.2 -> produce more modernized output so the
1329.659 -> terminal logger output groups errors
1331.4 -> with the project that they came from and
1333.98 -> it better differentiates the different
1335.539 -> Target Frameworks for multi-targeted
1337.7 -> projects and provides real-time
1339.5 -> information on what the build is doing
1342.08 -> which is pretty cool if you like to work
1344.84 -> in the command line
1346.46 -> now on this side over here
1349.52 -> I'm going to just get a few things ready
1354.22 -> CD Source City web
1357.44 -> and we'll go.net run so we'll just
1360.62 -> launch the web project
1363.5 -> and over here
1366.26 -> we'll get ready to run our tests
1370.28 -> so dot
1372.98 -> there we go dotnet test no build okay so
1377.12 -> this is going to run all tests in the
1378.679 -> solution so it'll run our unit test
1380.179 -> it'll run our integration test our
1381.98 -> functional tests and our acceptance
1383.539 -> tests uh let's just see that it started
1386.12 -> okay
1387.5 -> where did that where did that land
1390.38 -> not there
1392.419 -> this one that should do it
1395 -> here we go so that's our that's our
1397.28 -> react application of course we could go
1399.44 -> and sign in and all that sort of thing
1400.76 -> but I really just want to run the tests
1402.86 -> at this stage
1404.659 -> there we go
1406.34 -> to give that a second
1410.72 -> all right that always gets me but that's
1413.84 -> okay this is because I'm not running
1415.159 -> Docker so at the moment the functional
1419.539 -> tests can run in three different ways if
1422.059 -> you chose sqlite they'll run against uh
1424.159 -> the local sqlite database if you chose
1426.86 -> SQL Server they're going to run by
1429.38 -> default against test containers so SQL
1432.919 -> server and Docker and that'll get spun
1434.24 -> up automatically for you and it'll get
1435.86 -> cleaned up afterwards for you the third
1437.72 -> way that you can run it is it can point
1439.34 -> at a actual SQL server on your
1441.5 -> development machine and that Third Way
1443.539 -> is my preference for SQL Server because
1446.24 -> the fact of the matter is that that
1447.559 -> container whether that that real live
1450.08 -> SQL Server whether it's in a container
1452.179 -> or not is already running is already
1454.88 -> ready to go and so when I run my
1457.22 -> functional tests against that I don't
1459.14 -> have to wait for the container to be
1461.24 -> spun up and then the tests to run and
1462.919 -> the container to be removed it's already
1466.46 -> ready to go so it's just a little bit
1467.84 -> faster about nine nine or ten seconds
1469.7 -> faster not that I did any serious
1471.74 -> benchmarking on it so we'll go ahead and
1474.86 -> run that again
1478.52 -> and so you can see that when you when
1480.38 -> you use a template like this there might
1482.36 -> be a lot that you're not familiar with
1484.28 -> there might be a lot that you haven't
1486.44 -> seen before or maybe this is all
1489.08 -> um normal for you but you can come into
1491.6 -> this template and you can see how it
1493.64 -> works it's already working all the way
1495.5 -> through to production and you can ask
1497.299 -> questions on the GitHub repository and
1499.28 -> have discussions with other users
1501.62 -> so there we go I think all of those
1503.78 -> tests pass so that's good and that's
1506.84 -> really what I wanted to demonstrate as
1509.78 -> part of that uh
1512.179 -> part of that demo and it looks like
1514.28 -> everything's coming along nicely here so
1516.74 -> it's just started its deployment to
1518.78 -> development and deployment to
1520.76 -> development will include things like
1523.22 -> deploying the infrastructure
1524.48 -> initializing the database and actually
1526.22 -> deploying the website
1527.9 -> so we'll get to see that once it's
1530.659 -> finished
1533.059 -> all right
1534.679 -> yes question
1540.799 -> when I'm running SQL Lite do I run
1543.2 -> against files or in memory
1545.72 -> that's a good question so when the web
1549.02 -> application runs it's running against
1551.419 -> files but when the functional tests run
1555.919 -> it's running in memory
1561.08 -> yes
1574.179 -> yes
1576.02 -> so
1577.82 -> it is yes but only because I haven't
1580.4 -> configured the pipeline to do an
1582.14 -> approval so generally what I will do is
1585.5 -> set up an approval for the staging
1588.14 -> environment and the production
1589.34 -> environment and so it won't go through
1591.559 -> automatically unless there's an approval
1594.4 -> but there is still just one single build
1599.059 -> artifact for the website that gets
1601.4 -> promoted from development to staging and
1604.7 -> then to production so it's the same
1606.2 -> artifact that will move through the
1607.52 -> pipeline
1610.22 -> any other questions
1615.159 -> yeah yeah
1620 -> what licenses
1622.419 -> am I oh sorry I should
1625.22 -> I should repeat the question so the
1627.02 -> question was what license is the
1628.4 -> template released under it's MIT
1631.88 -> um I guess that's the most permissive I
1633.74 -> think of them because just out of
1635.48 -> Interest with templates like this
1637.46 -> there's the license of the template code
1639.799 -> apply to the code generated by the
1641.659 -> template yes I believe that's specified
1643.76 -> in the in the license
1647.6 -> yes
1652.22 -> oh yeah so
1654.5 -> so good club
1655.76 -> um steps yes
1657.2 -> um really just one yeah
1666.86 -> correct so the question was I did a a
1669.62 -> manual step when configuring the GitHub
1672.14 -> repo which was to enable read and write
1675.02 -> access to the workflow for the GitHub
1677.539 -> token and yeah I haven't found a way to
1680 -> do that either through the CLI the
1681.74 -> GitHub CLI all through the GitHub API so
1685.159 -> if someone does know a way to do that
1686.539 -> I'd appreciate a heads up
1691.94 -> okay thank you all right so now we get
1694.22 -> to I get to show you some of the things
1696.919 -> that I found exciting and I think you
1698.659 -> might find exciting
1700.12 -> that came through in this upgrade
1703.22 -> so the first thing that I found exciting
1705.559 -> was framework and package management so
1708.679 -> I've simplified managing Target
1710.24 -> framework and dependencies of projects
1713.059 -> across the solution so the required.net
1715.82 -> SDK version is specified in global.json
1718.46 -> now admittedly I know that that's not
1720.559 -> very exciting
1721.779 -> but it's important to remember that
1724.58 -> although generally speaking global.json
1726.919 -> is optional because you can always run
1728.72 -> on the latest SDK for this particular
1731.179 -> solution it's used in the pipeline to
1734.059 -> make sure that the correct SDK is
1736.4 -> installed on the build agent so so we do
1739.88 -> need global.json in this case unless we
1741.799 -> were to go and change the pipeline
1744.02 -> the other thing that's a bit exciting is
1745.94 -> the required.net runtime version is
1748.88 -> specified just once in directory
1750.799 -> build.props so directory build.props has
1753.62 -> some common properties and that will get
1755.179 -> applied to all what eight projects that
1758 -> are in the solution so if I want to
1759.98 -> change in the future from net 8 to net9
1762.2 -> I just change that in one place Plus
1764.299 -> global.json you can see there's some
1766.58 -> other common properties there treat
1768.26 -> errors as treat warnings as errors so
1771.2 -> that people can't check in code with
1772.7 -> warnings because that's really annoying
1775.22 -> um you don't have to have that
1776.299 -> conversation anymore
1777.58 -> implicit usings are nullable just across
1780.32 -> the board
1782.96 -> all right so package versions are
1785.179 -> managed centrally in directory
1787.34 -> packages.props so I've enabled the
1790.159 -> central package management feature which
1792.919 -> came out sometime last year and all we
1795.98 -> have to do is have this directory
1797.44 -> packages.props file
1799.22 -> set manage package version centrally to
1801.799 -> true and then all of the different
1803.419 -> packages that we have we list in this
1805.88 -> file with the appropriate version and so
1808.399 -> that means if I wanted to upgrade any
1810.559 -> unit across four different testing
1813.74 -> projects I just changed the version here
1816.32 -> and I don't have to change it inside of
1818.539 -> the individual project files
1821.539 -> yes question
1833.36 -> this so it kind of really doesn't work
1836.24 -> any differently so once you have
1838.179 -> directory.packages.props you list the
1839.96 -> versions you list all of the package and
1841.46 -> all the versions that you want but then
1843.02 -> your CS proj just lists the package so
1846.02 -> this is the Project Specific one so
1848.12 -> lists it without the version so it's
1850.039 -> nice nice and simple
1851.84 -> yeah yeah so let's let's think about the
1855.799 -> next so if we go go back a little bit
1857.84 -> here if we think about when I upgrade
1860.799 -> to.net preview seven I only have to
1863.779 -> change
1865.1 -> two files global.json and
1869.2 -> directory.packages.props I don't have to
1870.98 -> change eight different projects so I
1873.679 -> thought that was really exciting I
1874.88 -> really like that so there's a
1876.559 -> combination of features there
1890.72 -> yeah the question was
1892.58 -> um does this um uh what is it called
1895.46 -> again Central package management yeah
1897.74 -> Central package management does it only
1899.299 -> work with nuget or does it work with
1901.039 -> other repositories I believe that it
1904.039 -> only works with nuget because I believe
1905.48 -> it's actually a feature of nuget that's
1908.059 -> exposed and available so
1911.24 -> all right dependency injection so
1913.52 -> dependency injection in the template
1915.2 -> supported using the built-in.net
1916.7 -> dependency injection container that's
1918.62 -> nice and simple but I like to split it
1921.679 -> out with project service dependencies
1924.38 -> registered in a dependency injection.cs
1927.02 -> file so the way that works of course is
1929.6 -> I created an extension method on
1931.159 -> i-service collection so in this case
1933.62 -> we're doing it for our infrastructure
1935.96 -> project so I have a dependency injection
1938.659 -> file in the root of the infrastructure
1940.76 -> project an extension method called add
1942.679 -> infrastructure services and inside of
1945.32 -> this method I'll wire up all of the
1947.72 -> services that are related to
1949.159 -> infrastructure
1951.5 -> and then in the composition route which
1953.899 -> is generally program.cs I will just go
1956.419 -> ahead and call
1957.86 -> all of those extension methods and
1959.96 -> because I've built it as kind of a
1961.159 -> little fluent API I can just say add
1963.26 -> this add this and add this and then
1964.58 -> we're done
1965.539 -> and that keeps program.cs really clean
1967.88 -> right
1968.779 -> so I've even got one there for the web
1970.399 -> project there so that's sitting in the
1972.14 -> same same project but nice and clean
1985.34 -> well for me it's just that I get to use
1989 -> the simplest approach and the simplest
1991.64 -> approach is not always the best approach
1993.62 -> but it's kind of one of the goals of the
1995.72 -> template the goal is the simplest
1998.299 -> approach to Enterprise application
1999.86 -> architecture with asp.net core and so if
2002.679 -> I bring in too many other packages like
2005.34 -> say Auto fact or fast endpoints
2010.24 -> bring in the package just the yeah
2014.2 -> well this is
2015.519 -> I mean yeah
2017.919 -> yeah that's right well I guess it's
2020.559 -> essentially essentially for me it's the
2022.96 -> same end result I have a nice clean tidy
2025.96 -> place where I can Define my dependencies
2028.6 -> and uh it keeps my composition route
2032.32 -> looking very clean
2035.08 -> another question
2050.08 -> correct
2067.419 -> so the question was so to have that work
2070.06 -> the various projects would need to
2072.04 -> depend on some kind of dependency say
2075.099 -> say the Microsoft dependency injection
2077.32 -> abstractions project and is it is it
2082.06 -> what was the second part to it sorry
2083.5 -> yeah
2085.96 -> mainly yeah
2088.659 -> right yeah
2096.28 -> yes
2101.08 -> yeah so in in so in taking this approach
2104.98 -> then there might be a dependency say on
2107.44 -> the domain layer for
2109.54 -> um certain packages that probably
2112.66 -> shouldn't be there and so with clean
2114.7 -> architecture you know the goal has
2116.38 -> always been to be independent of
2118.24 -> anything external so it's independent of
2120.04 -> the UI independent of the database
2121.24 -> independent of Frameworks and and that
2123.4 -> sort of thing so if we take a really
2124.78 -> pure approach to clean architecture then
2127.66 -> yeah we probably want to avoid that in
2130.72 -> this case there's no dependencies being
2132.099 -> wired up in domain
2134.44 -> um so so that so that particular issue
2136.9 -> is not a problem but there is an
2138.28 -> application and infrastructure and web
2140.8 -> so I don't mind I always tend to take a
2143.5 -> bit of a pragmatic approach to clean
2145.48 -> architecture and so if you look at my
2148.359 -> application layer I've got a dependency
2150.22 -> on Entity framework core
2153.16 -> I don't have a dependency on a specific
2155.079 -> database but there is a dependency on
2157.839 -> Entity framework core and a few other
2159.46 -> things I'm trying to zoom in there
2161.68 -> uh
2163.9 -> and that and that's because
2166.72 -> I feel that the value proposition by not
2169.9 -> being dependent on an orm is not
2171.7 -> worthwhile to me I don't tend to change
2174.28 -> an orm
2175.72 -> it doesn't mean that
2177.88 -> I'm not ever going to implement a
2179.8 -> repository pattern or a unit of work I
2181.599 -> might I just have to figure out what
2183.4 -> problem that's going to solve so yes
2185.92 -> clean architecture being very pure and
2190 -> adhering strictly to the principles is
2192.339 -> one thing but I tend to take a pragmatic
2194.74 -> approach so they'll they'll there will
2196.599 -> generally be a compromise and and uh you
2199.78 -> know the question as to whether you
2201.88 -> should do one thing over another will
2203.2 -> always be it depends
2216.46 -> yeah
2218.02 -> okay
2220.24 -> yes I think um at the moment you've
2223.06 -> quite often see
2224.26 -> you promised you promised that you would
2226.599 -> walk out if you if I showed you
2228.099 -> something dirty in my clean architecture
2229.66 -> implementation yeah
2231.88 -> you see with the parents injection now
2233.74 -> they've got the pregnancy injection
2234.82 -> abstractions yes yeah and
2238.72 -> they think
2241.72 -> yeah
2244.18 -> I think anything foreign
2255.04 -> yes having that but yes
2257.44 -> solve a few arguments I think in that
2259.06 -> space I agree and so
2264.22 -> yeah
2266.74 -> so Brendan
2268.06 -> Brendan was sharing his opinion on um
2270.46 -> the
2271.78 -> the the the use of abstractions such as
2273.94 -> dependency injection extractions
2275.5 -> actually I was looking in the Cs project
2277.119 -> to see where I'd reference that I'm sure
2279.04 -> I'd referenced it in the past in certain
2280.72 -> projects in order to extend I service
2282.579 -> collection but I couldn't quite and he
2284.68 -> raised a very good point that it would
2286.06 -> be good if Entity framework core had
2287.74 -> some extraction so you'd be taking
2289 -> dependency on the abstraction instead of
2290.8 -> the actual framework but you know what I
2293.92 -> think that's the thing about Entity
2295.42 -> framework core it is one big abstraction
2297.82 -> it's an abstraction on the database so I
2301.9 -> can even though I have a dependency on
2303.46 -> energy framework core in the application
2304.839 -> layer I can switch to sqlite I can
2307.3 -> switch to SQL Server I've already proven
2308.98 -> that I can switch to postgresql any of
2312.46 -> the databases that are provided by any
2314.44 -> framework core I can switch
2316.599 -> so I get to use the RM directly and I
2319.54 -> don't have to jump through too many
2320.74 -> Hoops to leverage its powerful
2322.54 -> capabilities
2328.06 -> yeah
2329.079 -> well maybe
2331.839 -> no problem all right so next web API so
2335.2 -> it includes a a API built using asp.net
2338.32 -> core minimal API
2340.06 -> now I've built in some minimal API
2343.06 -> extension methods which support some
2345.88 -> defaults such as open API and some
2349.3 -> routing conventions because minimal API
2352.06 -> is fast and lightweight but a lot of the
2353.92 -> things that we know and love such as
2355.66 -> conventions are just not built into the
2358.119 -> framework at the moment now of course I
2359.92 -> could have gone on and chosen something
2361.96 -> like file standpoints but I really
2364.359 -> wanted to keep it simple and for me
2366.28 -> keeping it simple was using ASP netcore
2369.22 -> minimal API and seeing if I could get it
2371.38 -> to work in a way that I really liked now
2375.339 -> we have a lot of options for how we
2377.5 -> organize our API endpoints right we've
2380.26 -> all seen the demo where we have a tiny
2383.44 -> web API with one file and all of the
2386.8 -> endpoints are defined in that file
2389.079 -> and I think that that option is okay
2392.079 -> right if you have a very small service
2395.14 -> with a small number of endpoints and
2397.54 -> minimal logic in those endpoints
2399.82 -> right for a crud application with maybe
2402.16 -> only one or two entities
2404.2 -> the other option that we've seen is we
2406.06 -> can group endpoints into separate files
2408.04 -> such as this one get where the forecasts
2410.26 -> so this is a good option for where
2413.2 -> perhaps we're building an Enterprise API
2415.42 -> and there's quite a lot of logic in each
2417.82 -> endpoint
2418.839 -> we can kind of start to separate each
2420.7 -> endpoint into its own file perhaps into
2422.8 -> its own folder and in that folder we can
2425.619 -> have the endpoint we can have the
2427.54 -> request type the response type we'll
2429.64 -> have this nice little slice for that
2432.099 -> particular endpoint and we can go to
2434.079 -> that folder and work on that endpoint
2437.5 -> the other option is we could group
2439.18 -> related endpoints into a single file
2441.82 -> such as users.cs so all of the endpoints
2445.66 -> that are related to users will sit
2447.46 -> inside of this file and I think that's a
2449.98 -> good option again for an Enterprise API
2451.72 -> where there are a lot of endpoints to
2453.16 -> manage but the endpoints themselves
2455.2 -> don't contain very much logic
2457.839 -> now those are the type of endpoints that
2459.88 -> I have in the clean architecture
2461.74 -> solution template because my endpoints
2464.26 -> are only concerned with figuring out
2466.839 -> what type of request it is and passing
2469.3 -> it on to some Handler which lives in the
2471.28 -> application layer so my endpoints are
2473.38 -> quite small
2474.94 -> so let me show you what it looks like
2477.82 -> groups of endpoints are defined in
2479.92 -> separate files so I created an abstract
2482.44 -> Base Class called endpoint group base
2484.66 -> which defines a map method okay so this
2488.98 -> map method accepts as a parameter the
2491.74 -> web application
2493.48 -> and it calls map group now minimal API
2496.48 -> has a map group but this one's actually
2498.339 -> an extension method that I built and
2500.74 -> allows me to pass in this class an
2503.02 -> instance of weather forecasts I use that
2505.54 -> information to set up some defaults such
2508.24 -> as the group name is called weather
2509.74 -> forecast based after the class name I
2511.9 -> use it to specify tags so that the open
2513.82 -> API specification generates correctly I
2516.28 -> use it to specify that we do want to add
2518.079 -> open API so all of these defaults are
2520.78 -> built into my extension method and this
2523.359 -> map get well of course minimal API has a
2525.52 -> map get but again this is one of my
2527.14 -> extension methods I'm passing in the
2529.18 -> method that you see below which contains
2531.28 -> all of the logic for getting weather
2533.44 -> forecasts and do you see what I mean
2535.48 -> when I say my endpoints don't have much
2537.64 -> logic in them they're usually just one
2539.68 -> or two lines of code so grouping a set
2542.56 -> of related endpoints into a single file
2544.42 -> works really well for me
2546.94 -> so we've got the endpoint group base
2549.88 -> we've got the map Group which is an
2552.64 -> extension method and map get which is an
2554.44 -> extension method and of course there's a
2556.119 -> whole host of other extension methods to
2557.98 -> support put post delete and and
2560.26 -> different combinations of that
2563.859 -> so the endpoint groups are automatically
2565.72 -> registration registered you don't have
2567.7 -> to register them one at a time I've just
2569.5 -> created an extension method on web
2570.94 -> application you just say map endpoints
2572.8 -> it will look for all the endpoint group
2575.079 -> bases and just call map for you so
2577.599 -> essentially wires it up
2579.7 -> and that's been working really well for
2581.5 -> me I've got an example of another
2583.24 -> endpoint group later on and I'll show
2585.64 -> you show you why I think it's working
2586.96 -> well
2591.7 -> oh yes one of the other things that
2593.5 -> we've got in.net 8 is the new eye
2595.9 -> exception Handler so this works with the
2598.42 -> unhandled exception middleware and
2600.76 -> essentially it allows you to improve
2603.46 -> your exception handling with IX with I
2606.339 -> exception Handler which gives you a
2608.44 -> callback for handling known exceptions
2610.359 -> in a central location so you can see in
2612.579 -> this case I've got a custom exception
2614.2 -> Handler implementing I exception Handler
2617.079 -> and we've got this tri-handle async
2619.78 -> method and so inside of here we can
2622.24 -> create some logic to handle known
2624.04 -> exception types and if we were able to
2626.26 -> handle it we can return true otherwise
2629.14 -> false
2630.4 -> now in the template when you look at it
2632.02 -> I have a list of known exceptions that I
2634.78 -> will try to handle and I'll I will craft
2636.819 -> a more appropriate response but with
2640.54 -> this approach it kind of made me think
2641.92 -> well I don't have to just have one
2644.859 -> exception Handler I can have multiple so
2647.92 -> you could actually say this is the not
2649.96 -> found exception Handler this is the
2651.819 -> validation exception Handler whatever
2653.56 -> common case it is it is that you have
2655.96 -> that you'd like to manage and you can
2658.54 -> see there that I've got Services dot add
2660.16 -> exception Handler custom exception
2661.78 -> Handler so if you had many obviously
2664 -> you'd probably create an extension
2665.74 -> method on that to wire them up
2667.3 -> automatically
2668.859 -> the
2673 -> the old filter
2675.119 -> does I exception Handler replace the old
2678.3 -> exception filters no so it's an
2682.3 -> alternate option so this one is working
2684.28 -> through middleware so a little bit more
2686.74 -> Global the filters are still available
2689.099 -> and and you can manage exception
2691.72 -> handling through the filters I like this
2694.3 -> approach because I don't have to specify
2696.22 -> on each of my endpoints add this filter
2699.22 -> admittedly of course with the solution
2701.079 -> that I built it would be very easy to do
2702.819 -> so
2703.54 -> because I would just do it as one of the
2705.52 -> options when I call my map group
2707.14 -> extension method
2708.579 -> but yeah
2711.579 -> yes question
2716.74 -> to no this this happens as a
2720.76 -> no that's all right so the question was
2722.319 -> do you need a try catch to call it no
2724.78 -> this happens as a result of the
2726.46 -> exception and it's automatically so
2729.339 -> asp.net core the middleware which is
2731.619 -> which is dealing with these exceptions
2733 -> we'll call this filter and if it's able
2736.3 -> to kind of handle it if it returns true
2738.339 -> then that'll be the end of processing
2740.319 -> but if it can't it'll see if you've got
2742.42 -> some other exception handlers and it'll
2744.4 -> try them too otherwise it'll fall back
2746.92 -> to its default response so you'll get
2748.72 -> your 500.
2752.079 -> okay open API so of course the template
2755.5 -> includes open API support to improve
2757.66 -> productivity and easily adapt to API
2759.88 -> changes it generates an open API
2762.88 -> specification based on the included web
2766.18 -> API and it does that whenever the web
2768.46 -> project builds so you know your
2770.5 -> specification will always be up to date
2774.22 -> uh developers can of course use Swagger
2776.56 -> UI to visualize and interact with the
2779.02 -> endpoints
2780.52 -> now it also generates an angular or
2783.28 -> react typescript client based on the web
2785.5 -> API
2786.579 -> thank you the angular client is just as
2790.359 -> it always been but the react typescript
2792.88 -> client needed a little bit of
2794.859 -> customization so I'm using nswag to
2797.92 -> generate these clients the react client
2800.319 -> has
2801.94 -> a custom template which will handle the
2806.2 -> new ASP net core identity authentication
2809.26 -> correctly so if it returns a redirect to
2812.079 -> login that'll be handled automatically
2814.18 -> and so that works both for angular and
2816.4 -> react so this is really cool this is one
2818.5 -> of the really great productivity things
2820.3 -> when you're building your angular or
2822.22 -> react front end you don't have to
2823.599 -> manually write HTTP client code to
2825.819 -> interact with your API you have strongly
2827.859 -> typed interfaces and types and also
2831.66 -> strongly typed response and request
2835.42 -> types
2837.88 -> I've also included a web.http file if
2840.339 -> you prefer to use that and so if you
2842.14 -> haven't seen this this gives you a way
2843.579 -> that a little bit of a playground where
2845.56 -> you can interact with your API and it
2848.319 -> might be a little bit hard to see up the
2849.76 -> back there but in this particular one
2851.44 -> I'm demonstrating some of the
2852.819 -> capabilities of the new asp.net core
2855.52 -> identity API which I haven't talked
2857.38 -> about yet we'll get to
2860.38 -> all right authentication authorization
2863.14 -> is the next topic so as with the
2865 -> official.net 8 Spa templates I've
2867.7 -> migrated these ones over to asp.net core
2871.119 -> identity
2872.26 -> I mentioned that angular and reacts bars
2874.359 -> will use the default ASP Network
2876.22 -> identity UI with cookie based
2878.38 -> authentication and so that means you get
2880.359 -> all of those razor Pages for free and
2882.94 -> you don't have to build say login and
2884.68 -> register and profile and email all those
2886.96 -> sorts of things you can of course
2888.16 -> customize them but if you don't want to
2890.619 -> kind of mix those mix those things
2893.14 -> together you can now use the asp.net
2895.96 -> core identity API
2898.06 -> and so here I think I've got a highlight
2900.7 -> there yeah here
2902.68 -> I'm adding the identity API to this web
2906.22 -> API solution and it'll provide you some
2908.74 -> endpoints you'll see in a moment
2909.94 -> register login refresh that you can use
2913.119 -> so if you wanted to you could actually
2915.76 -> write your own UI in angular and react
2920.02 -> to manage login and register and all
2922.359 -> those sort of identity concerns and
2924.28 -> communicate with this backend API
2927.099 -> now I really like this I I was I talked
2929.56 -> to Brandon about this
2931.38 -> one day and we were we were on a run and
2934.3 -> I said I think I've done a good job with
2935.98 -> the minimal API implementation with the
2937.78 -> extension methods because when this map
2940.42 -> identity API became available
2943.359 -> it just seemed to fit really well into
2945.46 -> my implementation I created a new class
2948.099 -> called users it's inheriting or based on
2951.46 -> the endpoint group base the map method
2954.04 -> Maps the group so we get all the
2956.02 -> defaults like forward slash API users
2958.119 -> for the base route and all I had to do
2961.06 -> because it was an extension method was
2962.619 -> called the built-in method.map identity
2965.319 -> API
2966.64 -> and it looked really simple to me
2970.02 -> uh and and uh yeah I was happy with that
2973.42 -> result so I think I think I've taken the
2975.22 -> right direction
2977.619 -> all right so this is this is an example
2980.079 -> of the endpoints that you would get so
2982.24 -> obviously they can because it's part
2984.099 -> because it's part of the minimal API
2985.72 -> they'll go ahead and make them their way
2987.339 -> into the specification and if you have
2990.52 -> it so configured also into your angular
2992.92 -> and react typescript clients by default
2995.8 -> it's not configured to use identity API
2998.68 -> but it's just a matter of adding that uh
3001.5 -> that endpoint group base
3005.52 -> all right data access dot access is this
3008.339 -> is a little bit boring this slide I'm
3009.839 -> going to work on this one a little bit
3011.22 -> so just bear with me so data access is
3013.859 -> supported using Entity framework core
3015.48 -> either sqlite or Circle SQL Server those
3018.119 -> are the built-in options of course if
3020.04 -> you wanted to change to something else
3021.48 -> like postgresql today you just go ahead
3023.76 -> and delete the built-in migrations and
3025.38 -> change the provider and you're pretty
3026.94 -> much there
3028.079 -> you'll have to update the
3029.52 -> infrastructures code as well
3031.38 -> so the EF core migrations is enabled and
3033.78 -> it's almost completely automated you
3035.819 -> have to still create your own migrations
3037.619 -> but the rest of it is done for you for
3040.44 -> example database initialization and
3043.14 -> seeding which means creating the
3045.78 -> database applying the migrations and
3047.28 -> seeding the database occurs during
3049.079 -> startup for development environments so
3051.599 -> your local development environment don't
3053.4 -> have to worry about it for the deployed
3055.5 -> environments it's using the Entity
3057.059 -> framework core migrations bundle and
3059.52 -> that's a cross-platform app which will
3061.92 -> ensure that your deployed database as
3064.8 -> configured using a connection string is
3067.14 -> up to date with the latest migration
3069.24 -> so we build the CF Core migrations
3071.16 -> bundle in the pipeline and we run it in
3073.98 -> the pipeline for each environment
3076.64 -> so where we need to configure our
3079.859 -> entities where we're not happy with the
3082.319 -> conventions we want to override them the
3084.18 -> preference is to use EF core fluent API
3086.46 -> and so you'll see some examples of that
3088.14 -> in there and I also have some EF core
3090.42 -> interceptors to implement cross-cutting
3092.76 -> concerns such as auditable entities and
3095.4 -> dispatching domain events I'd love to
3097.26 -> show you
3098.16 -> just how clean that is because that's
3100.5 -> something that I was really excited
3101.64 -> about if you've worked with interceptors
3103.92 -> before
3105 -> you might agree with me and saying that
3107.7 -> it's not really very nice to wire them
3110.099 -> up like a lot of people will inject them
3112.44 -> in through the Constructor and then in
3115.14 -> on configuring register them well I
3117.24 -> don't have a Constructor well no I do
3118.859 -> have a Constructor I lied sorry my
3120.599 -> apologies I do have a Constructor but
3122.22 -> it's not doing that and I don't have on
3124.98 -> configuring so my appdb context is nice
3128.579 -> and empty but I'm still wiring up those
3130.92 -> interceptors so let me show you how I
3132.359 -> did it so I can't see that dependency
3135.859 -> inject that's the one
3138.18 -> so you can see here I just register the
3140.64 -> interceptors with dependency injection
3142.26 -> and then when I add my DB contacts I'm
3144.78 -> just telling that hey just add all of
3146.819 -> the interceptors use the service
3148.2 -> provider get the services anything
3149.76 -> that's implementing I save changes
3151.74 -> Interceptor and add it in so we can
3153.78 -> configure it here rather than in the
3155.88 -> appdb context and that's much cleaner I
3158.46 -> like that
3160.02 -> all right
3163.619 -> core features so core being application
3167.64 -> layer and domain layer has a number of
3169.5 -> features built into it such as automatic
3172.02 -> validation of invoked use cases now
3174.54 -> example of a use case might be create a
3177.599 -> customer or dispatch an order and those
3179.819 -> are the types of things that live in the
3181.2 -> application layer
3182.94 -> we also have the ability to specify
3185.359 -> authorized requirements for use case so
3187.98 -> if we have specific authorization
3189.599 -> requirements for a use case we can add
3191.88 -> an authorized attribute to that use case
3193.92 -> and specify those requirements now you
3196.14 -> might be a little bit worried there that
3197.339 -> that's kind of got a dependency on some
3199.44 -> kind of identity tooling it doesn't it's
3202.319 -> an abstraction I created the authorize
3204.26 -> attribute and the process to run it is
3208.319 -> relying completely on some
3211.26 -> implementation sitting in infrastructure
3212.88 -> which in this case is ASP Network
3214.26 -> identity but yeah
3217.28 -> we automatically log unhandled
3219.54 -> exceptions this is the some of these
3221.64 -> features the first one this is the
3223.92 -> second one and third one these are
3225.3 -> powered by mediator pipeline behaviors
3228.24 -> so if you haven't seen that sort of
3229.92 -> thing I'd encourage you to check it out
3231.119 -> I automatically log the details of any
3233.819 -> invoked use case so when our request is
3236.04 -> made to the system such as dispatching
3238.02 -> an order I will log that request I will
3240.839 -> log the input to that request and I will
3243.54 -> log uh the user who yes question
3249.42 -> not at this stage yeah that's something
3251.28 -> I've got a massive backlog and yeah
3254.22 -> there's a lot of things that I want to
3255.839 -> add to it but look listen um that that's
3258.78 -> a good question so the question was are
3260.579 -> you using open Telemetry and my answer
3262.619 -> of course was not at this stage
3263.7 -> something that I want to look into
3265.559 -> um
3266.28 -> if you do like to contribute to the to
3268.619 -> the template at any point I love
3270.599 -> contributions just keep in mind that the
3272.819 -> goal of the template is always the
3274.319 -> simplest approach to Enterprise
3275.339 -> architecture with asp.net core so I
3278.46 -> might not add in advanced caching
3280.559 -> capabilities
3282.059 -> but I might improve how logging is done
3284.64 -> simple things
3286.92 -> add and dispatch domain events is built
3289.38 -> in support for Value objects is built in
3291.599 -> and support for auditable entities is
3293.88 -> built in
3295.92 -> CI CD pipeline this was something that I
3298.14 -> worked very hard on so this is the CI CD
3300.059 -> pipeline as I mentioned it's based on
3301.859 -> GitHub actions and it deploys to Azure
3305.64 -> and manages the infrastructure using
3307.38 -> bicep templates so when a developer does
3310.44 -> the right thing and raises a pull
3312 -> request and that gets reviewed and
3313.44 -> approved and merged into main that'll
3315.3 -> kick off the CI Pipeline and that will
3317.46 -> build
3318.54 -> test and package the solution when it
3322.14 -> packages the solution it's built in The
3323.7 -> Entity framework core migrations bundle
3325.559 -> and the website the publish output of
3327.96 -> the website we'll then kick off the CI
3330.059 -> pipeline for each environment in the in
3333.119 -> in that's configured it will deploy the
3335.46 -> infrastructure using uh Azure and it
3338.88 -> will initialize the database using the
3340.619 -> Entity framework called migrations and
3342.54 -> that's really good right because this is
3344.94 -> a step on the deployment pipeline if the
3347.099 -> database fails to initialize you'll know
3349.559 -> about it much better than initializing
3352.14 -> it at startup when the application has
3354.78 -> been deployed already and users are
3356.64 -> using it but can't access their records
3358.619 -> so it's part of the pipeline it'll it'll
3361.079 -> fail much faster
3362.579 -> and then of course we deploy the website
3364.2 -> so that's development staging and
3366.18 -> production
3368.4 -> all right infrastructure is code so the
3371.7 -> template includes infrastructure as code
3373.44 -> using bicep templates it includes the
3375.9 -> components necessary to support a basic
3378.42 -> web app and that basic web app the
3380.7 -> infrastructure design is based on the
3383.04 -> Azure reference architecture for a basic
3384.839 -> web app so you can see the link there if
3388.079 -> you would like to learn more about that
3389.4 -> architecture so there's a lot like to
3391.38 -> align what I'm doing with something
3393.72 -> that's backed by a proven approach so if
3396.18 -> you'd like to learn more about this you
3397.559 -> can jump on on Microsoft learn and check
3400.619 -> that out
3404.04 -> all right code scaffolding so it
3405.96 -> includes built-in support for
3407.4 -> scaffolding new use cases as either
3411.18 -> a command or query because the template
3414.059 -> implements cqrs so use cases represent
3416.88 -> specific application logic such as
3418.94 -> create customer or dispatch order
3422.22 -> and when you use this CA use case
3425.24 -> template you'll want to use it within
3428.099 -> source application that's where it's
3429.9 -> been designed to create these use cases
3431.88 -> so essentially you'll go.net new use
3433.92 -> case
3434.7 -> you specify some options the name
3437.16 -> represents the name of the use case
3438.9 -> being created feature name represents
3441.839 -> the feature that this use case belongs
3444.059 -> to use case type either a command or
3446.16 -> query and the return type the name of
3449.28 -> the type being returned that can be
3450.78 -> whatever you want it to be maybe you
3452.04 -> haven't created it yet there's a
3453.9 -> demonstration of creating the dispatch
3456.24 -> orders use case so we go.net new see a
3460.26 -> use case feature name orders name of the
3462.78 -> use case dispatch order and the use case
3464.94 -> type is command
3466.92 -> so the customer that I don't have an
3468.54 -> example of the code that generates so
3470.28 -> I'll just I'll just do that now for you
3471.839 -> quickly
3472.74 -> so we want to jump into source and into
3476.22 -> web
3477.54 -> sorry not interweb into application
3479.339 -> follow my instructions go.net
3483.599 -> .net new ca use case
3488.64 -> thank you I was wondering where my
3490.22 -> intellisense was
3492.119 -> .net there we go I don't want help I
3494.579 -> want
3497.4 -> there we go that'll do so we'll create
3500.4 -> a new use case in the feature called
3502.38 -> weather forecasts
3504.54 -> and the use case name will be get
3507 -> today's forecast and the return type
3509.52 -> will be a type that doesn't exist yet
3511.74 -> it'll be the today's forecast VM so if I
3515.7 -> press enter on that
3518.819 -> there we go it fails okay I must look
3522.42 -> this is one that that I tried earlier
3524.46 -> that didn't work because I specified all
3526.38 -> the wrong things
3527.46 -> but I can fix it
3531.54 -> okay
3533.819 -> missing our use case type we can we can
3536.339 -> cover that too that's UT and this is a
3539.819 -> query
3542.46 -> boom got it okay so if we come into here
3548 -> and into application I'm going to zoom
3551.099 -> this in for you
3553.079 -> okay
3554.28 -> so I've got weather forecast folder if
3556.799 -> that folder didn't already exist that's
3558.599 -> the feature folder it would have created
3560.22 -> it
3561.599 -> inside of that there's a queries folder
3563.76 -> so I separate the queries into the
3565.02 -> queries following the commands into the
3566.22 -> commands folder it would have created
3567.78 -> that too
3568.74 -> here is my get today's forecast feature
3572.16 -> and here is the uh sorry feature use
3575.52 -> case and here is the code that it's
3577.079 -> generated so this is just to help us get
3579.54 -> started
3582.059 -> there we go so I have a
3584.7 -> query which is the input for the query
3586.74 -> we could put some parameters in there
3588.359 -> you know we might want today's forecast
3590.579 -> with um specific data return we can
3593.4 -> Define that we've got a validator so
3595.68 -> this is uh fluent fluent validation we
3598.079 -> can specify some validation on this
3599.94 -> input and we have a Handler and you can
3602.88 -> see it's just gone and basically created
3605.819 -> a skeleton for us to start working with
3607.799 -> so we don't have to go and create this
3609.66 -> folder structure in these files and that
3611.339 -> sort of thing so be interested in
3613.02 -> everyone's feedback on that if they do
3614.76 -> start using it what else do you want to
3616.92 -> see what options do you want should I
3619.079 -> include mapping should I make it
3620.7 -> optional whatever you whatever you need
3623.22 -> we can build on it because it's it's
3624.96 -> pretty easy to create these item
3626.579 -> templates
3628.68 -> all right documentation as mentioned it
3631.319 -> includes a readme.markdown file which is
3633.96 -> generated automatically and the file
3636.18 -> content is based on the type of solution
3638.04 -> that you create so the readme will
3640.079 -> change depending on whether it's react
3641.76 -> or angular or web API it includes basic
3644.88 -> details such as the template version
3646.68 -> used to create the solution so you know
3648.78 -> you know if you if you decide to upgrade
3650.819 -> to a new version of clean architecture
3652.44 -> solution template you can kind of
3653.64 -> compare those versions it includes how
3656.4 -> to build and run the app code
3657.66 -> scaffolding to generate use cases
3659.339 -> details on code Styles and formatting
3661.68 -> which is basically use editor config
3663.96 -> running automated tests and where to
3667.079 -> find help and other resources
3671.579 -> all right we just need to check our
3673.319 -> production deployment make sure that was
3675.299 -> successful
3676.319 -> so over here somewhere isn't it
3679.14 -> there we go
3680.76 -> so is this the right one all right yeah
3683.7 -> no that's right okay
3685.68 -> so that was our deployed to development
3687.599 -> you can see staging and production went
3689.16 -> through we'll just click on one of those
3690.839 -> sites just to see that it's running
3695.64 -> so this will be the first time that's
3696.9 -> run so of course
3699.059 -> deployed all of the infrastructure to
3700.98 -> initialize the database websites up and
3703.02 -> running it's all wired into application
3704.64 -> insights so there's Telemetry coming
3706.319 -> from like key Vault and from SQL Server
3709.859 -> the the actual logical server and the
3712.619 -> database itself so that yep that's all
3715.68 -> up and running oh always really focus
3719.16 -> thank you
3721.2 -> so we will check the other environments
3723.359 -> because you can only see so much hello
3724.799 -> world
3727.26 -> all right so
3729.24 -> I hope you enjoyed my talk tonight if
3731.28 -> you're Keen to learn more or hopefully
3733.44 -> contribute to the template you can
3735.299 -> access the project on GitHub there you
3738.42 -> can have a discussion with other users
3740.52 -> you can request a new feature you can
3743.819 -> point out a bug for me I'm on top of it
3748.079 -> at the moment so there's not any pull
3750.119 -> requests waiting to be merged or there's
3752.4 -> not really any issues that I'm worried
3754.02 -> about there's just a few there so if you
3755.819 -> do put something through it's likely
3758.099 -> that I'm going to respond very quickly
3760.319 -> if you do find the template valuable
3762.359 -> please give it a star on GitHub that's
3764.7 -> uh that's what I thrive on at the moment
3766.5 -> is GitHub Stars so I'd really appreciate
3769.2 -> that thank you
3771.599 -> foreign
Source: https://www.youtube.com/watch?v=jhgxdDhNicI