-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfeed.xml
1232 lines (1010 loc) · 175 KB
/
feed.xml
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
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.8.5">Jekyll</generator><link href="https://cfrenzel.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://cfrenzel.com/" rel="alternate" type="text/html" /><updated>2020-03-04T12:26:56-05:00</updated><id>https://cfrenzel.com/feed.xml</id><title type="html">cfrenzel</title><subtitle>Blog of Camron Frenzel</subtitle><entry><title type="html">Throwback: Prototype of AR Furniture Layout (2009)</title><link href="https://cfrenzel.com/augmented_reality_project/" rel="alternate" type="text/html" title="Throwback: Prototype of AR Furniture Layout (2009)" /><published>2020-02-28T00:00:00-05:00</published><updated>2020-02-28T00:00:00-05:00</updated><id>https://cfrenzel.com/augmented_reality_project</id><content type="html" xml:base="https://cfrenzel.com/augmented_reality_project/"><p>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.</p>
<iframe src="https://player.vimeo.com/video/394464714" width="640" height="480" frameborder="0" allow="autoplay; fullscreen" allowfullscreen=""></iframe>
<iframe src="https://player.vimeo.com/video/394463597" width="640" height="853" frameborder="0" allow="autoplay; fullscreen" allowfullscreen=""></iframe></content><author><name>camron</name></author><category term="creative" /><category term="development" /><summary type="html">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.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://cfrenzel.com/assets/images/ar_furniture.png" /></entry><entry><title type="html">Throwback: Projector with Microsoft Kinect (2013)</title><link href="https://cfrenzel.com/kinect_and_projector_project/" rel="alternate" type="text/html" title="Throwback: Projector with Microsoft Kinect (2013)" /><published>2020-02-27T00:00:00-05:00</published><updated>2020-02-27T00:00:00-05:00</updated><id>https://cfrenzel.com/kinect_and_projector_project</id><content type="html" xml:base="https://cfrenzel.com/kinect_and_projector_project/"><p>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.</p>
<iframe src="https://player.vimeo.com/video/394466517" width="640" height="360" frameborder="0" allow="autoplay; fullscreen" allowfullscreen=""></iframe></content><author><name>camron</name></author><category term="creative" /><category term="development" /><summary type="html">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.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://cfrenzel.com/assets/images/kinect_projector.png" /></entry><entry><title type="html">Learning From Open Source Part1: MediatR</title><link href="https://cfrenzel.com/learning-from-open-source-part1-mediatr/" rel="alternate" type="text/html" title="Learning From Open Source Part1: MediatR" /><published>2020-01-14T00:00:00-05:00</published><updated>2020-01-14T00:00:00-05:00</updated><id>https://cfrenzel.com/learning-from-open-source-part1-mediatr</id><content type="html" xml:base="https://cfrenzel.com/learning-from-open-source-part1-mediatr/"><p>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 <strong>magic</strong>. 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 <a href="https://github.com/jbogard/MediatR">MediatR</a>.</p>
<p>I use MediatR in many projects because of its “simple to use” yet powerful implementation of the <a href="https://en.wikipedia.org/wiki/Mediator_pattern">Mediator Pattern</a>. A mediator sits between method callers and receivers creating a configurable layer of abstraction that determines how callers and receivers get wired up.</p>
<p>Let’s look at a quick example of a Controller calling some Application Layer code with MediatR.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">CreateTicketCommand</span> <span class="p">:</span> <span class="n">IRequest</span><span class="p">&lt;</span><span class="n">CreateTicketResponse</span><span class="p">&gt;</span>
<span class="p">{</span>
<span class="k">public</span> <span class="kt">string</span> <span class="n">Description</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="k">public</span> <span class="kt">string</span> <span class="n">Department</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="k">public</span> <span class="kt">string</span> <span class="n">Severity</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">TicketController</span><span class="p">:</span> <span class="n">Controller</span>
<span class="p">{</span>
<span class="k">private</span> <span class="k">readonly</span> <span class="n">IMediator</span> <span class="n">_mediator</span><span class="p">;</span>
<span class="k">public</span> <span class="nf">TicketController</span><span class="p">(</span><span class="n">IMediator</span> <span class="n">mediator</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">_mediator</span> <span class="p">=</span> <span class="n">mediator</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">[</span><span class="n">HttpPost</span><span class="p">]</span>
<span class="k">public</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">ActionResult</span><span class="p">&gt;</span> <span class="nf">Create</span><span class="p">(</span><span class="n">CreateTicketModel</span> <span class="n">model</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">command</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">CreateTicketCommand</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">Description</span> <span class="p">=</span> <span class="n">model</span><span class="p">.</span><span class="n">Description</span><span class="p">,</span>
<span class="n">Department</span> <span class="p">=</span> <span class="n">model</span><span class="p">.</span><span class="n">Department</span><span class="p">,</span>
<span class="n">Severity</span> <span class="p">=</span> <span class="n">model</span><span class="p">.</span><span class="n">Severity</span>
<span class="p">};</span>
<span class="kt">var</span> <span class="n">res</span> <span class="p">=</span> <span class="k">await</span> <span class="n">_mediator</span><span class="p">.</span><span class="nf">Send</span><span class="p">(</span><span class="n">command</span><span class="p">);</span>
<span class="k">return</span> <span class="nf">RedirectToAction</span><span class="p">(</span><span class="s">"Show"</span><span class="p">,</span> <span class="k">new</span> <span class="p">{</span> <span class="n">id</span> <span class="p">=</span> <span class="n">res</span><span class="p">.</span><span class="n">TicketId</span><span class="p">});</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>There are a few things to notice here.</p>
<ul>
<li>The Command defines the type of it’s response <code class="highlighter-rouge">IRequest&lt;CreateTicketResponse&gt;</code></li>
<li>The <code class="highlighter-rouge">IMediator</code> is injected into the Controller</li>
<li>There is a single <code class="highlighter-rouge">Send</code> method on the <code class="highlighter-rouge">IMediator</code> used to dispatch all command/request types</li>
<li>The Controller doesn’t know who is handling the command</li>
</ul>
<p>Here’s a sample handler for <code>CreateTicketCommand</code></p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">CreateTicketHandler</span> <span class="p">:</span> <span class="n">IRequestHandler</span><span class="p">&lt;</span><span class="n">CreateTicketCommand</span><span class="p">,</span> <span class="n">CreateTicketResponse</span><span class="p">&gt;</span>
<span class="p">{</span>
<span class="k">private</span> <span class="k">readonly</span> <span class="n">ApplicationDbContext</span> <span class="n">_db</span><span class="p">;</span>
<span class="k">public</span> <span class="nf">CreateTicketHandler</span><span class="p">(</span><span class="n">ApplicationDbContext</span> <span class="n">db</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="n">_db</span> <span class="p">=</span> <span class="n">db</span><span class="p">;</span>
<span class="k">public</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">CreateTicketResponse</span><span class="p">&gt;</span> <span class="nf">Handle</span><span class="p">(</span><span class="n">CreateTicketCommand</span> <span class="n">command</span><span class="p">,</span> <span class="n">CancellationToken</span> <span class="n">cancellationToken</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Ticket</span> <span class="n">ticket</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">Ticket</span><span class="p">(</span><span class="n">command</span><span class="p">.</span><span class="n">Description</span><span class="p">,</span> <span class="n">command</span><span class="p">.</span><span class="n">Department</span><span class="p">,</span> <span class="n">command</span><span class="p">.</span><span class="n">Severity</span><span class="p">);</span>
<span class="n">_db</span><span class="p">.</span><span class="n">Tickets</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">ticket</span><span class="p">);</span>
<span class="k">await</span> <span class="n">_db</span><span class="p">.</span><span class="nf">SaveChangesAsync</span><span class="p">();</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">CreateTicketResponse</span><span class="p">()</span> <span class="p">{</span> <span class="n">TicektId</span> <span class="p">=</span> <span class="n">ticket</span><span class="p">.</span><span class="n">Id</span> <span class="p">};</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Notice:</p>
<ul>
<li>Handler doesn’t know who sent the command</li>
<li>Handler specifies the the message type that it handles and the response type <code class="highlighter-rouge">IRequestHandler&lt;CreateTicketCommand, CreateTicketResponse&gt;</code></li>
<li>Handler has constructor parameters that must be injected by the caller</li>
</ul>
<p>We configure MediatR in our app’s startup with a single line</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">services</span><span class="p">.</span><span class="nf">AddMediatR</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">Program</span><span class="p">));</span>
</code></pre></div></div>
<p>Here’s what I’m thinking</p>
<ul>
<li>
<p>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.</p>
</li>
<li>
<p>The call to <code class="highlighter-rouge">_mediator.Send(command)</code> 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 <strong>magic</strong> behind this!</p>
</li>
</ul>
<p><strong>Going to the Source</strong></p>
<p>Let’s dig in. First download the source or browse online at <a href="https://github.com/jbogard/MediatR/tree/master/src/MediatR">https://github.com/jbogard/MediatR/tree/master/src/MediatR</a></p>
<pre>
&gt; git clone https://github.com/jbogard/MediatR.git .
</pre>
<p>You’ll first notice a handful of simple interfaces and <code class="highlighter-rouge">Mediator.cs</code> with the core class. Since we’re curious about it’s <code class="highlighter-rouge">Send</code> method let’s take a look inside. The file is surprisingly small, and at first glance it looks like the <code class="highlighter-rouge">Send</code> method is actually doing some of the real work.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">public</span> <span class="nf">Mediator</span><span class="p">(</span><span class="n">ServiceFactory</span> <span class="n">serviceFactory</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">_serviceFactory</span> <span class="p">=</span> <span class="n">serviceFactory</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">public</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">TResponse</span><span class="p">&gt;</span> <span class="n">Send</span><span class="p">&lt;</span><span class="n">TResponse</span><span class="p">&gt;(</span><span class="n">IRequest</span><span class="p">&lt;</span><span class="n">TResponse</span><span class="p">&gt;</span> <span class="n">request</span><span class="p">,</span> <span class="n">CancellationToken</span> <span class="n">cancellationToken</span> <span class="p">=</span> <span class="k">default</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">request</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">ArgumentNullException</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">request</span><span class="p">));</span>
<span class="p">}</span>
<span class="kt">var</span> <span class="n">requestType</span> <span class="p">=</span> <span class="n">request</span><span class="p">.</span><span class="nf">GetType</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">handler</span> <span class="p">=</span> <span class="p">(</span><span class="n">RequestHandlerWrapper</span><span class="p">&lt;</span><span class="n">TResponse</span><span class="p">&gt;)</span><span class="n">_requestHandlers</span><span class="p">.</span><span class="nf">GetOrAdd</span><span class="p">(</span><span class="n">requestType</span><span class="p">,</span>
<span class="n">t</span> <span class="p">=&gt;</span> <span class="n">Activator</span><span class="p">.</span><span class="nf">CreateInstance</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">RequestHandlerWrapperImpl</span><span class="p">&lt;,&gt;).</span><span class="nf">MakeGenericType</span><span class="p">(</span><span class="n">requestType</span><span class="p">,</span> <span class="k">typeof</span><span class="p">(</span><span class="n">TResponse</span><span class="p">))));</span>
<span class="k">return</span> <span class="n">handler</span><span class="p">.</span><span class="nf">Handle</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">cancellationToken</span><span class="p">,</span> <span class="n">_serviceFactory</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>First things first, above I made a call using <code class="highlighter-rouge">Send(command)</code>, but the send method here is generic <code class="highlighter-rouge">Send&lt;TResponse&gt;(IRequest&lt;TResponse&gt; request)</code>. It turns out that the compiler can infer the type argument; so you can omit it. Our call above looks much prettier than <code class="highlighter-rouge">Send&lt;CreateTicketResponse&gt;(command)</code> <a href="https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/generic-methods">(generics methods).</a> Moving on…</p>
<p>I’m starting to get excited because the <code class="highlighter-rouge">Send</code> 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.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">handler</span> <span class="p">=</span> <span class="p">(</span><span class="n">RequestHandlerWrapper</span><span class="p">&lt;</span><span class="n">TResponse</span><span class="p">&gt;)</span><span class="n">_requestHandlers</span><span class="p">.</span><span class="nf">GetOrAdd</span><span class="p">(</span><span class="n">requestType</span><span class="p">,</span>
<span class="n">t</span> <span class="p">=&gt;</span> <span class="n">Activator</span><span class="p">.</span><span class="nf">CreateInstance</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">RequestHandlerWrapperImpl</span><span class="p">&lt;,&gt;).</span><span class="nf">MakeGenericType</span><span class="p">(</span><span class="n">requestType</span><span class="p">,</span> <span class="k">typeof</span><span class="p">(</span><span class="n">TResponse</span><span class="p">))));</span>
</code></pre></div></div>
<p>The outer <code class="highlighter-rouge">_requestHandlers.GetOrAdd</code> is just checking if a handler already exists before creating a new one. The real magic seems to be:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Activator</span><span class="p">.</span><span class="nf">CreateInstance</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">RequestHandlerWrapperImpl</span><span class="p">&lt;,&gt;).</span><span class="nf">MakeGenericType</span><span class="p">(</span><span class="n">requestType</span><span class="p">,</span> <span class="k">typeof</span><span class="p">(</span><span class="n">TResponse</span><span class="p">)))</span>
</code></pre></div></div>
<p>We’re getting close to something. We’re taking a <code class="highlighter-rouge">RequestHandlerWrapperImpl&lt;,&gt;</code> calling <code class="highlighter-rouge">.MakeGenericType(requestType, typeof(TResponse))</code> on it then instantiating the result, which is apparently assignable to <code class="highlighter-rouge">RequestHandlerWrapper&lt;TResponse&gt;</code>. Let’s plug in our command type above to see what it looks like.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typeof</span><span class="p">(</span><span class="n">RequestHandlerWrapperImpl</span><span class="p">&lt;,&gt;).</span><span class="nf">MakeGenericType</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">CreateTicketCommand</span><span class="p">),</span> <span class="k">typeof</span><span class="p">(</span><span class="n">CreateTicketResponse</span><span class="p">))</span>
</code></pre></div></div>
<p>This gives us a <code class="highlighter-rouge">RequestHandlerWrapperImpl&lt;CreateTicketCommand,CreateTicketResponse&gt;</code> which is assignable to <code class="highlighter-rouge">RequestHandlerWrapper&lt;CreateTicketResponse&gt;</code>. For now let’s think of “RequestHandlerWrapper” as some kind of wrapper around our actual handler (<code class="highlighter-rouge">CreateTicketHandler</code>). 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.</p>
<p>But whats up with the cast from <code class="highlighter-rouge">RequestHandlerWrapperImpl</code> down to the less generic <code class="highlighter-rouge">RequestHandlerWrapper</code>? Believe it or not, this seemingly benign cast is part of the real <strong>magic</strong>. 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 <code class="highlighter-rouge">TRequest</code> goes away when casting <code class="highlighter-rouge">RequestHandlerWrapperImpl&lt;TRequest,TResponse&gt;</code> to <code class="highlighter-rouge">RequestHandlerWrapper&lt;TResponse&gt;</code>.</p>
<p>Lets take a look inside:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="k">internal</span> <span class="k">abstract</span> <span class="k">class</span> <span class="nc">RequestHandlerWrapper</span><span class="p">&lt;</span><span class="n">TResponse</span><span class="p">&gt;</span> <span class="p">:</span> <span class="n">RequestHandlerBase</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">abstract</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">TResponse</span><span class="p">&gt;</span> <span class="nf">Handle</span><span class="p">(</span><span class="n">IRequest</span><span class="p">&lt;</span><span class="n">TResponse</span><span class="p">&gt;</span> <span class="n">request</span><span class="p">,</span> <span class="n">CancellationToken</span> <span class="n">cancellationToken</span><span class="p">,</span>
<span class="n">ServiceFactory</span> <span class="n">serviceFactory</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">internal</span> <span class="k">class</span> <span class="nc">RequestHandlerWrapperImpl</span><span class="p">&lt;</span><span class="n">TRequest</span><span class="p">,</span> <span class="n">TResponse</span><span class="p">&gt;</span> <span class="p">:</span> <span class="n">RequestHandlerWrapper</span><span class="p">&lt;</span><span class="n">TResponse</span><span class="p">&gt;</span>
<span class="k">where</span> <span class="n">TRequest</span> <span class="p">:</span> <span class="n">IRequest</span><span class="p">&lt;</span><span class="n">TResponse</span><span class="p">&gt;</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">override</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">TResponse</span><span class="p">&gt;</span> <span class="nf">Handle</span><span class="p">(</span><span class="n">IRequest</span><span class="p">&lt;</span><span class="n">TResponse</span><span class="p">&gt;</span> <span class="n">request</span><span class="p">,</span> <span class="n">CancellationToken</span> <span class="n">cancellationToken</span><span class="p">,</span>
<span class="n">ServiceFactory</span> <span class="n">serviceFactory</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Task</span><span class="p">&lt;</span><span class="n">TResponse</span><span class="p">&gt;</span> <span class="nf">Handler</span><span class="p">()</span> <span class="p">=&gt;</span> <span class="n">GetHandler</span><span class="p">&lt;</span><span class="n">IRequestHandler</span><span class="p">&lt;</span><span class="n">TRequest</span><span class="p">,</span> <span class="n">TResponse</span><span class="p">&gt;&gt;(</span><span class="n">serviceFactory</span><span class="p">).</span><span class="nf">Handle</span><span class="p">((</span><span class="n">TRequest</span><span class="p">)</span> <span class="n">request</span><span class="p">,</span> <span class="n">cancellationToken</span><span class="p">);</span>
<span class="k">return</span> <span class="n">serviceFactory</span>
<span class="p">.</span><span class="n">GetInstances</span><span class="p">&lt;</span><span class="n">IPipelineBehavior</span><span class="p">&lt;</span><span class="n">TRequest</span><span class="p">,</span> <span class="n">TResponse</span><span class="p">&gt;&gt;()</span>
<span class="p">.</span><span class="nf">Reverse</span><span class="p">()</span>
<span class="p">.</span><span class="nf">Aggregate</span><span class="p">((</span><span class="n">RequestHandlerDelegate</span><span class="p">&lt;</span><span class="n">TResponse</span><span class="p">&gt;)</span> <span class="n">Handler</span><span class="p">,</span> <span class="p">(</span><span class="n">next</span><span class="p">,</span> <span class="n">pipeline</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="n">pipeline</span><span class="p">.</span><span class="nf">Handle</span><span class="p">((</span><span class="n">TRequest</span><span class="p">)</span><span class="n">request</span><span class="p">,</span> <span class="n">cancellationToken</span><span class="p">,</span> <span class="n">next</span><span class="p">))();</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Cool. So <code class="highlighter-rouge">RequestHandlerWrapperImpl&lt;TRequest, TResponse&gt;</code> implements the abstract <code class="highlighter-rouge">RequestHandlerWrapper&lt;TResponse&gt;</code>. So we have the generic implementation extending the non-generic (with respect to TRequest). Ultimately, <code class="highlighter-rouge">RequestHandlerWrapper&lt;TResponse&gt;</code> 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:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">public</span> <span class="k">override</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">TResponse</span><span class="p">&gt;</span> <span class="nf">Handle</span><span class="p">(</span><span class="n">IRequest</span><span class="p">&lt;</span><span class="n">TResponse</span><span class="p">&gt;</span> <span class="n">request</span><span class="p">,</span> <span class="n">CancellationToken</span> <span class="n">cancellationToken</span><span class="p">,</span>
<span class="n">ServiceFactory</span> <span class="n">serviceFactory</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Task</span><span class="p">&lt;</span><span class="n">TResponse</span><span class="p">&gt;</span> <span class="nf">Handler</span><span class="p">()</span> <span class="p">=&gt;</span> <span class="n">GetHandler</span><span class="p">&lt;</span><span class="n">IRequestHandler</span><span class="p">&lt;</span><span class="n">TRequest</span><span class="p">,</span> <span class="n">TResponse</span><span class="p">&gt;&gt;(</span><span class="n">serviceFactory</span><span class="p">).</span><span class="nf">Handle</span><span class="p">((</span><span class="n">TRequest</span><span class="p">)</span> <span class="n">request</span><span class="p">,</span> <span class="n">cancellationToken</span><span class="p">);</span>
<span class="k">return</span> <span class="n">serviceFactory</span>
<span class="p">.</span><span class="n">GetInstances</span><span class="p">&lt;</span><span class="n">IPipelineBehavior</span><span class="p">&lt;</span><span class="n">TRequest</span><span class="p">,</span> <span class="n">TResponse</span><span class="p">&gt;&gt;()</span>
<span class="p">.</span><span class="nf">Reverse</span><span class="p">()</span>
<span class="p">.</span><span class="nf">Aggregate</span><span class="p">((</span><span class="n">RequestHandlerDelegate</span><span class="p">&lt;</span><span class="n">TResponse</span><span class="p">&gt;)</span> <span class="n">Handler</span><span class="p">,</span> <span class="p">(</span><span class="n">next</span><span class="p">,</span> <span class="n">pipeline</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="p">()</span> <span class="p">=&gt;</span> <span class="n">pipeline</span><span class="p">.</span><span class="nf">Handle</span><span class="p">((</span><span class="n">TRequest</span><span class="p">)</span><span class="n">request</span><span class="p">,</span> <span class="n">cancellationToken</span><span class="p">,</span> <span class="n">next</span><span class="p">))();</span>
<span class="p">}</span>
</code></pre></div></div>
<p>MediatR has some cool features around pipelines, but a basic mediator doesn’t need any of that. Let’s focus on how the <code class="highlighter-rouge">RequestHandlerWrapperImpl&lt;TRequest, TResponse&gt;</code> does it’s job of calling our <code class="highlighter-rouge">CreateTicketHandler</code> with this line:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Task</span><span class="p">&lt;</span><span class="n">TResponse</span><span class="p">&gt;</span> <span class="nf">Handler</span><span class="p">()</span> <span class="p">=&gt;</span> <span class="n">GetHandler</span><span class="p">&lt;</span><span class="n">IRequestHandler</span><span class="p">&lt;</span><span class="n">TRequest</span><span class="p">,</span> <span class="n">TResponse</span><span class="p">&gt;&gt;(</span><span class="n">serviceFactory</span><span class="p">).</span><span class="nf">Handle</span><span class="p">((</span><span class="n">TRequest</span><span class="p">)</span> <span class="n">request</span><span class="p">,</span> <span class="n">cancellationToken</span><span class="p">);</span>
</code></pre></div></div>
<p>Let’s break this down</p>
<ul>
<li>First we call <code class="highlighter-rouge">GetHandler()</code> on our base <code class="highlighter-rouge">RequestHandlerBase</code> class. This should return our actual handler (<code class="highlighter-rouge">CreateTicketHandler</code>). We’ll take a look inside a little later</li>
</ul>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">GetHandler</span><span class="p">&lt;</span><span class="n">IRequestHandler</span><span class="p">&lt;</span><span class="n">TRequest</span><span class="p">,</span> <span class="n">TResponse</span><span class="p">&gt;&gt;(</span><span class="n">serviceFactory</span><span class="p">)</span>
</code></pre></div></div>
<ul>
<li>Then we call the <code class="highlighter-rouge">.Handle()</code> method on the handler (<code class="highlighter-rouge">CreateTicketHandler</code>). We must cast the <code class="highlighter-rouge">IRequest&lt;TResponse&gt;</code> to <code class="highlighter-rouge">TRequest</code> to complete the bridge from the non-generic to generic.</li>
</ul>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">.</span><span class="nf">Handle</span><span class="p">((</span><span class="n">TRequest</span><span class="p">)</span> <span class="n">request</span><span class="p">,</span> <span class="n">cancellationToken</span><span class="p">)</span>
</code></pre></div></div>
<ul>
<li>With our command it would look like this</li>
</ul>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//request is an IRequest&lt;CreateTicketResponse&gt; from the non-generic</span>
<span class="p">.</span><span class="nf">Handle</span><span class="p">((</span><span class="n">CreateTicketCommand</span><span class="p">)</span> <span class="n">request</span><span class="p">,</span> <span class="n">cancellationToken</span><span class="p">)</span>
</code></pre></div></div>
<ul>
<li>Now instead of immediately running the <code class="highlighter-rouge">Handle()</code> method above, we’re using a lambda to create Task that we can pass around and call later</li>
</ul>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Task</span><span class="p">&lt;</span><span class="n">TResponse</span><span class="p">&gt;</span> <span class="nf">Handler</span><span class="p">()</span> <span class="p">=&gt;</span>
</code></pre></div></div>
<p>At this point awaiting the Handler would wrap up our dispatch to <code class="highlighter-rouge">CreateTicketHandler</code>. Let’s back up one step and see how the instantiation of our handler with Dependency Injection went down in <code class="highlighter-rouge">RequestHandlerBase</code>.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">protected</span> <span class="k">static</span> <span class="n">THandler</span> <span class="n">GetHandler</span><span class="p">&lt;</span><span class="n">THandler</span><span class="p">&gt;(</span><span class="n">ServiceFactory</span> <span class="n">factory</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">THandler</span> <span class="n">handler</span><span class="p">;</span>
<span class="k">try</span>
<span class="p">{</span>
<span class="n">handler</span> <span class="p">=</span> <span class="n">factory</span><span class="p">.</span><span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">THandler</span><span class="p">&gt;();</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Interesting, I really expected more code. Let’s take a look at <code class="highlighter-rouge">ServiceFactory</code> to see what’s up.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">delegate</span> <span class="kt">object</span> <span class="nf">ServiceFactory</span><span class="p">(</span><span class="n">Type</span> <span class="n">serviceType</span><span class="p">);</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">class</span> <span class="nc">ServiceFactoryExtensions</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">static</span> <span class="n">T</span> <span class="n">GetInstance</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="k">this</span> <span class="n">ServiceFactory</span> <span class="n">factory</span><span class="p">)</span>
<span class="p">=&gt;</span> <span class="p">(</span><span class="n">T</span><span class="p">)</span> <span class="nf">factory</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">T</span><span class="p">));</span>
<span class="k">public</span> <span class="k">static</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;</span> <span class="n">GetInstances</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="k">this</span> <span class="n">ServiceFactory</span> <span class="n">factory</span><span class="p">)</span>
<span class="p">=&gt;</span> <span class="p">(</span><span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;)</span> <span class="nf">factory</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;));</span>
<span class="p">}</span>
</code></pre></div></div>
<p><strong>Mind Blown!</strong> <code class="highlighter-rouge">ServiceFactory</code> is just a delegate. As a bonus the method <code class="highlighter-rouge">GetInstance&lt;THandler&gt;</code> is an extension method on the delegate. That’s right <mark>C# supports extension methods on delegates</mark>. Essentially, <code class="highlighter-rouge">ServiceFactory</code> is a single method wrapper around our Dependency Injection container. The only burden <code class="highlighter-rouge">ServiceFactory</code> puts on the underlying container is to have a method that takes in a <code class="highlighter-rouge">Type</code> parameter and returns an instance of that type. Using a couple of extension methods we overlay a nicer generic interface <code class="highlighter-rouge">T GetInstance&lt;T&gt;</code> and <code class="highlighter-rouge">IEnumerable&lt;T&gt; GetInstances&lt;T&gt;</code>. You don’t see this kind of expressiveness in strongly-typed languages every day.</p>
<p><mark>MediatR's support for all the different dependency injection frameworks boils down to a simple delegate</mark>. Ironically, if you look into one of the Dependency Injection integrations like <a href="https://github.com/jbogard/MediatR.Extensions.Microsoft.DependencyInjection/blob/master/src/MediatR.Extensions.Microsoft.DependencyInjection/Registration/ServiceRegistrar.cs">MediatR.Extensions.Microsoft.DependencyInjection</a>, it has about as much code for registering all the bells and whistles for handlers as the core of MediatR itself.</p></content><author><name>camron</name></author><category term="featured" /><category term="mediatR" /><category term="tutorial" /><summary type="html">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.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://cfrenzel.com/assets/images/mediatr.jpeg" /></entry><entry><title type="html">Simple Domain Events with EFCore and MediatR</title><link href="https://cfrenzel.com/domain-events-efcore-mediatr/" rel="alternate" type="text/html" title="Simple Domain Events with EFCore and MediatR" /><published>2020-01-03T00:00:00-05:00</published><updated>2020-01-03T00:00:00-05:00</updated><id>https://cfrenzel.com/domain-events-efcore-mediatr</id><content type="html" xml:base="https://cfrenzel.com/domain-events-efcore-mediatr/"><p>This post relates to the <strong>Domain Driven Design (DDD)</strong> concept of <strong>Domain Events</strong>. 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 <a href="https://www.amazon.com/exec/obidos/ASIN/0321125215/domainlanguag-20">Domain Driven Design</a> by Eric Evans and <a href="https://www.oreilly.com/library/view/implementing-domain-driven-design/9780133039900/">Implementing Domain Driven Design</a> by Vaughn Vernon.</p>
<p>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.</p>
<p>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 <a href="https://github.com/jbogard/MediatR">MediatR</a> 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.</p>
<p>Sound good? Let’s get started!</p>
<h4>The Entity Side</h4>
<p>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.</p>
<ul>
<li>First let’s define an interface for the Entity</li>
</ul>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="nn">System</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System.Collections.Concurrent</span><span class="p">;</span>
<span class="k">namespace</span> <span class="nn">DomainEventsMediatR.Domain</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">interface</span> <span class="nc">IEntity</span>
<span class="p">{</span>
<span class="n">IProducerConsumerCollection</span><span class="p">&lt;</span><span class="n">IDomainEvent</span><span class="p">&gt;</span> <span class="n">DomainEvents</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">interface</span> <span class="nc">IDomainEvent</span> <span class="p">{</span> <span class="p">}</span>
</code></pre></div></div>
<ul>
<li>Now a base class implementation for our EFCore entities marking the DomainEvents as <code>[NotMapped]</code> to let EFCore know that they are not to be persisted to the db.</li>
</ul>
<div class="alert alert-primary">
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).
</div>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="nn">System</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System.Collections.Concurrent</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System.ComponentModel.DataAnnotations.Schema</span><span class="p">;</span>
<span class="k">namespace</span> <span class="nn">DomainEventsMediatR.Domain</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">abstract</span> <span class="k">class</span> <span class="nc">Entity</span> <span class="p">:</span> <span class="n">IEntity</span>
<span class="p">{</span>
<span class="p">[</span><span class="n">NotMapped</span><span class="p">]</span>
<span class="k">private</span> <span class="k">readonly</span> <span class="n">ConcurrentQueue</span><span class="p">&lt;</span><span class="n">IDomainEvent</span><span class="p">&gt;</span> <span class="n">_domainEvents</span> <span class="p">=</span> <span class="k">new</span> <span class="n">ConcurrentQueue</span><span class="p">&lt;</span><span class="n">IDomainEvent</span><span class="p">&gt;();</span>
<span class="p">[</span><span class="n">NotMapped</span><span class="p">]</span>
<span class="k">public</span> <span class="n">IProducerConsumerCollection</span><span class="p">&lt;</span><span class="n">IDomainEvent</span><span class="p">&gt;</span> <span class="n">DomainEvents</span> <span class="p">=&gt;</span> <span class="n">_domainEvents</span><span class="p">;</span>
<span class="k">protected</span> <span class="k">void</span> <span class="nf">PublishEvent</span><span class="p">(</span><span class="n">IDomainEvent</span> <span class="n">@event</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">_domainEvents</span><span class="p">.</span><span class="nf">Enqueue</span><span class="p">(</span><span class="n">@event</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">protected</span> <span class="n">Guid</span> <span class="nf">NewIdGuid</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">return</span> <span class="n">MassTransit</span><span class="p">.</span><span class="n">NewId</span><span class="p">.</span><span class="nf">NextGuid</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<ul>
<li>Now a Domain Event: <code>BacklogItemCommitted</code> and an entity: <code>BacklogItem</code> that publishes the event when it is commited to a <code>Sprint</code></li>
</ul>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">namespace</span> <span class="nn">DomainEventsMediatR.Domain</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">BacklogItemCommitted</span> <span class="p">:</span> <span class="n">IDomainEvent</span>
<span class="p">{</span>
<span class="k">public</span> <span class="n">Guid</span> <span class="n">BacklogItemId</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
<span class="k">public</span> <span class="n">Guid</span> <span class="n">SprintId</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="k">public</span> <span class="n">DateTime</span> <span class="n">CreatedAtUtc</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
<span class="k">private</span> <span class="nf">BacklogItemCommitted</span><span class="p">()</span> <span class="p">{</span> <span class="p">}</span>
<span class="k">public</span> <span class="nf">BacklogItemCommitted</span><span class="p">(</span><span class="n">BacklogItem</span> <span class="n">b</span><span class="p">,</span> <span class="n">Sprint</span> <span class="n">s</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="n">BacklogItemId</span> <span class="p">=</span> <span class="n">b</span><span class="p">.</span><span class="n">Id</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="n">CreatedAtUtc</span> <span class="p">=</span> <span class="n">b</span><span class="p">.</span><span class="n">CreatedAtUtc</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="n">SprintId</span> <span class="p">=</span> <span class="n">s</span><span class="p">.</span><span class="n">Id</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">using</span> <span class="nn">System</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System.ComponentModel.DataAnnotations</span><span class="p">;</span>
<span class="k">namespace</span> <span class="nn">DomainEventsMediatR.Domain</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">BacklogItem</span> <span class="p">:</span> <span class="n">Entity</span>
<span class="p">{</span>
<span class="k">public</span> <span class="n">Guid</span> <span class="n">Id</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">private</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="p">[</span><span class="nf">MaxLength</span><span class="p">(</span><span class="m">255</span><span class="p">)]</span>
<span class="k">public</span> <span class="kt">string</span> <span class="n">Description</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">private</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="k">public</span> <span class="k">virtual</span> <span class="n">Sprint</span> <span class="n">Sprint</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">private</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="k">public</span> <span class="n">DateTime</span> <span class="n">CreatedAtUtc</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">private</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="n">DateTime</span><span class="p">.</span><span class="n">UtcNow</span><span class="p">;</span>
<span class="k">private</span> <span class="nf">BacklogItem</span><span class="p">()</span> <span class="p">{</span> <span class="p">}</span>
<span class="k">public</span> <span class="nf">BacklogItem</span><span class="p">(</span><span class="kt">string</span> <span class="n">desc</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="n">Id</span> <span class="p">=</span> <span class="nf">NewIdGuid</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="n">Description</span> <span class="p">=</span> <span class="n">desc</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">CommitTo</span><span class="p">(</span><span class="n">Sprint</span> <span class="n">s</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="n">Sprint</span> <span class="p">=</span> <span class="n">s</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nf">PublishEvent</span><span class="p">(</span><span class="k">new</span> <span class="nf">BacklogItemCommitted</span><span class="p">(</span><span class="k">this</span><span class="p">,</span> <span class="n">s</span><span class="p">));</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<ul>
<li>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 dispatcher</li>
</ul>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="nn">System.Threading.Tasks</span><span class="p">;</span>
<span class="k">namespace</span> <span class="nn">DomainEventsMediatR.Domain</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">interface</span> <span class="nc">IDomainEventDispatcher</span>
<span class="p">{</span>
<span class="n">Task</span> <span class="nf">Dispatch</span><span class="p">(</span><span class="n">IDomainEvent</span> <span class="n">devent</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<ul>
<li>Now we can configure the dispatcher to be injected into our DbContext constructor</li>
</ul>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">public</span> <span class="k">class</span> <span class="nc">ApplicationDbContext</span> <span class="p">:</span> <span class="n">DbContext</span>
<span class="p">{</span>
<span class="k">private</span> <span class="k">readonly</span> <span class="n">IDomainEventDispatcher</span> <span class="n">_dispatcher</span><span class="p">;</span>
<span class="k">public</span> <span class="nf">ApplicationDbContext</span><span class="p">(</span><span class="n">DbContextOptions</span><span class="p">&lt;</span><span class="n">ApplicationDbContext</span><span class="p">&gt;</span> <span class="n">options</span><span class="p">,</span>
<span class="n">IDomainEventDispatcher</span> <span class="n">dispatcher</span><span class="p">)</span>
<span class="p">:</span> <span class="k">base</span><span class="p">(</span><span class="n">options</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">_dispatcher</span> <span class="p">=</span> <span class="n">dispatcher</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<ul>
<li>We can hook into EFCore and dispatch Domain Events before entities are persisted by overriding <code>SaveChanges</code></li>
</ul>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">override</span> <span class="kt">int</span> <span class="nf">SaveChanges</span><span class="p">()</span>
<span class="p">{</span>
<span class="nf">_preSaveChanges</span><span class="p">().</span><span class="nf">GetAwaiter</span><span class="p">().</span><span class="nf">GetResult</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">res</span> <span class="p">=</span> <span class="k">base</span><span class="p">.</span><span class="nf">SaveChanges</span><span class="p">();</span>
<span class="k">return</span> <span class="n">res</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">override</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="kt">int</span><span class="p">&gt;</span> <span class="nf">SaveChangesAsync</span><span class="p">(</span><span class="n">CancellationToken</span> <span class="n">cancellationToken</span> <span class="p">=</span> <span class="k">default</span><span class="p">(</span><span class="n">CancellationToken</span><span class="p">))</span>
<span class="p">{</span>
<span class="k">await</span> <span class="nf">_preSaveChanges</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">res</span> <span class="p">=</span> <span class="k">await</span> <span class="k">base</span><span class="p">.</span><span class="nf">SaveChangesAsync</span><span class="p">(</span><span class="n">cancellationToken</span><span class="p">);</span>
<span class="k">return</span> <span class="n">res</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">_preSaveChanges</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">await</span> <span class="nf">_dispatchDomainEvents</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">_dispatchDomainEvents</span><span class="p">()</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">domainEventEntities</span> <span class="p">=</span> <span class="n">ChangeTracker</span><span class="p">.</span><span class="n">Entries</span><span class="p">&lt;</span><span class="n">IEntity</span><span class="p">&gt;()</span>
<span class="p">.</span><span class="nf">Select</span><span class="p">(</span><span class="n">po</span> <span class="p">=&gt;</span> <span class="n">po</span><span class="p">.</span><span class="n">Entity</span><span class="p">)</span>
<span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">po</span> <span class="p">=&gt;</span> <span class="n">po</span><span class="p">.</span><span class="n">DomainEvents</span><span class="p">.</span><span class="nf">Any</span><span class="p">())</span>
<span class="p">.</span><span class="nf">ToArray</span><span class="p">();</span>
<span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">entity</span> <span class="k">in</span> <span class="n">domainEventEntities</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">IDomainEvent</span> <span class="n">dev</span><span class="p">;</span>
<span class="k">while</span> <span class="p">(</span><span class="n">entity</span><span class="p">.</span><span class="n">DomainEvents</span><span class="p">.</span><span class="nf">TryTake</span><span class="p">(</span><span class="k">out</span> <span class="n">dev</span><span class="p">))</span>
<span class="k">await</span> <span class="n">_dispatcher</span><span class="p">.</span><span class="nf">Dispatch</span><span class="p">(</span><span class="n">dev</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h4>The Dispatcher</h4>
<p>We need an implementation of <code>IDomainEventDispatcher</code> 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 <code>INotification</code>. We’ll overcome this by creating a generic <code>INotification</code> to wrap our Domain Event.</p>
<ul>
<li>Create a custom generic <code>INotification</code>.</li>
</ul>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="nn">System</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">MediatR</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">DomainEventsMediatR.Domain</span><span class="p">;</span>
<span class="k">namespace</span> <span class="nn">DomainEventsMediatR.Application</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">DomainEventNotification</span><span class="p">&lt;</span><span class="n">TDomainEvent</span><span class="p">&gt;</span> <span class="p">:</span> <span class="n">INotification</span> <span class="k">where</span> <span class="n">TDomainEvent</span> <span class="p">:</span> <span class="n">IDomainEvent</span>
<span class="p">{</span>
<span class="k">public</span> <span class="n">TDomainEvent</span> <span class="n">DomainEvent</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
<span class="k">public</span> <span class="nf">DomainEventNotification</span><span class="p">(</span><span class="n">TDomainEvent</span> <span class="n">domainEvent</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">DomainEvent</span> <span class="p">=</span> <span class="n">domainEvent</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<ul>
<li>Create a Dispatcher that wraps Domain Events in MediatR notificatoins and publishes them</li>
</ul>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="nn">System</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System.Threading.Tasks</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">Microsoft.Extensions.Logging</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">MediatR</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">DomainEventsMediatR.Domain</span><span class="p">;</span>
<span class="k">namespace</span> <span class="nn">DomainEventsMediatR.Application</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">MediatrDomainEventDispatcher</span> <span class="p">:</span> <span class="n">IDomainEventDispatcher</span>
<span class="p">{</span>
<span class="k">private</span> <span class="k">readonly</span> <span class="n">IMediator</span> <span class="n">_mediator</span><span class="p">;</span>
<span class="k">private</span> <span class="k">readonly</span> <span class="n">ILogger</span><span class="p">&lt;</span><span class="n">MediatrDomainEventDispatcher</span><span class="p">&gt;</span> <span class="n">_log</span><span class="p">;</span>
<span class="k">public</span> <span class="nf">MediatrDomainEventDispatcher</span><span class="p">(</span><span class="n">IMediator</span> <span class="n">mediator</span><span class="p">,</span> <span class="n">ILogger</span><span class="p">&lt;</span><span class="n">MediatrDomainEventDispatcher</span><span class="p">&gt;</span> <span class="n">log</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">_mediator</span> <span class="p">=</span> <span class="n">mediator</span><span class="p">;</span>
<span class="n">_log</span> <span class="p">=</span> <span class="n">log</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">Dispatch</span><span class="p">(</span><span class="n">IDomainEvent</span> <span class="n">devent</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">domainEventNotification</span> <span class="p">=</span> <span class="nf">_createDomainEventNotification</span><span class="p">(</span><span class="n">devent</span><span class="p">);</span>
<span class="n">_log</span><span class="p">.</span><span class="nf">LogDebug</span><span class="p">(</span><span class="s">"Dispatching Domain Event as MediatR notification. EventType: {eventType}"</span><span class="p">,</span> <span class="n">devent</span><span class="p">.</span><span class="nf">GetType</span><span class="p">());</span>
<span class="k">await</span> <span class="n">_mediator</span><span class="p">.</span><span class="nf">Publish</span><span class="p">(</span><span class="n">domainEventNotification</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">private</span> <span class="n">INotification</span> <span class="nf">_createDomainEventNotification</span><span class="p">(</span><span class="n">IDomainEvent</span> <span class="n">domainEvent</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">genericDispatcherType</span> <span class="p">=</span> <span class="k">typeof</span><span class="p">(</span><span class="n">DomainEventNotification</span><span class="p">&lt;&gt;).</span><span class="nf">MakeGenericType</span><span class="p">(</span><span class="n">domainEvent</span><span class="p">.</span><span class="nf">GetType</span><span class="p">());</span>
<span class="k">return</span> <span class="p">(</span><span class="n">INotification</span><span class="p">)</span><span class="n">Activator</span><span class="p">.</span><span class="nf">CreateInstance</span><span class="p">(</span><span class="n">genericDispatcherType</span><span class="p">,</span> <span class="n">domainEvent</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<ul>
<li>Create a handler for the <code>BacklogItemCommitted</code> Domain Event</li>
</ul>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="nn">System</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System.Threading</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System.Threading.Tasks</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">Microsoft.Extensions.Logging</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">MediatR</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">DomainEventsMediatR.Domain</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">DomainEventsMediatR.Persistence</span><span class="p">;</span>
<span class="k">namespace</span> <span class="nn">DomainEventsMediatR.Application</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">OnBacklogItemCommitted</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">Handler</span> <span class="p">:</span> <span class="n">INotificationHandler</span><span class="p">&lt;</span><span class="n">DomainEventNotification</span><span class="p">&lt;</span><span class="n">BacklogItemCommitted</span><span class="p">&gt;&gt;</span>
<span class="p">{</span>
<span class="k">private</span> <span class="k">readonly</span> <span class="n">ApplicationDbContext</span> <span class="n">_db</span><span class="p">;</span>
<span class="k">private</span> <span class="k">readonly</span> <span class="n">ILogger</span><span class="p">&lt;</span><span class="n">Handler</span><span class="p">&gt;</span> <span class="n">_log</span><span class="p">;</span>
<span class="k">public</span> <span class="nf">Handler</span><span class="p">(</span><span class="n">ApplicationDbContext</span> <span class="n">db</span><span class="p">,</span> <span class="n">ILogger</span><span class="p">&lt;</span><span class="n">Handler</span><span class="p">&gt;</span> <span class="n">log</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">_db</span> <span class="p">=</span> <span class="n">db</span><span class="p">;</span>
<span class="n">_log</span> <span class="p">=</span> <span class="n">log</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">public</span> <span class="n">Task</span> <span class="nf">Handle</span><span class="p">(</span><span class="n">DomainEventNotification</span><span class="p">&lt;</span><span class="n">BacklogItemCommitted</span><span class="p">&gt;</span> <span class="n">notification</span><span class="p">,</span> <span class="n">CancellationToken</span> <span class="n">cancellationToken</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">domainEvent</span> <span class="p">=</span> <span class="n">notification</span><span class="p">.</span><span class="n">DomainEvent</span><span class="p">;</span>
<span class="k">try</span>
<span class="p">{</span>
<span class="n">_log</span><span class="p">.</span><span class="nf">LogDebug</span><span class="p">(</span><span class="s">"Handling Domain Event. BacklogItemId: {itemId} Type: {type}"</span><span class="p">,</span> <span class="n">domainEvent</span><span class="p">.</span><span class="n">BacklogItemId</span><span class="p">,</span> <span class="n">notification</span><span class="p">.</span><span class="nf">GetType</span><span class="p">());</span>
<span class="c1">//from here you could </span>
<span class="c1">// - create/modify entities within the same transaction as the backlogItem commit</span>
<span class="c1">// - trigger the publishing of an integration event on a servicebus (don't write it directly though, you need an outbox scoped to this transaction)</span>
<span class="c1">//Remember NOT to call SaveChanges on dbcontext if making db changes when handling DomainEvents</span>
<span class="k">return</span> <span class="n">Task</span><span class="p">.</span><span class="n">CompletedTask</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">exc</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">_log</span><span class="p">.</span><span class="nf">LogError</span><span class="p">(</span><span class="n">exc</span><span class="p">,</span> <span class="s">"Error handling domain event {domainEvent}"</span><span class="p">,</span> <span class="n">domainEvent</span><span class="p">.</span><span class="nf">GetType</span><span class="p">());</span>
<span class="k">throw</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<ul>
<li>Now we just need to configure dependency injection in our application and we’re done</li>
</ul>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">services</span><span class="p">.</span><span class="n">AddTransient</span><span class="p">&lt;</span><span class="n">IDomainEventDispatcher</span><span class="p">,</span> <span class="n">MediatrDomainEventDispatcher</span><span class="p">&gt;();</span>
<span class="n">services</span><span class="p">.</span><span class="nf">AddMediatR</span><span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="n">MediatrDomainEventDispatcher</span><span class="p">).</span><span class="nf">GetTypeInfo</span><span class="p">().</span><span class="n">Assembly</span><span class="p">);</span>
</code></pre></div></div>
<p>You can find the full source code for this post at <a href="https://github.com/cfrenzel/DomainEventsWithMediatR">https://github.com/cfrenzel/DomainEventsWithMediatR</a></p></content><author><name>camron</name></author><category term="dotnet" /><category term="efcore" /><category term="ddd" /><category term="mediatR" /><summary type="html">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.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://cfrenzel.com/assets/images/book-Evans_2004_ddd.jpg" /></entry><entry><title type="html">Quickly Create Your Own .NET Code Templates and Use Them From Anywhere</title><link href="https://cfrenzel.com/dotnet-new-templating-nuget/" rel="alternate" type="text/html" title="Quickly Create Your Own .NET Code Templates and Use Them From Anywhere" /><published>2019-12-20T00:00:00-05:00</published><updated>2019-12-20T00:00:00-05:00</updated><id>https://cfrenzel.com/dotnet-new-templating-nuget</id><content type="html" xml:base="https://cfrenzel.com/dotnet-new-templating-nuget/"><p>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 <code>dotnet new</code> templating! The advantages of this approach include:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>- 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 command
</code></pre></div></div>
<h4>Let's get started:</h4>
<p>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:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">&gt;</span> dotnet new <span class="nt">-l</span>
</code></pre></div></div>
<pre>
Templates Short Name Language Tags
----------------------------------------------------------------------------------------------------------------------------------
Console Application console [C#], F#, VB Common/Console
Class library classlib [C#], F#, VB Common/Library
</pre>
<p>You 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 <code>console</code> in the list above we can type:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">&gt;</span> dotnet new console <span class="nt">-n</span> SampleFromTemplate
</code></pre></div></div>
<p>This will create a new folder with a console app named <code>SampleFromTemplate</code>. It’s ready to go with nuget packages restored and the namespaces set to <em>SampleFromTemplate</em>.</p>
<pre>
SampleFromTemplate
└─── SampleFromTemplate.csproj
└─── Program.cs
└─── /obj
</pre>
<p>To begin creating custom templates with <code>dotnet new</code> 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:</p>
<pre>
└───mycustomtemplate
└─── Templating.ConsoleApp.csproj
└─── Program.cs
└─── /.template_config
└─── template.json
</pre>
<ul>
<li>Start with any existing project and from the project root folder</li>
</ul>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">&gt;</span> <span class="nb">mkdir</span> .template_config
</code></pre></div></div>
<div class="alert alert-warning">
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 <code>.template_config</code> folder. Otherwise you can leave it up to the user to specify on the command line using the <code>-o</code> option.
</div>
<div class="alert alert-warning">
If you want to create empty folders inside your template such as <code>/src</code> <code>/test</code> <code>/doc</code> <code>/build</code> <code>/migrations</code>. For now you will need to place a file named <code>-.-</code> inside the folder otherwise the empty folder will be ignored in the output
</div>
<ul>
<li>Add a <code>template.json</code> to the <code>.template_config</code> folder</li>
</ul>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span>
<span class="s2">"$schema"</span><span class="p">:</span> <span class="s2">"http://json.schemastore.org/template"</span><span class="p">,</span>
<span class="s2">"author"</span><span class="p">:</span> <span class="s2">"Camron Frenzel"</span><span class="p">,</span>
<span class="s2">"classifications"</span><span class="p">:</span> <span class="p">[</span> <span class="s2">"cfrenzel"</span><span class="p">,</span> <span class="s2">"core"</span><span class="p">,</span> <span class="s2">"console"</span> <span class="p">],</span>
<span class="s2">"tags"</span><span class="p">:</span> <span class="p">{</span>
<span class="s2">"language"</span><span class="p">:</span> <span class="s2">"C#"</span>
<span class="p">},</span>
<span class="s2">"identity"</span><span class="p">:</span> <span class="s2">"demo.console"</span><span class="p">,</span>
<span class="s2">"name"</span><span class="p">:</span> <span class="s2">"demo.console_2.2"</span><span class="p">,</span>
<span class="s2">"shortName"</span><span class="p">:</span> <span class="s2">"dm-console-2.2"</span><span class="p">,</span>
<span class="s2">"sourceName"</span><span class="p">:</span> <span class="s2">"Templating"</span><span class="p">,</span>
<span class="s2">"sources"</span><span class="p">:</span> <span class="p">[</span>
<span class="p">{</span>
<span class="s2">"modifiers"</span><span class="p">:</span> <span class="p">[</span>
<span class="p">{</span> <span class="s2">"exclude"</span><span class="p">:</span> <span class="p">[</span> <span class="s2">".vs/**"</span><span class="p">,</span> <span class="s2">".template_config/**"</span> <span class="p">]</span> <span class="p">}</span>
<span class="p">]</span>
<span class="p">}</span>
<span class="p">],</span>
<span class="p">}</span>
</code></pre></div></div>
<ul>
<li><code>identity</code> a unique name for the template</li>
<li><code>name</code> for display purposes</li>
<li><code>shortName</code> what users will type to specify your template</li>
<li><code>sources -&gt; exclude:</code> This is a little trick to keep some unwanted files out of the template</li>
<li>
<p><code>sourceName</code> the name in the source tree to replace with the user specified name (using <code>-n</code> or <code>--name</code>).</p>
<p><strong><code>sourceName</code> is important!</strong>. <code>dotnet new</code> 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</p>
<pre>
└─── Templating.sln
└─── /src
└─── /Templating.ConsoleApp
└─── Templating.ConsoleApp.csproj
└─── /Templating.Domain
└─── Templating.Domain.csproj
└─── /Templating.Application
└─── Templating.Application.csproj
</pre>
<p>Then passing in <code>-n Demo</code> will produce:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp"> &gt;</span> dotnet new demo.console_2.2 <span class="nt">-n</span> Demo
</code></pre></div> </div>
<pre>
└─── Demo.sln
└─── /src
└─── /Demo.ConsoleApp
└─── Demo.ConsoleApp.csproj
└─── /Demo.Domain
└─── Demo.Domain.csproj
└─── /Demo.Application
└─── Demo.Application.csproj
namespaces: Templating.ConsoleApp -&gt; Demo.ConsoleApp
</pre>
</li>
<li>At this point you should be comfortable with these concepts
<ul>
<li>a template is a normal solution/project/file</li>
<li>add a <code>.template_config</code> folder with a <code>template.config</code> file in it to configure a template</li>
<li>the user will pass in a –name <em>MyApp</em> to the template that will replace the configured <code>sourceName</code> text in all folders/solutions/projects/namespaces</li>
</ul>
</li>
</ul>
<div class="alert alert-primary">
<strong>Tip!</strong> To have nuget restore automatically - add this to your template.config
<pre>
"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
}
]
</pre>
</div>
<div class="alert alert-danger">
<strong>Issue!</strong> 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.
<pre>
"primaryOutputs": [
{ "path": "SolutionName.ConsoleApp/SolutionName.ConsoleApp.csproj" }
],
"postActions": [
{
"description": "Add project to solution",
"manualInstructions": [],
"primaryOutputIndexes": "0",
"actionId": "D396686C-DE0E-4DE6-906D-291CD29FC5DE",
"continueOnError": true
}
]
</pre>
<a href="https://github.com/dotnet/templating/issues/1489">https://github.com/dotnet/templating/issues/1489</a>
</div>
<p>If you haven’t created your own template at this point you can follow along by downloading a console app template with logging/DI/configuration <a href="https://github.com/cfrenzel/dotnet-new-templates-2.2/tree/master/templates/ConsoleApp">here</a></p>
<h4>Installing a template</h4>
<p>We could install our template locally from the template root folder.</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">dotnet new -i .
</span></code></pre></div></div>
<p>List the installed templates and you should see your template listed</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">dotnet new -l
</span></code></pre></div></div>
<p>You can use it by passing in it’s <code>shortName</code> and provide a name</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp"> &gt;</span> dotnet new <span class="o">{</span>shortname<span class="o">}</span> <span class="nt">-n</span> DemoApp
</code></pre></div></div>
<p>To remove your template</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">dotnet new -u
</span></code></pre></div></div>
<p>You should see your template along with an <code>Uninstall command:</code>. This command will come in handy as things can get confusing when managing multiple versions of your templates and installing them from different sources.</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go"> dotnet new -u C:\temptemplate\temptemplate
</span></code></pre></div></div>
<p>Not 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.</p>
<h4>Packaging templates</h4>
<p>The <code>dotnet new</code> 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.</p>
<p>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:</p>
<pre>
└─── /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
</pre>
<p>The idea is that you have a solution with a /templates folder and a special project: <code>template.csproj</code> 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 <code>templates.csproj</code> so it’s nice to have a seperate solution for running/editing each template.</p>
<ul>
<li>You can start by creating <code>templates.csproj</code> as a console app. Open the .csproj file and edit it to look like this:</li>
</ul>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;Project</span> <span class="na">Sdk=</span><span class="s">"Microsoft.NET.Sdk"</span><span class="nt">&gt;</span>
<span class="nt">&lt;PropertyGroup&gt;</span>
<span class="nt">&lt;PackageType&gt;</span>Template<span class="nt">&lt;/PackageType&gt;</span>
<span class="nt">&lt;TargetFramework&gt;</span>netcoreapp2.2<span class="nt">&lt;/TargetFramework&gt;</span>
<span class="nt">&lt;PackageId&gt;</span>cfrenzel-dotnet-new-templates-2.2<span class="nt">&lt;/PackageId&gt;</span>
<span class="nt">&lt;Title&gt;</span>cfrenzel dotnet-new-templates<span class="nt">&lt;/Title&gt;</span>
<span class="nt">&lt;IncludeContentInPack&gt;</span>true<span class="nt">&lt;/IncludeContentInPack&gt;</span>
<span class="nt">&lt;IncludeBuildOutput&gt;</span>false<span class="nt">&lt;/IncludeBuildOutput&gt;</span>
<span class="nt">&lt;ContentTargetFolders&gt;</span>content<span class="nt">&lt;/ContentTargetFolders&gt;</span>
<span class="nt">&lt;/PropertyGroup&gt;</span>
<span class="nt">&lt;ItemGroup&gt;</span>
<span class="nt">&lt;Content</span> <span class="na">Include=</span><span class="s">"ConsoleApp\**"</span> <span class="na">Exclude=</span><span class="s">"ConsoleApp\SolutionName.sln;ConsoleApp\**\bin\**;ConsoleApp\**\obj\**;ConsoleApp\**\.vs\**"</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;Content</span> <span class="na">Include=</span><span class="s">"EFCore.MigrationProjects\**"</span> <span class="na">Exclude=</span><span class="s">"EFCore.MigrationProjects\**\bin\**;EFCore.MigrationProjects\**\obj\**;EFCore.MigrationProjects\**\.vs\**"</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;Content</span> <span class="na">Include=</span><span class="s">"Solution\**"</span> <span class="na">Exclude=</span><span class="s">"Solution\**\bin\**;Solution\**\obj\**;Solution\**\.vs\**"</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;Compile</span> <span class="na">Remove=</span><span class="s">"**\*"</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;/ItemGroup&gt;</span>
<span class="nt">&lt;/Project&gt;</span>
</code></pre></div></div>
<ul>
<li><code class="highlighter-rouge">&lt;PackageType&gt;Template&lt;/PackageType&gt;</code> - set special package type for project</li>
<li>For each template in our package we are adding a <code class="highlighter-rouge">&lt;Content&gt;</code> tag that specifies which files to include and exclude
<ul>
<li><code class="highlighter-rouge">&lt;Content Include="ConsoleApp\**"</code> - include everything from our /ConsoleApp folder</li>
<li><code class="highlighter-rouge">Exclude="ConsoleApp\Templating.sln;ConsoleApp\**\bin\**;ConsoleApp\**\obj\**;ConsoleApp\**\.vs\**" /&gt;</code> - exclude the solution file and bin/obj folders</li>
</ul>
</li>
<li>
<p><code class="highlighter-rouge">&lt;Compile Remove="**\*" /&gt;</code> - we’re not interested in the output of the compiled project</p>
</li>
<li>We can specify metadata for the package in <code>Directory.Build.props</code></li>
</ul>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;Project&gt;</span>
<span class="nt">&lt;PropertyGroup&gt;</span>
<span class="nt">&lt;Authors&gt;</span>Camron Frenzel<span class="nt">&lt;/Authors&gt;</span>
<span class="nt">&lt;RepositoryUrl&gt;</span>https://github.com/cfrenzel/dotnet-new-templates-2.2.git<span class="nt">&lt;/RepositoryUrl&gt;</span>
<span class="nt">&lt;PackageProjectUrl&gt;</span>https://github.com/cfrenzel/dotnet-new-templates-2.2<span class="nt">&lt;/PackageProjectUrl&gt;</span>
<span class="nt">&lt;Description&gt;</span>dotnet new templates for core 2.2<span class="nt">&lt;/Description&gt;</span>
<span class="nt">&lt;PackageTags&gt;</span>template dotnet console migration web<span class="nt">&lt;/PackageTags&gt;</span>
<span class="nt">&lt;PackageLicense&gt;&lt;/PackageLicense&gt;</span>
<span class="nt">&lt;Version&gt;</span>1.0.0<span class="nt">&lt;/Version&gt;</span>
<span class="nt">&lt;/PropertyGroup&gt;</span>
<span class="nt">&lt;/Project&gt;</span>
</code></pre></div></div>
<ul>
<li>Now we can create our nuget package using <code>templates.csproj</code></li>
</ul>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">dotnet pack .\templates\templates.csproj -o .\artifacts\ --no-build
</span></code></pre></div></div>
<p>And install all of our templates locally from our <code>.nupkg</code> file</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">dotnet new -i .\artifacts\cfrenzel-dotnet-new-templates-2.2.1.0.0
</span></code></pre></div></div>
<p>Find the <code>Uninstall command:</code> to remove</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">dotnet new -u
</span></code></pre></div></div>
<h4>Publish package for access online</h4>
<p>You can host your template .nupkg for free using my <a href="https://www.myget.org/">MyGet</a> or make it official/perminent using <a href="https://www.nuget.org/">NuGet.org</a>. This can be as simple as typing</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">dotnet nuget push artifacts\**\*.nupkg -s "https://www.myget.org/F/{youraccount}/api/v2/package" -k {yourkey}
</span></code></pre></div></div>
<p>Then installing your templates from anywhere using</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">dotnet new --install {yourpackagename} --nuget-source https://www.myget.org/F/{youraccount}/api/v3/index.json
</span></code></pre></div></div>
<div class="alert alert-primary">
If you publish it to <strong>nuget.org</strong> you don't even have to specify the package url!
dotnet new --install {yourpackagename}
</div>
<p>-Since we’re pretty much one configuration file away from free continuous build and deployment, let’s setup <a href="https://www.appveyor.com/">AppVeyor</a> to build and publish our template package every time we commit a change to the source code.</p>
<ul>
<li>Save you code to <a href="https://github.com">Github</a> or wherever</li>
<li>Add an <code>appveyor.yml</code> to build and publish template package to MyGet</li>
</ul>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>version: '1.{build}'
image: Visual Studio 2019
environment:
MyGetApiKey:
secure: 56nW3KcP4naYX9mlsVEIKLj5xPdfmpt6lMALR6wQmorRQOaoUOtlwMZ2V0BtGTAM
NugetApiKey:
secure: /54XAunyBETRa1Fp/qSrwvebSnTAcHDO2OVZ+exMtQtOtrBzHKvp4RC1AB8RD2PQ
pull_requests:
do_not_increment_build_number: true
branches:
only:
- master
nuget:
disable_publish_on_pr: true
test: off
build_script:
- dotnet restore
- dotnet pack .\templates\templates.csproj -o .\artifacts\ --no-build
deploy_script:
- ps: dotnet nuget push artifacts\**\*.nupkg -s "https://www.myget.org/F/cfrenzel-ci/api/v2/package" -k $env:MyGetApiKey
</code></pre></div></div>
<p>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.</p>
<h4>Final Thoughts</h4>
<p>Though templating with <code>dotnet new</code> has some more powerful features including:</p>
<ul>
<li>conditional logic</li>
<li>custom parameters</li>
<li>post actions</li>
<li>multi-language</li>
<li><a href="https://github.com/dotnet/templating/wiki/Reference-for-template.json">see docs - template.json</a></li>
</ul>
<p>I 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.</p>
<p><a href="https://github.com/cfrenzel/dotnet-new-templates-2.2">full source code </a> for this post.</p></content><author><name>camron</name></author><category term="featured" /><category term="dotnet" /><category term="automation" /><category term="nuget" /><category term="appveyor" /><summary type="html">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:</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://cfrenzel.com/assets/images/dotnet-new.png" /></entry><entry><title type="html">Publishing .NET Core NuGet Packages with Nuke and AppVeyor</title><link href="https://cfrenzel.com/publishing-nuget-nuke-appveyor/" rel="alternate" type="text/html" title="Publishing .NET Core NuGet Packages with Nuke and AppVeyor" /><published>2019-12-17T00:00:00-05:00</published><updated>2019-12-17T00:00:00-05:00</updated><id>https://cfrenzel.com/publishing-nuget-nuke-appveyor</id><content type="html" xml:base="https://cfrenzel.com/publishing-nuget-nuke-appveyor/"><p>This article builds on concepts discussed by <a href="https://andrewlock.net/publishing-your-first-nuget-package-with-appveyor-and-myget/">Andrew Lock</a>, <a href="https://lostechies.com/jimmybogard/2016/05/24/my-oss-cicd-pipeline/">Jimmy Bogard</a> and <a href="https://blog.dangl.me/archive/escalating-automation-the-nuclear-option/">Georg Dangl</a>. Here we’re going use <a href="https://nuke.build/">Nuke</a> to make build, packaging and publishing even nicer!!!</p>
<p>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 <a href="https://nuke.build/">Nuke</a> on a project and for the first time I feel like I didn’t waste any time fighting with it.</p>
<p>Nuke creates a CSharp Console App within your solution containing a simple <code>Build.cs</code> 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!</p>
<p>Let’s jump in.</p>
<h4>Using Nuke to Build</h4>
<ul>
<li>Install Nuke</li>
</ul>
<pre>
&gt; dotnet tool install Nuke.GlobalTool --global
</pre>
<ul>
<li>Add Nuke to your solution - let the wizard get you started</li>
</ul>
<pre>
&gt; nuke :setup
</pre>
<p><img src="/assets/images/nuke-setup-screen.png" alt="nuke setup" title="nuke setup" height="400" /></p>
<div class="alert alert-warning" role="alert">
<strong>Warning:</strong> 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<br />
TODO:/// Figure out Nuke's logic for framework selection and see if it's configurable
</div>
<p>You’ll notice a new project in your solution named <code>_build</code>. Take note of a few files</p>
<ol>
<li><code>Build.cs</code> - a fluent “make style” build Class in C#
<ul>
<li>Defines targets and their dependencies</li>
</ul>
</li>
<li>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.
<ul>
<li><code>build.ps1</code> - a powershell script used to execute builds (platform independent - must have powershell installed)</li>
<li><code>build.sh</code> - a shell script version (linux/osx/etc..)</li>
</ul>
</li>
</ol>
<ul>
<li>Now compile your code</li>
</ul>
<pre>
&gt; .\build.ps1 Compile
</pre>
<p><img src="/assets/images/nuke-compile-screen.png" alt="nuke compile" title="nuke compile" height="600" /></p>
<p><strong>Success!</strong> 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.</p>
<ul>
<li>Add a <strong>Pack</strong> step to our build script</li>
</ul>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Target</span> <span class="n">Pack</span> <span class="p">=&gt;</span> <span class="n">_</span> <span class="p">=&gt;</span> <span class="n">_</span>
<span class="p">.</span><span class="nf">DependsOn</span><span class="p">(</span><span class="n">Compile</span><span class="p">)</span>
<span class="p">.</span><span class="nf">Executes</span><span class="p">(()</span> <span class="p">=&gt;</span>
<span class="p">{</span>
<span class="nf">DotNetPack</span><span class="p">(</span><span class="n">s</span> <span class="p">=&gt;</span> <span class="n">s</span>
<span class="p">.</span><span class="nf">SetProject</span><span class="p">(</span><span class="n">Solution</span><span class="p">.</span><span class="nf">GetProject</span><span class="p">(</span><span class="s">"Nuke.Sample"</span><span class="p">))</span>
<span class="p">.</span><span class="nf">SetConfiguration</span><span class="p">(</span><span class="n">Configuration</span><span class="p">)</span>
<span class="p">.</span><span class="nf">EnableNoBuild</span><span class="p">()</span>
<span class="p">.</span><span class="nf">EnableNoRestore</span><span class="p">()</span>
<span class="p">.</span><span class="nf">SetDescription</span><span class="p">(</span><span class="s">"Sample package produced by NUKE"</span><span class="p">)</span>
<span class="p">.</span><span class="nf">SetPackageTags</span><span class="p">(</span><span class="s">"nuke demonstration c# library"</span><span class="p">)</span>
<span class="p">.</span><span class="nf">SetNoDependencies</span><span class="p">(</span><span class="k">true</span><span class="p">)</span>
<span class="p">.</span><span class="nf">SetOutputDirectory</span><span class="p">(</span><span class="n">ArtifactsDirectory</span> <span class="p">/</span> <span class="s">"nuget"</span><span class="p">));</span>
<span class="p">});</span>
</code></pre></div></div>
<p>We want our NuGet package to specify an author, repository, homepage, etc… We could do this programatically from Nuke</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">Target</span> <span class="n">Pack</span> <span class="p">=&gt;</span> <span class="n">_</span> <span class="p">=&gt;</span> <span class="n">_</span>
<span class="p">.</span><span class="nf">DependsOn</span><span class="p">(</span><span class="n">Compile</span><span class="p">)</span>
<span class="p">.</span><span class="nf">Executes</span><span class="p">(()</span> <span class="p">=&gt;</span>
<span class="p">{</span>
<span class="nf">DotNetPack</span><span class="p">(</span><span class="n">s</span> <span class="p">=&gt;</span> <span class="n">s</span>
<span class="p">***</span>