-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathreading-list.html
883 lines (675 loc) · 93.4 KB
/
reading-list.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Reading List | cfrenzel</title>
<!-- Begin Jekyll SEO tag v2.5.0 -->
<title>Reading List | cfrenzel</title>
<meta name="generator" content="Jekyll v3.8.5" />
<meta property="og:title" content="Reading List" />
<meta property="og:locale" content="en_US" />
<meta name="description" content="Blog of Camron Frenzel" />
<meta property="og:description" content="Blog of Camron Frenzel" />
<link rel="canonical" href="https://cfrenzel.com/reading-list.html" />
<meta property="og:url" content="https://cfrenzel.com/reading-list.html" />
<meta property="og:site_name" content="cfrenzel" />
<script type="application/ld+json">
{"description":"Blog of Camron Frenzel","@type":"WebPage","url":"https://cfrenzel.com/reading-list.html","publisher":{"@type":"Organization","logo":{"@type":"ImageObject","url":"https://cfrenzel.com/assets/images/logo.png"}},"headline":"Reading List","@context":"http://schema.org"}</script>
<!-- End Jekyll SEO tag -->
<link rel="shortcut icon" type="image/x-icon" href="/assets/images/favicon.ico">
<!-- Font Awesome Icons -->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css" integrity="sha384-mzrmE5qonljUremFsqc01SB46JvROS7bZs3IO2EmfFsd15uHvIt+Y8vEf7N7fWAU" crossorigin="anonymous">
<!-- Google Fonts-->
<link href="https://fonts.googleapis.com/css?family=Lora:400,400i,700" rel="stylesheet">
<!-- Bootstrap Modified -->
<link rel="stylesheet" href="/assets/css/main.css">
<!-- Theme Stylesheet -->
<link rel="stylesheet" href="/assets/css/theme.css">
<!-- Syntax Highlighter http://jwarby.github.io/jekyll-pygments-themes/languages/javascript.html -->
<link rel="stylesheet" href="/assets/css/vs.css">
<!-- Jquery on header to make sure everything works, the rest of the scripts in footer for fast loading -->
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<!-- This goes before </head> closing tag, Google Analytics can be placed here -->
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-154588304-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-154588304-1');
</script>
</head>
<body class="">
<!-- Navbar -->
<nav id="MagicMenu" class="topnav navbar navbar-expand-lg navbar-light bg-white fixed-top">
<div class="container">
<a class="navbar-brand" href="/index.html"><strong>cfrenzel</strong></a>
<!-- <a class="feed d-lg-none" style="margin-right: auto;" href="/feed.xml"><i class="fas fa-rss-square"></i></a> -->
<a class="feed d-lg-none" style="margin-right: auto;" href="http://feeds.feedburner.com/cfrenzel"><i class="fas fa-rss-square"></i></a>
<button class="navbar-toggler collapsed" type="button" data-toggle="collapse" data-target="#navbarColor02" aria-controls="navbarColor02" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse" id="navbarColor02">
<ul class="navbar-nav mr-auto d-flex align-items-center">
<!-- Replace menu links here -->
<li class="nav-item">
<a class="nav-link" href="/index.html">Home</a>
</li>
<!-- <li class="nav-item">
<a class="nav-link" href="/authors-list.html">Authors</a>
</li> -->
<li class="nav-item">
<a class="nav-link" href="/contact.html">Contact</a>
</li>
</ul>
<ul class="navbar-nav ml-auto d-flex align-items-center">
<li>
<script src="/assets/js/lunr.js"></script>
<script>
$(function() {
$("#lunrsearchresults").on('click', '#btnx', function () {
$('#lunrsearchresults').hide( 1000 );
$( "body" ).removeClass( "modal-open" );
});
});
var documents = [{
"id": 0,
"url": "https://cfrenzel.com/404/",
"title": "",
"body": " 404 Page not found :( The requested page could not be found. "
}, {
"id": 1,
"url": "https://cfrenzel.com/categories.html",
"title": "Categories",
"body": " Categories development: Throwback: Prototype of AR Furniture Layout (2009) : Was going through some old video and found rough demo of a prototype that I built back in 2009. I was experimenting with AR at the time but nothing really came of it; so I thought I’d. . . development creative creative development Feb 28, 2020 Throwback: Projector with Microsoft Kinect (2013) : Found some more footage that I thought was pretty cool from back in 2013. This uses a microsoft kinect to track people at a party. I used Quartz Composer to build some visuals and pr. . . development creative creative development Feb 27, 2020 Learning From Open Source Part1: MediatR : It can be intimidating and time consuming to explore a mature open source project. Often an attempt to find inspiration results in a surface level understanding of a few components w. . . development mediatR tutorial Jan 14, 2020 Simple Domain Events with EFCore and MediatR : This post relates to the Domain Driven Design (DDD) concept of Domain Events. These events originate in the Domain Model and are broadcast within a Bounded Context. These are not ev. . . development dotnet efcore ddd mediatR Jan 03, 2020 Quickly Create Your Own . NET Code Templates and Use Them From Anywhere : Whether you need to throw together a quick console app or scaffold an enterprise solution, it can be a real time suck just creating, naming and referencing projects. Setting up boile. . . development dotnet automation nuget appveyor Dec 20, 2019 Publishing . NET Core NuGet Packages with Nuke and AppVeyor : This article builds on concepts discussed by Andrew Lock, Jimmy Bogard and Georg Dangl. Here we’re going use Nuke to make build, packaging and publishing even nicer!!! development appveyor nuke dotnet nuget Dec 17, 2019 creative: Throwback: Prototype of AR Furniture Layout (2009) : Was going through some old video and found rough demo of a prototype that I built back in 2009. I was experimenting with AR at the time but nothing really came of it; so I thought I’d. . . development creative creative development Feb 28, 2020 Throwback: Projector with Microsoft Kinect (2013) : Found some more footage that I thought was pretty cool from back in 2013. This uses a microsoft kinect to track people at a party. I used Quartz Composer to build some visuals and pr. . . development creative creative development Feb 27, 2020 books reading list categories creative development tags appveyor automation creative ddd development dotnet efcore featured mediatR nuget nuke tutorial "
}, {
"id": 2,
"url": "https://cfrenzel.com/contact.html",
"title": "Contact",
"body": "Please send your message to cfrenzel. We will reply as soon as possible! "
}, {
"id": 3,
"url": "https://cfrenzel.com/",
"title": "cfrenzel",
"body": " Father, Geek, Musician, Small Dog Lover I’ve built systems of great value from simple components, and I’ve built systems of great complexity that were never even used. Mainly I just love to build things Alexander Schimmeck Learning From Open Source Part1: MediatR In development, Quickly Create Your Own . NET Code Templates and Use Them From Anywhere In development, Publishing . NET Core NuGet Packages with Nuke and AppVeyor In development, Throwback: Prototype of AR Furniture Layout (2009) : Was going through some old video and found rough demo of a prototype that I built back in 2009. I was experimenting with AR at the time but nothing really came of it; so I thought I’d. . . development creative creative development Feb 28, 2020 Throwback: Projector with Microsoft Kinect (2013) : Found some more footage that I thought was pretty cool from back in 2013. This uses a microsoft kinect to track people at a party. I used Quartz Composer to build some visuals and pr. . . development creative creative development Feb 27, 2020 Learning From Open Source Part1: MediatR : It can be intimidating and time consuming to explore a mature open source project. Often an attempt to find inspiration results in a surface level understanding of a few components w. . . development mediatR tutorial Jan 14, 2020 Simple Domain Events with EFCore and MediatR : This post relates to the Domain Driven Design (DDD) concept of Domain Events. These events originate in the Domain Model and are broadcast within a Bounded Context. These are not ev. . . development dotnet efcore ddd mediatR Jan 03, 2020 Quickly Create Your Own . NET Code Templates and Use Them From Anywhere : Whether you need to throw together a quick console app or scaffold an enterprise solution, it can be a real time suck just creating, naming and referencing projects. Setting up boile. . . development dotnet automation nuget appveyor Dec 20, 2019 Publishing . NET Core NuGet Packages with Nuke and AppVeyor : This article builds on concepts discussed by Andrew Lock, Jimmy Bogard and Georg Dangl. Here we’re going use Nuke to make build, packaging and publishing even nicer!!! development appveyor nuke dotnet nuget Dec 17, 2019 books reading list categories creative development tags appveyor automation creative ddd development dotnet efcore featured mediatR nuget nuke tutorial "
}, {
"id": 4,
"url": "https://cfrenzel.com/privacy-policy.html",
"title": "Privacy Policy",
"body": "“cfrenzel” takes your privacy seriously. To better protect your privacy we provide this privacy policy notice explaining the way your personal information is collected and used. Collection of Routine Information: This website track basic information about their visitors. This information includes, but is not limited to, IP addresses, browser details, timestamps and referring pages. None of this information can personally identify specific visitor to this website. The information is tracked for routine administration and maintenance purposes. Cookies: Where necessary, this website uses cookies to store information about a visitor’s preferences and history in order to better serve the visitor and/or present the visitor with customized content. Advertisement and Other Third Parties: Advertising partners and other third parties may use cookies, scripts and/or web beacons to track visitor activities on this website in order to display advertisements and other useful information. Such tracking is done directly by the third parties through their own servers and is subject to their own privacy policies. This website has no access or control over these cookies, scripts and/or web beacons that may be used by third parties. Learn how to opt out of Google’s cookie usage. Links to Third Party Websites: We have included links on this website for your use and reference. We are not responsible for the privacy policies on these websites. You should be aware that the privacy policies of these websites may differ from our own. Security: The security of your personal information is important to us, but remember that no method of transmission over the Internet, or method of electronic storage, is 100% secure. While we strive to use commercially acceptable means to protect your personal information, we cannot guarantee its absolute security. Changes To This Privacy Policy: This Privacy Policy is effective and will remain in effect except with respect to any changes in its provisions in the future, which will be in effect immediately after being posted on this page. We reserve the right to update or change our Privacy Policy at any time and you should check this Privacy Policy periodically. If we make any material changes to this Privacy Policy, we will notify you either through the email address you have provided us, or by placing a prominent notice on our website. Contact Information: For any questions or concerns regarding the privacy policy, please contact us here. "
}, {
"id": 5,
"url": "https://cfrenzel.com/reading-list.html",
"title": "Reading List",
"body": " Reading List: The Visual MBA : Two Years of Business School Packed into One Priceless Book of Pure Awesomeness Jason Barron https://www. thevisualmbabook. com/ I love reading business books, but for me the concepts fade pretty quickly while switching betweens roles. This book provides simple and meaningful visuals to help burn the basics of business school into your mind. Dec 13, 2019 Algorithms To Live By : The Computer Science of Human Decisions Brian Christian https://brianchristian. org/algorithms-to-live-by/ audible. com A surprisingly fun read with no prior geekiness required. If the hidden patterns behind the age that we marry or why the increase in superhero movie sequels is foreshadowing the end of an era sounds exciting to you, check it out. Dec 12, 2019 Designing Data-Intensive Applications : The Big Ideas Behind Reliable, Scalable, and Maintainable Systems Martin Kleppmann http://dataintensive. net/ I love the style of this book. It’s broad in scope, but it tries to build understanding on first principles. Whether you consider your work “intensive” or not, if your working with data/databases this book is full of useful concepts. Also checkout Martin’s Blog. It’s a great resource for distributed system concepts. Dec 01, 2019 Pentesting Azure Applications : The Definitive Guide to Testing and Securing Deployments Matt Burrough https://nostarch. com/azure Get started securing your azure resources with no former security expertise required. This book is full of actionable practices and tools that you can put into place right now. Aug 24, 2019 Why We Sleep : Unlocking the Power of Sleep and Dreams Matthew Walker https://www. simonandschuster. com/books/Why-We-Sleep/Matthew-Walker/9781501144325 audible. com An accessible dive into the current state of sleep science that will have you making changes immediately. You’ll never think of sleep the same way again. Feb 27, 2019 Real-Life BPMN : Jakob Freund, Bernd Rücker https://www. amazon. com/Real-Life-BPMN-4th-introduction-DMN/dp/1086302095 This book helped me greatly while I was searching for a clean notation for communicating workflows within dev teams, operational teams, and with execs. The authors provide an opinionated guide to which parts of BPMN are useful as well as a style that you can adopt from day 1. Having a single notation that I could use to capture a strategic and operational model was key. It’s also a natural fit with message-based systems. The authors also provide some great free tools for building models. Dec 01, 2017 Data Science for Business : What You Need to Know About Data Mining and Data-Analytic Thinking Foster Provost & Tom Fawcett http://data-science-for-biz. com/ An excellent survey of data science with just the right amount of depth to give you some real direction. If you don’t know where to start, start here. Nov 15, 2013 Implementing Domain-Driven Design : Vaughn Vernon https://dddcommunity. org/book/implementing-domain-driven-design-by-vaughn-vernon/ This book is a great companion to the original Domain Driven-Design. You can read them side-by-side for deeper understanding of the concepts. It provides the missing concrete examples and implementations that will unlock the value of DDD. Oct 01, 2013 How to Measure Anything : Finding the Value of Intangibles in Business Douglas W. Hubbard https://www. howtomeasureanything. com/3rd-edition/ This is one of my favorite books. I’d recommend it to anyone. Learn to tap into the information that you didn’t even know you had. Dec 01, 2012 Enterprise Integration Patterns : Gregor Hohpe and Bobby Woolf https://www. enterpriseintegrationpatterns. com/gregor. html This book is another classic. It provides a foundation for the concepts of system integration and explore dozens of timeless patterns Dec 01, 2012 Domain-Driven Design : Tackling Complexity in the Heart of Software Eric Evans https://dddcommunity. org/book/evans_2003/ This is a classic that influenced my early ideas on software design. It seems to offer new wisdom every time I revisit it (even after 15 years). With the rise of microservices this book is as relevant as ever. It offers a fundamental approach to determine the boundaries between components/services. Jan 01, 2004 books reading list categories creative development tags appveyor automation creative ddd development dotnet efcore featured mediatR nuget nuke tutorial "
}, {
"id": 6,
"url": "https://cfrenzel.com/tags.html",
"title": "Tags",
"body": " Tags {% for tag in site. tags %} {{ tag[0] }}: {% assign pages_list = tag[1] %} {% for post in pages_list %} {% if post. title != null %} {% if group == null or group == post. group %} {% include main-loop-card. html %} {% endif %} {% endif %} {% endfor %} {% assign pages_list = nil %} {% assign group = nil %} {% endfor %} {% include sidebar-category. html %} "
}, {
"id": 7,
"url": "https://cfrenzel.com/tags/featured/",
"title": "",
"body": ""
}, {
"id": 8,
"url": "https://cfrenzel.com/tags/appveyor/",
"title": "",
"body": ""
}, {
"id": 9,
"url": "https://cfrenzel.com/tags/nuke/",
"title": "",
"body": ""
}, {
"id": 10,
"url": "https://cfrenzel.com/tags/dotnet/",
"title": "",
"body": ""
}, {
"id": 11,
"url": "https://cfrenzel.com/tags/nuget/",
"title": "",
"body": ""
}, {
"id": 12,
"url": "https://cfrenzel.com/tags/automation/",
"title": "",
"body": ""
}, {
"id": 13,
"url": "https://cfrenzel.com/tags/efcore/",
"title": "",
"body": ""
}, {
"id": 14,
"url": "https://cfrenzel.com/tags/ddd/",
"title": "",
"body": ""
}, {
"id": 15,
"url": "https://cfrenzel.com/tags/mediatr/",
"title": "",
"body": ""
}, {
"id": 16,
"url": "https://cfrenzel.com/tags/tutorial/",
"title": "",
"body": ""
}, {
"id": 17,
"url": "https://cfrenzel.com/tags/creative/",
"title": "",
"body": ""
}, {
"id": 18,
"url": "https://cfrenzel.com/tags/development/",
"title": "",
"body": ""
}, {
"id": 19,
"url": "https://cfrenzel.com/robots.txt",
"title": "",
"body": " Sitemap: {{ “sitemap. xml” absolute_url }} "
}, {
"id": 20,
"url": "https://cfrenzel.com/augmented_reality_project/",
"title": "Throwback: Prototype of AR Furniture Layout (2009)",
"body": "2020/02/28 - Was going through some old video and found rough demo of a prototype that I built back in 2009. I was experimenting with AR at the time but nothing really came of it; so I thought I’d throw it up here. The prototype uses a webcam under a sheet of glass to track markers on the bottom of blocks. Here I’m experimenting with the layout of some office furniture. "
}, {
"id": 21,
"url": "https://cfrenzel.com/kinect_and_projector_project/",
"title": "Throwback: Projector with Microsoft Kinect (2013)",
"body": "2020/02/27 - Found some more footage that I thought was pretty cool from back in 2013. This uses a microsoft kinect to track people at a party. I used Quartz Composer to build some visuals and projected it realtime on the side of a barn. Some of the visualizations are influenced by the audio, but I never got much going with body tracking. Might have to expand on this one in the future. "
}, {
"id": 22,
"url": "https://cfrenzel.com/learning-from-open-source-part1-mediatr/",
"title": "Learning From Open Source Part1: MediatR",
"body": "2020/01/14 - It can be intimidating and time consuming to explore a mature open source project. Often an attempt to find inspiration results in a surface level understanding of a few components with no real insight into the magic. In this series I hope to find projects of just the right size and complexity to “get in there” and learn something valuable. Let’s start by taking a look at MediatR. I use MediatR in many projects because of its “simple to use” yet powerful implementation of the Mediator Pattern. A mediator sits between method callers and receivers creating a configurable layer of abstraction that determines how callers and receivers get wired up. Let’s look at a quick example of a Controller calling some Application Layer code with MediatR. public class CreateTicketCommand : IRequest<CreateTicketResponse>{ public string Description { get; set; } public string Department { get; set; } public string Severity { get; set; }}public class TicketController: Controller{ private readonly IMediator _mediator; public TicketController(IMediator mediator) { _mediator = mediator; } [HttpPost] public async Task<ActionResult> Create(CreateTicketModel model) { var command = new CreateTicketCommand() { Description = model. Description, Department = model. Department, Severity = model. Severity }; var res = await _mediator. Send(command); return RedirectToAction( Show , new { id = res. TicketId}); }}There are a few things to notice here. The Command defines the type of it’s response IRequest<CreateTicketResponse> The IMediator is injected into the Controller There is a single Send method on the IMediator used to dispatch all command/request types The Controller doesn’t know who is handling the commandHere’s a sample handler for CreateTicketCommand public class CreateTicketHandler : IRequestHandler<CreateTicketCommand, CreateTicketResponse>{ private readonly ApplicationDbContext _db; public CreateTicketHandler(ApplicationDbContext db) => _db = db; public async Task<CreateTicketResponse> Handle(CreateTicketCommand command, CancellationToken cancellationToken) { Ticket ticket = new Ticket(command. Description, command. Department, command. Severity); _db. Tickets. Add(ticket); await _db. SaveChangesAsync(); return new CreateTicketResponse() { TicektId = ticket. Id }; }}Notice: Handler doesn’t know who sent the command Handler specifies the the message type that it handles and the response type IRequestHandler<CreateTicketCommand, CreateTicketResponse> Handler has constructor parameters that must be injected by the callerWe configure MediatR in our app’s startup with a single line services. AddMediatR(typeof(Program));Here’s what I’m thinking I never registered any handlers explicitly; so I know that MediatR is scanning my assembly for handlers. This is pretty common and shouldn’t be much different than something like ASP. NET MVC finding your controllers, but I’d like to look under the hood a little. The call to _mediator. Send(command) stands out as the interesting bit. Somehow this method can take any request type, find a concrete handler implementation for that request type, instantiate it, and call it. Let’s try to uncover the magic behind this! Going to the Source Let’s dig in. First download the source or browse online at https://github. com/jbogard/MediatR/tree/master/src/MediatR > git clone https://github. com/jbogard/MediatR. git . You’ll first notice a handful of simple interfaces and Mediator. cs with the core class. Since we’re curious about it’s Send method let’s take a look inside. The file is surprisingly small, and at first glance it looks like the Send method is actually doing some of the real work. public Mediator(ServiceFactory serviceFactory) { _serviceFactory = serviceFactory; } public Task<TResponse> Send<TResponse>(IRequest<TResponse> request, CancellationToken cancellationToken = default) { if (request == null) { throw new ArgumentNullException(nameof(request)); } var requestType = request. GetType(); var handler = (RequestHandlerWrapper<TResponse>)_requestHandlers. GetOrAdd(requestType, t => Activator. CreateInstance(typeof(RequestHandlerWrapperImpl<,>). MakeGenericType(requestType, typeof(TResponse)))); return handler. Handle(request, cancellationToken, _serviceFactory); }First things first, above I made a call using Send(command), but the send method here is generic Send<TResponse>(IRequest<TResponse> request). It turns out that the compiler can infer the type argument; so you can omit it. Our call above looks much prettier than Send<CreateTicketResponse>(command) (generics methods). Moving on… I’m starting to get excited because the Send method is basically a fat one-liner, yet it appears to be instantiating a handler and calling it (which is all a mediator really does). Let’s dig a little deeper. var handler = (RequestHandlerWrapper<TResponse>)_requestHandlers. GetOrAdd(requestType, t => Activator. CreateInstance(typeof(RequestHandlerWrapperImpl<,>). MakeGenericType(requestType, typeof(TResponse))));The outer _requestHandlers. GetOrAdd is just checking if a handler already exists before creating a new one. The real magic seems to be: Activator. CreateInstance(typeof(RequestHandlerWrapperImpl<,>). MakeGenericType(requestType, typeof(TResponse)))We’re getting close to something. We’re taking a RequestHandlerWrapperImpl<,> calling . MakeGenericType(requestType, typeof(TResponse)) on it then instantiating the result, which is apparently assignable to RequestHandlerWrapper<TResponse>. Let’s plug in our command type above to see what it looks like. typeof(RequestHandlerWrapperImpl<,>). MakeGenericType(typeof(CreateTicketCommand), typeof(CreateTicketResponse))This gives us a RequestHandlerWrapperImpl<CreateTicketCommand,CreateTicketResponse> which is assignable to RequestHandlerWrapper<CreateTicketResponse>. For now let’s think of “RequestHandlerWrapper” as some kind of wrapper around our actual handler (CreateTicketHandler). We know that instantiating our actual handler will require Dependency Injection to resolve the dependencies (like ApplicationDbContext); so perhaps the wrapper is hiding these details. But whats up with the cast from RequestHandlerWrapperImpl down to the less generic RequestHandlerWrapper? Believe it or not, this seemingly benign cast is part of the real magic. The bigger concept at play here is a technique for allowing non-generic code to call into generic code. It’s a little hard to see here because the return type is still generic, but notice how the TRequest goes away when casting RequestHandlerWrapperImpl<TRequest,TResponse> to RequestHandlerWrapper<TResponse>. Lets take a look inside: internal abstract class RequestHandlerWrapper<TResponse> : RequestHandlerBase { public abstract Task<TResponse> Handle(IRequest<TResponse> request, CancellationToken cancellationToken, ServiceFactory serviceFactory); } internal class RequestHandlerWrapperImpl<TRequest, TResponse> : RequestHandlerWrapper<TResponse> where TRequest : IRequest<TResponse> { public override Task<TResponse> Handle(IRequest<TResponse> request, CancellationToken cancellationToken, ServiceFactory serviceFactory) { Task<TResponse> Handler() => GetHandler<IRequestHandler<TRequest, TResponse>>(serviceFactory). Handle((TRequest) request, cancellationToken); return serviceFactory . GetInstances<IPipelineBehavior<TRequest, TResponse>>() . Reverse() . Aggregate((RequestHandlerDelegate<TResponse>) Handler, (next, pipeline) => () => pipeline. Handle((TRequest)request, cancellationToken, next))(); }Cool. So RequestHandlerWrapperImpl<TRequest, TResponse> implements the abstract RequestHandlerWrapper<TResponse>. So we have the generic implementation extending the non-generic (with respect to TRequest). Ultimately, RequestHandlerWrapper<TResponse> is providing a single non-generic handler interface that we can use to make calls into all the generic implementations for each request type. Let’s see how the generic version accomplishes this: public override Task<TResponse> Handle(IRequest<TResponse> request, CancellationToken cancellationToken, ServiceFactory serviceFactory) { Task<TResponse> Handler() => GetHandler<IRequestHandler<TRequest, TResponse>>(serviceFactory). Handle((TRequest) request, cancellationToken); return serviceFactory . GetInstances<IPipelineBehavior<TRequest, TResponse>>() . Reverse() . Aggregate((RequestHandlerDelegate<TResponse>) Handler, (next, pipeline) => () => pipeline. Handle((TRequest)request, cancellationToken, next))(); }MediatR has some cool features around pipelines, but a basic mediator doesn’t need any of that. Let’s focus on how the RequestHandlerWrapperImpl<TRequest, TResponse> does it’s job of calling our CreateTicketHandler with this line: Task<TResponse> Handler() => GetHandler<IRequestHandler<TRequest, TResponse>>(serviceFactory). Handle((TRequest) request, cancellationToken);Let’s break this down First we call GetHandler() on our base RequestHandlerBase class. This should return our actual handler (CreateTicketHandler). We’ll take a look inside a little laterGetHandler<IRequestHandler<TRequest, TResponse>>(serviceFactory) Then we call the . Handle() method on the handler (CreateTicketHandler). We must cast the IRequest<TResponse> to TRequest to complete the bridge from the non-generic to generic. . Handle((TRequest) request, cancellationToken) With our command it would look like this//request is an IRequest<CreateTicketResponse> from the non-generic. Handle((CreateTicketCommand) request, cancellationToken) Now instead of immediately running the Handle() method above, we’re using a lambda to create Task that we can pass around and call laterTask<TResponse> Handler() => At this point awaiting the Handler would wrap up our dispatch to CreateTicketHandler. Let’s back up one step and see how the instantiation of our handler with Dependency Injection went down in RequestHandlerBase. protected static THandler GetHandler<THandler>(ServiceFactory factory) { THandler handler; try { handler = factory. GetInstance<THandler>(); }Interesting, I really expected more code. Let’s take a look at ServiceFactory to see what’s up. public delegate object ServiceFactory(Type serviceType);public static class ServiceFactoryExtensions{ public static T GetInstance<T>(this ServiceFactory factory) => (T) factory(typeof(T)); public static IEnumerable<T> GetInstances<T>(this ServiceFactory factory) => (IEnumerable<T>) factory(typeof(IEnumerable<T>));}Mind Blown! ServiceFactory is just a delegate. As a bonus the method GetInstance<THandler> is an extension method on the delegate. That’s right C# supports extension methods on delegates. Essentially, ServiceFactory is a single method wrapper around our Dependency Injection container. The only burden ServiceFactory puts on the underlying container is to have a method that takes in a Type parameter and returns an instance of that type. Using a couple of extension methods we overlay a nicer generic interface T GetInstance<T> and IEnumerable<T> GetInstances<T>. You don’t see this kind of expressiveness in strongly-typed languages every day. MediatR's support for all the different dependency injection frameworks boils down to a simple delegate. Ironically, if you look into one of the Dependency Injection integrations like MediatR. Extensions. Microsoft. DependencyInjection, it has about as much code for registering all the bells and whistles for handlers as the core of MediatR itself. "
}, {
"id": 23,
"url": "https://cfrenzel.com/domain-events-efcore-mediatr/",
"title": "Simple Domain Events with EFCore and MediatR",
"body": "2020/01/03 - This post relates to the Domain Driven Design (DDD) concept of Domain Events. These events originate in the Domain Model and are broadcast within a Bounded Context. These are not events used directly for integration. For the purpose of this implementation I want to frame things as EFCore entities publishing events that can be handled locally by one or more subscribers within a Unit Of Work. For more information about what Domain Events are/aren’t and what they can be used for, check out Domain Driven Design by Eric Evans and Implementing Domain Driven Design by Vaughn Vernon. Beyond the initial difficulty of understanding what Domain Events are, lies figuring out a way to implement the things. How the heck can you cleanly publish an event from an Entity? How would you wire up listeners, and where in the architecture would the listeners live? Our entities are often in a core assembly that doesn’t have any dependencies. There is no concept of a UnitOfWork/Transaction at this level, and they sure as heck don’t have access to anything interesting like databases or an Application Layer where you might normally think about hydrating other entities and handling events. This post describes a method to allow EFCore entities to publish Domain Events. I’ve seen this technique used a handful of times, but to make this implementation a little more interesting Domain Events will be published as MediatR notifications that can be handled in the Application Layer. In addition, this must be done without the entities taking on any external dependencies. Specifically the entities won’t have a dependency on MediatR. Sound good? Let’s get started! The Entity Side: The entity needs to call “Publish” on something. One of the simplest implementations from the entity’s perspective is just to have the entity inherit from a base class that contains the publish logic. In this implementation the entity won’t actually do the event dispatching, it will just hold a collection of events that a dispatcher will later examine. First let’s define an interface for the Entityusing System;using System. Collections. Concurrent;namespace DomainEventsMediatR. Domain{ public interface IEntity { IProducerConsumerCollection<IDomainEvent> DomainEvents { get; } }} public interface IDomainEvent { } Now a base class implementation for our EFCore entities marking the DomainEvents as [NotMapped] to let EFCore know that they are not to be persisted to the db. We also add a helper for entities to initialize there own Id's. It can be very useful and efficient for entities to have their Id's generated locally on or before instantiation rather than on save or in the database. This allows transient entities to reference eachother by Id, to store Id's in Domain Events, and generally to use Id's in all kinds of eventual consistency scenarios. You can pass the entity itself in the domain event, but remember that it hasn't been persisted yet; so you can't trust the transient Id assigned by EFcore (a new Id will be assigned by the database when persisted). using System;using System. Collections. Concurrent;using System. ComponentModel. DataAnnotations. Schema;namespace DomainEventsMediatR. Domain{ public abstract class Entity : IEntity { [NotMapped] private readonly ConcurrentQueue<IDomainEvent> _domainEvents = new ConcurrentQueue<IDomainEvent>(); [NotMapped] public IProducerConsumerCollection<IDomainEvent> DomainEvents => _domainEvents; protected void PublishEvent(IDomainEvent @event) { _domainEvents. Enqueue(@event); } protected Guid NewIdGuid() { return MassTransit. NewId. NextGuid(); } }} Now a Domain Event: BacklogItemCommitted and an entity: BacklogItem that publishes the event when it is commited to a Sprintnamespace DomainEventsMediatR. Domain{ public class BacklogItemCommitted : IDomainEvent { public Guid BacklogItemId { get; } public Guid SprintId { get; set; } public DateTime CreatedAtUtc { get; } private BacklogItemCommitted() { } public BacklogItemCommitted(BacklogItem b, Sprint s) { this. BacklogItemId = b. Id; this. CreatedAtUtc = b. CreatedAtUtc; this. SprintId = s. Id; } }}using System;using System. ComponentModel. DataAnnotations;namespace DomainEventsMediatR. Domain{ public class BacklogItem : Entity { public Guid Id { get; private set; } [MaxLength(255)] public string Description { get; private set; } public virtual Sprint Sprint { get; private set; } public DateTime CreatedAtUtc { get; private set; } = DateTime. UtcNow; private BacklogItem() { } public BacklogItem(string desc) { this. Id = NewIdGuid(); this. Description = desc; } public void CommitTo(Sprint s) { this. Sprint = s; this. PublishEvent(new BacklogItemCommitted(this, s)); } }} The real magic with this technique is how the Domain Events are dispatched. Currently they’re just sitting in the Entity. We’ll use some hooks in our DbContext to dispatch them, but first let’s define an interface for the dispatcherusing System. Threading. Tasks;namespace DomainEventsMediatR. Domain{ public interface IDomainEventDispatcher { Task Dispatch(IDomainEvent devent); }} Now we can configure the dispatcher to be injected into our DbContext constructor public class ApplicationDbContext : DbContext { private readonly IDomainEventDispatcher _dispatcher; public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options, IDomainEventDispatcher dispatcher) : base(options) { _dispatcher = dispatcher; } We can hook into EFCore and dispatch Domain Events before entities are persisted by overriding SaveChangespublic override int SaveChanges(){ _preSaveChanges(). GetAwaiter(). GetResult(); var res = base. SaveChanges(); return res;}public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken)){ await _preSaveChanges(); var res = await base. SaveChangesAsync(cancellationToken); return res;}private async Task _preSaveChanges(){ await _dispatchDomainEvents();}private async Task _dispatchDomainEvents(){ var domainEventEntities = ChangeTracker. Entries<IEntity>() . Select(po => po. Entity) . Where(po => po. DomainEvents. Any()) . ToArray(); foreach (var entity in domainEventEntities) { IDomainEvent dev; while (entity. DomainEvents. TryTake(out dev)) await _dispatcher. Dispatch(dev); }}The Dispatcher: We need an implementation of IDomainEventDispatcher that will publish the Domain Event as a MediatR notification. We’ll implement this in our Application Layer. We do have to deal with the small issue of our Domain Event not being a valid MediatR INotification. We’ll overcome this by creating a generic INotification to wrap our Domain Event. Create a custom generic INotification. using System;using MediatR;using DomainEventsMediatR. Domain;namespace DomainEventsMediatR. Application{ public class DomainEventNotification<TDomainEvent> : INotification where TDomainEvent : IDomainEvent { public TDomainEvent DomainEvent { get; } public DomainEventNotification(TDomainEvent domainEvent) { DomainEvent = domainEvent; } }} Create a Dispatcher that wraps Domain Events in MediatR notificatoins and publishes themusing System;using System. Threading. Tasks;using Microsoft. Extensions. Logging;using MediatR;using DomainEventsMediatR. Domain;namespace DomainEventsMediatR. Application{ public class MediatrDomainEventDispatcher : IDomainEventDispatcher { private readonly IMediator _mediator; private readonly ILogger<MediatrDomainEventDispatcher> _log; public MediatrDomainEventDispatcher(IMediator mediator, ILogger<MediatrDomainEventDispatcher> log) { _mediator = mediator; _log = log; } public async Task Dispatch(IDomainEvent devent) { var domainEventNotification = _createDomainEventNotification(devent); _log. LogDebug( Dispatching Domain Event as MediatR notification. EventType: {eventType} , devent. GetType()); await _mediator. Publish(domainEventNotification); } private INotification _createDomainEventNotification(IDomainEvent domainEvent) { var genericDispatcherType = typeof(DomainEventNotification<>). MakeGenericType(domainEvent. GetType()); return (INotification)Activator. CreateInstance(genericDispatcherType, domainEvent); } }} Create a handler for the BacklogItemCommitted Domain Eventusing System;using System. Threading;using System. Threading. Tasks;using Microsoft. Extensions. Logging;using MediatR;using DomainEventsMediatR. Domain;using DomainEventsMediatR. Persistence;namespace DomainEventsMediatR. Application{ public class OnBacklogItemCommitted { public class Handler : INotificationHandler<DomainEventNotification<BacklogItemCommitted>> { private readonly ApplicationDbContext _db; private readonly ILogger<Handler> _log; public Handler(ApplicationDbContext db, ILogger<Handler> log) { _db = db; _log = log; } public Task Handle(DomainEventNotification<BacklogItemCommitted> notification, CancellationToken cancellationToken) { var domainEvent = notification. DomainEvent; try { _log. LogDebug( Handling Domain Event. BacklogItemId: {itemId} Type: {type} , domainEvent. BacklogItemId, notification. GetType()); //from here you could // - create/modify entities within the same transaction as the backlogItem commit // - trigger the publishing of an integration event on a servicebus (don't write it directly though, you need an outbox scoped to this transaction) //Remember NOT to call SaveChanges on dbcontext if making db changes when handling DomainEvents return Task. CompletedTask; } catch (Exception exc) { _log. LogError(exc, Error handling domain event {domainEvent} , domainEvent. GetType()); throw; } } } }} Now we just need to configure dependency injection in our application and we’re done services. AddTransient<IDomainEventDispatcher, MediatrDomainEventDispatcher>(); services. AddMediatR(typeof(MediatrDomainEventDispatcher). GetTypeInfo(). Assembly);You can find the full source code for this post at https://github. com/cfrenzel/DomainEventsWithMediatR "
}, {
"id": 24,
"url": "https://cfrenzel.com/dotnet-new-templating-nuget/",
"title": "Quickly Create Your Own .NET Code Templates and Use Them From Anywhere",
"body": "2019/12/20 - Whether you need to throw together a quick console app or scaffold an enterprise solution, it can be a real time suck just creating, naming and referencing projects. Setting up boilerplate logging, dependency injection, data access, messaging, gulp and other tools can send you hunting through previous work to copy and paste code. Let’s put an end to all that once and for all with less than an hour of work using dotnet new templating! The advantages of this approach include: - Use a tool that's already on any development machine - No new templating language to learn- Use runnable Solution/Project/Files as templates- Bundle many templates into a single distributable package- Access templates from any machine with a single commandLet's get started:: Our goal is to be able to easily create and distribute custom templates to any machine; so let’s first take a look at what templates already exist on our machine: > dotnet new -lTemplates Short Name Language Tags----------------------------------------------------------------------------------------------------------------------------------Console Application console [C#], F#, VB Common/ConsoleClass library classlib [C#], F#, VB Common/LibraryYou should see a list of templates longer but similar to above. Our custom templates will show up in this list when we’re done. To create a new project from the template named console in the list above we can type: > dotnet new console -n SampleFromTemplateThis will create a new folder with a console app named SampleFromTemplate. It’s ready to go with nuget packages restored and the namespaces set to SampleFromTemplate. SampleFromTemplate └─── SampleFromTemplate. csproj └─── Program. cs └─── /objTo begin creating custom templates with dotnet new simply create a normal project or solution (or just one or more files) that represents your boilerplate code for a given scenario. That’s almost all there is to it. Adding a configuration file to setup some metadata and behavior will result in a resuable template. The template folder structure for a simple console app project will look something like this: └───mycustomtemplate └─── Templating. ConsoleApp. csproj └─── Program. cs └─── /. template_config └─── template. json Start with any existing project and from the project root folder> mkdir . template_config You have control over whether the generated output of your template is placed in a new folder or just dumped in the output location. If you want everything inside a folder then include the folder at the top level of the template beside the . template_config folder. Otherwise you can leave it up to the user to specify on the command line using the -o option. If you want to create empty folders inside your template such as /src /test /doc /build /migrations. For now you will need to place a file named -. - inside the folder otherwise the empty folder will be ignored in the output Add a template. json to the . template_config folder{ $schema : http://json. schemastore. org/template , author : Camron Frenzel , classifications : [ cfrenzel , core , console ], tags : { language : C# }, identity : demo. console , name : demo. console_2. 2 , shortName : dm-console-2. 2 , sourceName : Templating , sources : [ { modifiers : [ { exclude : [ . vs/** , . template_config/** ] } ] } ],} identity a unique name for the template name for display purposes shortName what users will type to specify your template sources -> exclude: This is a little trick to keep some unwanted files out of the template sourceName the name in the source tree to replace with the user specified name (using -n or --name). sourceName is important!. dotnet new will replace all the folders/files/namespaces/etc. . containing this name with whatever the user passes in on the command line. For example: If I’m using a convention such as └─── Templating. sln └─── /src └─── /Templating. ConsoleApp └─── Templating. ConsoleApp. csproj └─── /Templating. Domain └─── Templating. Domain. csproj └─── /Templating. Application └─── Templating. Application. csproj Then passing in -n Demo will produce: > dotnet new demo. console_2. 2 -n Demo └─── Demo. sln └─── /src └─── /Demo. ConsoleApp └─── Demo. ConsoleApp. csproj └─── /Demo. Domain └─── Demo. Domain. csproj └─── /Demo. Application └─── Demo. Application. csproj namespaces: Templating. ConsoleApp -> Demo. ConsoleApp At this point you should be comfortable with these concepts a template is a normal solution/project/file add a . template_config folder with a template. config file in it to configure a template the user will pass in a –name MyApp to the template that will replace the configured sourceName text in all folders/solutions/projects/namespaces Tip! To have nuget restore automatically - add this to your template. config symbols : { skipRestore : { type : parameter , datatype : bool , description : If specified, skips the automatic restore of the project on create. , defaultValue : false } }, postActions : [ { condition : (!skipRestore) , description : Restore NuGet packages required by this project. , manualInstructions : [ { text : Run 'dotnet restore' } ], actionId : 210D431B-A78B-4D2F-B762-4ED3E3EA9025 , continueOnError : true } ] Issue! If your template creates one or more projects, often you would like the generated projects to be automatically added to an existing solution. This is supported, but I haven't had any luck with it. The essence of the problem seems to be a bug rendering the output project path/name. primaryOutputs : [ { path : SolutionName. ConsoleApp/SolutionName. ConsoleApp. csproj } ], postActions : [ { description : Add project to solution , manualInstructions : [], primaryOutputIndexes : 0 , actionId : D396686C-DE0E-4DE6-906D-291CD29FC5DE , continueOnError : true } ] https://github. com/dotnet/templating/issues/1489If you haven’t created your own template at this point you can follow along by downloading a console app template with logging/DI/configuration here Installing a template: We could install our template locally from the template root folder. dotnet new -i . List the installed templates and you should see your template listed dotnet new -lYou can use it by passing in it’s shortName and provide a name > dotnet new {shortname} -n DemoAppTo remove your template dotnet new -uYou should see your template along with an Uninstall command:. This command will come in handy as things can get confusing when managing multiple versions of your templates and installing them from different sources. dotnet new -u C:\temptemplate\temptemplateNot bad, but the workflow leaves a lot to be desired. It would be a pain to manage even a modest number of templates using this method. Packaging templates: The dotnet new templating tool supports installing templates from nuget packages locally or in remote repositories. Multiple templates can be included in a single package, which allows adding and removing collections of templates from the internet with a single command. Packaging templates took some tinkering for me; so let’s get straight to what works by creating a special project that will help us get all of our templates into a single package. The structure of our multi-template solution will look like this: └─── /my-dotnet-templates └─── my-dotnet-templates. sln └─── /templates └─── Directory. Build. props //metadata for package └─── templates. csproj └─── /ConsoleApp //template 1 └─── Templating. sln └─── /. template_config └───template. json └─── /Templating. ConsoleApp └─── Templating. ConsoleApp. csproj └─── /WebApp //template 2 └─── Templating. sln └─── /. template_config └───template. json └─── /Templating. WebbApp └─── Templating. WebApp. csproj The idea is that you have a solution with a /templates folder and a special project: template. csproj that will aid in building the multi-template package. Within the /templates folder you will have a folder for each template. The folder for each template should contain everything you need to develop and test the template. You won’t be able to run the template from our special templates. csproj so it’s nice to have a seperate solution for running/editing each template. You can start by creating templates. csproj as a console app. Open the . csproj file and edit it to look like this:<Project Sdk= Microsoft. NET. Sdk > <PropertyGroup> <PackageType>Template</PackageType> <TargetFramework>netcoreapp2. 2</TargetFramework> <PackageId>cfrenzel-dotnet-new-templates-2. 2</PackageId> <Title>cfrenzel dotnet-new-templates</Title> <IncludeContentInPack>true</IncludeContentInPack> <IncludeBuildOutput>false</IncludeBuildOutput> <ContentTargetFolders>content</ContentTargetFolders> </PropertyGroup> <ItemGroup> <Content Include= ConsoleApp\** Exclude= ConsoleApp\SolutionName. sln;ConsoleApp\**\bin\**;ConsoleApp\**\obj\**;ConsoleApp\**\. vs\** /> <Content Include= EFCore. MigrationProjects\** Exclude= EFCore. MigrationProjects\**\bin\**;EFCore. MigrationProjects\**\obj\**;EFCore. MigrationProjects\**\. vs\** /> <Content Include= Solution\** Exclude= Solution\**\bin\**;Solution\**\obj\**;Solution\**\. vs\** /> <Compile Remove= **\* /> </ItemGroup></Project> <PackageType>Template</PackageType> - set special package type for project For each template in our package we are adding a <Content> tag that specifies which files to include and exclude <Content Include= ConsoleApp\** - include everything from our /ConsoleApp folder Exclude= ConsoleApp\Templating. sln;ConsoleApp\**\bin\**;ConsoleApp\**\obj\**;ConsoleApp\**\. vs\** /> - exclude the solution file and bin/obj folders <Compile Remove= **\* /> - we’re not interested in the output of the compiled project We can specify metadata for the package in Directory. Build. props<Project> <PropertyGroup> <Authors>Camron Frenzel</Authors> <RepositoryUrl>https://github. com/cfrenzel/dotnet-new-templates-2. 2. git</RepositoryUrl> <PackageProjectUrl>https://github. com/cfrenzel/dotnet-new-templates-2. 2</PackageProjectUrl> <Description>dotnet new templates for core 2. 2</Description> <PackageTags>template dotnet console migration web</PackageTags> <PackageLicense></PackageLicense> <Version>1. 0. 0</Version> </PropertyGroup></Project> Now we can create our nuget package using templates. csprojdotnet pack . \templates\templates. csproj -o . \artifacts\ --no-buildAnd install all of our templates locally from our . nupkg file dotnet new -i . \artifacts\cfrenzel-dotnet-new-templates-2. 2. 1. 0. 0Find the Uninstall command: to remove dotnet new -uPublish package for access online: You can host your template . nupkg for free using my MyGet or make it official/perminent using NuGet. org. This can be as simple as typing dotnet nuget push artifacts\**\*. nupkg -s https://www. myget. org/F/{youraccount}/api/v2/package -k {yourkey}Then installing your templates from anywhere using dotnet new --install {yourpackagename} --nuget-source https://www. myget. org/F/{youraccount}/api/v3/index. json If you publish it to nuget. org you don't even have to specify the package url! dotnet new --install {yourpackagename}-Since we’re pretty much one configuration file away from free continuous build and deployment, let’s setup AppVeyor to build and publish our template package every time we commit a change to the source code. Save you code to Github or wherever Add an appveyor. yml to build and publish template package to MyGetversion: '1. {build}'image: Visual Studio 2019environment: MyGetApiKey: secure: 56nW3KcP4naYX9mlsVEIKLj5xPdfmpt6lMALR6wQmorRQOaoUOtlwMZ2V0BtGTAM NugetApiKey: secure: /54XAunyBETRa1Fp/qSrwvebSnTAcHDO2OVZ+exMtQtOtrBzHKvp4RC1AB8RD2PQpull_requests: do_not_increment_build_number: truebranches: only: - masternuget: disable_publish_on_pr: truetest: offbuild_script: - dotnet restore - dotnet pack . \templates\templates. csproj -o . \artifacts\ --no-builddeploy_script: - ps: dotnet nuget push artifacts\**\*. nupkg -s https://www. myget. org/F/cfrenzel-ci/api/v2/package -k $env:MyGetApiKey After you link your AppVeyor project to your source repo, your template . nupkg will be updated in MyGet/Nuget every time you commit to master. Final Thoughts: Though templating with dotnet new has some more powerful features including: conditional logic custom parameters post actions multi-language see docs - template. jsonI really appreciate the simplicity of the tool. You simply use what you’re already doing to make doing what you’re already doing faster. No need to learn a new complex template language. full source code for this post. "
}, {
"id": 25,
"url": "https://cfrenzel.com/publishing-nuget-nuke-appveyor/",
"title": "Publishing .NET Core NuGet Packages with Nuke and AppVeyor",
"body": "2019/12/17 - This article builds on concepts discussed by Andrew Lock, Jimmy Bogard and Georg Dangl. Here we’re going use Nuke to make build, packaging and publishing even nicer!!! I’ve been eking out build solutions using various Powershell based tools for years. They serve their purpose, but I always dread getting familiar with the scripts again when I need to make a change. I recently used Nuke on a project and for the first time I feel like I didn’t waste any time fighting with it. Nuke creates a CSharp Console App within your solution containing a simple Build. cs file that can handle a variety of common build/deployment tasks out of the box. The real joy is that you can now author and debug platform independent build scripts in C# within your favorite IDE! Let’s jump in. Using Nuke to Build: Install Nuke> dotnet tool install Nuke. GlobalTool --global Add Nuke to your solution - let the wizard get you started> nuke :setup Warning: For me the Nuke build project defaulted to . NET Core 3. 0. This isn't necessarily a problem, but it's worth noting. This was true when buidling an app on . NET Core 2. 2; so it's a bit odd for my build environment to require . Net Core 3. 0 TODO:/// Figure out Nuke's logic for framework selection and see if it's configurable You’ll notice a new project in your solution named _build. Take note of a few files Build. cs - a fluent “make style” build Class in C# Defines targets and their dependencies Two scripts used to run builds. These scripts will install dotnet if it doesn’t exist and then call your build application. Choose one based on your build environment. build. ps1 - a powershell script used to execute builds (platform independent - must have powershell installed) build. sh - a shell script version (linux/osx/etc. . ) Now compile your code> . \build. ps1 Compile Success! I’ll admit that compiling a project isn’t that impressive, but we’re now scripting in C#. Let’s take it a step further and make a NuGet package. Add a Pack step to our build scriptTarget Pack => _ => _ . DependsOn(Compile) . Executes(() => { DotNetPack(s => s . SetProject(Solution. GetProject( Nuke. Sample )) . SetConfiguration(Configuration) . EnableNoBuild() . EnableNoRestore() . SetDescription( Sample package produced by NUKE ) . SetPackageTags( nuke demonstration c# library ) . SetNoDependencies(true) . SetOutputDirectory(ArtifactsDirectory / nuget )); });We want our NuGet package to specify an author, repository, homepage, etc… We could do this programatically from Nuke Target Pack => _ => _ . DependsOn(Compile) . Executes(() => { DotNetPack(s => s *** . SetAuthors( Your Name ) . SetPackageProjectUrl( https://github. com/yourrepo/NukeSample ) *** }); But it’s simpler to add a Directory. Build. props to your solution folder <Project> <PropertyGroup> <Authors>Your Name</Authors> <RepositoryUrl>https://github. com/yourrepo/NukeSample</RepositoryUrl> <PackageProjectUrl>https://github. com/yourrepo/NukeSample</PackageProjectUrl> <PackageLicense>https://github. com/yourrepo/NukeSample/blob/master/LICENSE</PackageLicense> </PropertyGroup></Project> Now call our new Pack target> . \build. ps1 PackNow we’ve got our nuget package: artifacts\nuget\Nuke. Sample. 1. 0. 0. nupkg. If we unzip the . nupkg file we can take a look inside at our Nuke. Sample. nuspec file. <?xml version= 1. 0 encoding= utf-8 ?><package xmlns= http://schemas. microsoft. com/packaging/2012/06/nuspec. xsd > <metadata> <id>Nuke. Sample</id> <version>1. 0. 0</version> <authors>Your Name</authors> <owners>Your Name</owners> <requireLicenseAcceptance>false</requireLicenseAcceptance> <projectUrl>https://github. com/yourrepo/NukeSample</projectUrl> <description>Sample package produced by NUKE</description> <tags>nuke demonstration c# library</tags> <repository url= https://github. com/yourrepo/NukeSample /> <dependencies> <group targetFramework= . NETStandard2. 0 /> </dependencies> </metadata></package>Success! Not bad for a few minutes of our time. Before we move on let’s touch on versioning. If you have an approach that you love, it shouldn’t be hard to work it into our current workflow with Nuke. Here we’ll consider a manual option and using the popular GitVersion tool. Manual Versioning Let’s add add a couple of lines to our Directory. Build. props. <Project> <PropertyGroup> --- <VersionPrefix>0. 1. 1</VersionPrefix> <VersionSuffix>alpha</VersionSuffix> </PropertyGroup></Project> Now let’s call our Pack target again> . \build. ps1 PackOur package name reflects the new version: artifacts\nuget\Nuke. Sample. 0. 1. 1-alpha. nupkg. If we unzip and look inside Nuke. Sample. nuspec we can see the updated version. <?xml version= 1. 0 encoding= utf-8 ?><package xmlns= http://schemas. microsoft. com/packaging/2012/06/nuspec. xsd > <metadata> <id>Nuke. Sample</id> <version>0. 1. 1-alpha</version>Versioning with GitVersion toolNuke has great integration with the GitVersion tool. You’ll need to read the docs to fully understand how GitVersion determines the current version name for a branch, but to use - simply: Add these 2 properties to your Build. cs class [GitRepository] readonly GitRepository GitRepository; [GitVersion] readonly GitVersion GitVersion; Add the . SetVersion(GitVersion. NuGetVersionV2) to your Pack Target DotNetPack(s => s --- . SetVersion(GitVersion. NuGetVersionV2) . SetNoDependencies(true) . SetOutputDirectory(ArtifactsDirectory / nuget )); Now GitVersion will work it’s magic to determine the current version name! Publishing to a NuGet Repository with NukeNow that we have our source compiling and our package versioned and waiting in our artifacts folder, lets use Nuke to push it to a repository where it can be used by others. In order to make this as flexible as possible, we’ll pass the nuget repository’s url and auth_key as parameters to the Nuke build script. Inside the script Nuke makes it easy for us to Require that it’s a Release build Require that the url and auth_key have been set Get values from commandline / environment using c# fields Add 2 Fields to to your Build file with the [Parameter] attribute [Parameter] string NugetApiUrl = https://api. nuget. org/v3/index. json ; //default [Parameter] string NugetApiKey; Add a Push Target to your Build file Target Push => _ => _ . DependsOn(Pack) . Requires(() => NugetApiUrl) . Requires(() => NugetApiKey) . Requires(() => Configuration. Equals(Configuration. Release)) . Executes(() => { GlobFiles(NugetDirectory, *. nupkg ) . NotEmpty() . Where(x => !x. EndsWith( symbols. nupkg )) . ForEach(x => { DotNetNuGetPush(s => s . SetTargetPath(x) . SetSource(NugetApiUrl) . SetApiKey(NugetApiKey) ); }); }); Push to a NuGet repository> . /build. ps1 Push --NugetApiUrl https://api. nuget. org/v3/index. json --NugetApiKey yoursecretkey Using AppVeyor for Continuous Integration and Deployment: AppVeyor is a CI/CD tool with good support for windows/dotnet (and linux). For open source projects you can setup a free account to build and deploy every time you publish changes to source control. Here we’re going to use GitHub, but you could configure something similar with Azure DevOps We’re going to build a popular workflow as described by Andrew Lock and Jimmy Bogard. It uses two seperate nuget repositories to publish under different conditions: Build all commits on master branch and publish to MyGet. org Useful for reviewing and testing packages before releasing to the world Nightly/experimental builds If a commit is tagged we want to build and publish to NuGet. org Allows us to use git tags to control versioning and our intent to publish to the world Build-only for pull request We don’t want to publish a nuget package on pull requests, but we will confirm that the pull request builds We can accomplish all of this with a simple appveyor. yml file. Add appveyor. yml to our root folderversion: '{build}'image: Ubuntuenvironment:MyGetApiKey: secure: 56nW3KcP4naYX9mlsVEIKLj5xPdfmpt6lMALR6wQmorRQOaoUOtlwMZ2V0BtGTAMNugetApiKey: secure: /54XAunyBETRa1Fp/qSrwvebSnTAcHDO2OVZ+exMtQtOtrBzHKvp4RC1AB8RD2PQpull_requests:do_not_increment_build_number: truebranches:only:- masternuget:disable_publish_on_pr: truebuild_script:- ps: . /build. ps1test: offdeploy_script:- ps: . /build. ps1 Pack- ps: . /build. ps1 Push --NugetApiUrl https://www. myget. org/F/cfrenzel-ci/api/v2/package --NugetApiKey $env:MyGetApiKey- ps: | if ($env:APPVEYOR_REPO_TAG -eq true ){ . /build. ps1 Push --NugetApiUrl https://api. nuget. org/v3/index. json --NugetApiKey $env:NugetApiKey }There are a couple of important bits here build_script: - ps: . /build. ps1This tells appveyor to call our Nuke build script during the build phase deploy_script: - ps: . /build. ps1 Pack - ps: . /build. ps1 Push --NugetApiUrl https://www. myget. org/F/cfrenzel-ci/api/v2/package --NugetApiKey $env:MyGetApiKey - ps: | if ($env:APPVEYOR_REPO_TAG -eq true ){ . /build. ps1 Push --NugetApiUrl https://api. nuget. org/v3/index. json --NugetApiKey $env:NugetApiKey }This tells appveyor to run a series of powershell commands during the Deploy phase. We call Pack to create the nuget package. Then we Push it to MyGet. org using secure environment variables that we declared earlier Then we check an appveyor environement variable APPVEYOR_REPO_TAG to see if the branch has a tag If it does we Push to NuGet. OrgFor a full working example with multiple nuget packages in a single solution checkout out my repo: https://github. com/cfrenzel/Eventfully/blob/master/build/Build. cshttps://github. com/cfrenzel/Eventfully/blob/master/appveyor. ymlhttps://github. com/cfrenzel/Eventfully "
}];
var idx = lunr(function () {
this.ref('id')
this.field('title')
this.field('body')
documents.forEach(function (doc) {
this.add(doc)
}, this)
});
function lunr_search(term) {
$('#lunrsearchresults').show( 1000 );
$( "body" ).addClass( "modal-open" );
document.getElementById('lunrsearchresults').innerHTML = '<div id="resultsmodal" class="modal fade show d-block" tabindex="-1" role="dialog" aria-labelledby="resultsmodal"> <div class="modal-dialog shadow-lg" role="document"> <div class="modal-content"> <div class="modal-header" id="modtit"> <button type="button" class="close" id="btnx" data-dismiss="modal" aria-label="Close"> × </button> </div> <div class="modal-body"> <ul class="mb-0"> </ul> </div> <div class="modal-footer"><button id="btnx" type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">Close</button></div></div> </div></div>';
if(term) {
document.getElementById('modtit').innerHTML = "<h5 class='modal-title'>Search results for '" + term + "'</h5>" + document.getElementById('modtit').innerHTML;
//put results on the screen.
var results = idx.search(term);
if(results.length>0){
//console.log(idx.search(term));
//if results
for (var i = 0; i < results.length; i++) {
// more statements
var ref = results[i]['ref'];
var url = documents[ref]['url'];
var title = documents[ref]['title'];
var body = documents[ref]['body'].substring(0,160)+'...';
document.querySelectorAll('#lunrsearchresults ul')[0].innerHTML = document.querySelectorAll('#lunrsearchresults ul')[0].innerHTML + "<li class='lunrsearchresult'><a href='" + url + "'><span class='title'>" + title + "</span><br /><small><span class='body'>"+ body +"</span><br /><span class='url'>"+ url +"</span></small></a></li>";
}
} else {
document.querySelectorAll('#lunrsearchresults ul')[0].innerHTML = "<li class='lunrsearchresult'>Sorry, no results found. Close & try a different search!</li>";
}
}
return false;
}
</script>
<style>
.lunrsearchresult .title {color: #d9230f;}
.lunrsearchresult .url {color: silver;}
.lunrsearchresult a {display: block; color: #777;}
.lunrsearchresult a:hover, .lunrsearchresult a:focus {text-decoration: none;}
.lunrsearchresult a:hover .title {text-decoration: underline;}
</style>
<form class="bd-search hidden-sm-down" onSubmit="return lunr_search(document.getElementById('lunrsearch').value);">
<input type="text" class="form-control text-small" id="lunrsearch" name="q" value="" placeholder="Type keyword and enter...">
</form>
</li>
</ul>
</div>
<!-- <a class="feed d-none d-lg-inline" href="/feed.xml"><i class="fas fa-rss-square"></i></a> -->
<a class="feed d-none d-lg-inline" href="http://feeds.feedburner.com/cfrenzel"><i class="fas fa-rss-square"></i></a> </div>
</nav>
<!-- Search Results -->
<div id="lunrsearchresults">
<ul class="mb-0"></ul>
</div>
<!-- Content -->
<main role="main" class="site-content">
<div class="container remove-site-content-margin">
<div class="row">
<div class=splash-bg style="height:70px; width:100%;margin-bottom: 42px;"></div>
</div>
</div>
<!--endif page url is / -->
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<h2 class="books bg-highlight" style="font-size:1.8rem; display:inline-block;margin-bottom: 32px;">Reading List</h2>
<br/>
<div class="mb-5 d-flex justify-content-between main-loop-card">
<div id="the-visual-mba" class="pr-3">
<h4 class="mb-1 font-italic">
The Visual MBA
</h4>
<span class="mb-1 text-muted">Two Years of Business School Packed into One Priceless Book of Pure Awesomeness</span><br/>
<strong>Jason Barron</strong><br/>
<a href="https://www.thevisualmbabook.com/">https://www.thevisualmbabook.com/</a><br/>
<blockquote class="styled text-muted">
<p>I love reading business books, but for me the concepts fade pretty quickly while switching betweens roles. This book provides simple and meaningful visuals to help burn the basics of business school into your mind.</p>
</blockquote>
<!-- <small class="d-block text-muted">
</small> -->
<small class="text-muted">
Dec 13, 2019
</small>
</div>
<div class="col-md-3 pr-0 text-right">
<a href="https://www.thevisualmbabook.com/">
<img class="w-100" src="/assets/images/book_the-visual-mba-book-cover.jpg" alt="The Visual MBA">
</a>
</div>
</div>
<div class="mb-5 d-flex justify-content-between main-loop-card">
<div id="algorithms-to-live-by" class="pr-3">
<h4 class="mb-1 font-italic">
Algorithms To Live By
</h4>
<span class="mb-1 text-muted">The Computer Science of Human Decisions</span><br/>
<strong>Brian Christian</strong><br/>
<a href="https://brianchristian.org/algorithms-to-live-by/">https://brianchristian.org/algorithms-to-live-by/</a><br/>
<a class="audiobook" href="https://www.audible.com/pd/Algorithms-to-Live-By-Audiobook/B01D24NLWO"><i class="fab fa-audible"></i>audible.com</a>
<blockquote class="styled text-muted">
<p>A surprisingly fun read with no prior geekiness required. If the hidden patterns behind the age that we marry or why the increase in superhero movie sequels is foreshadowing the end of an era sounds exciting to you, check it out.</p>
</blockquote>
<!-- <small class="d-block text-muted">
</small> -->
<small class="text-muted">
Dec 12, 2019
</small>
</div>
<div class="col-md-3 pr-0 text-right">
<a href="https://brianchristian.org/algorithms-to-live-by/">
<img class="w-100" src="/assets/images/book_Algorithms-to-Live-By-Hardcover-Front-Cover.png" alt="Algorithms To Live By">
</a>
</div>
</div>
<div class="mb-5 d-flex justify-content-between main-loop-card">
<div id="designing-data-intensive-applications" class="pr-3">
<h4 class="mb-1 font-italic">
Designing Data-Intensive Applications
</h4>
<span class="mb-1 text-muted">The Big Ideas Behind Reliable, Scalable, and Maintainable Systems</span><br/>
<strong>Martin Kleppmann</strong><br/>
<a href="http://dataintensive.net/">http://dataintensive.net/</a><br/>
<blockquote class="styled text-muted">
<p>I love the style of this book. It’s broad in scope, but it tries to build understanding on first principles. Whether you consider your work “intensive” or not, if your working with data/databases this book is full of useful concepts. Also checkout <a href="https://martin.kleppmann.com/">Martin’s Blog</a>. It’s a great resource for distributed system concepts.</p>
</blockquote>
<!-- <small class="d-block text-muted">
</small> -->
<small class="text-muted">
Dec 01, 2019
</small>
</div>
<div class="col-md-3 pr-0 text-right">
<a href="http://dataintensive.net/">
<img class="w-100" src="/assets/images/book-data-intensive.png" alt="Designing Data-Intensive Applications">
</a>
</div>
</div>
<div class="mb-5 d-flex justify-content-between main-loop-card">
<div id="pentesting-azure-applications" class="pr-3">
<h4 class="mb-1 font-italic">
Pentesting Azure Applications
</h4>
<span class="mb-1 text-muted">The Definitive Guide to Testing and Securing Deployments</span><br/>
<strong>Matt Burrough</strong><br/>
<a href="https://nostarch.com/azure">https://nostarch.com/azure</a><br/>
<blockquote class="styled text-muted">
<p>Get started securing your azure resources with no former security expertise required. This book is full of actionable practices and tools that you can put into place right now.</p>
</blockquote>
<!-- <small class="d-block text-muted">
</small> -->
<small class="text-muted">
Aug 24, 2019
</small>
</div>
<div class="col-md-3 pr-0 text-right">
<a href="https://nostarch.com/azure">
<img class="w-100" src="/assets/images/book_azure-pen-testing.png" alt="Pentesting Azure Applications">
</a>
</div>
</div>
<div class="mb-5 d-flex justify-content-between main-loop-card">
<div id="why-we-sleep" class="pr-3">
<h4 class="mb-1 font-italic">
Why We Sleep
</h4>
<span class="mb-1 text-muted">Unlocking the Power of Sleep and Dreams</span><br/>
<strong>Matthew Walker</strong><br/>
<a href="https://www.simonandschuster.com/books/Why-We-Sleep/Matthew-Walker/9781501144325">https://www.simonandschuster.com/books/Why-We-Sleep/Matthew-Walker/9781501144325</a><br/>
<a class="audiobook" href="https://www.audible.com/pd/Why-We-Sleep-Audiobook/B0752ZQR33"><i class="fab fa-audible"></i>audible.com</a>
<blockquote class="styled text-muted">
<p>An accessible dive into the current state of sleep science that will have you making changes immediately. You’ll never think of sleep the same way again.</p>
</blockquote>
<!-- <small class="d-block text-muted">
</small> -->
<small class="text-muted">
Feb 27, 2019
</small>
</div>
<div class="col-md-3 pr-0 text-right">
<a href="https://www.simonandschuster.com/books/Why-We-Sleep/Matthew-Walker/9781501144325">
<img class="w-100" src="/assets/images/book_why-we-sleep-cover.jpg" alt="Why We Sleep">
</a>
</div>
</div>
<div class="mb-5 d-flex justify-content-between main-loop-card">
<div id="real-life-bpmn" class="pr-3">
<h4 class="mb-1 font-italic">
Real-Life BPMN
</h4>
<strong>Jakob Freund, Bernd Rücker</strong><br/>
<a href="https://www.amazon.com/Real-Life-BPMN-4th-introduction-DMN/dp/1086302095">https://www.amazon.com/Real-Life-BPMN-4th-introduction-DMN/dp/1086302095</a><br/>
<blockquote class="styled text-muted">
<p>This book helped me greatly while I was searching for a clean notation for communicating workflows within dev teams, operational teams, and with execs. The authors provide an opinionated guide to which parts of BPMN are useful as well as a style that you can adopt from day 1. Having a single notation that I could use to capture a strategic and operational model was key. It’s also a natural fit with message-based systems. The authors also provide some great <a href="https://camunda.com/products/modeler/">free tools</a> for building models.</p>
</blockquote>
<!-- <small class="d-block text-muted">
</small> -->
<small class="text-muted">
Dec 01, 2017
</small>
</div>
<div class="col-md-3 pr-0 text-right">
<a href="https://www.amazon.com/Real-Life-BPMN-4th-introduction-DMN/dp/1086302095">
<img class="w-100" src="/assets/images/book-real-life-bpmn.jpeg" alt="Real-Life BPMN">
</a>
</div>
</div>
<div class="mb-5 d-flex justify-content-between main-loop-card">
<div id="data-science-for-business" class="pr-3">
<h4 class="mb-1 font-italic">
Data Science for Business
</h4>
<span class="mb-1 text-muted">What You Need to Know About Data Mining and Data-Analytic Thinking</span><br/>
<strong>Foster Provost & Tom Fawcett</strong><br/>
<a href="http://data-science-for-biz.com/">http://data-science-for-biz.com/</a><br/>
<blockquote class="styled text-muted">
<p>An excellent survey of data science with just the right amount of depth to give you some real direction. If you don’t know where to start, start here.</p>
</blockquote>
<!-- <small class="d-block text-muted">
</small> -->
<small class="text-muted">
Nov 15, 2013
</small>
</div>
<div class="col-md-3 pr-0 text-right">
<a href="http://data-science-for-biz.com/">
<img class="w-100" src="/assets/images/book_data-science-business.png" alt="Data Science for Business">
</a>
</div>
</div>
<div class="mb-5 d-flex justify-content-between main-loop-card">
<div id="implementing-domain-driven-design" class="pr-3">
<h4 class="mb-1 font-italic">
Implementing Domain-Driven Design
</h4>
<strong>Vaughn Vernon</strong><br/>
<a href="https://dddcommunity.org/book/implementing-domain-driven-design-by-vaughn-vernon/">https://dddcommunity.org/book/implementing-domain-driven-design-by-vaughn-vernon/</a><br/>
<blockquote class="styled text-muted">
<p>This book is a great companion to the original Domain Driven-Design. You can read them side-by-side for deeper understanding of the concepts. It provides the missing concrete examples and implementations that will unlock the value of DDD.</p>
</blockquote>
<!-- <small class="d-block text-muted">
</small> -->
<small class="text-muted">
Oct 01, 2013
</small>
</div>
<div class="col-md-3 pr-0 text-right">
<a href="https://dddcommunity.org/book/implementing-domain-driven-design-by-vaughn-vernon/">
<img class="w-100" src="/assets/images/book-implementing-domain-driven-design.jpeg" alt="Implementing Domain-Driven Design">
</a>
</div>
</div>
<div class="mb-5 d-flex justify-content-between main-loop-card">
<div id="how-to-measure-anything" class="pr-3">
<h4 class="mb-1 font-italic">
How to Measure Anything
</h4>
<span class="mb-1 text-muted">Finding the Value of Intangibles in Business</span><br/>
<strong>Douglas W. Hubbard</strong><br/>
<a href="https://www.howtomeasureanything.com/3rd-edition/">https://www.howtomeasureanything.com/3rd-edition/</a><br/>
<blockquote class="styled text-muted">
<p>This is one of my favorite books. I’d recommend it to anyone. Learn to tap into the information that you didn’t even know you had.</p>
</blockquote>
<!-- <small class="d-block text-muted">
</small> -->
<small class="text-muted">
Dec 01, 2012
</small>
</div>
<div class="col-md-3 pr-0 text-right">
<a href="https://www.howtomeasureanything.com/3rd-edition/">
<img class="w-100" src="/assets/images/book-howto-measure-anything.png" alt="How to Measure Anything">
</a>
</div>
</div>
<div class="mb-5 d-flex justify-content-between main-loop-card">
<div id="enterprise-integration-patterns" class="pr-3">
<h4 class="mb-1 font-italic">
Enterprise Integration Patterns
</h4>
<strong>Gregor Hohpe and Bobby Woolf</strong><br/>
<a href="https://www.enterpriseintegrationpatterns.com/gregor.html">https://www.enterpriseintegrationpatterns.com/gregor.html</a><br/>
<blockquote class="styled text-muted">
<p>This book is another classic. It provides a foundation for the concepts of system integration and explore dozens of timeless patterns</p>
</blockquote>
<!-- <small class="d-block text-muted">
</small> -->
<small class="text-muted">
Dec 01, 2012
</small>
</div>
<div class="col-md-3 pr-0 text-right">
<a href="https://www.enterpriseintegrationpatterns.com/gregor.html">
<img class="w-100" src="/assets/images/book-enterprise-integration-patterns.gif" alt="Enterprise Integration Patterns">
</a>
</div>
</div>
<div class="mb-5 d-flex justify-content-between main-loop-card">
<div id="domain-driven-design" class="pr-3">
<h4 class="mb-1 font-italic">
Domain-Driven Design
</h4>
<span class="mb-1 text-muted">Tackling Complexity in the Heart of Software</span><br/>
<strong>Eric Evans</strong><br/>
<a href="https://dddcommunity.org/book/evans_2003/">https://dddcommunity.org/book/evans_2003/</a><br/>
<blockquote class="styled text-muted">
<p>This is a classic that influenced my early ideas on software design. It seems to offer new wisdom every time I revisit it (even after 15 years). With the rise of microservices this book is as relevant as ever. It offers a fundamental approach to determine the boundaries between components/services.</p>
</blockquote>
<!-- <small class="d-block text-muted">
</small> -->
<small class="text-muted">
Jan 01, 2004
</small>
</div>
<div class="col-md-3 pr-0 text-right">
<a href="https://dddcommunity.org/book/evans_2003/">
<img class="w-100" src="/assets/images/book-domain-driven-design.jpg" alt="Domain-Driven Design">
</a>
</div>
</div>
</div>
<div class="col-md-4">
<div class="sticky-top sticky-top-offset">
<div class="sidebar-label">
<span>books</span>
<hr/>
</div>
<div class="taglist">
<ul>
<li>
<!-- <a class="books badge badge-pill" href="/reading-list.html">reading list</a> -->
<a class="books bg-highlight" href="/reading-list.html">reading list</a></li>
</ul>
</div>
<div class="sidebar-label">
<span>categories</span>
<hr/>
</div>
<div class="taglist">
<ul>
<!--
<li>
<a class="category badge badge-pill smoothscroll" href="/categories.html#creative">creative</a>
</li>
<li>
<a class="category badge badge-pill smoothscroll" href="/categories.html#development">development</a>
</li>
-->
<li>
<a class="sscroll smoothscroll category bg-highlight" href="/categories.html#creative">creative</a>
</li>
<li>
<a class="sscroll smoothscroll category bg-highlight" href="/categories.html#development">development</a>
</li>
</ul>
</div>
<div class="sidebar-label">
<span>tags</span>
<hr/>
</div>
<div class="taglist">
<ul>
<!--
<li>
<a href="/tag/appveyor" class="tag badge badge-pill">appveyor</a>
</li>
<li>
<a href="/tag/automation" class="tag badge badge-pill">automation</a>
</li>
<li>
<a href="/tag/creative" class="tag badge badge-pill">creative</a>
</li>
<li>
<a href="/tag/ddd" class="tag badge badge-pill">ddd</a>
</li>
<li>
<a href="/tag/development" class="tag badge badge-pill">development</a>
</li>
<li>
<a href="/tag/dotnet" class="tag badge badge-pill">dotnet</a>
</li>
<li>
<a href="/tag/efcore" class="tag badge badge-pill">efcore</a>
</li>
<li>
<a href="/tag/featured" class="tag badge badge-pill">featured</a>
</li>
<li>
<a href="/tag/mediatr" class="tag badge badge-pill">mediatR</a>
</li>
<li>
<a href="/tag/nuget" class="tag badge badge-pill">nuget</a>
</li>
<li>
<a href="/tag/nuke" class="tag badge badge-pill">nuke</a>
</li>
<li>
<a href="/tag/tutorial" class="tag badge badge-pill">tutorial</a>
</li>
-->
<li>
<a class="sscroll tag smoothscroll bg-highlight" href="/tags/appveyor/">appveyor</a>
</li>
<li>
<a class="sscroll tag smoothscroll bg-highlight" href="/tags/automation/">automation</a>
</li>
<li>
<a class="sscroll tag smoothscroll bg-highlight" href="/tags/creative/">creative</a>
</li>
<li>
<a class="sscroll tag smoothscroll bg-highlight" href="/tags/ddd/">ddd</a>
</li>
<li>
<a class="sscroll tag smoothscroll bg-highlight" href="/tags/development/">development</a>
</li>
<li>
<a class="sscroll tag smoothscroll bg-highlight" href="/tags/dotnet/">dotnet</a>
</li>
<li>
<a class="sscroll tag smoothscroll bg-highlight" href="/tags/efcore/">efcore</a>
</li>
<li>
<a class="sscroll tag smoothscroll bg-highlight" href="/tags/featured/">featured</a>
</li>
<li>
<a class="sscroll tag smoothscroll bg-highlight" href="/tags/mediatr/">mediatR</a>
</li>
<li>
<a class="sscroll tag smoothscroll bg-highlight" href="/tags/nuget/">nuget</a>
</li>
<li>
<a class="sscroll tag smoothscroll bg-highlight" href="/tags/nuke/">nuke</a>
</li>
<li>
<a class="sscroll tag smoothscroll bg-highlight" href="/tags/tutorial/">tutorial</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</main>
<!-- Scripts: popper, bootstrap, theme, lunr -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js" integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script>
<script src="/assets/js/theme.js"></script>
<!-- Footer -->
<footer class="bg-white border-top p-3 text-muted small">
<div class="container">
<div class="row align-items-center justify-content-between">
<div>
<span class="navbar-brand mr-2 mb-0"><strong>cfrenzel</strong></span>
<span>© <script>document.write(new Date().getFullYear())</script> all rights reserved</span>
<!-- Github Repo Star Btn-->
<a class="text-dark ml-1" target="_blank" href="https://github.com/wowthemesnet/mundana-theme-jekyll"><i class="fab fa-github"></i> Fork on Github</a>
</div>
<div>
Made with <a target="_blank" class="text-dark font-weight-bold" href="https://www.wowthemes.net/mundana-jekyll-theme/"> Mundana Jekyll Theme </a> by <a class="text-dark" target="_blank" href="https://www.wowthemes.net">WowThemes</a>.
</div>
</div>
</div>
</footer>
<!-- All this area goes before </body> closing tag -->
</body>
</html>