SlideShare a Scribd company logo
Net In Action Second Edition Meap V06 2nd
Chapters 1 To 12 Of 13 Dustin Metzgar download
https://ebookbell.com/product/net-in-action-second-edition-
meap-v06-2nd-chapters-1-to-12-of-13-dustin-metzgar-53733100
Explore and download more ebooks at ebookbell.com
Here are some recommended products that we believe you will be
interested in. You can click the link to download.
Net In Action Second Edition Meap 2nd Edition Dustin Melager
https://ebookbell.com/product/net-in-action-second-edition-meap-2nd-
edition-dustin-melager-56838458
Aspnet Core In Action Second Edition 2nd Edition Andrew Lock
https://ebookbell.com/product/aspnet-core-in-action-second-
edition-2nd-edition-andrew-lock-23669072
Rxnet In Action With Examples In C 1st Edition Tamir Dresher
https://ebookbell.com/product/rxnet-in-action-with-examples-in-c-1st-
edition-tamir-dresher-7004318
Net Maui In Action Meap V06 Chapters 1 To 9 Of 12 Matt Goldman
https://ebookbell.com/product/net-maui-in-action-
meap-v06-chapters-1-to-9-of-12-matt-goldman-49608804
Net Core In Action 1st Edition Dustin Metzgar
https://ebookbell.com/product/net-core-in-action-1st-edition-dustin-
metzgar-7144112
Aspnet Core In Action Meap V05 3rd Chapters 1 To 11 Andrew Lock
https://ebookbell.com/product/aspnet-core-in-action-meap-v05-3rd-
chapters-1-to-11-andrew-lock-47541526
Aspnet Mvc In Action 1st Edition Jeffrey Palermo Ben Scheirman
https://ebookbell.com/product/aspnet-mvc-in-action-1st-edition-
jeffrey-palermo-ben-scheirman-2194282
Aspnet Ajax In Action 1st Edition Alessandro Gallo David Barkol Rama
Krishna Vavilala
https://ebookbell.com/product/aspnet-ajax-in-action-1st-edition-
alessandro-gallo-david-barkol-rama-krishna-vavilala-4097390
Aspnet Core In Action 1st Edition Andrew Lock
https://ebookbell.com/product/aspnet-core-in-action-1st-edition-
andrew-lock-7042438
Net In Action Second Edition Meap V06 2nd Chapters 1 To 12 Of 13 Dustin Metzgar
Net In Action Second Edition Meap V06 2nd Chapters 1 To 12 Of 13 Dustin Metzgar
Net In Action Second Edition Meap V06 2nd Chapters 1 To 12 Of 13 Dustin Metzgar
.NET in Action, Second Edition
1. 1 Why_.NET?
2. 2 Building_a_console_application
3. 3 Creating_web_services_and_applications_with_ASP.NET_Core
4. 4 File_and_network_IO
5. 5 Using_Entity_Framework_Core_with_relational_databases
6. 6 Unit_testing_fundamentals
7. 7 Substituting_dependencies_in_tests
8. 8 Integration_testing
9. 9 Security
10. 10 Performance_and_profiling
11. 11_Handling_failures
12. 12_Building_world-ready_applications
13. About_this_MEAP
14. Welcome
15. index
1 Why .NET?
This chapter covers
What is .NET?
Where is .NET used?
.NET in the job market
What is in the .NET runtime?
There has never been a better time to be a .NET developer. .NET runs on
almost everything: from embedded devices and sensors to game engines like
Unity and Godot, from mobile devices to all major clouds. The skills you’ll
learn from this book apply across the broad .NET ecosystem. This book
covers the necessary foundation and gets you building production-ready
applications.
.NET looks a lot different now than it did in 2002 when I was first starting
working with it professionally. Features were introduced, improved, and
sometimes replaced or deprecated but still supported. Microsoft maintained
backward-compatibility with each version of the .NET Framework to prevent
breaking existing applications. This was great for customers but resulted in
the accumulation of some "baggage" over the past 20 years.
The first edition of this book, .NET Core in Action, explored how Microsoft
decided to "hit refresh" and begin anew. They mixed the best parts of .NET
with some new ideas and modern techniques to create .NET Core. Having
different .NET’s, like Framework and Core (and Standard), caused some
confusion and Core was clearly the future. So Microsoft decided to drop the
"Core" and just go with .NET when they released .NET 5 (5 being greater
than .NET Core 3.0 and .NET Framework 4.8). In .NET 6, 7, 8, and beyond
we’re seeing an evolution of what was once .NET Core. Whether you’re new
to .NET or an experienced veteran, this is an exciting time to be a .NET
developer.
What happened to Core, Framework, and Standard?
In the beginning, there was the .NET Framework. Over time, the .NET
Framework struggled to stay competitive - burdened by the weight of
backward compatibility. To start fresh, the .NET team started to work on a
new version called .NET Core. .NET Core incorporated a lot of new ideas:
design and build in the open, work on any platform, focus on web
performance, etc.
To make existing libraries port easily between Framework and Core, the
.NET Standard was introduced. The .NET Standard only defines the APIs
that a .NET implementation needs to implement. If you have some projects
that are .NET Framework and others that are .NET Core, 5, or later, those
projects can use common libraries that target the .NET Standard. So even
though there will be no new iterations to the .NET Standard, it is still a very
useful tool for incrementally porting applications to the newest versions of
.NET.
Starting with .NET 5, Microsoft has tried to simplify by culling Core,
Framework, and Standard and just having one .NET with some OS-specific
targeting capabilities. If you want to develop in .NET, forget about Core and
Framework and just target the latest long-term support (LTS) release of
.NET. If you need to support older versions of .NET, try targeting the .NET
Standard as that will give your libraries the broadest reach. This subject is
explored more in appendix A, A brief history of .NET.
1.1 What is .NET?
.NET is free, cross-platform, and open source. It is a runtime, not a
programming language. There is only one language that the .NET runtime
understands called the Common Intermediate Language, or CIL (this is more
commonly referred to as IL but I’ll try to keep with CIL to disambiguate from
other intermediate languages). CIL is a low-level language, similar to
Assembly. Don’t worry though, you won’t have to learn CIL because .NET
comes with compilers that compile high level languages to CIL.
.NET fully supports three languages: C#, F#, and Visual Basic (VB.NET). C#
is the most widely used by a large margin and all examples in this book are in
C#. Code written in .NET has access to other .NET code, regardless of the
language used. This means if some part of your C# application is better
expressed in F# you don’t need to convert everything to F#. This works
because the .NET compilers all produce CIL. The C#, F#, and VB.NET
compilers are packaged with .NET but any language that compiles to CIL
will work with .NET. There are many other languages contributed by the
.NET community. You can even create your own.
What other languages are supported by .NET?
The .NET open source community has created compilers for other languages
to work in .NET.
Project Name Language Website
PeachPie PHP https://www.peachpie.io/
IronPython Python https://ironpython.net/
MoonSharp Lua https://www.moonsharp.org/
Jint JavaScript Interpreter https://github.com/sebastienros/jint
I’ve mentioned that .NET is a runtime, but what does that mean? Think of a
runtime as an interpreter that can read code in a certain format (Intermediate
Language or IL - think bytecode if you’re familiar with Java) and execute it.
The .NET runtime is called the CoreCLR. CLR stands for Common Language
Runtime, with common referring to how every .NET language uses the same
runtime. When .NET was originally built, the runtime was simply called
CLR, without the "Core". The Core part was added as part of .NET Core to
distinguish it from the original CLR (part of the .NET Framework) and the
name stuck. The runtime has important features such as Just-In-Time (JIT)
compilation and memory management that we’ll explore later in this book.
How CIL, the compilers, and the CoreCLR fit together is shown in 1.1.
Figure 1.1. .NET compilers, CIL, and CoreCLR
In addition to the runtime and some language compilers, .NET has a class
library. The .NET class library is called the Framework Class Library, but is
referred to as CoreFX. .NET veterans may remember this used to be called
the Base Class Library, or BCL (sometimes called FX by Microsoft
internally), but that has been replaced with CoreFX. CoreFX provides a set of
APIs that handle many base-level functions (console output, file I/O, network
I/O, etc).
Outside of the .NET class library (CoreFX) there are some powerful features
that come with .NET. These are built by .NET teams and supported by
Microsoft. This book will introduce you to the following key features as well
as some useful projects created by the open source community.
Entity Framework Core for access to data stores
ASP.NET Core for web services and applications
Blazor for running .NET in a browser using WebAssembly
Multi-platform App UI (MAUI) for desktop and phone applications
1.2 Where is .NET used?
ASP.NET Core is .NET’s web framework. It can be hosted in either a
lightweight server called Kestrel or in the Windows Internet Information
Services (IIS) host. Kestrel enables ASP.NET Core to run on containers,
which makes ASP.NET Core perfect for microservices. There are a number
of hosting services available in cloud providers that either use the container
model, IIS, or serverless options.
.NET is also used in desktop (aka thick client) applications. There are many
options to choose from. Traditional Windows Forms applications are
available, which is helpful for maintaining older applications. Windows
Presentation Foundation (WPF) has an XML-based approach and is widely
used for desktop applications.
You can also write .NET applications with WinUI. This gives you access to
PC, tablet, Xbox, and Hololens. WinUI makes it easier to interact with touch,
pen, and game controller input as well as mouse and keyboard. To write iOS,
macOS, and Android applications, use Xamarin or the new Multi-platform
App UI (MAUI), which is an evolution of Xamarin.
If you’re interested in small devices, sensors, and micro-controllers, there are
many opportunities to use .NET. For instance, .NET runs on boards like the
Raspberry Pi and the Hummingboard. The .NET IoT (Internet of Things)
community maintains a set of components for device bindings to work with
specific hardware. These are things such as LCDs, temperature sensors, and
analog-to-digital converters. If the hardware is too small to run .NET 6, there
are "lighter" implementations like the .NET nanoFramework and Meadow,
which work on embedded devices.
1.2.1 .NET in gaming
Unity has been using C# for scripting game objects since its early releases.
Before .NET Core, Unity used Mono, which was an unofficial, cross-
platform, open source port of .NET. This had enough capability to handle
scripting for many years. Mainstream cross-platform support, language
enhancements, and performance improvements convinced Unity to migrate to
.NET Core.
One of the objections to using .NET or similar runtimes like Java is that they
are "managed" rather than "native". Native code is compiled to work on a
specific machine and usually manages memory on its own. Managed code, by
contrast, executes in a runtime using an interpreter. The runtime often
provides memory management via garbage collection. Garbage collection is
undesirable in real-time applications because it can create unpredictable
pauses while the garbage collector runs. We’ll learn why that happens later
on.
Unity uses .NET for scripting game objects, but not for its engine code. That
is written in native C++. The same goes for Godot and CRYENGINE (two
other popular game engines). It begs the question: can managed code be used
for the entire game engine?
One answer to this question is Stride, an open source game engine written in
C#. Stride is a powerful, free engine that handles real-time 3D and VR. It is
still young and doesn’t yet have the community of Unity but does show that
.NET even does pretty well with real-time 3D. Visit https://www.stride3d.net/
to learn more about the project.
Another project called Ryujinx makes a compelling case that .NET can
handle realtime games. Ryujinx is a Nintendo Switch emulator that is written
entirely in C# and emulates the ARM CPU. The Ryujinx team has even
driven some performance improvements in .NET. Check the project out at
https://ryujinx.org/.
1.2.2 Popular .NET open source projects
This book will introduce many important .NET concepts and reinforce your
learning with exercises. Writing code for the exercises helps with the learning
process. I also suggest contributing to open source projects. Reading code
from other projects is a great way to see how .NET constructs are used. If
you’re looking for .NET projects to participate in, the .NET Foundation is a
good place to start. .NET Foundation projects have common rules about
contributor agreements, code of conduct, and licensing. Most, but not all,
projects mentioned in this book are part of the .NET Foundation; all of them
are on GitHub.
ASP.NET Core is .NET’s web framework and is a great starting point for
building web applications and services. Naturally, many open source projects
are for ASP.NET Core applications. If you want more features than those
built-in to ASP.NET Core, there are a few open source (and commercial)
options. For instance, DotVVM has built-in components and reduces the
number of round-trips to the server by implementing most features in
Knockout JS. There is also ASP.NET Boilerplate - a framework that handles
common development tasks by convention and provides a lot of templates. If
you’re interested in Blazor (introduced later in this book), check out Oqtane
or the Ant Design Blazor project. If you want a full web site that handles just
about everything where you can build your application as a custom
component, check out some of the .NET content management systems (CMS)
like Orchard, Umbraco, Piranha, or DNN (aka DotNetNuke).
MAUI, the Multi-platform App User Interface, is a relatively new product for
building applications for any platform. There are other options in this space
as well that are worth investigating. Reactive UI, for example, is a framework
for building applications using functional reactive programming. If you’ve
not heard of reactive programming, check out ReactiveX at
https://reactivex.io. Another cross-platform UI framework is Avalonia.
Avalonia makes the XAML-based UI programming from WPF (Windows
Presentation Foundation) work on other platforms like Linux and Mac but
also in the browser (via WebAssembly).
Some other interesting projects to use or contribute to:
Graphics
ImageSharp, Silk.NET, SkiaSharp
Database
Dapper, LINQ to DB, Marten
Testing utilities
xUnit, Verify, BenchmarkDotNet, Moq, FluentAssertions
Distributed systems
Akka.NET, Orleans
Workflow
Elsa Workflows
Build tools
Cake
1.3 .NET in the job market
Stack Overflow (which is built with .NET) holds an annual developer survey
to learn about all facets of development from geography and years in industry
to the most loved or dreaded frameworks. In the 2021 survey, .NET is
mentioned in a few key areas:
.NET Core / .NET 5 is the most loved framework and the 2nd highest
paying
ASP.NET Core is the 2nd most loved web framework, losing only by a
small percentage but with 7 times as many votes as the #1 web
framework
ASP.NET Core also ranked as the 3rd highest paying web framework
F# ranked as the 2nd highest-paying programming language
There is a lot of information in the report and it’s worth a read. You can find
each year’s report here: https://insights.stackoverflow.com/survey
1.4 When to use .NET
At one time, .NET was a Windows-only framework. This hasn’t been true for
years. .NET works on Windows, Linux, and Mac for desktop applications as
well as Android and iOS for phone and tablet. .NET is used in
microcontrollers, IoT devices, and games. You can even use .NET in shell
scripting via PowerShell. But the bulk of jobs in .NET will be for web
services and applications.
Whether or not you should use .NET depends on your scenario. Here is a list
of scenarios where .NET is an option but not commonly used.
Data science
While some strides have been made in using .NET for data science and
machine learning, it would be better to start with Python.
Hardware drivers
Managed code in hardware drivers could be useful in that the code is
safer and easier to write. However, it requires an understanding of
garbage collection, JIT/AOT compilation, and trimming. A language
like Rust may be a better starting point.
Games
Game developers using an engine like Unity or Godot can use C# in
their scripts. There are books and tutorials specifically covering C# for
these use cases that would be more targeted than this book. .NET has
been used in the past to write entire games but this book doesn’t explore
those frameworks.
This is not to say that .NET cannot be used in these scenarios. Choosing what
language/framework to use depends on many factors, such as performance,
security, what the development team is comfortable with, what support is
available, and how big (and welcoming) the community is. .NET has 20 years
of hardening and improvements plus millions of active developers. It is open
source with a large and engaged community. .NET has strong support from
Microsoft, even without the support contracts that many companies already
have.
Given that you’re reading this book, you’re at least considering .NET for
your application. Try building the examples for the first few chapters and see
for yourself how powerful and easy to use .NET can be.
1.5 What will I learn from this book?
This book aims at two types of developer: (1) those that are familiar with
other programming languages and are new to .NET and (2) those that have
previous .NET experience but are looking to catch up with the latest. If
you’re new to programming in general, this book may be difficult to follow. I
assume you have a general idea of the following concepts:
Software patterns
Some basic patterns are used in this book such as Singleton, MVC, and
method-chaining. A lot of these patterns are well-known so the book
only does a brief introduction. It’s generally important to know what
software patterns are as they provide a language for communicating with
other software developers.
Web services and web applications
If you know about URLs, HTTP, requests, responses, and web servers
then you should be able to follow the examples.
Terminal usage
The examples in this book provide instructions that are executed in the
terminal (command line in Windows). If you’re using an IDE like
Visual Studio or Rider, you may need to look up how to translate those
commands into actions in the UI or just have a terminal open along with
your IDE.
Developers reading this book that have used .NET in the past may want to
consider skimming the first few chapters. If you haven’t used .NET in a
while, here are some relatively new concepts (as of .NET 6) that are covered
in the first three chapters:
Top-level statements
Records
Nullable reference types, null coalescing, and other null operators
Global and implicit usings
"dotnet watch" and Hot Reload
As you read the table of contents for this book, you may wonder how
everything fits together. 1.2 shows how these topics align. In this chapter,
we’re building an understanding of the CoreCLR and the services it offers.
On top of that, we’ll learn C# throughout the first few chapters. The class
libraries available in CoreFX are essential to understand what is available in
.NET and what has to be pulled in via external packages.
Figure 1.2. High level diagram of how topics covered in the book fit together
The dashed boxes arranged vertically indicate cross-cutting concerns. For
example, performance is a subject that impacts everything from
understanding how the JIT compiler impacts your application to how to use
ASP.NET Core more efficiently. While there are several areas that involve
ASP.NET Core, such as security and fault-handling, this book is focused on
.NET in general and not intended to be a comprehensive reference on
ASP.NET Core.
By the end of this book, you should be able to author and deploy libraries,
console applications, web services, and web applications. Your applications
will be able to store and manipulate data in databases and through other
services. You will have an intermediate-level understanding of important
.NET concepts and features. My goal with this book is to quickly get you to
the point where you can develop .NET applications professionally. It’s
definitely possible to dive deeper into many of the subjects introduced here
and there are other books available from Manning that will help you do that.
1.6 What is in the .NET runtime?
I mentioned before that .NET is managed, which means it uses a runtime.
.NET’s runtime, the CoreCLR, has three important concepts that influence
how you write code in .NET: Intermediate Language (CIL), Just-In-Time
(JIT) Compilation, and Garbage Collection (GC). We’ll explore these at a
high level first and get into details as they become relevant later in the book.
1.6.1 Intermediate language
The code you write in any language needs to be compiled into some machine-
readable form. But what does machine-readable mean? In order for code to
execute on a processor, it needs to use the right set of instructions. The two
most popular instruction sets for modern computers are x86 and ARM. There
are many others especially when you include GPUs (graphical processing
units), which are used for games (think shaders), cryptocurrency mining, and
data processing. New generations of processors may add new instructions to
an instruction set so it’s important to know what generation a processor is.
Operating systems also impose some requirements on application machine
code (i.e. an Android executable won’t run on Windows). Often you’ll need
different compilers for different platforms.
Figure 1.3. Creating an executable application without a runtime (unmanaged)
1.3 shows a simplified matrix of producing machine-readable code for one
specific OS and CPU. MacOS/iOS applications typically use the xCode
compiler and choose the CPU architecture to build for. OS versions matter,
for example OSX 10, 11, and 12 have compatibility differences. OS flavors
also matter (think Redhat vs Ubuntu vs Debian).
Intermediate language offers an alternative. It’s a language that can be
quickly translated into machine code. The compiler is specific to the
language, not the OS or processor architecture you’re targeting. If you’re
familiar with Assembly language, CIL is similar but has instructions at a
slightly higher level of abstraction. Having your code compiled into CIL
means that your application’s binaries (the files produced through
compilation) can run on any processor or OS with a .NET runtime.
Figure 1.4. .NET languages compile to CIL in a DLL file, that can be run on any machine with a
.NET runtime
In 1.4 the compiler is only specific to the language. The compiler creates
Common Intermediate Language (CIL) code and puts it in a DLL file. The
DLL file can be transferred to any machine regardless of OS or processor
architecture as long as there is a .NET runtime. The .NET runtime converts
the CIL to machine readable code (typically at runtime using the Just-In-
Time compiler introduced in the next section).
What is a DLL?
When you write programs, you almost always make calls into some library to
invoke operations. Writing to the console, allocating memory, creating a
thread, opening a file, and many other functions are relatively simple
operations because of libraries. For some languages, like C/C++, there is a
"link" step during the build process that links your code to the static libraries
it uses. Static linking includes the library in your application and that library
cannot be reused by other applications. If the library is updated, the
application has to be rebuilt and redistributed.
DLL stands for Dynamically Linked Library. DLLs expose a public surface
area and can be reused by any application. This reduces the size of a
distributed application while also allowing .NET to distribute new (minor)
versions with bugfixes without each application needing to rebuild and
redistribute. DLLs are usually installed or registered with the operating
system so they can be shared (but if applications use different versions or
DLLs reference other DLLs with different versions you get into what many
refer to as "DLL hell"). The concept of a DLL is not exclusive to .NET.
1.6.2 Just-In-Time Compilation
In the previous section, 1.4 shows that .NET has compilers for C#, F#, and
VB included. Since these languages have already been compiled, why is there
another compiler inside the CoreCLR (.NET runtime)? A compiler is really
only a program that translates a program in one language into another
language. The name compiler is typically used for translating a high-level
language into a low-level language and that is true of the VB, C#, and F#
compilers.
Note
If a compiler translates one high-level language into another, like C# to
JavaScript, it is typically called a transpiler.
There are also compilers that translate a program in a low-level language into
a high-level language. These are typically called decompilers.
As noted before, CIL is still at a higher level than machine code. CIL makes
no assumptions about processor architecture specifics (registers, instruction
sets, cache sizes, etc.) so that it can work on as many platforms as possible.
How this works is something we’ll explore in more depth in chapter 10,
Performance and profiling.
Before .NET code can be executed on a processor, the CIL needs to be
compiled further down into machine code. The CoreCLR will perform this
compilation at runtime so that the CIL DLLs don’t need to be compiled into
processor-specific DLLs ahead of time. But compilation can be an expensive
process and compiling an entire application every time it runs could impact
startup performance. This is handled by a smart compiler that only compiles
the code that is about to be used. In other words, the CIL is compiled "just-in-
time", which is where the CoreCLR’s JIT compiler gets its name.
Note
There are cases where you know exactly what processor architecture and
operating system your application will be running on. Like when building a
Docker container, for example. The impact of JIT compilation can be avoided
in this case using an Ahead-Of-Time (AOT) compiler. We’ll explore this in
chapter 13, Working with containers.
1.6.3 Garbage Collection
Earlier in this chapter, I mentioned that the CoreCLR (the .NET runtime) has
a memory management component. The memory manager uses a technique
called garbage collection. Garbage collection is used in many functional
programming languages like Lisp or Haskell. It is also used in Java and some
JavaScript interpreters. The essence of the technique is to keep track of the
references to a chunk of memory and when no references remain, the
memory can be safely "freed" or made available for allocation again.
Garbage collection changes how you write programs. To illustrate how this
works, let’s look at the simple C++ program shown in 1.1.
Listing 1.1. Create dynamic array in C++
#include <stdio.h>
#include <stdlib.h>
int main() {
int n = 4, i, *p;
p = (int*) malloc(n * sizeof(int)); #1
if(p == NULL) { #2
printf("nError! memory not allocated.");
exit(0);
}
printf("nEnter elements of array : ");
for(i = 0; i < n; i++) {
scanf("%d", p + i); #3
}
printf("nSum : %d", sum(p, n));
free(p); #4
return 0;
}
int sum(int *arr, int length) { #5
int i, sum = 0;
for (i = 0; i < length; i++) {
sum += *(arr + i);
}
return sum;
}
In 1.1 the array size is hard-coded but it doesn’t have to be. If the number of
elements to store in an array is not known until runtime and it could be large,
it’s better to allocate the array from memory at runtime. But memory
allocation can fail, so you have to make sure it worked and handle the case
where it doesn’t. After you’re done with the memory, you have to explicitly
free it so that it can be used by other parts of the program.
Managing memory manually in this way is cumbersome and error-prone but
is preferred in high performance scenarios such as gaming or real-time
devices. By contrast, .NET handles memory management so you don’t have
to explicitly allocate, free, or handle allocation failures. The .NET garbage
collector handles cleaning up unused memory for you. Let’s compare the
C++ code in 1.1 with a C# equivalent shown in 1.2.
Listing 1.2. Create dynamic array in C#
public class Program
{
public static void Main()
{
int n = 4, i;
int[] p = new int[n]; #1
Console.WriteLine("Enter elements of array : ");
for (i = 0; i < n; i++) {
p[i] = int.Parse(Console.ReadLine()); #2
}
Console.WriteLine("Sum : " + Sum(p)); #3
}
private static int Sum(int[] arr)
{
int i, sum = 0;
for (i = 0; i < arr.Length; i++) #4
{
sum += arr[i];
}
return sum;
}
}
Notice that in 1.2 there is no check if the memory successfully allocated and
no explicit free. If memory could not be allocated, the garbage collector
would run and try to free up memory and then attempt the allocation again. If
the collector was unable to free up enough memory, an
OutOfMemoryException is thrown, which gives the host a chance to
determine how to handle the issue. .NET also knows the bounds of the array
so it can detect if the program tries to exceed those bounds, where the C++
program has to do that manually.
.NET memory management isn’t free though. Garbage collection will need to
freeze some code execution so it can safely reorganize memory. The
unpredictability of collection events is what makes managed languages scary
for real-time scenarios (you wouldn’t want your pacemaker to pause every
now and then to free memory). For most applications, the benefits of
CoreCLR memory management simplifying an application’s code far
outweigh the cost. As some developers have found, it’s possible to control
memory in .NET to minimize the impact of the garbage collector. We’ll
explore the garbage collector in more depth in chapter 10, Performance and
profiling.
1.7 Summary
.NET supports multiple languages: C#, VB.NET, F#, and community
contributions
.NET applications compile to an intermediate language (CIL) that is not
specific to any processor architecture
.NET runs on a wide variety of platforms and in a broad set of use cases
Developers that use .NET enjoy working with it, their skills apply across
many types of applications, and have abundant job opportunities
.NET has powerful features like JIT compilation and garbage collection
built into the platform
2 Building a console application
This chapter covers
Generating projects with templates
Creating and using namespaces
Importing NuGet packages
Chapter 1 introduced .NET concepts and the breadth of applications where it
can be used. Now it’s time to put this into practice and start writing apps. If
you’ve programmed with .NET Framework before, you’ll want to read
through this chapter as there are many differences from the Framework. .NET
Core developers will find a lot of similarities but may be surprised by the
minimal APIs. To install .NET, follow the instructions for your OS at
https://dotnet.microsoft.com/download. All you need is a terminal/command
line and a text editor. If you’re interested in more information about IDEs
(Integrated Development Environments) for .NET, check out appendix B,
Setting up your development environment.
As discussed in chapter 1, .NET works in many types of applications. There
are three types of applications used throughout this book: console
applications, web applications, and web services. Except for chapter 15,
MAUI, this book’s examples will use only these application types. Many of
the samples will work in any of these three so you can use whatever you feel
most comfortable with. We’ll start with console applications.
2.1 Creating new applications from templates
If using an IDE, your instructions for creating new projects will vary. The
.NET 6 SDK comes with several built-in templates for creating applications.
This book will use only the built-in templates.
From a terminal, open a folder under which your .NET projects will go. Then
execute the command dotnet new console -n HelloDotnet. This will
create a new console application in the HelloDotnet folder. The code for this
application is in the Program.cs file as shown in 2.1.
Listing 2.1. Console application Program.cs
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");
Note
If you’ve used .NET in the past, you may be surprised that there is no
Program class with a Main method. .NET now has a concept of top-level
statements that do not belong to a class. Only one file in a project can do this
and it doesn’t need to be named Program.
The other file in the folder, HelloDotnet.csproj, contains important project
settings that we will explore later.
2.2 Building and running
From the HelloDotnet folder, execute this command in the terminal: dotnet
build. After the build is finished, a new bin folder will appear under
HelloDotnet. The bin folder contains the binaries from the build. They are
organized in subfolders first by configuration, with the default configuration
being "Debug", and then by runtime, with the runtime being .NET 6. Go to
the HelloDotnet/bin/Debug/net7.0 (or whatever .NET SDK version you’re
using) to find the DLL and executable for the console application.
Assemblies
A DLL file contains an assembly. An assembly (usually) maps one-to-one
with a project. The csproj file represents the project and controls how the
assembly is built. The HelloDotnet.dll in the net7.0 folder has all the
compiled code from the project. I will use assembly and DLL
interchangeably throughout this book.
There is a ref subfolder of the net7.0 folder that also has a HelloDotnet.dll
file in it. This DLL is different. It represents the public surface area of the
project, but does not contain the implementation. We won’t use reference
assemblies in this book so you can ignore this folder.
You can run the application by executing HelloDotnet at the terminal, or
.HelloDotnet if you have a PowerShell console. The application can
execute because you have the .NET 6 SDK installed on your computer. If you
copy the same files to another computer with the .NET 6 SDK installed, the
executable will still run regardless of any difference in operating system or
processor architecture. There are OS-specific builds that don’t require an
SDK that we’ll explore later in chapter 13, Working with containers.
2.3 Writing code
If you have programmed with .NET in the past, you may be surprised by the
simplicity of the Program.cs file. While it is nice to see that all of the
boilerplate code is gone, one has to wonder what has happened to all that
code. That will become more apparent as you progress through this chapter.
Let’s try a small example where we generate some ASCII art based on the
parameters passed in from the command line. We will use an ASCII art
generator NuGet package called Figgle. Let’s first add it to the .csproj file as
shown in 2.2.
Listing 2.2. HelloDotNet.csproj with Figgle package reference
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework> #1
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup> #2
<PackageReference Include="Figgle" Version="0.4.0" />
</ItemGroup>
</Project>
In 2.2, we add an ItemGroup node with a PackageReference. I found the
value for the package reference by looking up the Figgle package on
NuGet.org (https://www.nuget.org/packages/Figgle/). There is a tab on each
package called "PackageReference" that shows the exact XML node you can
insert into your project file.
Replace the code in Program.cs to use the Figgle library to write ASCII art
to the console as shown in 2.3. This code will write a usage statement if there
are no command line arguments and return a non-zero exit code. Otherwise,
it will write the first command line argument in ASCII art.
Listing 2.3. Code to write ASCII art
using Figgle; #1
if (args.Length == 0) #2
{
Console.WriteLine("Usage: HelloDotnet <text>");
Environment.Exit(1); #3
}
Console.WriteLine(FiggleFonts.Standard.Render(args[0])); #4
Now try running this from your project folder by executing dotnet run
"Hello, .NET" from the terminal. You should see the text as shown in 2.4.
Listing 2.4. Output from the ASCII art HelloDotnet
> dotnet run "Hello, .NET!"
_ _ _ _ _ _ _____ _____ _
| | | | ___| | | ___ |  | | ____|_ _| |
| |_| |/ _  | |/ _  | | | _| | | | |
| _ | __/ | | (_) | _| | | |___ | | |_|
|_| |_|___|_|_|___( ) (_)_| _|_____| |_| (_)
|/
2.4 Namespaces and conventions
.NET 6 and above use a minimal style that avoids a lot of boilerplate code. In
the Program.cs file there is no main method. The main method is assumed
by convention to consist of "top-level" statements. If you’ve done shell
scripting or JavaScript, this should look familiar.
Note
It’s not important that the top-level statements be in a file called Program.cs.
Try renaming Program.cs and the application will still work. But if you add
another .cs file and put some top-level statements in it like a
Console.WriteLine, you will get a build error. Only one file can contain top-
level statements.
Since Program.cs contains top-level code, it is not part of a namespace.
Namespaces are used to organize .NET types. For example, Figgle is a
namespace that contains the classes for generating the ASCII art. We include
the use of the Figgle namespace with the code using Figgle;. The package
and assembly (DLL) are also named Figgle, but it’s not necessary for the
namespace to match either of them. Let’s move the code to create the ASCII
art to its own class. Create a new file named AsciiArt.cs with the code shown
in 2.5.
Listing 2.5. Contents of the AsciiArt.cs file that uses the Figgle library to render text in ASCII art
and also writes the full type name of the AsciiArt class
using Figgle;
namespace HelloDotnet; #1
public static class AsciiArt #2
{
public static void Write(string text)
{
Console.WriteLine(FiggleFonts.Standard.Render(text));
Console.WriteLine("Brought to you by "
+ typeof(AsciiArt).FullName); #3
}
}
Then modify Program.cs to call the new class, as shown in 2.6.
Listing 2.6. Call AsciiArt class from Program
using HelloDotnet; #1
if (args.Length == 0)
{
Console.WriteLine("Usage: HelloDotnet <text>");
Environment.Exit(1);
}
AsciiArt.Write(args[0]); #2
Execute the program as before. In addition to the ASCII art, there should be
another line below. The line below should say "Brought to you by
HelloDotnet.AsciiArt". The FullName property has the namespace and type
name separated by a dot/period (.). Namespace names can also contain dots,
which is a way to create a hierarchy of namespaces.
To illustrate how namespace hierarchies work, consider the Regex class that
is part of CoreFX (the .NET framework class library) and is used for
applying regular expressions. Regex is part of the
System.Text.RegularExpressions namespace. The dots in the namespace
indicate the hierarchy. 2.1 shows how this hierarchy works.
Figure 2.1. Namespace hierarchy of System.Text.RegularExpressions.Regex
The System namespace is at the top level and has many children, such as
System.IO and System.Collections. System.Text is focused on handling text
and has some types of its own such as StringBuilder. The Regex class is a
type that is part of the System.Text.RegularExpressions namespace.
What is a type?
Types in .NET are similar to other languages like Java and Go. A type can be
a class, struct, enum, value type (int, float, etc.), record, and so on. .NET has
a Common Type System (CTS) such that types can be used in any .NET
language.
C# is a strongly typed language. This means that every expression that
evaluates to a value, every variable, and every constant has a specific type.
One exception to this rule is the dynamic type, which bypasses static type
checking. We won’t explore dynamic types in this book but will go into some
of the more complex types such as generic, implicit, anonymous, and nullable
types.
A "using" statement indicates that we want to use that namespace in our code.
By using a namespace, we get access to the types in that namespace without
having to "fully qualify" them, i.e. without having to write the namespace and
type name. This allows us to write Regex instead of
System.Text.RegularExpressions.Regex.
The types that you write also need to be put in a namespace. .NET 6 uses C#
10, which allows for file-level namespace declarations. In 2.5 you created a
class called AsciiArt and declared it as part of the HelloDotNet namespace
with the statement namespace HelloDotNet;. Prior to C# 10 namespaces
declarations could only be written as code blocks with brackets around them
with all the types in the file placed inside. C# 10 is backwards compatible so
you still have the option of using this form of namespace declaration. File-
level namespaces save one level of indentation (a small but very welcome
improvement).
Something that you may see in other codebases is that the namespace can be
declared before or after the using statements. Be aware that the placement has
meaning. Let’s compare the two listings 2.7 and 2.8.
Listing 2.7. namespace after using
using System.Text.RegularExpressions; #1
namespace System.Text;
public static class Bar
{
public static readonly Regex Letters = new Regex(@"[a-z]+");
}
Listing 2.8. namespace before using
namespace System.Text;
using RegularExpressions; #1
public static class Bar
{
public static readonly Regex Letters = new Regex(@"[a-z]+");
}
In this case, we’re adding a new static class called Bar into the System.Text
namespace. Bar uses the Regex class in its code. In 2.7, the namespace of Bar
is declared after the using, so the using has to be the full namespace of
Regex. In 2.8, the namespace of System.Text is declared first. This means
that the usings declared after the namespace can be relative to the namespace
that the code is in. If there is no RegularExpressions namespace at the top
level, then .NET will look for the System.Text.RegularExpressions
namespace.
Figure 2.2. Namespace hierarchy of System.Text.Bar and System.Text.RegularExpressions.Regex
Relative usings may make the code look cleaner but many .NET developers
avoid it because it can cause confusion. For example, if I had a class in the
namespace HelloDotnet.Figgle and I put a using Figgle; in my code, it is
unclear which namespace I’m referring to. The examples in this book don’t
use relative namespaces for clarity.
2.5 Global usings
While we had to explicitly declare usings for the namespace of the NuGet
package we’re using, the same is not true of the Console.WriteLine
statements. The WriteLine is a static method on the Console class, which is
part of the System namespace. The reason we don’t need a using System;
statement in Program.cs is because the System namespace is included via a
global using. There are default global usings for the commonly used .NET
CoreFX namespaces that can be included implicitly with a flag in the .csproj
file. You saw this earlier in 2.2 where the property <ImplicitUsings> is set
to "enable".
It is also possible to add global usings of your own if your project has
namespaces it uses in many classes. A global using can be created by adding
a statement such as global using Figgle; to one of your classes. The
convention is to create a separate file for this in your project, like
GlobalUsings.cs. Another way is to add the global using to the .csproj file
like in 2.9.
Listing 2.9. Global using in project file
<Project Sdk="Microsoft.NET.Sdk">
<!-- ... -->
<ItemGroup>
<Using Include="Figgle" /> #1
</ItemGroup>
</Project>
Global usings are a good way to reduce the boilerplate code at the top of your
code files. The examples in this book will use this technique to reduce the
size of the listings. There is another way to employ the using statement in C#
that helps reduce the amount of typing needed, which is called a static using.
2.6 Static usings
A static using allows access to static members on .NET types without
needing to write out the type name. 2.10 applies a static using to the
AsciiArt.cs file.
Listing 2.10. AsciiArt.cs with static using
using static System.Console; #1
using static Figgle.FiggleFonts; #2
namespace HelloDotnet;
public static class AsciiArt
{
public static void Write(string text)
{
WriteLine(Standard.Render(text)); #3
WriteLine("Brought to you by "
+ typeof(AsciiArt).FullName);
}
}
Static usings can also be paired with global usings, e.g. global using
static System.Console; will make WriteLine available to all the code in
your project without prefacing with Console.. Global static usings can also
be specified in the .csproj file like is shown in 2.11.
Listing 2.11. Global static usings in project file
<Project Sdk="Microsoft.NET.Sdk">
<!-- ... -->
<ItemGroup>
<Using Include="System.Console" Static="True" /> #1
<Using Include="Figgle.FiggleFonts" Static="True" />
</ItemGroup>
</Project>
There is a balance with static usings between brevity and readability. This
book will employ static usings only where it’s clear that the members come
from the static using and it makes the listing easier to read.
2.7 Handling more command line arguments
In Program.cs we have an array of command line arguments stored in the
variable "args". The parsing of command line arguments is very basic, with
splitting arguments on spaces except if contained within quotes. You’ll
typically want more control over the arguments such as converting to types
other than string or optional arguments and the args array quickly becomes
unwieldy. Luckily, NuGet has a few good packages for handling command
line arguments.
Let’s first establish some rules about the command line arguments. The text
to convert to ASCII art should be required. If the text is not present or if there
are other issues with the arguments, we should show a usage message. The
usage message should also be available by specifying --help as an argument.
To make it interesting, we’ll allow an optional parameter to set the font used
for the ASCII art.
Command line parameter conventions
A generally accepted practice for command line arguments is that the single
dash - is used for single-letter options and the double dash -- is for the long-
form word options (called "GNU" or "long-option" style). For example, in
most terminals you can list the contents of the current folder including files
that start with a "." using the command ls -a. The same command can be
written as ls --all since --all and -a are both aliases.
The single dash allows for specifying multiple commands quickly. For
example, to extract a tar file in LinuxUnix operating systems, one typically
uses the command tar -xvf file.tar. The letters x, v, and f are single-
letter aliases for --extract, --verbose, and --file= respectively.
A NuGet package called CommandLineParser can handle the parameter
parsing for us. There are many command line parsing libraries on NuGet,
including one published by the .NET team (but still in beta) so feel free to
look into other ones. Make the changes to the HelloDotnet.csproj file as
shown in 2.12.
Listing 2.12. Add CommandLineParser library to HelloDotnet.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> #1
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Figgle" Version="0.4.0" />
<PackageReference Include="CommandLineParser" #2
Version="2.8.0" />
</ItemGroup>
<ItemGroup> #3
<Using Include="Figgle" />
<Using Include="System.Console" Static="True" /> #4
</ItemGroup>
</Project>
Next, create a file called Options.cs. This file will hold the parsed command
line parameters. Add the code from 2.13.
Listing 2.13. Contents of the Options record, which holds parsed command line parameters
using CommandLine; #1
namespace HelloDotnet; #2
public record Options #3
{
[Value(0, Required = true)] #4
public string? Text { get; init; } #5
[Option('f', "font")] #6
public string? Font { get; init; } #7
}
What is a record?
Records are immutable types in C#. The command line parameters are parsed
when the application starts and put into an Options object. After initialization,
the contents of the object should not change. To enforce this in the code, use
a record type instead of a class type. Besides compile-time checking that the
parameters are not modified, there are other advantages to using records
regarding checking for equality. We’ll explore these advantages later in the
book.
In 2.13, the Options record has two properties. The Text property holds the
text to convert to ASCII art. Since this is the primary use of the console
application, the text doesn’t have a parameter name and is instead specific by
it’s position in the command line parameters. Note that the --font parameter
can still come before the text because it’s a named parameter. The Font
property holds the name of the font to draw the ASCII art in. The font doesn’t
have to be specified so this parameter is marked as an Option. The parameter
for font can be specified as -f or --font.
2.7.1 C# properties
The original idea behind properties came from a desire to control access to
fields. A field in a class is some variable that has scope to the object or static
scope to the class. If the field is exposed directly, the class doesn’t know
when code outside of the class is accessing or modifying the field. Some
development practices enforced a discipline of creating getters and setters
for fields. These are methods that control access to the field. C# formalizes
this into properties.
If we remove the shorthand, the Text property from 2.13 would look like the
code in 2.14.
Listing 2.14. Options Text property without the shorthand
public record Options
{
private string? _text; #1
[Value(0, Required = true)]
public string? Text
{
get
{
return _text; #2
}
init #3
{
_text = value; #4
}
}
}
The record has "init" statements for the properties but there are also "set"
statements for properties on classes. Properties can be read-only or have
different visibility for get and set. There are also other shorthand notations for
properties such as expression-bodied members. We’ll explore more of these
different permutations of properties throughout the book.
Another question that may come to mind if you’re not familiar with C# is the
purpose of string?. This is not the property having an identity crisis but a
way of signifying to the compiler that this property can be null. This may
seem weird if you’re a .NET Framework programmer because the type string
itself is a reference type and therefore can be null. If you recall in 2.12 the
MSBuild property (no relation to C# property)
<Nullable>enable</Nullable> was called out. Nullable in the project
settings tells the compiler that we have to be explicit about when something
can be null. Nullable reference types help for compile-time checking of
potential issues with null values. Technically, since Text is a required
parameter, CommandLineParser won’t create the Options object if the text
parameter is not in the command line parameters. But the compiler doesn’t
know this and will display a warning that the property needs to be marked as
nullable.
The problem with null references
In 2009, Sir Charles Antony Richard Hoare (a.k.a Tony Hoare) offered an
apology for introducing the concept of null references (or pointers). He called
it the "billion dollar mistake" because of the impact it has on software. C#
also struggles with how to handle nulls correctly and succinctly. The C#
language is slowly moving towards a safer design regarding nulls but needs
to be backwards-compatible. That is why there are so many operators having
to do with null as well as nullable types. This book will use the latest
preferred techniques, which allows for better static analysis when compiling.
Now that we have a record to hold the parsed command line parameters, let’s
add the code that will perform the parsing. Modify the Program.cs to match
the code in 2.15.
Listing 2.15. Program.cs parsing command line options with CommandLineParser
using HelloDotnet;
using CommandLine; #1
Parser.Default.ParseArguments<Options>(args) #2
.WithParsed<Options>(AsciiArt.Write) #3
.WithNotParsed(_ => #4
WriteLine("Usage: HelloDotnet <text> --font Big")); #5
The ParseArguments method has a modifier before the arguments are passed
in. This method uses a generic. To understand how this generic works, let’s
look at the method signature of ParseArguments as shown in 2.3.
Figure 2.3. ParseArguments method signature
T is used to represent the generic type. ParseArguments will return an object
of ParserResult<T>. The type you use to hold the parsed command line
arguments is not known ahead of time by the CommandLineParser library
and that makes it difficult to return the object you want. The generic allows
you to specify the type so that ParseArguments can read the type information
and give you the object you want. Similarly, the parameter to
ParseArguments, IEnumerable<string>, uses a generic to say that whatever
enumerable is provided must be an enumerable of strings (IEnumerable is an
interface applied to arrays, lists, and other collections).
Interfaces and abstract classes
Like most object-oriented languages, C# has interfaces and abstract classes.
A brief list of important rules for these constructs is as follows:
Abstract classes cannot be directly instantiated into objects
A class can only inherit from one abstract class but can implement any
number of interfaces
Methods or properties that are not implemented in an abstract class must
be marked with the abstract keyword
Interface properties and methods are public
The next method call, WithParsed<T> is taking AsciiArt.Write as a
parameter. We know from earlier that this is a method, so how does it work?
Let’s first look at the method signature, which is shown in 2.4.
Figure 2.4. WithParsed method signature
We know from 2.3 that ParseArguments will return a ParserResult<T>. The
extension method WithParsed can be chained onto that ParserResult object to
check if the ParserResult was successful and execute some code, "action", if
that’s the case. The Action<T> specifies that the code we’ll execute is a
method that takes an object of type T as a parameter. In our case, this is the
Options object. We need a method that will take the Options object as a
parameter. Luckily, we will soon have one of those. The AsciiArt.Write code
has previously taken only a string as a parameter but we’ll soon change this
to take the Options object so we can use it to determine what font to write the
ASCII art in.
What is an extension method?
Sometimes you want to add a method to an existing type without modifying
or inheriting from that type. Extension methods allow you to do this. Let’s
consider a (contrived) example. The class String is part of CoreFX and
cannot be inherited (aka "sealed") but I would like to add a method that gives
me every other character. I can create my own extension method to
accomplish this like in 2.16.
Listing 2.16. Extension method to get every other character in a string
public static class MyStringExtensions
{
public static string EveryOtherCharacter(this string s) #1
{
char[] newChars = new char[s.Length / 2 + 1]; #2
int sPos, nPos; #3
for (sPos = 0, nPos = 0;
sPos < s.Length;
sPos += 2, nPos++)
{
newChars[nPos] = s[sPos]; #4
}
return new string(newChars, 0, nPos); #5
}
}
This extension method can then be used on any string as if it were part of the
string type, e.g. "abcdefghijklmn".EveryOtherCharacter(). Likewise, the
methods WithParsed and WithNotParsed are not part of the ParserResult
class but are extension methods.
In the case, that the command line parser is unable to create the Options
object, we want to write the usage string to the console output. The
WithParsed extension method uses a design pattern called "method-chaining"
that allows us to apply another extension method: WithNotParsed.
WithParsed is executed first and checks if the ParserResult indicates that the
parsing was succesful. If not, WithParsed does nothing and returns the
ParserResult object. The next method in the chain, WithNotParsed, will
check in the ParserResult object indicates parsing failed and execute an
action if that’s the case. Let’s look at the signature for that method, which is
shown in 2.5.
Figure 2.5. WithNotParsed method signature
This is very similar to WithParsed except that the Action takes a parameter of
IEnumerable<Error>. There is no method like that available already so we
could create one in the AsciiArt class. But the logic for writing the usage
string should not be in AsciiArt. A new method cannot be introduced in the
top-level code in Program.cs. We could declare a namespace and type with a
method for this purpose but C# provides a cleaner way: anonymous methods.
2.17 shows different ways that the Action used for WithNotParsed could be
written.
Listing 2.17. Four different ways to write the same Action ranging from the verbose method
definition to an anonymous method that discards the parameter.
void WriteUsageAndIgnoreErrors1(IEnumerable<Error> errors)#1
{
WriteLine("Usage: HelloDotnet <text> --font Big");
}
void WriteUsageAndIgnoreErrors2(IEnumerable<Error> _) #2
{
WriteLine("Usage: HelloDotnet <text> --font Big");
}
void CallToAction(IEnumerable<Error> errors)
{
Action<IEnumerable<Error>> action1 = WriteUsageAndIgnoreErrors1;
action1(errors);
Action<IEnumerable<Error>> action2 = WriteUsageAndIgnoreErrors2;
action2(errors);
Action<IEnumerable<Error>> action3 =
(IEnumerable<Error> _) => #3
{
WriteLine("Usage: HelloDotnet <text> --font Big");
}
action3(errors);
Action<IEnumerable<Error>> action4 = _ => #4
WriteLine("Usage: HelloDotnet <text> --font Big");
action4(errors);
}
An anonymous method is what the name suggests: a method whose name is
unimportant. Anonymous methods are one of my favorite .NET features
because naming is hard and coming up with a name for a method I only use
once is a waste of time. The compiler is able to tell from the WithNotParsed
method signature that the Action should take an IEnumerable<Error>
parameter and uses that for the parameter passed to the anonymous method
without the code needing to explicitly declare it. Also, if there is only one
statement or expression in the method you can use a technique called
expression-bodied members. An expression-bodied member is a member
that consists of only an expression and therefore doesn’t need brackets or a
return statement.
We’re almost done with the modifications to the console application. The
next step is to update the AsciiArt class to lookup the font. Modify
AsciiArt.cs to contain the code from 2.18.
Listing 2.18. AsciiArt class updated to lookup the font passed in from the command line options.
using System.Reflection; #1
namespace HelloDotNet;
public static class AsciiArt
{
public static void Write(Options o) #2
{
FiggleFont? font = null; #3
if (!string.IsNullOrWhiteSpace(o.Font)) #4
{
font = typeof(FiggleFonts)
.GetProperty(o.Font, #5
BindingFlags.Static | BindingFlags.Public) #6
?.GetValue(null) #7
as FiggleFont; #8
if (font == null) #9
{
WriteLine($"Could not find font '{o.Font}'"); #10
}
}
font ??= FiggleFonts.Standard; #11
if (o?.Text != null)
{
WriteLine(font.Render(o.Text)); #12
WriteLine($"Brought to you by {typeof(AsciiArt).FullName}");
}
}
}
Reflection
.NET has an extensive set of reflection libraries under the System.Reflection
namespace. Many interpreted languages have some form of reflection.
Reflection allows you to get information about assemblies and types in .NET
code at runtme. In 2.18, the FiggleFonts type has a static property for each
font. The static property we use by default is FiggleFonts.Standard and is of
type FiggleFont. By using reflection, we can attempt to find a property by
name and get the FiggleFont object that represents it.
Interpolated strings
Normal strings in C# are enclosed in double-quotes ("). Interpolated strings
allow substituting values into strings. If you’ve used C# in the past, you may
be familiar with string.Format() which can substitute values into a string.
Interpolated strings are similar to string.Format() but not the same. As in
2.18 the string value of o.Font is insert into the string by enclosing it in curly
brackets ({}).
Null operators
In 2.18, there are two new null operators used. The first one is in
GetProperty()?.GetValue(). If the result of GetProperty is null, the null-
conditional operator will return null immediately instead of executing the
right side of the expression (GetValue). The null-conditional operator is a
shorthand, especially considering that without it the alternative is like the
code in 2.19.
Listing 2.19. Long form of null check on GetProperty
PropertyInfo pi = typeof(FiggleFonts).GetProperty( #1
o.Font, BindingFlags.Static | BindingFlags.Public);
if (pi != null)
{
font = pi.GetValue(null) as FiggleFont;
}
The second null operator, ??, is called the null-coalescing operator. It
evaluates the expression on the left side first. If the left-hand expression is
null, it will then return the value of the right-hand expression. This works
similar to how short-circuiting works with the || boolean operator. In 2.18
this operator is used in the line font ??= FiggleFonts.Standard. Like in
other languages, this is a shorthand for font = font ??
FiggleFonts.Standard. If font is null then FiggleFonts.Standard is assigned
to font, otherwise nothing changes.
Casting objects to types
In 2.18, the result of the GetProperty().GetValue() is an object that can be
null. The value of the expression needs to be casted to type FiggleFont before
it can be assigned to the font variable. However, there is no guarantee that the
object return by the expression is of that type so if we use an explicit cast,
that may cause an exception at runtime. The as operator in C# is a safe way
to cast the object. It will return null if the type of object being casted does not
match the target type.
All the code for the console application is finished. Experiment with missing
or invalid parameters. Some other fonts to try are ThreeD, Alligator, Avatar,
Cosmic, DotMatrix, and Ghost. Have a look at the properties on FiggleFonts
to find more.
Exercise: Multiple words in ASCII art
The first unnamed parameter passed to HelloDotnet is the text that will be
written in ASCII art. A string containing spaces can be used if enclosed in
quotes. Modify the command line parameter parsing so that if multiple
unnamed parameters are passed, each string will be written to the console
separately. It will help to look at CommandLineParser’s wiki:
https://github.com/commandlineparser/commandline/wiki
Exercise: List all fonts in help text
The help text could be made more helpful by telling the user what fonts are
available. There are many ways to do this. One way is to use reflection to
enumerate the public static properties of FiggleFonts and expose that as a
static method in AsciiArt. Another way is to grab the list from the Figgle
source code and store as an array or an enum (not covered yet but an option if
you know C#).
2.8 Summary
Use dotnet new to create .NET applications from the command line
NuGet has an extensive collection of packages available with helpful
links and instructions
Types are organized into namespaces that can be included either for a
whole project or an individual file
C# has a lot of ways to handle null references
Anonymous methods and expression-bodied members are common
techniques to make C# code more succinct
3 Creating web services and
applications with ASP.NET Core
This chapter covers
Creating web services
Creating web applications
LINQ - Language Integrated Query
3.1 Web services
The console application from the prior section receives command line
parameters and writes the specified string in ASCII art to the console output.
The command line parsing library helps with parsing and is fairly easy to
execute from a terminal. It is just as easy to create a web service that
performs the same function. In this section we’ll port the ASCII art program
into a web service using ASP.NET Core.
In the previous section, we used the dotnet new console command to create
a console application from a template. There are many other templates
available. You can see a list by running dotnet new --list. We will use the
empty Web template for the ASCII art service. Use the command shown in
3.1 to create a new folder with the new project.
Listing 3.1. Command to create Web API from template
dotnet new web --name AsciiArtSvc
This template will create files similar to the ones shown in 3.1.
Figure 3.1. Files and folders created by the empty web template (image created with a custom
CodePen and Font Awesome icons)
There is a Web API template that will look much more like the ASP.NET
Core projects you see in the real world. We use the empty template in this
example because with the minimal API design of ASP.NET Core, creating a
web service is as easy as creating a console application.
From the project’s directory, execute the dotnet run command and you
should see output similar to 3.2.
Listing 3.2. Output from running the empty web service
> dotnet run
Building...
info: Microsoft.Hosting.Lifetime[14]
Now listening on: https://localhost:7041 #1
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5292 #2
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
Development certificate
.NET includes a certificate for local development to make it easier to test
https endpoints. If you installed an IDE like Visual Studio or JetBrains Rider,
then the certificate was probably setup for you. Regardless, you can check if
the certificate is trusted with the command dotnet dev-certs https --
check.
To trust the certificate on your development machine (or on a build agent in
your CI/CD pipeline), use the command dotnet dev-certs https --trust.
Web service ports for local development
The port numbers used for web services generated from the .NET template
are chosen randomly. You may need to change them if they conflict with a
port that another application is using. To do this, find the
Properties/launchSettings.json file and look for a section like the one
shown in 3.3.
Listing 3.3. launchSettings for AsciiArtSvc project
"profiles": {
"AsciiArtSvc": {
"commandName": "Project", #1
"dotnetRunMessages": true,
"launchBrowser": true, #2
"applicationUrl":
"https://localhost:7041;http://localhost:5292", #3
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
The default profile generated with the template will launch the default
browser and navigate to the configured URL. The browser sends a GET
request that the service responds to by returning "Hello World!". The browser
launch happens with IDEs that use the launch profiles. The dotnet run
command will not open a browser.
The first step in getting the web service to convert strings into ASCII art is to
add the Figgle package just as we did with the console application (shown in
3.4).
Listing 3.4. Add Figgle package to AsciiArtSvc
<Project Sdk="Microsoft.NET.Sdk.Web"> #1
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup> #2
<PackageReference Include="Figgle" Version="0.4.0" />
</ItemGroup>
</Project>
Next, open the Program.cs to see how the current "Hello World!" response
works. The content should be similar to 3.5.
Listing 3.5. AsciiArtSvc Program.cs
var builder = WebApplication.CreateBuilder(args); #1
var app = builder.Build(); #2
app.MapGet("/", () => "Hello World!"); #3
app.Run();
Earlier in this book we noted that C# is a strongly-typed language. However,
in 3.5 we use the keyword "var" to declare variables instead of the .NET
types. In C# var can be used to declare a variable only if the compiler is able
to determine what the variable type is. For instance, we can make a statement
such as var i = 0; because the compiler can infer that since 0 is an integer
then i is an integer. But we couldn’t write something like var myString;
because there is nothing assigned to myString that the compiler can use to
infer the type. The var keyword is a style choice. It has the benefit of saving
characters both in that you don’t need to write the type name but also that you
don’t need to have a "using" for that type’s namespace. The drawback is that
developers reading the code don’t know the type without some investigation.
Random documents with unrelated
content Scribd suggests to you:
If presently we learn that by order of the All-Highest every
buttonhole in Brussels is sewn up, it will hardly be matter for
surprise. It would be a charactertistic step.
Those ribbon favours have proved prickly thorns to the Germans.
They seem to act upon the Prussian mind as a red rag upon the bull,
and like the rag, when in the deft hands of a skilled toriro, they
frequently lure the victim to his own undoing. It happened once,
soon after the display of national colours had been prohibited, that a
Prussian officer, entering a Brussels tramcar, found himself seated
opposite a Belgian lady upon whose coat the forbidden red, black,
and yellow ribbons were flauntingly displayed. It is the custom of
many Belgian ladies, on finding themselves in a public vehicle with a
German officer, to quit their seats and stand on the conductor's
platform outside. Ruffled, perhaps, by the omission of this somewhat
pointed tribute to his presence, the intruder leaned forward and
requested the removal of the offending colours. The suggestion was
greeted by a stony stare, the demand which followed it by an
expressive and provocative shrug of the shoulders.
"If you will not take off those colours, madam, I shall remove them
myself."
This menace eliciting no response, the Prussian officer stretched
forth a Prussian fist and made a Prussian grab. The favour came
away in his clutch, but that was not the end of it. Within his fair
antagonist's dress ample lengths of ribbon were concealed, and the
more the discomfited officer pulled the more streamers of red, black,
and yellow reeled forth. It was a case literally of getting more than
he bargained for, and the charming murmur of thanks which he
received when, in sheer desperation, he dropped the tangle of
ribbon on the floor and made hastily for the door must have gratified
that Prussian exceedingly.
IV—THE JOKERS OF BRUSSELS
Practical joking has become popular in Brussels since the German
occupation. "Everybody's doing it"—amongst the Bruxellois, that is.
A prohibition was lately placed upon the use of motor-cars by the
civil population, and orders were issued for the enforcement of dire
penalties in cases of disobedience. One afternoon a couple of
German officers were seated in a café discussing mugs of beer with
that portentous solemnity which the Teutonic mind finds proper to
such an occasion, when a loud "Honk, honk!" the unmistakable blast
of a motor-horn, was heard in the street outside. Forth dashed the
officers, indignant at this flagrant transgression of orders, but when
they reached the pavement no car was there. None was even in
sight upon the whole length of the boulevard, though the sound of
the horn had been close at hand. Crestfallen, the representatives of
law and order—Prussian style—returned to their beer-mugs, but
were hardly seated when again the loud "Honk, honk!" fell upon
their ears, and again they dashed into the street, with the same
result. Convinced that some impudent guttersnipe must be playing a
trick, they questioned the nearest sentry. But the latter had seen
neither car nor urchin; he had not even heard the mysterious sound,
he averred, and the baffled officers began almost to doubt their
ears. But the smile on the face of the Belgian proprietor of the café
was suspicious.
Fresh mugs of beer were requisitioned, but the very first "Prosit"
was interrupted by the malevolent "Honk, honk!" With froth-flecked
lips that gave them an aspect admirably suited to their mood, the
enraged officers set down the mugs with a bang and once more
strode forth in quest of the miscreant. Once more a perfectly empty
street met their gaze. But even as they scowled abroad, a mocking
"Honk, honk!" sounded, this time just above their heads. The
listeners started and looked up, to see a green parrot in a cage upon
the window-sill above regarding them imperturably with a beady
inscrutable eye. So flagrant a case of lèse majesté could not be
overlooked, and the green parrot was executed.
But even in his murders the Boche lacks a sense of proportion,
which is, of course, merely another way of saying that he has no
sense of humor. To the martyrdom of the parrot must be added that
of two luckless pigeons whose sole crime against the Deutches Reich
was that of being born after a certain date. It was decreed soon
after the occupation of Brussels that all owners of pigeons must
notify the authorities the number of birds which they possessed.
Amongst those complying with the order was a certain shopkeeper
who kept a pair of pigeons as pets. They were not of the carrier
variety, and he was allowed to retain them. But pigeons are
notoriously domesticated creatures, and presently an interesting
event occurred in the establishment of this happy couple. A couple
of squabs were hatched out. These duly assumed down, which in
turn became feathers, and presently there were four pigeons where
formerly had been but two. At this stage a German official, armed
with a registration list, paid a visit of inspection. He noted the well-
preened quartette, and referred to his papers. Then he frowned
ominously.
"On such and such a date you registered two pigeons."
"That is so," was the answer. "Since then——"
"But you have four there."
"Quite true. You are——"
"But you are only entitled to have two."
"A thousand pardons, mein Herr. But one cannot interfere with
Nature. My two pigeons, you see——"
"If you registered two only, you cannot be allowed to have four. It is
self-evident."
It is needless to repeat the colloquy at length. Though that
explanations were cut short, refused a hearing. No German official
was ever known to "use his discretion"; that is a prerogative of the
muddle-headed British. The list had two pigeons; here were four.
Obviously there was only one course to be taken. The abundant
pigeons shared the fate of the indiscreet parrot.
Next day there appeared suspended in the mourning owner's shop-
window two feathered corpses adorned with this pathetic placard:—
MORTS
POUR LA PATRIE!
V—THE SECRET NEWSPAPER—LIBRE BELGIQUE
But the most brilliant and daring feat achieved in Brussels is
unquestionably the publication of Libre Belgique, a mysterious
weekly journal which makes its appearance with unfailing regularity,
though how, where, and by whom produced the Germans have
never been able to discover. This is the very apotheosis of Boche-
baiting, for Libre Belgique is a fiery sheet. It does not mince words,
but flagellates the Germans with the most scornful virulence, holding
them up to ridicule and contempt. Every week it pours the vials of
bitter wrath and hatred upon the Boche's devoted head, and the
Boche can do nothing but sit meekly under this scorching cataract.
For though a reward, which has already risen from a thousand
pounds to three times that figure, is offered for a denunciation of
those responsible for this "scurrilous rag," the secret of Libre
Belgique remains inviolate. Exhaustive searches have been
conducted, many arrests have been made upon suspicion, but
except for two minor actors in the great comedy, whose function
was merely the distribution of copies, no one has been caught. Yet
Libre Belgique has already celebrated one anniversary of its birth,
and is well into its second year of existence. And every week,
without fail, General von Bissing, the German governor of Brussels,
receives a "complimentary" copy, which he doubtless peruses with
absorbed interest.
It is characteristic of Brussels wit that in conformity with law the
paper announces in each issue the address of its office and printing
works. These, it appears, are in "a cellar on wheels," and in view of
the peripatetic habits thus suggested, correspondents are desired to
address their communications to the Kommandatur, i.e., the
headquarters of the German authorities!
But Libre Belgique has another function to discharge beyond that of
a courageous jest, well calculated to keep the Bruxellois in good
heart. Drastic in its satire upon the enemy, it is equally unsparing in
its record of German crimes and its dissection of the often grotesque
claims made by the German official communiqués. Von Bissing and
his staff may affect to make light of this gadfly among journals, but
the rewards offered for its betrayal and the energetic measures
taken to bring about its suppression tell another story. Libre
Belgique, indeed, aptly illustrates the parable at which Burgomaster
Max so subtly hinted when he laid his pen beside his interlocutor's
pistol. The pen is far mightier—in the long run—than the sword, and
the Germans, though they will not perhaps admit it even to
themselves, have an uncomfortable inkling of that fact.
That Libre Belgique, in spite of all proffered bribes, should never yet
have been betrayed is a wonderful testimony to the high patriotic
spirit of the Bruxellois. For though the operations of the paper's staff
are doubtless closely guarded, the number of persons who are in the
secret must inevitably be considerable, and leakage is difficult to
prevent. But the Belgian spirit is a thing with which we are all
familiar now, and when to that is added Brussels wit the whole
phenomenon is explained.
One fancies, indeed, that when the Belgian capital is at length
evacuated by the Germans the populace will be half sorry to see
them go. The Boche is not exactly a lovable fellow, but to people of
a satirical turn of mind, naïveté, which he possesses in unparalleled
degree, is always engaging. As a butt the Boche is unique, and in
that capacity, if in no other, he has positively endeared himself to the
witty citizens of Brussels.
HOW SERGEANT O'LEARY WON HIS
VICTORIA CROSS
Story of the First Battalion of the Irish Guards
He shot eight Germans in eight seconds, captured a machine
gun, took two barricades single handed, and saved his whole
company from being exterminated. The story is told in the New
York American as dispatched from London.
I—WHO IS THE BRAVEST MAN IN THE WAR?
Who is the bravest man that the war has produced?
It would probably be impossible to answer this question with any
approach to accuracy and impartiality. But it is interesting to
compare some of the incidents reported and see how modern
courage compares with that of past history.
It is generally admitted that all the nations engaged have fought
with remarkable bravery and steadiness, so that a man must have
done some extraordinarily daring action to make himself notable.
Thousands and thousands of acts of bravery have been performed
by many among the millions of soldiers engaged. Doubtless some of
the most heroic have died without having their acts mentioned.
Of the innumerable feats of bravery reported the one that has
impressed the British public most is that of Sergeant Michael
O'Leary, of the Irish Guards, who is a native of Ireland, as his name
suggests.
He has received the coveted Victoria Cross, been promoted Sergeant
and a long description of his deeds has been given him on the
official records—a very great honor. He has also been offered a
commission, but will not take it at present because he does not want
to leave the Irish Guards, and there is no place for him there as an
officer.
The cold official record says that O'Leary won his Victoria Cross "for
conspicuous bravery at Cuinchy. When forming one of the storming
party which advanced against the enemy's barricades he rushed to
the front and himself killed five Germans who were behind the first
barricade, after which he attacked a second barricade, about sixty
yards further on, which he captured, after killing three of the enemy
and making prisoners of two more. Lance Corporal O'Leary thus
practically captured the enemy's position by himself and prevented
the rest of the attacking party from being fired on."
Further details of O'Leary's wonderful exploit were given by
Company Quartermaster Sergeant J. G. Lowry, of the Irish Guards,
who was engaged in the fight.
"Our First Battalion," he said, "had been holding trenches near the
La Bassee brickfield, and our losses were heavy. The Germans had
excellent cover, both in trenches and behind stacks of bricks.
"We were all delighted when the order came that the brickfield had
to be taken by assault next day.
"Lance Corporal O'Leary never looked to see if his mates were
coming, and he must have done pretty near even time over that
patch of ground. When he got near the end of one of the German
trenches he dropped, and so did many others a long way behind
him. The enemy had discovered what was up.
"A machine-gun was O'Leary's mark. Before the Germans could
manage to slew it around and meet the charging men O'Leary
picked off the whole of the five of the machine crew, and leaving
some of his mates to come up and capture the gun, he dashed
forward to the second barricade, which the Germans were quitting in
a hurry and shot three more.
"O'Leary came back from his killing as cool as if he had been for a
walk in the park and accompanied by two prisoners he had taken.
He probably saved the lives of a whole company.
"Had that machine gun got slewed round, No. 1 Company might
have been nearly wiped out."
II—STORY OF THE YOUNG IRISH GUARD
What impresses people in O'Leary's deed is not only his bravery but
the triumphant success with which he carried out the whole act.
Other soldiers may have displayed more self-sacrifice and
endurance, but not one of them appears to have done more for his
side by one individual act of bravery than O'Leary.
It is the dashing quality of his deed that wins admiration and this
quality, it is to be noted, is peculiarly Irish. He is credited by his
admirers with having shot eight men in eight seconds. His quickness
must have been phenomenal, and here again he showed a peculiarly
Irish trait.
How one man could have shot eight soldiers, when all eight of them
were armed and many of their comrades were only a few yards
away, must appear a mystery to many. The Germans were perhaps
retiring hastily from their positions, but they had magazine rifles in
their hands and fired many shots at the British.
Why did they not get O'Leary, who was running out alone ahead of
his companions? He must have been amazingly lucky, as well as
amazingly quick.
Then it is almost equally astonishing that he could have shot eight
men in a few moments while running. The best explanation of this is
that the British soldier has a rifle carrying more bullets than that of
any other army.
The Lee Enfield rifle now used in the British army carries ten bullets
in the magazine and one in the barrel. O'Leary, of course, fired all
his eleven bullets, and he is credited with making eight of them kill a
man apiece. That is an amazing shooting record, said to be
unequalled for a soldier.
Sergeant O'Leary is not a particularly fierce looking soldier, as might
be expected, but a tall, slender, fair-haired young fellow. He is only
twenty-five years old.
"A quiet, easy-going young fellow O'Leary is," said his friend,
Sergeant Daly, of the Second Battalion of the Irish Guards. "But he is
remarkably quick on his feet."
O'Leary was born in the little village of Inchigeelach, in the County
Cork. His father and mother still live there. He has an older brother
and four sisters, who are now in America.
He served for several years in the Canadian Northwest Mounted
Police, but went back and joined the British Army in order to be
nearer home.
After the fight in which he won his decoration he wrote home:
"Dear Parents: I guess you will be glad to hear that I was promoted
full sergeant on the field on account of distinguished conduct on
February 1, when we charged the Huns and routed them in disorder.
"You bet the Irish Guards are getting back now."
Mrs. O'Leary, the old mother of the hero, has been interviewed at
her home in Ireland. As might be expected her words were very
simple.
"It's proud I am of Mike," said Mrs. O'Leary, "but I wish he was
home instead of being in that cruel war.
"When that telegram came for me, I thought sure Mike was dead,
but when I opened it I found that he had been promoted. Sure I
was better pleased to know that he was alive than promoted.
"Mike is a good boy. He never gave me a moment's uneasiness since
he was in the cradle, except when he went away on his foreign
adventures. I suppose he had to leave me. There's little enough
chance for a boy here, with only the pigs to look after and his father
and me."
We have been inclined to think that the days were over when a
mighty warrior could rush in among the foe and slay many with his
own hands but O'Leary and many others in this war have proved
that that is not the case.
III—TALE OF A GORDON HIGHLANDER
Many of the famous deeds of antiquity have been curiously
paralleled in the war. For instance, one of the ancient feats that
everybody mentions occasionally was how the brave Horatius held
the bridge across the Tiber with two companions against the whole
Etruscan army.
Now we find again and again that a bridge has been the scene of
deeds of conspicuous heroism in this war. The British were defending
a river bank and bridge against a fierce German attack. The crew of
a British Maxim gun had all been killed. Then Angus MacLeod, of the
Gordon Highlanders, rose from cover, seized the Maxim gun and all
alone carried it, under fire, to the far side of the bridge, where he
played it on the advancing Germans.
He is credited with having killed sixty Germans. Finally he fell dead
and thirty bullets were counted in his body. The delay enabled the
British to rally and repel their opponents.
An extraordinary act of heroism was reported of an unnamed French
soldier during the disastrous retreat of the French from the Belgian
frontier and the Meuse River early in the war.
This man had been taken prisoner with some companions. The
Germans, according to the report, drove their prisoners before them
when attempting to cross a strongly defended bridge, to make the
French think it was a party of their own men returning. As the
French prisoners stepped on the bridge, one of them, a big and
strong-voiced man, yelled:
"Fire, nom de Dieu, or you will be wiped out."
His own act made his death certain. He fell riddled with bullets from
both sides.
Lieutenant Leach and Sergeant Hogan of the British Army each
received the Victoria Cross for an extraordinarily daring and
ingenious action. The two men killed two Germans, took sixteen
unwounded prisoners and twenty wounded men. Leach and Hogan
with ten men crawled unobserved to a section of trench that had
been captured by the Germans earlier in the day. Leach and Hogan
dropped into the trench unnoticed and the ten men lay in wait to
shoot any Germans who showed themselves.
A trench is built in zigzags so that there is only a straight section of
about twenty yards along which an enemy could shoot. The
Germans in the first section were taken by surprise and all killed or
wounded. Then the two men hurried on to the next turning. As they
walked Hogan put his cap on his rifle and held it above the trench to
show their men outside where they were.
Lieutenant Leach poked his automatic revolver round the corner of
the trench and began shooting at the Germans from cover. The
German soldiers with their big clumsy rifles could not hit the deadly
hand that was the only object to aim at. While the Lieutenant was
shooting, Hogan watched over the top of the trench to shoot any
German who tried to get out or attack them in the rear. Thus all the
men in each section were killed, wounded or captured.
How do these and the many other brave men who have been
reported in the present war compare with the heroes of antiquity?
Achilles is the foremost of Greek warriors. He personified the Greek
ideal of bravery, manly beauty and fiery enthusiasm. The "Iliad"
contains pages and pages about his deeds, his speeches, how he
sulked in his tent, and his quarrel with Agamemnon, but it does not
seem after all that he did a vast amount of harm to the enemy. Of
course, he killed Hector, but that was not amazing, and he acted
with considerable brutality about it.
Achilles was undoubtedly a fine orator, but in achievement he
appeared to compare badly with modest Sergeant O'Leary.
Net In Action Second Edition Meap V06 2nd Chapters 1 To 12 Of 13 Dustin Metzgar
STORY OF A RUSSIAN IN AN
AUSTRIAN PRISON
An Officer's Remarkable Experience
This very unusual narrative, with its light on Austrian prison
conditions, appeared in the Russkoe Slovo, Moscow, June 30,
1916. It was written by a petty officer of the Russian Army at
the request of the paper's Paris correspondent. The
correspondent tells of a party of thirty Russians who had
recently arrived in Paris from Italy, all war prisoners from
Austria, who had managed at different times to slip through the
lines on the Italian front. It was translated for Current History.
I—"I WAS PRISONER OF THE MAGYARS"
I was taken prisoner by the Magyars in the Carpathians. We were
driven to the station of Kashitzi, where we found more Russians, I
don't know how many, and were placed in dirty cars, from which
cattle had just been removed. The stench was terrible, the crowd
unthinkable. The doors were locked all the time.... We travelled two
days; on the third we arrived in a camp called Lintz. What did I see
in this camp? Filthy barracks, naked bunks on which our soldiers
were scattered, pale, exhausted, hungry, nearly all barefoot or in
wooden clogs. Many were suffering from inflamed feet and
exhaustion. I don't know how they call it in medicine, but to my
mind it was the fever of starvation. One gets yellow, trembles
incessantly, longs for food....
The prisoners were fed very poorly, mainly with turnips, beans, and
peas.
Once a soldier decided to complain to Francis Joseph or Wilhelm. He
went up to an electric pole, formed his fingers so that it looked as if
he were speaking into a telephone horn, and shouted, "Hello,
Germans, give us some more bread!" He called and knocked with his
fists for some time, but, of course, received no reply. Many soldiers
made fun of him at first, but others began to look for a way to
complain against such treatment of war prisoners. Meanwhile the
bread became poorer and poorer in quality and less in quantity. The
meals consisted of beans, and in addition there were bugs in the
beans. We got meat three times a week, the other days we got
herring.
On the 24th of May, 1915, a company was recruited among us to be
sent away to do some "agricultural" work. The soldiers would not
believe it, claiming that peace was near. I was in the first contingent.
Our train was passing between mountains covered with evergreen.
Every now and then it would shoot through tunnels. This surprised
me greatly. I understood that we were not going in the direction of
Russia. And so it was. We finally arrived in a place, where the
thousand of us were quartered in one building. We at once began to
be treated differently, much more insolently and severely. On the
27th we were driven to the fields to work. We wondered what the
agricultural labour we were to do could be. We were supplied with
shovels and pick-axes, led to a wood on a hill some 1,600 metres
high, mustered into rows, and ordered to dig a ditch—that is what
the Germans called it—but we called it otherwise. It became clear
that we were to dig trenches.
The first day passed in idleness and grumbling. All unanimously
refused to work, even if we had to pay with our lives for it.
We waited for the following morning. The guards came to take us
out to work, but we said that we would not dig trenches. Then the
Colonel came and asked in Russian: "Why don't you want to work?"
We all answered: "This work is against the law. You are violating the
European laws and breaking all agreements by forcing us to
construct defensive lines for you." The Colonel said: "Look out, don't
resist, or we will shoot every one of you. We don't care now for the
laws to which you point us. All Europe is at war now—this is no time
for laws. If you don't go to work, I will have you shot."
We all exclaimed: "We won't. Shoot us, but we will not do the work."
II—STANDING BEFORE THE EXECUTIONER
All of the 28th we were in our yard. No food was given us. Thus we
were held for three days without food. On the fourth day a company
of cadets arrived. Leading them was the executioner, with stripes on
his sleeves. They loaded their rifles, holding them ready. Then the
Colonel asked: "Who will go to work?" The crowd answered "No!"
The Colonel said: "I am sorry for you, boys, you don't understand
that you are resisting in vain." Suddenly the crowd was split into
two. Those who agreed to work were given dinner and put to work.
The other half, in which I was included, was led away to another
yard. From among us ten were picked out and taken away—we
knew not where. We were ordered to lie on the ground with our
faces downward, and not to turn our heads.
On June 2 there remained only fifty men who still refused to work,
suffering hunger for the sixth day. The ten soldiers who were daily
taken away from us were subjected to, besides hunger, suspense in
the air from rings, with their hands tied to their backs. In about
thirty minutes one would lose consciousness, and then he would be
taken down to the ground. After he recovered his senses he would
be asked if he agreed to work. What could one answer? To say "I
refuse" meant another ordeal. He would begin to cry and agree to
work.
The following day our heroes were led out into the open, ten were
selected from our midst, arranged in a line facing the rest of us, and
told that they would be shot immediately. Of the remainder half
were to be shot in the evening, the other half the following morning.
Their graves had been dug by the ten heroes themselves. I have not
the slightest hesitancy in calling them so.
Then a space was cleared, and Ivan Tistchenko, Feodor Lupin, Ivan
Katayev, and Philip Kulikov were ordered forward. The first was Ivan
Tistchenko. An officer and four cadets approached him. The officer
asked him if he would agree to work. He answered "No," and
crossed himself. His eyes were bound with a white 'kerchief, and
these pitiless and unjust cadets fired at the order of the officer. Two
bullets pierced his head and two his breast, and the brave fellow fell
to the wet ground noiselessly and peacefully.
In the same manner the second, third, and fourth were treated.
When the fifth was led forward he also refused to work, and they
already had his eyes bound. But some one in the crowd exclaimed:
"Halt—don't fire!" And the comrades asked for his life, all agreeing to
go to work. And I never learned the identity of the chap who saved
that fellow's life and many other lives.
We remained in that camp for two and a half months. Then we were
removed closer to the front, to a locality inhabited by Italians. Our
soldiers there would inquire from the Italian labourers, to whom the
guards paid no attention, where the boundary lay. We learned the
direction and the distance to the boundary, which was about thirty
miles. It was even nearer to the Italian front. And so on Sept. 29 a
comrade and I decided to escape.
(Some particulars of the escape have been deleted by the Russian
censor.)
Toward dawn we emerged from the thick of the pine trees and
bushes, and descended to the base of the mountain. At our feet was
a stream, about fifty feet wide, rapid, and full of rocks. Here we
made good use of our training in gymnastics. My comrade, a tall
fellow, was light on his feet. He jumped like a squirrel from rock to
rock. To me it seemed that I would slip and be swept away by the
current. My comrade was already on the opposite shore when I,
making my last jump, failed to gain the beach. Fortunately he was
quick to stretch out to me his long stick, and drew me out of the
water as wet as a lobster.
We walked along the stream all day without encountering anybody.
At the end of the day we came in sight of a tiny village, but there
were no people nor soldiers to be seen. Only near one house smoke
was rising. We decided to approach stealthily and investigate. We
saw an old woman at the fire, bending over a kettle of sweet corn.
We surmised that the inhabitants of the village must have deserted
it because of its proximity to the front, while the old woman refused
to abandon her home.
We approached her and confessed that we were Russian soldiers.
She thought long. What "Russian" meant she did not know, but she
understood the meaning of the word "soldiers." She presented us
with some of her sweet corn and pointed out the way to the Italian
front.
III—"WE ESCAPED TO ITALIAN FRONTIER"
It was six in the evening when we came upon an advanced Italian
post. The sentinel stopped us with a "Halt!" He was pointing his rifle
at us, showing that he would shoot if we advanced. He called for his
superior. We were searched and taken into their quarters. An officer
soon came in. Through an interpreter he asked us for our names,
regiments, and army branches. He gave each of us a package of
cigarettes.
Only then I understood that we were received as guests. When the
officer gave us the cigarettes, saying "Bravo, Russi!" the soldiers
began showering us with cigarettes, chocolate, and confetti. One
soldier guessed better than the rest; he brought us a dish of soup,
meat, and a bottle of wine. After this there was a regular wedding
feast. Each of the soldiers brought something to eat, cheese, butter,
sardines. We, knowing our condition, abstained from eating too
much. Thinking that on the following day we would have to suffer
hunger again, we put all the presents into a bag presented us by
one of the Italians. Thus we accumulated about fifteen pounds of
bread, cheese, butter, chocolate, lard, and boiled beef. Then the
Italians noticed that our clothes were wet, and began presenting us
with underwear and clothing, so that we soon changed our
appearance. We were anxious to converse with them. The
interpreter, who spoke Russian imperfectly, had a great deal of work.
Just the same, I will never in my life forget his first words in Russian,
as he asked us, by order of the officer: "Who are you—brothers?" In
tears we answered him that we were Russian officers escaped from
captivity; he asked it so kindly, and we were infinitely gladdened by
his sweet words.
The following day we were taken to the corps headquarters. Officers
would come in, shake hands—some even kissed us, which
embarrassed us. Unwittingly tears would come to our eyes when we
recalled our life in the prison camp and this sudden change for the
better.
The General also visited us. He pressed our hands, gave each of us a
package of cigarettes, and presented us with 10 lire in gold. We
wanted to decline the money, but the interpreter said, "Take," and
we did.
We lived for about a month in Italy. What a noble people!—soldiers,
civilians, and officers. It is impossible to describe! At every station
(on the way to France) the public would surround us, all anxious to
do us some favours, all showing their deep affection for the
Russians. Once a Sister of Mercy was distributing coffee to our party
as the train began to move. She ran along till the train gained full
speed, desiring not to leave some of us without coffee. Our soldiers
would wonder at the affection of the entire Italian people for the
Russians, and would shout incessantly: "Viva Italia! Viva Italia!"
TWO WEEKS ON A SUBMARINE
Told by Carl List
This article, by a German-American sailor on a Norwegian ship
bound for Queenstown with a cargo of wheat, was
communicated to L'Illustrazione Italiana, from which it is here
translated for Current History.
I—"I WAS ON A NORWEGIAN SHIP"
The Norwegian ship on which I was embarked was nearing the Irish
Channel. The afternoon was misty, the sea rough. We were warned
by an English steamer of the presence of German submarines in the
vicinity. There was a certain depression among those on board.
I asked the Captain if there were anything to do. "No," he answered.
Boom! a cannon shot was heard at the very moment. General
confusion. All the men ran up on deck and looked about, terrified.
Boom! another cannon shot. Then one of the German sailors,
pointing to a spot on the horizon, said: "A German submarine."
It was true. The black spot grew rapidly larger, and then one could
make out some human figures near the small cannon on the deck. It
was the famous U-39. We hoisted our flag and awaited events. The
Captain sent the mate with our ship's papers over to the submarine,
which was now near. Soon those who were not German received
orders to take to the boats. The Germans were taken on board the
U-39, I among them. When this was done our ship was sunk.
So there I was on board a submarine. The impression of it was
strange enough. The first evening, quite exhausted, I threw myself
down in a corner. I heard a few short orders, then the sound of the
machinery.... After that everything was in absolute silence. Some
said we were navigating at such a depth that big ships could pass
overhead of us.... I fell asleep.
Next day on waking I tried to get my bearings. We Germans were
treated as friends. We were permitted to go about everywhere.
The boat had the shape of a gigantic cigar, about 200 feet long,
divided into numerous compartments. They were full of shining
instruments. Now there was a buzzing sound, like the inside of a
bee-hive, now absolute silence reigned. Every nerve was tense with
the expectation of the orders on which our lives depended. Toward
the prow was the room from which the torpedo was launched, a
room full of tubes and valves. The officers' lodgings are very
restricted, since the space on board a submarine proscribes any
comfort. The commander was Lieut. Capt. Foerstner, a tall young
man, thin and pale—which is not surprising, since he never had a
moment's repose; neither he nor the men of the crew ever got their
clothes off during the twelve days I was on board.
The periscope, the eye of the submarine, made known to us
everything that took place on the surface of the water, and it did so
with such clearness that it was almost like looking through a
telescope. There was always a man on watch there.
II—"I WAS ABOARD THE U-39"
Suddenly a ship comes in sight. Its smoke is like a black line drawn
on the horizon. A bell rings. It is a signal for each man to be at his
post. The U-39 slowly rises to the surface. A last look is given at the
mirror of the periscope; no English coast guard is in sight. So
everything is ready for action. We hear the command, "Empty the
water cistern." Freed from her ballast, the submarine rises to the
surface. "Both engines ahead at full speed!" The boat cleaves her
way through the water that cascades her sides with foam. In a short
time the ship is reached. The submarine hoists her flag and fires a
cannon shot. No flag betrays the nationality of the captured ship, but
we can read the name, Gadsby, on her side. She is English. We
signal that her whole crew is to take to the lifeboats, and quickly! At
any moment we may be surprised.
Through the megaphone we indicate to the men the nearest way to
land; then a cannon shot, then a second one. The captured ship,
after pitching for a while, sinks.
The time necessary for the sinking of a ship differs considerably in
different cases. Some disappear in five minutes, others float for
several hours. The finest spectacle I witnessed was the sinking of
the Fiery Cross. The crew received orders to get off in the boats.
Some of our men rowed up close to the abandoned ship and
attached hand grenades to her sides. They were fired and the three-
master was blown up with all her sails spread and set. The hull and
the rigging went down to the depths, but the sails spread out on the
surface of the water like so many little fields of polar ice. Eleven
ships were destroyed during my stay on board. Quite a number of
others were captured, besides these, but they were let go again.
This trip, which I shall never forget, lasted twelve days. It was
dangerous, but it was exciting and so fine that I would not have
missed it for anything in the world.
A GERMAN BATTALION THAT
PERISHED IN THE SNOW
Told by a Russian Officer
This is a tragic story of a night fight in snow-buried barbed wire
entanglements where a whole German battalion perished. It
comes from Petrograd to Montgomery Schuyler in the form of a
letter from a Russian officer.
I—TRAGIC STORY OF A NIGHT FIGHT
"We were creeping across the snow, when we hear a frightened 'Wer
kommt da?'
"'Hold on, Germans! Where the devil do they come from?' ask our
men in surprise. 'Are they numerous?'
"'Wer ist da?' we hear again.
"Our only reply is to fire by the squad, and then again. The Germans
are a little surprised, but pull themselves together and return the
fire. It is dark and neither side can see the other. In groping about,
we finally meet, and it is give and take with the bayonet. We strike
in silence, but bullets are falling about us like rain. Nobody knows
who is firing and every one is crying in his own language, 'Don't fire!
Stop!' From the side where the firing comes from, beyond and to the
right, they are yelling at us, both in German and Russian, 'What's
the matter? Where are you?'
"Our men cry to the Germans, 'Surrender!'
"They answer: 'Throw down your arms. We have surrounded you
and you are all prisoners.'
"Wild with rage, we throw ourselves forward with the bayonet,
pushing the enemy back along the trenches. In their holes the
Germans cry, peering into the impenetrable darkness, 'Help! Don't
fire! Bayonet them!' Hundreds of shouts answer them, like a wave
rolling in on us from every hand.
"'Oh, little brothers, their force is numberless. We are surrounded on
three sides. Would it not be better to surrender?' cries some one
with a sob.
"'Crack him over the head! Pull out his tongue! Drive him to the
Germans with the bayonet!' are the growling comments this evokes.
"A command rings out, vibrating like a cord: 'Rear ranks, wheel, fire,
fire!'
"The crowd before us yells, moves, and seems to stop. But behind
them new ranks groan and approach. Anew the command is given,
'Fire, fire!'
"Cries and groans answer the fusillade and a hand-to-hand struggle
along the trenches ensues.
"German shouts are heard: 'Help! Here, this way! Fall on their
backs!'
"But it is we who fall on their backs. We pry them out and clear the
trenches.
"In front of us all is quiet. On the right we hear the Germans
struggling, growling, repeating the commands of the officers:
'Vorwärts! Vorwärts!' But nobody fires and nobody attacks our
trenches. We fire in the general direction of the German voices,
infrequent shots far apart answer us. The commands of 'Vorwärts'
have stopped. They are at the foot of the trenches, but they do not
storm them. 'After them with the bayonet,' our men cry, 'Finish them
as we finished the others.'
"'Halt, boys,' calls the sharp, vibrating voice of our commander. 'This
may be only another German trick. They don't come on; we are
firing and they do not answer. Shoot further and lower. Fire!'"
II—"SO PERISHED A WHOLE BATTALION"
"New cries and groans come from the Germans, followed by some
isolated shots, which fly high above us. After five or six rounds
silence settles upon the trenches and continues unbroken. 'What can
this mean?' wonder our men. 'Have we exterminated them all?'
"'Excellency, permit me to go and feel around,' offers S., chief scout,
already decorated with the Cross of St. George.
"'Wait, I am going to look into it myself.'
"The officer lights a little electric lamp, and prudently sticks his arm
above the rampart. The light does not draw a single shot. We peer
cautiously over and see, almost within reach of our hands, the
Germans lying in ranks, piled on top of one another.
"'Excellency,' the soldiers marvel, 'they are all dead. They don't
move, or are they pretending?'
"The officer raises himself and directs the rays from his lamp on the
heaps. We see that they are buried in the snow up to the waist, or
to the neck, but none of them moves. The officer throws the light
right and left, and shows us hundreds of Germans extended, their
fallen rifles sticking up in the snow like planted things.
"'I don't understand,' he mutters.
"'Excellency, I am going to see,' says the chief scout.
"'Go on,' the officer consents, 'and you, boys, have your rifles ready
and fire at anything suspicious without waiting for orders from me.'
"S. gets out of the trench and immediately disappears, swallowed by
the soft snow up to the neck. He tries to get one leg out, but
without success. He tries to lean on one hand, pushes it down into
the snow, then pulls hard and swears. His hands are frightfully
scratched; the blood tinges the snow with dark blotches.
"'It's the barbed wire defenses,' he cries. 'Help me, little brothers.
Alone I can do nothing.'
Welcome to our website – the perfect destination for book lovers and
knowledge seekers. We believe that every book holds a new world,
offering opportunities for learning, discovery, and personal growth.
That’s why we are dedicated to bringing you a diverse collection of
books, ranging from classic literature and specialized publications to
self-development guides and children's books.
More than just a book-buying platform, we strive to be a bridge
connecting you with timeless cultural and intellectual values. With an
elegant, user-friendly interface and a smart search system, you can
quickly find the books that best suit your interests. Additionally,
our special promotions and home delivery services help you save time
and fully enjoy the joy of reading.
Join us on a journey of knowledge exploration, passion nurturing, and
personal growth every day!
ebookbell.com

More Related Content

PDF
Dot NET Core Interview Questions PDF By ScholarHat
PPTX
Introduction to .net
PDF
Net Framework vs .Net Core A Complete Comparison.pdf
PPTX
The ultimate cheat sheet on .net core, .net framework, and .net standard
PDF
Future of .NET - .NET on Non Windows Platforms
PDF
.Net framework vs .net core a complete comparison
PPT
.Net introduction by Quontra Solutions
DOCX
The Seven Pillars Of Asp.Net
Dot NET Core Interview Questions PDF By ScholarHat
Introduction to .net
Net Framework vs .Net Core A Complete Comparison.pdf
The ultimate cheat sheet on .net core, .net framework, and .net standard
Future of .NET - .NET on Non Windows Platforms
.Net framework vs .net core a complete comparison
.Net introduction by Quontra Solutions
The Seven Pillars Of Asp.Net

Similar to Net In Action Second Edition Meap V06 2nd Chapters 1 To 12 Of 13 Dustin Metzgar (20)

PDF
Dot net interview_questions
PPTX
EF Core (RC2)
DOCX
The seven pillars of aspnet
PPTX
NET app modernization and Microsoft Azure.pptx
PPT
Introduction to .net
PPT
PDF
Unit I- Introduction to .NET Framework.pdf
PDF
Microsoft .NET 6 -What's All About The New Update
PPTX
Dot net-interview-questions-and-answers part i
PDF
Dot net-interview-questions-and-answers part i
PDF
Chapter1
PDF
Pro ASP.NET Core 7, MEAP V03 10th Edition Adam Freeman
PDF
Dotnet basics
PPTX
Session i
PDF
PPTX
Dotnet Basics Presentation
PDF
tybsc it asp.net full unit 1,2,3,4,5,6 notes
PPTX
DOCX
Difference between .net and asp.net all you need to know
PDF
Asp.net Web Development.pdf
Dot net interview_questions
EF Core (RC2)
The seven pillars of aspnet
NET app modernization and Microsoft Azure.pptx
Introduction to .net
Unit I- Introduction to .NET Framework.pdf
Microsoft .NET 6 -What's All About The New Update
Dot net-interview-questions-and-answers part i
Dot net-interview-questions-and-answers part i
Chapter1
Pro ASP.NET Core 7, MEAP V03 10th Edition Adam Freeman
Dotnet basics
Session i
Dotnet Basics Presentation
tybsc it asp.net full unit 1,2,3,4,5,6 notes
Difference between .net and asp.net all you need to know
Asp.net Web Development.pdf
Ad

Recently uploaded (20)

PPTX
Cell Types and Its function , kingdom of life
PDF
Saundersa Comprehensive Review for the NCLEX-RN Examination.pdf
PDF
Anesthesia in Laparoscopic Surgery in India
PPTX
Institutional Correction lecture only . . .
PDF
102 student loan defaulters named and shamed – Is someone you know on the list?
PPTX
master seminar digital applications in india
PDF
Mark Klimek Lecture Notes_240423 revision books _173037.pdf
PDF
STATICS OF THE RIGID BODIES Hibbelers.pdf
PPTX
IMMUNITY IMMUNITY refers to protection against infection, and the immune syst...
PDF
Business Ethics Teaching Materials for college
PPTX
Microbial diseases, their pathogenesis and prophylaxis
PPTX
Cell Structure & Organelles in detailed.
PDF
O5-L3 Freight Transport Ops (International) V1.pdf
PDF
Physiotherapy_for_Respiratory_and_Cardiac_Problems WEBBER.pdf
PDF
Module 4: Burden of Disease Tutorial Slides S2 2025
PDF
Origin of periodic table-Mendeleev’s Periodic-Modern Periodic table
PDF
O7-L3 Supply Chain Operations - ICLT Program
PDF
Classroom Observation Tools for Teachers
PDF
grade 11-chemistry_fetena_net_5883.pdf teacher guide for all student
PPTX
Pharmacology of Heart Failure /Pharmacotherapy of CHF
Cell Types and Its function , kingdom of life
Saundersa Comprehensive Review for the NCLEX-RN Examination.pdf
Anesthesia in Laparoscopic Surgery in India
Institutional Correction lecture only . . .
102 student loan defaulters named and shamed – Is someone you know on the list?
master seminar digital applications in india
Mark Klimek Lecture Notes_240423 revision books _173037.pdf
STATICS OF THE RIGID BODIES Hibbelers.pdf
IMMUNITY IMMUNITY refers to protection against infection, and the immune syst...
Business Ethics Teaching Materials for college
Microbial diseases, their pathogenesis and prophylaxis
Cell Structure & Organelles in detailed.
O5-L3 Freight Transport Ops (International) V1.pdf
Physiotherapy_for_Respiratory_and_Cardiac_Problems WEBBER.pdf
Module 4: Burden of Disease Tutorial Slides S2 2025
Origin of periodic table-Mendeleev’s Periodic-Modern Periodic table
O7-L3 Supply Chain Operations - ICLT Program
Classroom Observation Tools for Teachers
grade 11-chemistry_fetena_net_5883.pdf teacher guide for all student
Pharmacology of Heart Failure /Pharmacotherapy of CHF
Ad

Net In Action Second Edition Meap V06 2nd Chapters 1 To 12 Of 13 Dustin Metzgar

  • 1. Net In Action Second Edition Meap V06 2nd Chapters 1 To 12 Of 13 Dustin Metzgar download https://ebookbell.com/product/net-in-action-second-edition- meap-v06-2nd-chapters-1-to-12-of-13-dustin-metzgar-53733100 Explore and download more ebooks at ebookbell.com
  • 2. Here are some recommended products that we believe you will be interested in. You can click the link to download. Net In Action Second Edition Meap 2nd Edition Dustin Melager https://ebookbell.com/product/net-in-action-second-edition-meap-2nd- edition-dustin-melager-56838458 Aspnet Core In Action Second Edition 2nd Edition Andrew Lock https://ebookbell.com/product/aspnet-core-in-action-second- edition-2nd-edition-andrew-lock-23669072 Rxnet In Action With Examples In C 1st Edition Tamir Dresher https://ebookbell.com/product/rxnet-in-action-with-examples-in-c-1st- edition-tamir-dresher-7004318 Net Maui In Action Meap V06 Chapters 1 To 9 Of 12 Matt Goldman https://ebookbell.com/product/net-maui-in-action- meap-v06-chapters-1-to-9-of-12-matt-goldman-49608804
  • 3. Net Core In Action 1st Edition Dustin Metzgar https://ebookbell.com/product/net-core-in-action-1st-edition-dustin- metzgar-7144112 Aspnet Core In Action Meap V05 3rd Chapters 1 To 11 Andrew Lock https://ebookbell.com/product/aspnet-core-in-action-meap-v05-3rd- chapters-1-to-11-andrew-lock-47541526 Aspnet Mvc In Action 1st Edition Jeffrey Palermo Ben Scheirman https://ebookbell.com/product/aspnet-mvc-in-action-1st-edition- jeffrey-palermo-ben-scheirman-2194282 Aspnet Ajax In Action 1st Edition Alessandro Gallo David Barkol Rama Krishna Vavilala https://ebookbell.com/product/aspnet-ajax-in-action-1st-edition- alessandro-gallo-david-barkol-rama-krishna-vavilala-4097390 Aspnet Core In Action 1st Edition Andrew Lock https://ebookbell.com/product/aspnet-core-in-action-1st-edition- andrew-lock-7042438
  • 7. .NET in Action, Second Edition 1. 1 Why_.NET? 2. 2 Building_a_console_application 3. 3 Creating_web_services_and_applications_with_ASP.NET_Core 4. 4 File_and_network_IO 5. 5 Using_Entity_Framework_Core_with_relational_databases 6. 6 Unit_testing_fundamentals 7. 7 Substituting_dependencies_in_tests 8. 8 Integration_testing 9. 9 Security 10. 10 Performance_and_profiling 11. 11_Handling_failures 12. 12_Building_world-ready_applications 13. About_this_MEAP 14. Welcome 15. index
  • 8. 1 Why .NET? This chapter covers What is .NET? Where is .NET used? .NET in the job market What is in the .NET runtime? There has never been a better time to be a .NET developer. .NET runs on almost everything: from embedded devices and sensors to game engines like Unity and Godot, from mobile devices to all major clouds. The skills you’ll learn from this book apply across the broad .NET ecosystem. This book covers the necessary foundation and gets you building production-ready applications. .NET looks a lot different now than it did in 2002 when I was first starting working with it professionally. Features were introduced, improved, and sometimes replaced or deprecated but still supported. Microsoft maintained backward-compatibility with each version of the .NET Framework to prevent breaking existing applications. This was great for customers but resulted in the accumulation of some "baggage" over the past 20 years. The first edition of this book, .NET Core in Action, explored how Microsoft decided to "hit refresh" and begin anew. They mixed the best parts of .NET with some new ideas and modern techniques to create .NET Core. Having different .NET’s, like Framework and Core (and Standard), caused some confusion and Core was clearly the future. So Microsoft decided to drop the "Core" and just go with .NET when they released .NET 5 (5 being greater than .NET Core 3.0 and .NET Framework 4.8). In .NET 6, 7, 8, and beyond we’re seeing an evolution of what was once .NET Core. Whether you’re new to .NET or an experienced veteran, this is an exciting time to be a .NET developer.
  • 9. What happened to Core, Framework, and Standard? In the beginning, there was the .NET Framework. Over time, the .NET Framework struggled to stay competitive - burdened by the weight of backward compatibility. To start fresh, the .NET team started to work on a new version called .NET Core. .NET Core incorporated a lot of new ideas: design and build in the open, work on any platform, focus on web performance, etc. To make existing libraries port easily between Framework and Core, the .NET Standard was introduced. The .NET Standard only defines the APIs that a .NET implementation needs to implement. If you have some projects that are .NET Framework and others that are .NET Core, 5, or later, those projects can use common libraries that target the .NET Standard. So even though there will be no new iterations to the .NET Standard, it is still a very useful tool for incrementally porting applications to the newest versions of .NET. Starting with .NET 5, Microsoft has tried to simplify by culling Core, Framework, and Standard and just having one .NET with some OS-specific targeting capabilities. If you want to develop in .NET, forget about Core and Framework and just target the latest long-term support (LTS) release of .NET. If you need to support older versions of .NET, try targeting the .NET Standard as that will give your libraries the broadest reach. This subject is explored more in appendix A, A brief history of .NET. 1.1 What is .NET? .NET is free, cross-platform, and open source. It is a runtime, not a programming language. There is only one language that the .NET runtime understands called the Common Intermediate Language, or CIL (this is more commonly referred to as IL but I’ll try to keep with CIL to disambiguate from other intermediate languages). CIL is a low-level language, similar to Assembly. Don’t worry though, you won’t have to learn CIL because .NET comes with compilers that compile high level languages to CIL.
  • 10. .NET fully supports three languages: C#, F#, and Visual Basic (VB.NET). C# is the most widely used by a large margin and all examples in this book are in C#. Code written in .NET has access to other .NET code, regardless of the language used. This means if some part of your C# application is better expressed in F# you don’t need to convert everything to F#. This works because the .NET compilers all produce CIL. The C#, F#, and VB.NET compilers are packaged with .NET but any language that compiles to CIL will work with .NET. There are many other languages contributed by the .NET community. You can even create your own. What other languages are supported by .NET? The .NET open source community has created compilers for other languages to work in .NET. Project Name Language Website PeachPie PHP https://www.peachpie.io/ IronPython Python https://ironpython.net/ MoonSharp Lua https://www.moonsharp.org/ Jint JavaScript Interpreter https://github.com/sebastienros/jint I’ve mentioned that .NET is a runtime, but what does that mean? Think of a runtime as an interpreter that can read code in a certain format (Intermediate Language or IL - think bytecode if you’re familiar with Java) and execute it. The .NET runtime is called the CoreCLR. CLR stands for Common Language Runtime, with common referring to how every .NET language uses the same
  • 11. runtime. When .NET was originally built, the runtime was simply called CLR, without the "Core". The Core part was added as part of .NET Core to distinguish it from the original CLR (part of the .NET Framework) and the name stuck. The runtime has important features such as Just-In-Time (JIT) compilation and memory management that we’ll explore later in this book. How CIL, the compilers, and the CoreCLR fit together is shown in 1.1. Figure 1.1. .NET compilers, CIL, and CoreCLR In addition to the runtime and some language compilers, .NET has a class library. The .NET class library is called the Framework Class Library, but is referred to as CoreFX. .NET veterans may remember this used to be called the Base Class Library, or BCL (sometimes called FX by Microsoft internally), but that has been replaced with CoreFX. CoreFX provides a set of APIs that handle many base-level functions (console output, file I/O, network I/O, etc). Outside of the .NET class library (CoreFX) there are some powerful features that come with .NET. These are built by .NET teams and supported by Microsoft. This book will introduce you to the following key features as well as some useful projects created by the open source community. Entity Framework Core for access to data stores
  • 12. ASP.NET Core for web services and applications Blazor for running .NET in a browser using WebAssembly Multi-platform App UI (MAUI) for desktop and phone applications 1.2 Where is .NET used? ASP.NET Core is .NET’s web framework. It can be hosted in either a lightweight server called Kestrel or in the Windows Internet Information Services (IIS) host. Kestrel enables ASP.NET Core to run on containers, which makes ASP.NET Core perfect for microservices. There are a number of hosting services available in cloud providers that either use the container model, IIS, or serverless options. .NET is also used in desktop (aka thick client) applications. There are many options to choose from. Traditional Windows Forms applications are available, which is helpful for maintaining older applications. Windows Presentation Foundation (WPF) has an XML-based approach and is widely used for desktop applications. You can also write .NET applications with WinUI. This gives you access to PC, tablet, Xbox, and Hololens. WinUI makes it easier to interact with touch, pen, and game controller input as well as mouse and keyboard. To write iOS, macOS, and Android applications, use Xamarin or the new Multi-platform App UI (MAUI), which is an evolution of Xamarin. If you’re interested in small devices, sensors, and micro-controllers, there are many opportunities to use .NET. For instance, .NET runs on boards like the Raspberry Pi and the Hummingboard. The .NET IoT (Internet of Things) community maintains a set of components for device bindings to work with specific hardware. These are things such as LCDs, temperature sensors, and analog-to-digital converters. If the hardware is too small to run .NET 6, there are "lighter" implementations like the .NET nanoFramework and Meadow, which work on embedded devices. 1.2.1 .NET in gaming Unity has been using C# for scripting game objects since its early releases.
  • 13. Before .NET Core, Unity used Mono, which was an unofficial, cross- platform, open source port of .NET. This had enough capability to handle scripting for many years. Mainstream cross-platform support, language enhancements, and performance improvements convinced Unity to migrate to .NET Core. One of the objections to using .NET or similar runtimes like Java is that they are "managed" rather than "native". Native code is compiled to work on a specific machine and usually manages memory on its own. Managed code, by contrast, executes in a runtime using an interpreter. The runtime often provides memory management via garbage collection. Garbage collection is undesirable in real-time applications because it can create unpredictable pauses while the garbage collector runs. We’ll learn why that happens later on. Unity uses .NET for scripting game objects, but not for its engine code. That is written in native C++. The same goes for Godot and CRYENGINE (two other popular game engines). It begs the question: can managed code be used for the entire game engine? One answer to this question is Stride, an open source game engine written in C#. Stride is a powerful, free engine that handles real-time 3D and VR. It is still young and doesn’t yet have the community of Unity but does show that .NET even does pretty well with real-time 3D. Visit https://www.stride3d.net/ to learn more about the project. Another project called Ryujinx makes a compelling case that .NET can handle realtime games. Ryujinx is a Nintendo Switch emulator that is written entirely in C# and emulates the ARM CPU. The Ryujinx team has even driven some performance improvements in .NET. Check the project out at https://ryujinx.org/. 1.2.2 Popular .NET open source projects This book will introduce many important .NET concepts and reinforce your learning with exercises. Writing code for the exercises helps with the learning process. I also suggest contributing to open source projects. Reading code
  • 14. from other projects is a great way to see how .NET constructs are used. If you’re looking for .NET projects to participate in, the .NET Foundation is a good place to start. .NET Foundation projects have common rules about contributor agreements, code of conduct, and licensing. Most, but not all, projects mentioned in this book are part of the .NET Foundation; all of them are on GitHub. ASP.NET Core is .NET’s web framework and is a great starting point for building web applications and services. Naturally, many open source projects are for ASP.NET Core applications. If you want more features than those built-in to ASP.NET Core, there are a few open source (and commercial) options. For instance, DotVVM has built-in components and reduces the number of round-trips to the server by implementing most features in Knockout JS. There is also ASP.NET Boilerplate - a framework that handles common development tasks by convention and provides a lot of templates. If you’re interested in Blazor (introduced later in this book), check out Oqtane or the Ant Design Blazor project. If you want a full web site that handles just about everything where you can build your application as a custom component, check out some of the .NET content management systems (CMS) like Orchard, Umbraco, Piranha, or DNN (aka DotNetNuke). MAUI, the Multi-platform App User Interface, is a relatively new product for building applications for any platform. There are other options in this space as well that are worth investigating. Reactive UI, for example, is a framework for building applications using functional reactive programming. If you’ve not heard of reactive programming, check out ReactiveX at https://reactivex.io. Another cross-platform UI framework is Avalonia. Avalonia makes the XAML-based UI programming from WPF (Windows Presentation Foundation) work on other platforms like Linux and Mac but also in the browser (via WebAssembly). Some other interesting projects to use or contribute to: Graphics ImageSharp, Silk.NET, SkiaSharp Database Dapper, LINQ to DB, Marten Testing utilities
  • 15. xUnit, Verify, BenchmarkDotNet, Moq, FluentAssertions Distributed systems Akka.NET, Orleans Workflow Elsa Workflows Build tools Cake 1.3 .NET in the job market Stack Overflow (which is built with .NET) holds an annual developer survey to learn about all facets of development from geography and years in industry to the most loved or dreaded frameworks. In the 2021 survey, .NET is mentioned in a few key areas: .NET Core / .NET 5 is the most loved framework and the 2nd highest paying ASP.NET Core is the 2nd most loved web framework, losing only by a small percentage but with 7 times as many votes as the #1 web framework ASP.NET Core also ranked as the 3rd highest paying web framework F# ranked as the 2nd highest-paying programming language There is a lot of information in the report and it’s worth a read. You can find each year’s report here: https://insights.stackoverflow.com/survey 1.4 When to use .NET At one time, .NET was a Windows-only framework. This hasn’t been true for years. .NET works on Windows, Linux, and Mac for desktop applications as well as Android and iOS for phone and tablet. .NET is used in microcontrollers, IoT devices, and games. You can even use .NET in shell scripting via PowerShell. But the bulk of jobs in .NET will be for web services and applications. Whether or not you should use .NET depends on your scenario. Here is a list
  • 16. of scenarios where .NET is an option but not commonly used. Data science While some strides have been made in using .NET for data science and machine learning, it would be better to start with Python. Hardware drivers Managed code in hardware drivers could be useful in that the code is safer and easier to write. However, it requires an understanding of garbage collection, JIT/AOT compilation, and trimming. A language like Rust may be a better starting point. Games Game developers using an engine like Unity or Godot can use C# in their scripts. There are books and tutorials specifically covering C# for these use cases that would be more targeted than this book. .NET has been used in the past to write entire games but this book doesn’t explore those frameworks. This is not to say that .NET cannot be used in these scenarios. Choosing what language/framework to use depends on many factors, such as performance, security, what the development team is comfortable with, what support is available, and how big (and welcoming) the community is. .NET has 20 years of hardening and improvements plus millions of active developers. It is open source with a large and engaged community. .NET has strong support from Microsoft, even without the support contracts that many companies already have. Given that you’re reading this book, you’re at least considering .NET for your application. Try building the examples for the first few chapters and see for yourself how powerful and easy to use .NET can be. 1.5 What will I learn from this book? This book aims at two types of developer: (1) those that are familiar with other programming languages and are new to .NET and (2) those that have previous .NET experience but are looking to catch up with the latest. If you’re new to programming in general, this book may be difficult to follow. I assume you have a general idea of the following concepts:
  • 17. Software patterns Some basic patterns are used in this book such as Singleton, MVC, and method-chaining. A lot of these patterns are well-known so the book only does a brief introduction. It’s generally important to know what software patterns are as they provide a language for communicating with other software developers. Web services and web applications If you know about URLs, HTTP, requests, responses, and web servers then you should be able to follow the examples. Terminal usage The examples in this book provide instructions that are executed in the terminal (command line in Windows). If you’re using an IDE like Visual Studio or Rider, you may need to look up how to translate those commands into actions in the UI or just have a terminal open along with your IDE. Developers reading this book that have used .NET in the past may want to consider skimming the first few chapters. If you haven’t used .NET in a while, here are some relatively new concepts (as of .NET 6) that are covered in the first three chapters: Top-level statements Records Nullable reference types, null coalescing, and other null operators Global and implicit usings "dotnet watch" and Hot Reload As you read the table of contents for this book, you may wonder how everything fits together. 1.2 shows how these topics align. In this chapter, we’re building an understanding of the CoreCLR and the services it offers. On top of that, we’ll learn C# throughout the first few chapters. The class libraries available in CoreFX are essential to understand what is available in .NET and what has to be pulled in via external packages. Figure 1.2. High level diagram of how topics covered in the book fit together
  • 18. The dashed boxes arranged vertically indicate cross-cutting concerns. For example, performance is a subject that impacts everything from understanding how the JIT compiler impacts your application to how to use ASP.NET Core more efficiently. While there are several areas that involve ASP.NET Core, such as security and fault-handling, this book is focused on .NET in general and not intended to be a comprehensive reference on ASP.NET Core. By the end of this book, you should be able to author and deploy libraries, console applications, web services, and web applications. Your applications will be able to store and manipulate data in databases and through other
  • 19. services. You will have an intermediate-level understanding of important .NET concepts and features. My goal with this book is to quickly get you to the point where you can develop .NET applications professionally. It’s definitely possible to dive deeper into many of the subjects introduced here and there are other books available from Manning that will help you do that. 1.6 What is in the .NET runtime? I mentioned before that .NET is managed, which means it uses a runtime. .NET’s runtime, the CoreCLR, has three important concepts that influence how you write code in .NET: Intermediate Language (CIL), Just-In-Time (JIT) Compilation, and Garbage Collection (GC). We’ll explore these at a high level first and get into details as they become relevant later in the book. 1.6.1 Intermediate language The code you write in any language needs to be compiled into some machine- readable form. But what does machine-readable mean? In order for code to execute on a processor, it needs to use the right set of instructions. The two most popular instruction sets for modern computers are x86 and ARM. There are many others especially when you include GPUs (graphical processing units), which are used for games (think shaders), cryptocurrency mining, and data processing. New generations of processors may add new instructions to an instruction set so it’s important to know what generation a processor is. Operating systems also impose some requirements on application machine code (i.e. an Android executable won’t run on Windows). Often you’ll need different compilers for different platforms. Figure 1.3. Creating an executable application without a runtime (unmanaged)
  • 20. 1.3 shows a simplified matrix of producing machine-readable code for one specific OS and CPU. MacOS/iOS applications typically use the xCode compiler and choose the CPU architecture to build for. OS versions matter, for example OSX 10, 11, and 12 have compatibility differences. OS flavors also matter (think Redhat vs Ubuntu vs Debian). Intermediate language offers an alternative. It’s a language that can be quickly translated into machine code. The compiler is specific to the language, not the OS or processor architecture you’re targeting. If you’re familiar with Assembly language, CIL is similar but has instructions at a slightly higher level of abstraction. Having your code compiled into CIL means that your application’s binaries (the files produced through compilation) can run on any processor or OS with a .NET runtime. Figure 1.4. .NET languages compile to CIL in a DLL file, that can be run on any machine with a .NET runtime
  • 21. In 1.4 the compiler is only specific to the language. The compiler creates Common Intermediate Language (CIL) code and puts it in a DLL file. The DLL file can be transferred to any machine regardless of OS or processor architecture as long as there is a .NET runtime. The .NET runtime converts the CIL to machine readable code (typically at runtime using the Just-In- Time compiler introduced in the next section). What is a DLL? When you write programs, you almost always make calls into some library to invoke operations. Writing to the console, allocating memory, creating a thread, opening a file, and many other functions are relatively simple operations because of libraries. For some languages, like C/C++, there is a "link" step during the build process that links your code to the static libraries it uses. Static linking includes the library in your application and that library cannot be reused by other applications. If the library is updated, the application has to be rebuilt and redistributed. DLL stands for Dynamically Linked Library. DLLs expose a public surface area and can be reused by any application. This reduces the size of a distributed application while also allowing .NET to distribute new (minor) versions with bugfixes without each application needing to rebuild and redistribute. DLLs are usually installed or registered with the operating
  • 22. system so they can be shared (but if applications use different versions or DLLs reference other DLLs with different versions you get into what many refer to as "DLL hell"). The concept of a DLL is not exclusive to .NET. 1.6.2 Just-In-Time Compilation In the previous section, 1.4 shows that .NET has compilers for C#, F#, and VB included. Since these languages have already been compiled, why is there another compiler inside the CoreCLR (.NET runtime)? A compiler is really only a program that translates a program in one language into another language. The name compiler is typically used for translating a high-level language into a low-level language and that is true of the VB, C#, and F# compilers. Note If a compiler translates one high-level language into another, like C# to JavaScript, it is typically called a transpiler. There are also compilers that translate a program in a low-level language into a high-level language. These are typically called decompilers. As noted before, CIL is still at a higher level than machine code. CIL makes no assumptions about processor architecture specifics (registers, instruction sets, cache sizes, etc.) so that it can work on as many platforms as possible. How this works is something we’ll explore in more depth in chapter 10, Performance and profiling. Before .NET code can be executed on a processor, the CIL needs to be compiled further down into machine code. The CoreCLR will perform this compilation at runtime so that the CIL DLLs don’t need to be compiled into processor-specific DLLs ahead of time. But compilation can be an expensive process and compiling an entire application every time it runs could impact startup performance. This is handled by a smart compiler that only compiles the code that is about to be used. In other words, the CIL is compiled "just-in- time", which is where the CoreCLR’s JIT compiler gets its name.
  • 23. Note There are cases where you know exactly what processor architecture and operating system your application will be running on. Like when building a Docker container, for example. The impact of JIT compilation can be avoided in this case using an Ahead-Of-Time (AOT) compiler. We’ll explore this in chapter 13, Working with containers. 1.6.3 Garbage Collection Earlier in this chapter, I mentioned that the CoreCLR (the .NET runtime) has a memory management component. The memory manager uses a technique called garbage collection. Garbage collection is used in many functional programming languages like Lisp or Haskell. It is also used in Java and some JavaScript interpreters. The essence of the technique is to keep track of the references to a chunk of memory and when no references remain, the memory can be safely "freed" or made available for allocation again. Garbage collection changes how you write programs. To illustrate how this works, let’s look at the simple C++ program shown in 1.1. Listing 1.1. Create dynamic array in C++ #include <stdio.h> #include <stdlib.h> int main() { int n = 4, i, *p; p = (int*) malloc(n * sizeof(int)); #1 if(p == NULL) { #2 printf("nError! memory not allocated."); exit(0); } printf("nEnter elements of array : "); for(i = 0; i < n; i++) { scanf("%d", p + i); #3 } printf("nSum : %d", sum(p, n));
  • 24. free(p); #4 return 0; } int sum(int *arr, int length) { #5 int i, sum = 0; for (i = 0; i < length; i++) { sum += *(arr + i); } return sum; } In 1.1 the array size is hard-coded but it doesn’t have to be. If the number of elements to store in an array is not known until runtime and it could be large, it’s better to allocate the array from memory at runtime. But memory allocation can fail, so you have to make sure it worked and handle the case where it doesn’t. After you’re done with the memory, you have to explicitly free it so that it can be used by other parts of the program. Managing memory manually in this way is cumbersome and error-prone but is preferred in high performance scenarios such as gaming or real-time devices. By contrast, .NET handles memory management so you don’t have to explicitly allocate, free, or handle allocation failures. The .NET garbage collector handles cleaning up unused memory for you. Let’s compare the C++ code in 1.1 with a C# equivalent shown in 1.2. Listing 1.2. Create dynamic array in C# public class Program { public static void Main() { int n = 4, i; int[] p = new int[n]; #1 Console.WriteLine("Enter elements of array : "); for (i = 0; i < n; i++) { p[i] = int.Parse(Console.ReadLine()); #2 } Console.WriteLine("Sum : " + Sum(p)); #3 }
  • 25. private static int Sum(int[] arr) { int i, sum = 0; for (i = 0; i < arr.Length; i++) #4 { sum += arr[i]; } return sum; } } Notice that in 1.2 there is no check if the memory successfully allocated and no explicit free. If memory could not be allocated, the garbage collector would run and try to free up memory and then attempt the allocation again. If the collector was unable to free up enough memory, an OutOfMemoryException is thrown, which gives the host a chance to determine how to handle the issue. .NET also knows the bounds of the array so it can detect if the program tries to exceed those bounds, where the C++ program has to do that manually. .NET memory management isn’t free though. Garbage collection will need to freeze some code execution so it can safely reorganize memory. The unpredictability of collection events is what makes managed languages scary for real-time scenarios (you wouldn’t want your pacemaker to pause every now and then to free memory). For most applications, the benefits of CoreCLR memory management simplifying an application’s code far outweigh the cost. As some developers have found, it’s possible to control memory in .NET to minimize the impact of the garbage collector. We’ll explore the garbage collector in more depth in chapter 10, Performance and profiling. 1.7 Summary .NET supports multiple languages: C#, VB.NET, F#, and community contributions .NET applications compile to an intermediate language (CIL) that is not specific to any processor architecture
  • 26. .NET runs on a wide variety of platforms and in a broad set of use cases Developers that use .NET enjoy working with it, their skills apply across many types of applications, and have abundant job opportunities .NET has powerful features like JIT compilation and garbage collection built into the platform
  • 27. 2 Building a console application This chapter covers Generating projects with templates Creating and using namespaces Importing NuGet packages Chapter 1 introduced .NET concepts and the breadth of applications where it can be used. Now it’s time to put this into practice and start writing apps. If you’ve programmed with .NET Framework before, you’ll want to read through this chapter as there are many differences from the Framework. .NET Core developers will find a lot of similarities but may be surprised by the minimal APIs. To install .NET, follow the instructions for your OS at https://dotnet.microsoft.com/download. All you need is a terminal/command line and a text editor. If you’re interested in more information about IDEs (Integrated Development Environments) for .NET, check out appendix B, Setting up your development environment. As discussed in chapter 1, .NET works in many types of applications. There are three types of applications used throughout this book: console applications, web applications, and web services. Except for chapter 15, MAUI, this book’s examples will use only these application types. Many of the samples will work in any of these three so you can use whatever you feel most comfortable with. We’ll start with console applications. 2.1 Creating new applications from templates If using an IDE, your instructions for creating new projects will vary. The .NET 6 SDK comes with several built-in templates for creating applications. This book will use only the built-in templates. From a terminal, open a folder under which your .NET projects will go. Then execute the command dotnet new console -n HelloDotnet. This will
  • 28. create a new console application in the HelloDotnet folder. The code for this application is in the Program.cs file as shown in 2.1. Listing 2.1. Console application Program.cs // See https://aka.ms/new-console-template for more information Console.WriteLine("Hello, World!"); Note If you’ve used .NET in the past, you may be surprised that there is no Program class with a Main method. .NET now has a concept of top-level statements that do not belong to a class. Only one file in a project can do this and it doesn’t need to be named Program. The other file in the folder, HelloDotnet.csproj, contains important project settings that we will explore later. 2.2 Building and running From the HelloDotnet folder, execute this command in the terminal: dotnet build. After the build is finished, a new bin folder will appear under HelloDotnet. The bin folder contains the binaries from the build. They are organized in subfolders first by configuration, with the default configuration being "Debug", and then by runtime, with the runtime being .NET 6. Go to the HelloDotnet/bin/Debug/net7.0 (or whatever .NET SDK version you’re using) to find the DLL and executable for the console application. Assemblies A DLL file contains an assembly. An assembly (usually) maps one-to-one with a project. The csproj file represents the project and controls how the assembly is built. The HelloDotnet.dll in the net7.0 folder has all the compiled code from the project. I will use assembly and DLL interchangeably throughout this book.
  • 29. There is a ref subfolder of the net7.0 folder that also has a HelloDotnet.dll file in it. This DLL is different. It represents the public surface area of the project, but does not contain the implementation. We won’t use reference assemblies in this book so you can ignore this folder. You can run the application by executing HelloDotnet at the terminal, or .HelloDotnet if you have a PowerShell console. The application can execute because you have the .NET 6 SDK installed on your computer. If you copy the same files to another computer with the .NET 6 SDK installed, the executable will still run regardless of any difference in operating system or processor architecture. There are OS-specific builds that don’t require an SDK that we’ll explore later in chapter 13, Working with containers. 2.3 Writing code If you have programmed with .NET in the past, you may be surprised by the simplicity of the Program.cs file. While it is nice to see that all of the boilerplate code is gone, one has to wonder what has happened to all that code. That will become more apparent as you progress through this chapter. Let’s try a small example where we generate some ASCII art based on the parameters passed in from the command line. We will use an ASCII art generator NuGet package called Figgle. Let’s first add it to the .csproj file as shown in 2.2. Listing 2.2. HelloDotNet.csproj with Figgle package reference <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net7.0</TargetFramework> #1 <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> <ItemGroup> #2 <PackageReference Include="Figgle" Version="0.4.0" /> </ItemGroup>
  • 30. </Project> In 2.2, we add an ItemGroup node with a PackageReference. I found the value for the package reference by looking up the Figgle package on NuGet.org (https://www.nuget.org/packages/Figgle/). There is a tab on each package called "PackageReference" that shows the exact XML node you can insert into your project file. Replace the code in Program.cs to use the Figgle library to write ASCII art to the console as shown in 2.3. This code will write a usage statement if there are no command line arguments and return a non-zero exit code. Otherwise, it will write the first command line argument in ASCII art. Listing 2.3. Code to write ASCII art using Figgle; #1 if (args.Length == 0) #2 { Console.WriteLine("Usage: HelloDotnet <text>"); Environment.Exit(1); #3 } Console.WriteLine(FiggleFonts.Standard.Render(args[0])); #4 Now try running this from your project folder by executing dotnet run "Hello, .NET" from the terminal. You should see the text as shown in 2.4. Listing 2.4. Output from the ASCII art HelloDotnet > dotnet run "Hello, .NET!" _ _ _ _ _ _ _____ _____ _ | | | | ___| | | ___ | | | ____|_ _| | | |_| |/ _ | |/ _ | | | _| | | | | | _ | __/ | | (_) | _| | | |___ | | |_| |_| |_|___|_|_|___( ) (_)_| _|_____| |_| (_) |/ 2.4 Namespaces and conventions .NET 6 and above use a minimal style that avoids a lot of boilerplate code. In
  • 31. the Program.cs file there is no main method. The main method is assumed by convention to consist of "top-level" statements. If you’ve done shell scripting or JavaScript, this should look familiar. Note It’s not important that the top-level statements be in a file called Program.cs. Try renaming Program.cs and the application will still work. But if you add another .cs file and put some top-level statements in it like a Console.WriteLine, you will get a build error. Only one file can contain top- level statements. Since Program.cs contains top-level code, it is not part of a namespace. Namespaces are used to organize .NET types. For example, Figgle is a namespace that contains the classes for generating the ASCII art. We include the use of the Figgle namespace with the code using Figgle;. The package and assembly (DLL) are also named Figgle, but it’s not necessary for the namespace to match either of them. Let’s move the code to create the ASCII art to its own class. Create a new file named AsciiArt.cs with the code shown in 2.5. Listing 2.5. Contents of the AsciiArt.cs file that uses the Figgle library to render text in ASCII art and also writes the full type name of the AsciiArt class using Figgle; namespace HelloDotnet; #1 public static class AsciiArt #2 { public static void Write(string text) { Console.WriteLine(FiggleFonts.Standard.Render(text)); Console.WriteLine("Brought to you by " + typeof(AsciiArt).FullName); #3 } } Then modify Program.cs to call the new class, as shown in 2.6.
  • 32. Listing 2.6. Call AsciiArt class from Program using HelloDotnet; #1 if (args.Length == 0) { Console.WriteLine("Usage: HelloDotnet <text>"); Environment.Exit(1); } AsciiArt.Write(args[0]); #2 Execute the program as before. In addition to the ASCII art, there should be another line below. The line below should say "Brought to you by HelloDotnet.AsciiArt". The FullName property has the namespace and type name separated by a dot/period (.). Namespace names can also contain dots, which is a way to create a hierarchy of namespaces. To illustrate how namespace hierarchies work, consider the Regex class that is part of CoreFX (the .NET framework class library) and is used for applying regular expressions. Regex is part of the System.Text.RegularExpressions namespace. The dots in the namespace indicate the hierarchy. 2.1 shows how this hierarchy works. Figure 2.1. Namespace hierarchy of System.Text.RegularExpressions.Regex
  • 33. The System namespace is at the top level and has many children, such as System.IO and System.Collections. System.Text is focused on handling text and has some types of its own such as StringBuilder. The Regex class is a type that is part of the System.Text.RegularExpressions namespace. What is a type? Types in .NET are similar to other languages like Java and Go. A type can be a class, struct, enum, value type (int, float, etc.), record, and so on. .NET has a Common Type System (CTS) such that types can be used in any .NET language. C# is a strongly typed language. This means that every expression that evaluates to a value, every variable, and every constant has a specific type. One exception to this rule is the dynamic type, which bypasses static type checking. We won’t explore dynamic types in this book but will go into some of the more complex types such as generic, implicit, anonymous, and nullable types. A "using" statement indicates that we want to use that namespace in our code. By using a namespace, we get access to the types in that namespace without
  • 34. having to "fully qualify" them, i.e. without having to write the namespace and type name. This allows us to write Regex instead of System.Text.RegularExpressions.Regex. The types that you write also need to be put in a namespace. .NET 6 uses C# 10, which allows for file-level namespace declarations. In 2.5 you created a class called AsciiArt and declared it as part of the HelloDotNet namespace with the statement namespace HelloDotNet;. Prior to C# 10 namespaces declarations could only be written as code blocks with brackets around them with all the types in the file placed inside. C# 10 is backwards compatible so you still have the option of using this form of namespace declaration. File- level namespaces save one level of indentation (a small but very welcome improvement). Something that you may see in other codebases is that the namespace can be declared before or after the using statements. Be aware that the placement has meaning. Let’s compare the two listings 2.7 and 2.8. Listing 2.7. namespace after using using System.Text.RegularExpressions; #1 namespace System.Text; public static class Bar { public static readonly Regex Letters = new Regex(@"[a-z]+"); } Listing 2.8. namespace before using namespace System.Text; using RegularExpressions; #1 public static class Bar { public static readonly Regex Letters = new Regex(@"[a-z]+"); } In this case, we’re adding a new static class called Bar into the System.Text
  • 35. namespace. Bar uses the Regex class in its code. In 2.7, the namespace of Bar is declared after the using, so the using has to be the full namespace of Regex. In 2.8, the namespace of System.Text is declared first. This means that the usings declared after the namespace can be relative to the namespace that the code is in. If there is no RegularExpressions namespace at the top level, then .NET will look for the System.Text.RegularExpressions namespace. Figure 2.2. Namespace hierarchy of System.Text.Bar and System.Text.RegularExpressions.Regex Relative usings may make the code look cleaner but many .NET developers avoid it because it can cause confusion. For example, if I had a class in the namespace HelloDotnet.Figgle and I put a using Figgle; in my code, it is unclear which namespace I’m referring to. The examples in this book don’t use relative namespaces for clarity. 2.5 Global usings
  • 36. While we had to explicitly declare usings for the namespace of the NuGet package we’re using, the same is not true of the Console.WriteLine statements. The WriteLine is a static method on the Console class, which is part of the System namespace. The reason we don’t need a using System; statement in Program.cs is because the System namespace is included via a global using. There are default global usings for the commonly used .NET CoreFX namespaces that can be included implicitly with a flag in the .csproj file. You saw this earlier in 2.2 where the property <ImplicitUsings> is set to "enable". It is also possible to add global usings of your own if your project has namespaces it uses in many classes. A global using can be created by adding a statement such as global using Figgle; to one of your classes. The convention is to create a separate file for this in your project, like GlobalUsings.cs. Another way is to add the global using to the .csproj file like in 2.9. Listing 2.9. Global using in project file <Project Sdk="Microsoft.NET.Sdk"> <!-- ... --> <ItemGroup> <Using Include="Figgle" /> #1 </ItemGroup> </Project> Global usings are a good way to reduce the boilerplate code at the top of your code files. The examples in this book will use this technique to reduce the size of the listings. There is another way to employ the using statement in C# that helps reduce the amount of typing needed, which is called a static using. 2.6 Static usings A static using allows access to static members on .NET types without needing to write out the type name. 2.10 applies a static using to the AsciiArt.cs file. Listing 2.10. AsciiArt.cs with static using
  • 37. using static System.Console; #1 using static Figgle.FiggleFonts; #2 namespace HelloDotnet; public static class AsciiArt { public static void Write(string text) { WriteLine(Standard.Render(text)); #3 WriteLine("Brought to you by " + typeof(AsciiArt).FullName); } } Static usings can also be paired with global usings, e.g. global using static System.Console; will make WriteLine available to all the code in your project without prefacing with Console.. Global static usings can also be specified in the .csproj file like is shown in 2.11. Listing 2.11. Global static usings in project file <Project Sdk="Microsoft.NET.Sdk"> <!-- ... --> <ItemGroup> <Using Include="System.Console" Static="True" /> #1 <Using Include="Figgle.FiggleFonts" Static="True" /> </ItemGroup> </Project> There is a balance with static usings between brevity and readability. This book will employ static usings only where it’s clear that the members come from the static using and it makes the listing easier to read. 2.7 Handling more command line arguments In Program.cs we have an array of command line arguments stored in the variable "args". The parsing of command line arguments is very basic, with splitting arguments on spaces except if contained within quotes. You’ll typically want more control over the arguments such as converting to types other than string or optional arguments and the args array quickly becomes
  • 38. unwieldy. Luckily, NuGet has a few good packages for handling command line arguments. Let’s first establish some rules about the command line arguments. The text to convert to ASCII art should be required. If the text is not present or if there are other issues with the arguments, we should show a usage message. The usage message should also be available by specifying --help as an argument. To make it interesting, we’ll allow an optional parameter to set the font used for the ASCII art. Command line parameter conventions A generally accepted practice for command line arguments is that the single dash - is used for single-letter options and the double dash -- is for the long- form word options (called "GNU" or "long-option" style). For example, in most terminals you can list the contents of the current folder including files that start with a "." using the command ls -a. The same command can be written as ls --all since --all and -a are both aliases. The single dash allows for specifying multiple commands quickly. For example, to extract a tar file in LinuxUnix operating systems, one typically uses the command tar -xvf file.tar. The letters x, v, and f are single- letter aliases for --extract, --verbose, and --file= respectively. A NuGet package called CommandLineParser can handle the parameter parsing for us. There are many command line parsing libraries on NuGet, including one published by the .NET team (but still in beta) so feel free to look into other ones. Make the changes to the HelloDotnet.csproj file as shown in 2.12. Listing 2.12. Add CommandLineParser library to HelloDotnet.csproj <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net7.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings>
  • 39. <Nullable>enable</Nullable> #1 </PropertyGroup> <ItemGroup> <PackageReference Include="Figgle" Version="0.4.0" /> <PackageReference Include="CommandLineParser" #2 Version="2.8.0" /> </ItemGroup> <ItemGroup> #3 <Using Include="Figgle" /> <Using Include="System.Console" Static="True" /> #4 </ItemGroup> </Project> Next, create a file called Options.cs. This file will hold the parsed command line parameters. Add the code from 2.13. Listing 2.13. Contents of the Options record, which holds parsed command line parameters using CommandLine; #1 namespace HelloDotnet; #2 public record Options #3 { [Value(0, Required = true)] #4 public string? Text { get; init; } #5 [Option('f', "font")] #6 public string? Font { get; init; } #7 } What is a record? Records are immutable types in C#. The command line parameters are parsed when the application starts and put into an Options object. After initialization, the contents of the object should not change. To enforce this in the code, use a record type instead of a class type. Besides compile-time checking that the parameters are not modified, there are other advantages to using records regarding checking for equality. We’ll explore these advantages later in the
  • 40. book. In 2.13, the Options record has two properties. The Text property holds the text to convert to ASCII art. Since this is the primary use of the console application, the text doesn’t have a parameter name and is instead specific by it’s position in the command line parameters. Note that the --font parameter can still come before the text because it’s a named parameter. The Font property holds the name of the font to draw the ASCII art in. The font doesn’t have to be specified so this parameter is marked as an Option. The parameter for font can be specified as -f or --font. 2.7.1 C# properties The original idea behind properties came from a desire to control access to fields. A field in a class is some variable that has scope to the object or static scope to the class. If the field is exposed directly, the class doesn’t know when code outside of the class is accessing or modifying the field. Some development practices enforced a discipline of creating getters and setters for fields. These are methods that control access to the field. C# formalizes this into properties. If we remove the shorthand, the Text property from 2.13 would look like the code in 2.14. Listing 2.14. Options Text property without the shorthand public record Options { private string? _text; #1 [Value(0, Required = true)] public string? Text { get { return _text; #2 } init #3 { _text = value; #4 }
  • 41. } } The record has "init" statements for the properties but there are also "set" statements for properties on classes. Properties can be read-only or have different visibility for get and set. There are also other shorthand notations for properties such as expression-bodied members. We’ll explore more of these different permutations of properties throughout the book. Another question that may come to mind if you’re not familiar with C# is the purpose of string?. This is not the property having an identity crisis but a way of signifying to the compiler that this property can be null. This may seem weird if you’re a .NET Framework programmer because the type string itself is a reference type and therefore can be null. If you recall in 2.12 the MSBuild property (no relation to C# property) <Nullable>enable</Nullable> was called out. Nullable in the project settings tells the compiler that we have to be explicit about when something can be null. Nullable reference types help for compile-time checking of potential issues with null values. Technically, since Text is a required parameter, CommandLineParser won’t create the Options object if the text parameter is not in the command line parameters. But the compiler doesn’t know this and will display a warning that the property needs to be marked as nullable. The problem with null references In 2009, Sir Charles Antony Richard Hoare (a.k.a Tony Hoare) offered an apology for introducing the concept of null references (or pointers). He called it the "billion dollar mistake" because of the impact it has on software. C# also struggles with how to handle nulls correctly and succinctly. The C# language is slowly moving towards a safer design regarding nulls but needs to be backwards-compatible. That is why there are so many operators having to do with null as well as nullable types. This book will use the latest preferred techniques, which allows for better static analysis when compiling. Now that we have a record to hold the parsed command line parameters, let’s add the code that will perform the parsing. Modify the Program.cs to match
  • 42. the code in 2.15. Listing 2.15. Program.cs parsing command line options with CommandLineParser using HelloDotnet; using CommandLine; #1 Parser.Default.ParseArguments<Options>(args) #2 .WithParsed<Options>(AsciiArt.Write) #3 .WithNotParsed(_ => #4 WriteLine("Usage: HelloDotnet <text> --font Big")); #5 The ParseArguments method has a modifier before the arguments are passed in. This method uses a generic. To understand how this generic works, let’s look at the method signature of ParseArguments as shown in 2.3. Figure 2.3. ParseArguments method signature T is used to represent the generic type. ParseArguments will return an object of ParserResult<T>. The type you use to hold the parsed command line arguments is not known ahead of time by the CommandLineParser library and that makes it difficult to return the object you want. The generic allows you to specify the type so that ParseArguments can read the type information and give you the object you want. Similarly, the parameter to ParseArguments, IEnumerable<string>, uses a generic to say that whatever enumerable is provided must be an enumerable of strings (IEnumerable is an interface applied to arrays, lists, and other collections).
  • 43. Interfaces and abstract classes Like most object-oriented languages, C# has interfaces and abstract classes. A brief list of important rules for these constructs is as follows: Abstract classes cannot be directly instantiated into objects A class can only inherit from one abstract class but can implement any number of interfaces Methods or properties that are not implemented in an abstract class must be marked with the abstract keyword Interface properties and methods are public The next method call, WithParsed<T> is taking AsciiArt.Write as a parameter. We know from earlier that this is a method, so how does it work? Let’s first look at the method signature, which is shown in 2.4. Figure 2.4. WithParsed method signature We know from 2.3 that ParseArguments will return a ParserResult<T>. The extension method WithParsed can be chained onto that ParserResult object to check if the ParserResult was successful and execute some code, "action", if that’s the case. The Action<T> specifies that the code we’ll execute is a method that takes an object of type T as a parameter. In our case, this is the Options object. We need a method that will take the Options object as a
  • 44. parameter. Luckily, we will soon have one of those. The AsciiArt.Write code has previously taken only a string as a parameter but we’ll soon change this to take the Options object so we can use it to determine what font to write the ASCII art in. What is an extension method? Sometimes you want to add a method to an existing type without modifying or inheriting from that type. Extension methods allow you to do this. Let’s consider a (contrived) example. The class String is part of CoreFX and cannot be inherited (aka "sealed") but I would like to add a method that gives me every other character. I can create my own extension method to accomplish this like in 2.16. Listing 2.16. Extension method to get every other character in a string public static class MyStringExtensions { public static string EveryOtherCharacter(this string s) #1 { char[] newChars = new char[s.Length / 2 + 1]; #2 int sPos, nPos; #3 for (sPos = 0, nPos = 0; sPos < s.Length; sPos += 2, nPos++) { newChars[nPos] = s[sPos]; #4 } return new string(newChars, 0, nPos); #5 } } This extension method can then be used on any string as if it were part of the string type, e.g. "abcdefghijklmn".EveryOtherCharacter(). Likewise, the methods WithParsed and WithNotParsed are not part of the ParserResult class but are extension methods. In the case, that the command line parser is unable to create the Options object, we want to write the usage string to the console output. The WithParsed extension method uses a design pattern called "method-chaining"
  • 45. that allows us to apply another extension method: WithNotParsed. WithParsed is executed first and checks if the ParserResult indicates that the parsing was succesful. If not, WithParsed does nothing and returns the ParserResult object. The next method in the chain, WithNotParsed, will check in the ParserResult object indicates parsing failed and execute an action if that’s the case. Let’s look at the signature for that method, which is shown in 2.5. Figure 2.5. WithNotParsed method signature This is very similar to WithParsed except that the Action takes a parameter of IEnumerable<Error>. There is no method like that available already so we could create one in the AsciiArt class. But the logic for writing the usage string should not be in AsciiArt. A new method cannot be introduced in the top-level code in Program.cs. We could declare a namespace and type with a method for this purpose but C# provides a cleaner way: anonymous methods. 2.17 shows different ways that the Action used for WithNotParsed could be written. Listing 2.17. Four different ways to write the same Action ranging from the verbose method definition to an anonymous method that discards the parameter. void WriteUsageAndIgnoreErrors1(IEnumerable<Error> errors)#1 { WriteLine("Usage: HelloDotnet <text> --font Big");
  • 46. } void WriteUsageAndIgnoreErrors2(IEnumerable<Error> _) #2 { WriteLine("Usage: HelloDotnet <text> --font Big"); } void CallToAction(IEnumerable<Error> errors) { Action<IEnumerable<Error>> action1 = WriteUsageAndIgnoreErrors1; action1(errors); Action<IEnumerable<Error>> action2 = WriteUsageAndIgnoreErrors2; action2(errors); Action<IEnumerable<Error>> action3 = (IEnumerable<Error> _) => #3 { WriteLine("Usage: HelloDotnet <text> --font Big"); } action3(errors); Action<IEnumerable<Error>> action4 = _ => #4 WriteLine("Usage: HelloDotnet <text> --font Big"); action4(errors); } An anonymous method is what the name suggests: a method whose name is unimportant. Anonymous methods are one of my favorite .NET features because naming is hard and coming up with a name for a method I only use once is a waste of time. The compiler is able to tell from the WithNotParsed method signature that the Action should take an IEnumerable<Error> parameter and uses that for the parameter passed to the anonymous method without the code needing to explicitly declare it. Also, if there is only one statement or expression in the method you can use a technique called expression-bodied members. An expression-bodied member is a member that consists of only an expression and therefore doesn’t need brackets or a return statement. We’re almost done with the modifications to the console application. The next step is to update the AsciiArt class to lookup the font. Modify AsciiArt.cs to contain the code from 2.18. Listing 2.18. AsciiArt class updated to lookup the font passed in from the command line options. using System.Reflection; #1
  • 47. namespace HelloDotNet; public static class AsciiArt { public static void Write(Options o) #2 { FiggleFont? font = null; #3 if (!string.IsNullOrWhiteSpace(o.Font)) #4 { font = typeof(FiggleFonts) .GetProperty(o.Font, #5 BindingFlags.Static | BindingFlags.Public) #6 ?.GetValue(null) #7 as FiggleFont; #8 if (font == null) #9 { WriteLine($"Could not find font '{o.Font}'"); #10 } } font ??= FiggleFonts.Standard; #11 if (o?.Text != null) { WriteLine(font.Render(o.Text)); #12 WriteLine($"Brought to you by {typeof(AsciiArt).FullName}"); } } } Reflection .NET has an extensive set of reflection libraries under the System.Reflection namespace. Many interpreted languages have some form of reflection. Reflection allows you to get information about assemblies and types in .NET code at runtme. In 2.18, the FiggleFonts type has a static property for each font. The static property we use by default is FiggleFonts.Standard and is of type FiggleFont. By using reflection, we can attempt to find a property by name and get the FiggleFont object that represents it. Interpolated strings
  • 48. Normal strings in C# are enclosed in double-quotes ("). Interpolated strings allow substituting values into strings. If you’ve used C# in the past, you may be familiar with string.Format() which can substitute values into a string. Interpolated strings are similar to string.Format() but not the same. As in 2.18 the string value of o.Font is insert into the string by enclosing it in curly brackets ({}). Null operators In 2.18, there are two new null operators used. The first one is in GetProperty()?.GetValue(). If the result of GetProperty is null, the null- conditional operator will return null immediately instead of executing the right side of the expression (GetValue). The null-conditional operator is a shorthand, especially considering that without it the alternative is like the code in 2.19. Listing 2.19. Long form of null check on GetProperty PropertyInfo pi = typeof(FiggleFonts).GetProperty( #1 o.Font, BindingFlags.Static | BindingFlags.Public); if (pi != null) { font = pi.GetValue(null) as FiggleFont; } The second null operator, ??, is called the null-coalescing operator. It evaluates the expression on the left side first. If the left-hand expression is null, it will then return the value of the right-hand expression. This works similar to how short-circuiting works with the || boolean operator. In 2.18 this operator is used in the line font ??= FiggleFonts.Standard. Like in other languages, this is a shorthand for font = font ?? FiggleFonts.Standard. If font is null then FiggleFonts.Standard is assigned to font, otherwise nothing changes. Casting objects to types In 2.18, the result of the GetProperty().GetValue() is an object that can be
  • 49. null. The value of the expression needs to be casted to type FiggleFont before it can be assigned to the font variable. However, there is no guarantee that the object return by the expression is of that type so if we use an explicit cast, that may cause an exception at runtime. The as operator in C# is a safe way to cast the object. It will return null if the type of object being casted does not match the target type. All the code for the console application is finished. Experiment with missing or invalid parameters. Some other fonts to try are ThreeD, Alligator, Avatar, Cosmic, DotMatrix, and Ghost. Have a look at the properties on FiggleFonts to find more. Exercise: Multiple words in ASCII art The first unnamed parameter passed to HelloDotnet is the text that will be written in ASCII art. A string containing spaces can be used if enclosed in quotes. Modify the command line parameter parsing so that if multiple unnamed parameters are passed, each string will be written to the console separately. It will help to look at CommandLineParser’s wiki: https://github.com/commandlineparser/commandline/wiki Exercise: List all fonts in help text The help text could be made more helpful by telling the user what fonts are available. There are many ways to do this. One way is to use reflection to enumerate the public static properties of FiggleFonts and expose that as a static method in AsciiArt. Another way is to grab the list from the Figgle source code and store as an array or an enum (not covered yet but an option if you know C#). 2.8 Summary Use dotnet new to create .NET applications from the command line NuGet has an extensive collection of packages available with helpful links and instructions Types are organized into namespaces that can be included either for a whole project or an individual file
  • 50. C# has a lot of ways to handle null references Anonymous methods and expression-bodied members are common techniques to make C# code more succinct
  • 51. 3 Creating web services and applications with ASP.NET Core This chapter covers Creating web services Creating web applications LINQ - Language Integrated Query 3.1 Web services The console application from the prior section receives command line parameters and writes the specified string in ASCII art to the console output. The command line parsing library helps with parsing and is fairly easy to execute from a terminal. It is just as easy to create a web service that performs the same function. In this section we’ll port the ASCII art program into a web service using ASP.NET Core. In the previous section, we used the dotnet new console command to create a console application from a template. There are many other templates available. You can see a list by running dotnet new --list. We will use the empty Web template for the ASCII art service. Use the command shown in 3.1 to create a new folder with the new project. Listing 3.1. Command to create Web API from template dotnet new web --name AsciiArtSvc This template will create files similar to the ones shown in 3.1. Figure 3.1. Files and folders created by the empty web template (image created with a custom CodePen and Font Awesome icons)
  • 52. There is a Web API template that will look much more like the ASP.NET Core projects you see in the real world. We use the empty template in this example because with the minimal API design of ASP.NET Core, creating a web service is as easy as creating a console application. From the project’s directory, execute the dotnet run command and you should see output similar to 3.2. Listing 3.2. Output from running the empty web service > dotnet run Building... info: Microsoft.Hosting.Lifetime[14] Now listening on: https://localhost:7041 #1 info: Microsoft.Hosting.Lifetime[14] Now listening on: http://localhost:5292 #2 info: Microsoft.Hosting.Lifetime[0] Application started. Press Ctrl+C to shut down. Development certificate .NET includes a certificate for local development to make it easier to test
  • 53. https endpoints. If you installed an IDE like Visual Studio or JetBrains Rider, then the certificate was probably setup for you. Regardless, you can check if the certificate is trusted with the command dotnet dev-certs https -- check. To trust the certificate on your development machine (or on a build agent in your CI/CD pipeline), use the command dotnet dev-certs https --trust. Web service ports for local development The port numbers used for web services generated from the .NET template are chosen randomly. You may need to change them if they conflict with a port that another application is using. To do this, find the Properties/launchSettings.json file and look for a section like the one shown in 3.3. Listing 3.3. launchSettings for AsciiArtSvc project "profiles": { "AsciiArtSvc": { "commandName": "Project", #1 "dotnetRunMessages": true, "launchBrowser": true, #2 "applicationUrl": "https://localhost:7041;http://localhost:5292", #3 "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } } The default profile generated with the template will launch the default browser and navigate to the configured URL. The browser sends a GET request that the service responds to by returning "Hello World!". The browser launch happens with IDEs that use the launch profiles. The dotnet run command will not open a browser. The first step in getting the web service to convert strings into ASCII art is to add the Figgle package just as we did with the console application (shown in
  • 54. 3.4). Listing 3.4. Add Figgle package to AsciiArtSvc <Project Sdk="Microsoft.NET.Sdk.Web"> #1 <PropertyGroup> <TargetFramework>net7.0</TargetFramework> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> </PropertyGroup> <ItemGroup> #2 <PackageReference Include="Figgle" Version="0.4.0" /> </ItemGroup> </Project> Next, open the Program.cs to see how the current "Hello World!" response works. The content should be similar to 3.5. Listing 3.5. AsciiArtSvc Program.cs var builder = WebApplication.CreateBuilder(args); #1 var app = builder.Build(); #2 app.MapGet("/", () => "Hello World!"); #3 app.Run(); Earlier in this book we noted that C# is a strongly-typed language. However, in 3.5 we use the keyword "var" to declare variables instead of the .NET types. In C# var can be used to declare a variable only if the compiler is able to determine what the variable type is. For instance, we can make a statement such as var i = 0; because the compiler can infer that since 0 is an integer then i is an integer. But we couldn’t write something like var myString; because there is nothing assigned to myString that the compiler can use to infer the type. The var keyword is a style choice. It has the benefit of saving characters both in that you don’t need to write the type name but also that you don’t need to have a "using" for that type’s namespace. The drawback is that developers reading the code don’t know the type without some investigation.
  • 55. Random documents with unrelated content Scribd suggests to you:
  • 56. If presently we learn that by order of the All-Highest every buttonhole in Brussels is sewn up, it will hardly be matter for surprise. It would be a charactertistic step. Those ribbon favours have proved prickly thorns to the Germans. They seem to act upon the Prussian mind as a red rag upon the bull, and like the rag, when in the deft hands of a skilled toriro, they frequently lure the victim to his own undoing. It happened once, soon after the display of national colours had been prohibited, that a Prussian officer, entering a Brussels tramcar, found himself seated opposite a Belgian lady upon whose coat the forbidden red, black, and yellow ribbons were flauntingly displayed. It is the custom of many Belgian ladies, on finding themselves in a public vehicle with a German officer, to quit their seats and stand on the conductor's platform outside. Ruffled, perhaps, by the omission of this somewhat pointed tribute to his presence, the intruder leaned forward and requested the removal of the offending colours. The suggestion was greeted by a stony stare, the demand which followed it by an expressive and provocative shrug of the shoulders. "If you will not take off those colours, madam, I shall remove them myself." This menace eliciting no response, the Prussian officer stretched forth a Prussian fist and made a Prussian grab. The favour came away in his clutch, but that was not the end of it. Within his fair antagonist's dress ample lengths of ribbon were concealed, and the more the discomfited officer pulled the more streamers of red, black, and yellow reeled forth. It was a case literally of getting more than he bargained for, and the charming murmur of thanks which he received when, in sheer desperation, he dropped the tangle of ribbon on the floor and made hastily for the door must have gratified that Prussian exceedingly. IV—THE JOKERS OF BRUSSELS Practical joking has become popular in Brussels since the German occupation. "Everybody's doing it"—amongst the Bruxellois, that is.
  • 57. A prohibition was lately placed upon the use of motor-cars by the civil population, and orders were issued for the enforcement of dire penalties in cases of disobedience. One afternoon a couple of German officers were seated in a café discussing mugs of beer with that portentous solemnity which the Teutonic mind finds proper to such an occasion, when a loud "Honk, honk!" the unmistakable blast of a motor-horn, was heard in the street outside. Forth dashed the officers, indignant at this flagrant transgression of orders, but when they reached the pavement no car was there. None was even in sight upon the whole length of the boulevard, though the sound of the horn had been close at hand. Crestfallen, the representatives of law and order—Prussian style—returned to their beer-mugs, but were hardly seated when again the loud "Honk, honk!" fell upon their ears, and again they dashed into the street, with the same result. Convinced that some impudent guttersnipe must be playing a trick, they questioned the nearest sentry. But the latter had seen neither car nor urchin; he had not even heard the mysterious sound, he averred, and the baffled officers began almost to doubt their ears. But the smile on the face of the Belgian proprietor of the café was suspicious. Fresh mugs of beer were requisitioned, but the very first "Prosit" was interrupted by the malevolent "Honk, honk!" With froth-flecked lips that gave them an aspect admirably suited to their mood, the enraged officers set down the mugs with a bang and once more strode forth in quest of the miscreant. Once more a perfectly empty street met their gaze. But even as they scowled abroad, a mocking "Honk, honk!" sounded, this time just above their heads. The listeners started and looked up, to see a green parrot in a cage upon the window-sill above regarding them imperturably with a beady inscrutable eye. So flagrant a case of lèse majesté could not be overlooked, and the green parrot was executed. But even in his murders the Boche lacks a sense of proportion, which is, of course, merely another way of saying that he has no sense of humor. To the martyrdom of the parrot must be added that of two luckless pigeons whose sole crime against the Deutches Reich
  • 58. was that of being born after a certain date. It was decreed soon after the occupation of Brussels that all owners of pigeons must notify the authorities the number of birds which they possessed. Amongst those complying with the order was a certain shopkeeper who kept a pair of pigeons as pets. They were not of the carrier variety, and he was allowed to retain them. But pigeons are notoriously domesticated creatures, and presently an interesting event occurred in the establishment of this happy couple. A couple of squabs were hatched out. These duly assumed down, which in turn became feathers, and presently there were four pigeons where formerly had been but two. At this stage a German official, armed with a registration list, paid a visit of inspection. He noted the well- preened quartette, and referred to his papers. Then he frowned ominously. "On such and such a date you registered two pigeons." "That is so," was the answer. "Since then——" "But you have four there." "Quite true. You are——" "But you are only entitled to have two." "A thousand pardons, mein Herr. But one cannot interfere with Nature. My two pigeons, you see——" "If you registered two only, you cannot be allowed to have four. It is self-evident." It is needless to repeat the colloquy at length. Though that explanations were cut short, refused a hearing. No German official was ever known to "use his discretion"; that is a prerogative of the muddle-headed British. The list had two pigeons; here were four. Obviously there was only one course to be taken. The abundant pigeons shared the fate of the indiscreet parrot. Next day there appeared suspended in the mourning owner's shop- window two feathered corpses adorned with this pathetic placard:—
  • 59. MORTS POUR LA PATRIE! V—THE SECRET NEWSPAPER—LIBRE BELGIQUE But the most brilliant and daring feat achieved in Brussels is unquestionably the publication of Libre Belgique, a mysterious weekly journal which makes its appearance with unfailing regularity, though how, where, and by whom produced the Germans have never been able to discover. This is the very apotheosis of Boche- baiting, for Libre Belgique is a fiery sheet. It does not mince words, but flagellates the Germans with the most scornful virulence, holding them up to ridicule and contempt. Every week it pours the vials of bitter wrath and hatred upon the Boche's devoted head, and the Boche can do nothing but sit meekly under this scorching cataract. For though a reward, which has already risen from a thousand pounds to three times that figure, is offered for a denunciation of those responsible for this "scurrilous rag," the secret of Libre Belgique remains inviolate. Exhaustive searches have been conducted, many arrests have been made upon suspicion, but except for two minor actors in the great comedy, whose function was merely the distribution of copies, no one has been caught. Yet Libre Belgique has already celebrated one anniversary of its birth, and is well into its second year of existence. And every week, without fail, General von Bissing, the German governor of Brussels, receives a "complimentary" copy, which he doubtless peruses with absorbed interest. It is characteristic of Brussels wit that in conformity with law the paper announces in each issue the address of its office and printing works. These, it appears, are in "a cellar on wheels," and in view of the peripatetic habits thus suggested, correspondents are desired to address their communications to the Kommandatur, i.e., the headquarters of the German authorities! But Libre Belgique has another function to discharge beyond that of a courageous jest, well calculated to keep the Bruxellois in good heart. Drastic in its satire upon the enemy, it is equally unsparing in
  • 60. its record of German crimes and its dissection of the often grotesque claims made by the German official communiqués. Von Bissing and his staff may affect to make light of this gadfly among journals, but the rewards offered for its betrayal and the energetic measures taken to bring about its suppression tell another story. Libre Belgique, indeed, aptly illustrates the parable at which Burgomaster Max so subtly hinted when he laid his pen beside his interlocutor's pistol. The pen is far mightier—in the long run—than the sword, and the Germans, though they will not perhaps admit it even to themselves, have an uncomfortable inkling of that fact. That Libre Belgique, in spite of all proffered bribes, should never yet have been betrayed is a wonderful testimony to the high patriotic spirit of the Bruxellois. For though the operations of the paper's staff are doubtless closely guarded, the number of persons who are in the secret must inevitably be considerable, and leakage is difficult to prevent. But the Belgian spirit is a thing with which we are all familiar now, and when to that is added Brussels wit the whole phenomenon is explained. One fancies, indeed, that when the Belgian capital is at length evacuated by the Germans the populace will be half sorry to see them go. The Boche is not exactly a lovable fellow, but to people of a satirical turn of mind, naïveté, which he possesses in unparalleled degree, is always engaging. As a butt the Boche is unique, and in that capacity, if in no other, he has positively endeared himself to the witty citizens of Brussels.
  • 61. HOW SERGEANT O'LEARY WON HIS VICTORIA CROSS Story of the First Battalion of the Irish Guards He shot eight Germans in eight seconds, captured a machine gun, took two barricades single handed, and saved his whole company from being exterminated. The story is told in the New York American as dispatched from London. I—WHO IS THE BRAVEST MAN IN THE WAR? Who is the bravest man that the war has produced? It would probably be impossible to answer this question with any approach to accuracy and impartiality. But it is interesting to compare some of the incidents reported and see how modern courage compares with that of past history. It is generally admitted that all the nations engaged have fought with remarkable bravery and steadiness, so that a man must have done some extraordinarily daring action to make himself notable. Thousands and thousands of acts of bravery have been performed by many among the millions of soldiers engaged. Doubtless some of the most heroic have died without having their acts mentioned. Of the innumerable feats of bravery reported the one that has impressed the British public most is that of Sergeant Michael O'Leary, of the Irish Guards, who is a native of Ireland, as his name suggests. He has received the coveted Victoria Cross, been promoted Sergeant and a long description of his deeds has been given him on the official records—a very great honor. He has also been offered a
  • 62. commission, but will not take it at present because he does not want to leave the Irish Guards, and there is no place for him there as an officer. The cold official record says that O'Leary won his Victoria Cross "for conspicuous bravery at Cuinchy. When forming one of the storming party which advanced against the enemy's barricades he rushed to the front and himself killed five Germans who were behind the first barricade, after which he attacked a second barricade, about sixty yards further on, which he captured, after killing three of the enemy and making prisoners of two more. Lance Corporal O'Leary thus practically captured the enemy's position by himself and prevented the rest of the attacking party from being fired on." Further details of O'Leary's wonderful exploit were given by Company Quartermaster Sergeant J. G. Lowry, of the Irish Guards, who was engaged in the fight. "Our First Battalion," he said, "had been holding trenches near the La Bassee brickfield, and our losses were heavy. The Germans had excellent cover, both in trenches and behind stacks of bricks. "We were all delighted when the order came that the brickfield had to be taken by assault next day. "Lance Corporal O'Leary never looked to see if his mates were coming, and he must have done pretty near even time over that patch of ground. When he got near the end of one of the German trenches he dropped, and so did many others a long way behind him. The enemy had discovered what was up. "A machine-gun was O'Leary's mark. Before the Germans could manage to slew it around and meet the charging men O'Leary picked off the whole of the five of the machine crew, and leaving some of his mates to come up and capture the gun, he dashed forward to the second barricade, which the Germans were quitting in a hurry and shot three more. "O'Leary came back from his killing as cool as if he had been for a walk in the park and accompanied by two prisoners he had taken.
  • 63. He probably saved the lives of a whole company. "Had that machine gun got slewed round, No. 1 Company might have been nearly wiped out." II—STORY OF THE YOUNG IRISH GUARD What impresses people in O'Leary's deed is not only his bravery but the triumphant success with which he carried out the whole act. Other soldiers may have displayed more self-sacrifice and endurance, but not one of them appears to have done more for his side by one individual act of bravery than O'Leary. It is the dashing quality of his deed that wins admiration and this quality, it is to be noted, is peculiarly Irish. He is credited by his admirers with having shot eight men in eight seconds. His quickness must have been phenomenal, and here again he showed a peculiarly Irish trait. How one man could have shot eight soldiers, when all eight of them were armed and many of their comrades were only a few yards away, must appear a mystery to many. The Germans were perhaps retiring hastily from their positions, but they had magazine rifles in their hands and fired many shots at the British. Why did they not get O'Leary, who was running out alone ahead of his companions? He must have been amazingly lucky, as well as amazingly quick. Then it is almost equally astonishing that he could have shot eight men in a few moments while running. The best explanation of this is that the British soldier has a rifle carrying more bullets than that of any other army. The Lee Enfield rifle now used in the British army carries ten bullets in the magazine and one in the barrel. O'Leary, of course, fired all his eleven bullets, and he is credited with making eight of them kill a man apiece. That is an amazing shooting record, said to be unequalled for a soldier.
  • 64. Sergeant O'Leary is not a particularly fierce looking soldier, as might be expected, but a tall, slender, fair-haired young fellow. He is only twenty-five years old. "A quiet, easy-going young fellow O'Leary is," said his friend, Sergeant Daly, of the Second Battalion of the Irish Guards. "But he is remarkably quick on his feet." O'Leary was born in the little village of Inchigeelach, in the County Cork. His father and mother still live there. He has an older brother and four sisters, who are now in America. He served for several years in the Canadian Northwest Mounted Police, but went back and joined the British Army in order to be nearer home. After the fight in which he won his decoration he wrote home: "Dear Parents: I guess you will be glad to hear that I was promoted full sergeant on the field on account of distinguished conduct on February 1, when we charged the Huns and routed them in disorder. "You bet the Irish Guards are getting back now." Mrs. O'Leary, the old mother of the hero, has been interviewed at her home in Ireland. As might be expected her words were very simple. "It's proud I am of Mike," said Mrs. O'Leary, "but I wish he was home instead of being in that cruel war. "When that telegram came for me, I thought sure Mike was dead, but when I opened it I found that he had been promoted. Sure I was better pleased to know that he was alive than promoted. "Mike is a good boy. He never gave me a moment's uneasiness since he was in the cradle, except when he went away on his foreign adventures. I suppose he had to leave me. There's little enough chance for a boy here, with only the pigs to look after and his father and me."
  • 65. We have been inclined to think that the days were over when a mighty warrior could rush in among the foe and slay many with his own hands but O'Leary and many others in this war have proved that that is not the case. III—TALE OF A GORDON HIGHLANDER Many of the famous deeds of antiquity have been curiously paralleled in the war. For instance, one of the ancient feats that everybody mentions occasionally was how the brave Horatius held the bridge across the Tiber with two companions against the whole Etruscan army. Now we find again and again that a bridge has been the scene of deeds of conspicuous heroism in this war. The British were defending a river bank and bridge against a fierce German attack. The crew of a British Maxim gun had all been killed. Then Angus MacLeod, of the Gordon Highlanders, rose from cover, seized the Maxim gun and all alone carried it, under fire, to the far side of the bridge, where he played it on the advancing Germans. He is credited with having killed sixty Germans. Finally he fell dead and thirty bullets were counted in his body. The delay enabled the British to rally and repel their opponents. An extraordinary act of heroism was reported of an unnamed French soldier during the disastrous retreat of the French from the Belgian frontier and the Meuse River early in the war. This man had been taken prisoner with some companions. The Germans, according to the report, drove their prisoners before them when attempting to cross a strongly defended bridge, to make the French think it was a party of their own men returning. As the French prisoners stepped on the bridge, one of them, a big and strong-voiced man, yelled: "Fire, nom de Dieu, or you will be wiped out." His own act made his death certain. He fell riddled with bullets from both sides.
  • 66. Lieutenant Leach and Sergeant Hogan of the British Army each received the Victoria Cross for an extraordinarily daring and ingenious action. The two men killed two Germans, took sixteen unwounded prisoners and twenty wounded men. Leach and Hogan with ten men crawled unobserved to a section of trench that had been captured by the Germans earlier in the day. Leach and Hogan dropped into the trench unnoticed and the ten men lay in wait to shoot any Germans who showed themselves. A trench is built in zigzags so that there is only a straight section of about twenty yards along which an enemy could shoot. The Germans in the first section were taken by surprise and all killed or wounded. Then the two men hurried on to the next turning. As they walked Hogan put his cap on his rifle and held it above the trench to show their men outside where they were. Lieutenant Leach poked his automatic revolver round the corner of the trench and began shooting at the Germans from cover. The German soldiers with their big clumsy rifles could not hit the deadly hand that was the only object to aim at. While the Lieutenant was shooting, Hogan watched over the top of the trench to shoot any German who tried to get out or attack them in the rear. Thus all the men in each section were killed, wounded or captured. How do these and the many other brave men who have been reported in the present war compare with the heroes of antiquity? Achilles is the foremost of Greek warriors. He personified the Greek ideal of bravery, manly beauty and fiery enthusiasm. The "Iliad" contains pages and pages about his deeds, his speeches, how he sulked in his tent, and his quarrel with Agamemnon, but it does not seem after all that he did a vast amount of harm to the enemy. Of course, he killed Hector, but that was not amazing, and he acted with considerable brutality about it. Achilles was undoubtedly a fine orator, but in achievement he appeared to compare badly with modest Sergeant O'Leary.
  • 68. STORY OF A RUSSIAN IN AN AUSTRIAN PRISON An Officer's Remarkable Experience This very unusual narrative, with its light on Austrian prison conditions, appeared in the Russkoe Slovo, Moscow, June 30, 1916. It was written by a petty officer of the Russian Army at the request of the paper's Paris correspondent. The correspondent tells of a party of thirty Russians who had recently arrived in Paris from Italy, all war prisoners from Austria, who had managed at different times to slip through the lines on the Italian front. It was translated for Current History. I—"I WAS PRISONER OF THE MAGYARS" I was taken prisoner by the Magyars in the Carpathians. We were driven to the station of Kashitzi, where we found more Russians, I don't know how many, and were placed in dirty cars, from which cattle had just been removed. The stench was terrible, the crowd unthinkable. The doors were locked all the time.... We travelled two days; on the third we arrived in a camp called Lintz. What did I see in this camp? Filthy barracks, naked bunks on which our soldiers were scattered, pale, exhausted, hungry, nearly all barefoot or in wooden clogs. Many were suffering from inflamed feet and exhaustion. I don't know how they call it in medicine, but to my mind it was the fever of starvation. One gets yellow, trembles incessantly, longs for food.... The prisoners were fed very poorly, mainly with turnips, beans, and peas.
  • 69. Once a soldier decided to complain to Francis Joseph or Wilhelm. He went up to an electric pole, formed his fingers so that it looked as if he were speaking into a telephone horn, and shouted, "Hello, Germans, give us some more bread!" He called and knocked with his fists for some time, but, of course, received no reply. Many soldiers made fun of him at first, but others began to look for a way to complain against such treatment of war prisoners. Meanwhile the bread became poorer and poorer in quality and less in quantity. The meals consisted of beans, and in addition there were bugs in the beans. We got meat three times a week, the other days we got herring. On the 24th of May, 1915, a company was recruited among us to be sent away to do some "agricultural" work. The soldiers would not believe it, claiming that peace was near. I was in the first contingent. Our train was passing between mountains covered with evergreen. Every now and then it would shoot through tunnels. This surprised me greatly. I understood that we were not going in the direction of Russia. And so it was. We finally arrived in a place, where the thousand of us were quartered in one building. We at once began to be treated differently, much more insolently and severely. On the 27th we were driven to the fields to work. We wondered what the agricultural labour we were to do could be. We were supplied with shovels and pick-axes, led to a wood on a hill some 1,600 metres high, mustered into rows, and ordered to dig a ditch—that is what the Germans called it—but we called it otherwise. It became clear that we were to dig trenches. The first day passed in idleness and grumbling. All unanimously refused to work, even if we had to pay with our lives for it. We waited for the following morning. The guards came to take us out to work, but we said that we would not dig trenches. Then the Colonel came and asked in Russian: "Why don't you want to work?" We all answered: "This work is against the law. You are violating the European laws and breaking all agreements by forcing us to construct defensive lines for you." The Colonel said: "Look out, don't
  • 70. resist, or we will shoot every one of you. We don't care now for the laws to which you point us. All Europe is at war now—this is no time for laws. If you don't go to work, I will have you shot." We all exclaimed: "We won't. Shoot us, but we will not do the work." II—STANDING BEFORE THE EXECUTIONER All of the 28th we were in our yard. No food was given us. Thus we were held for three days without food. On the fourth day a company of cadets arrived. Leading them was the executioner, with stripes on his sleeves. They loaded their rifles, holding them ready. Then the Colonel asked: "Who will go to work?" The crowd answered "No!" The Colonel said: "I am sorry for you, boys, you don't understand that you are resisting in vain." Suddenly the crowd was split into two. Those who agreed to work were given dinner and put to work. The other half, in which I was included, was led away to another yard. From among us ten were picked out and taken away—we knew not where. We were ordered to lie on the ground with our faces downward, and not to turn our heads. On June 2 there remained only fifty men who still refused to work, suffering hunger for the sixth day. The ten soldiers who were daily taken away from us were subjected to, besides hunger, suspense in the air from rings, with their hands tied to their backs. In about thirty minutes one would lose consciousness, and then he would be taken down to the ground. After he recovered his senses he would be asked if he agreed to work. What could one answer? To say "I refuse" meant another ordeal. He would begin to cry and agree to work. The following day our heroes were led out into the open, ten were selected from our midst, arranged in a line facing the rest of us, and told that they would be shot immediately. Of the remainder half were to be shot in the evening, the other half the following morning. Their graves had been dug by the ten heroes themselves. I have not the slightest hesitancy in calling them so.
  • 71. Then a space was cleared, and Ivan Tistchenko, Feodor Lupin, Ivan Katayev, and Philip Kulikov were ordered forward. The first was Ivan Tistchenko. An officer and four cadets approached him. The officer asked him if he would agree to work. He answered "No," and crossed himself. His eyes were bound with a white 'kerchief, and these pitiless and unjust cadets fired at the order of the officer. Two bullets pierced his head and two his breast, and the brave fellow fell to the wet ground noiselessly and peacefully. In the same manner the second, third, and fourth were treated. When the fifth was led forward he also refused to work, and they already had his eyes bound. But some one in the crowd exclaimed: "Halt—don't fire!" And the comrades asked for his life, all agreeing to go to work. And I never learned the identity of the chap who saved that fellow's life and many other lives. We remained in that camp for two and a half months. Then we were removed closer to the front, to a locality inhabited by Italians. Our soldiers there would inquire from the Italian labourers, to whom the guards paid no attention, where the boundary lay. We learned the direction and the distance to the boundary, which was about thirty miles. It was even nearer to the Italian front. And so on Sept. 29 a comrade and I decided to escape. (Some particulars of the escape have been deleted by the Russian censor.) Toward dawn we emerged from the thick of the pine trees and bushes, and descended to the base of the mountain. At our feet was a stream, about fifty feet wide, rapid, and full of rocks. Here we made good use of our training in gymnastics. My comrade, a tall fellow, was light on his feet. He jumped like a squirrel from rock to rock. To me it seemed that I would slip and be swept away by the current. My comrade was already on the opposite shore when I, making my last jump, failed to gain the beach. Fortunately he was quick to stretch out to me his long stick, and drew me out of the water as wet as a lobster.
  • 72. We walked along the stream all day without encountering anybody. At the end of the day we came in sight of a tiny village, but there were no people nor soldiers to be seen. Only near one house smoke was rising. We decided to approach stealthily and investigate. We saw an old woman at the fire, bending over a kettle of sweet corn. We surmised that the inhabitants of the village must have deserted it because of its proximity to the front, while the old woman refused to abandon her home. We approached her and confessed that we were Russian soldiers. She thought long. What "Russian" meant she did not know, but she understood the meaning of the word "soldiers." She presented us with some of her sweet corn and pointed out the way to the Italian front. III—"WE ESCAPED TO ITALIAN FRONTIER" It was six in the evening when we came upon an advanced Italian post. The sentinel stopped us with a "Halt!" He was pointing his rifle at us, showing that he would shoot if we advanced. He called for his superior. We were searched and taken into their quarters. An officer soon came in. Through an interpreter he asked us for our names, regiments, and army branches. He gave each of us a package of cigarettes. Only then I understood that we were received as guests. When the officer gave us the cigarettes, saying "Bravo, Russi!" the soldiers began showering us with cigarettes, chocolate, and confetti. One soldier guessed better than the rest; he brought us a dish of soup, meat, and a bottle of wine. After this there was a regular wedding feast. Each of the soldiers brought something to eat, cheese, butter, sardines. We, knowing our condition, abstained from eating too much. Thinking that on the following day we would have to suffer hunger again, we put all the presents into a bag presented us by one of the Italians. Thus we accumulated about fifteen pounds of bread, cheese, butter, chocolate, lard, and boiled beef. Then the Italians noticed that our clothes were wet, and began presenting us with underwear and clothing, so that we soon changed our
  • 73. appearance. We were anxious to converse with them. The interpreter, who spoke Russian imperfectly, had a great deal of work. Just the same, I will never in my life forget his first words in Russian, as he asked us, by order of the officer: "Who are you—brothers?" In tears we answered him that we were Russian officers escaped from captivity; he asked it so kindly, and we were infinitely gladdened by his sweet words. The following day we were taken to the corps headquarters. Officers would come in, shake hands—some even kissed us, which embarrassed us. Unwittingly tears would come to our eyes when we recalled our life in the prison camp and this sudden change for the better. The General also visited us. He pressed our hands, gave each of us a package of cigarettes, and presented us with 10 lire in gold. We wanted to decline the money, but the interpreter said, "Take," and we did. We lived for about a month in Italy. What a noble people!—soldiers, civilians, and officers. It is impossible to describe! At every station (on the way to France) the public would surround us, all anxious to do us some favours, all showing their deep affection for the Russians. Once a Sister of Mercy was distributing coffee to our party as the train began to move. She ran along till the train gained full speed, desiring not to leave some of us without coffee. Our soldiers would wonder at the affection of the entire Italian people for the Russians, and would shout incessantly: "Viva Italia! Viva Italia!"
  • 74. TWO WEEKS ON A SUBMARINE Told by Carl List This article, by a German-American sailor on a Norwegian ship bound for Queenstown with a cargo of wheat, was communicated to L'Illustrazione Italiana, from which it is here translated for Current History. I—"I WAS ON A NORWEGIAN SHIP" The Norwegian ship on which I was embarked was nearing the Irish Channel. The afternoon was misty, the sea rough. We were warned by an English steamer of the presence of German submarines in the vicinity. There was a certain depression among those on board. I asked the Captain if there were anything to do. "No," he answered. Boom! a cannon shot was heard at the very moment. General confusion. All the men ran up on deck and looked about, terrified. Boom! another cannon shot. Then one of the German sailors, pointing to a spot on the horizon, said: "A German submarine." It was true. The black spot grew rapidly larger, and then one could make out some human figures near the small cannon on the deck. It was the famous U-39. We hoisted our flag and awaited events. The Captain sent the mate with our ship's papers over to the submarine, which was now near. Soon those who were not German received orders to take to the boats. The Germans were taken on board the U-39, I among them. When this was done our ship was sunk. So there I was on board a submarine. The impression of it was strange enough. The first evening, quite exhausted, I threw myself down in a corner. I heard a few short orders, then the sound of the machinery.... After that everything was in absolute silence. Some
  • 75. said we were navigating at such a depth that big ships could pass overhead of us.... I fell asleep. Next day on waking I tried to get my bearings. We Germans were treated as friends. We were permitted to go about everywhere. The boat had the shape of a gigantic cigar, about 200 feet long, divided into numerous compartments. They were full of shining instruments. Now there was a buzzing sound, like the inside of a bee-hive, now absolute silence reigned. Every nerve was tense with the expectation of the orders on which our lives depended. Toward the prow was the room from which the torpedo was launched, a room full of tubes and valves. The officers' lodgings are very restricted, since the space on board a submarine proscribes any comfort. The commander was Lieut. Capt. Foerstner, a tall young man, thin and pale—which is not surprising, since he never had a moment's repose; neither he nor the men of the crew ever got their clothes off during the twelve days I was on board. The periscope, the eye of the submarine, made known to us everything that took place on the surface of the water, and it did so with such clearness that it was almost like looking through a telescope. There was always a man on watch there. II—"I WAS ABOARD THE U-39" Suddenly a ship comes in sight. Its smoke is like a black line drawn on the horizon. A bell rings. It is a signal for each man to be at his post. The U-39 slowly rises to the surface. A last look is given at the mirror of the periscope; no English coast guard is in sight. So everything is ready for action. We hear the command, "Empty the water cistern." Freed from her ballast, the submarine rises to the surface. "Both engines ahead at full speed!" The boat cleaves her way through the water that cascades her sides with foam. In a short time the ship is reached. The submarine hoists her flag and fires a cannon shot. No flag betrays the nationality of the captured ship, but we can read the name, Gadsby, on her side. She is English. We
  • 76. signal that her whole crew is to take to the lifeboats, and quickly! At any moment we may be surprised. Through the megaphone we indicate to the men the nearest way to land; then a cannon shot, then a second one. The captured ship, after pitching for a while, sinks. The time necessary for the sinking of a ship differs considerably in different cases. Some disappear in five minutes, others float for several hours. The finest spectacle I witnessed was the sinking of the Fiery Cross. The crew received orders to get off in the boats. Some of our men rowed up close to the abandoned ship and attached hand grenades to her sides. They were fired and the three- master was blown up with all her sails spread and set. The hull and the rigging went down to the depths, but the sails spread out on the surface of the water like so many little fields of polar ice. Eleven ships were destroyed during my stay on board. Quite a number of others were captured, besides these, but they were let go again. This trip, which I shall never forget, lasted twelve days. It was dangerous, but it was exciting and so fine that I would not have missed it for anything in the world.
  • 77. A GERMAN BATTALION THAT PERISHED IN THE SNOW Told by a Russian Officer This is a tragic story of a night fight in snow-buried barbed wire entanglements where a whole German battalion perished. It comes from Petrograd to Montgomery Schuyler in the form of a letter from a Russian officer. I—TRAGIC STORY OF A NIGHT FIGHT "We were creeping across the snow, when we hear a frightened 'Wer kommt da?' "'Hold on, Germans! Where the devil do they come from?' ask our men in surprise. 'Are they numerous?' "'Wer ist da?' we hear again. "Our only reply is to fire by the squad, and then again. The Germans are a little surprised, but pull themselves together and return the fire. It is dark and neither side can see the other. In groping about, we finally meet, and it is give and take with the bayonet. We strike in silence, but bullets are falling about us like rain. Nobody knows who is firing and every one is crying in his own language, 'Don't fire! Stop!' From the side where the firing comes from, beyond and to the right, they are yelling at us, both in German and Russian, 'What's the matter? Where are you?' "Our men cry to the Germans, 'Surrender!' "They answer: 'Throw down your arms. We have surrounded you and you are all prisoners.'
  • 78. "Wild with rage, we throw ourselves forward with the bayonet, pushing the enemy back along the trenches. In their holes the Germans cry, peering into the impenetrable darkness, 'Help! Don't fire! Bayonet them!' Hundreds of shouts answer them, like a wave rolling in on us from every hand. "'Oh, little brothers, their force is numberless. We are surrounded on three sides. Would it not be better to surrender?' cries some one with a sob. "'Crack him over the head! Pull out his tongue! Drive him to the Germans with the bayonet!' are the growling comments this evokes. "A command rings out, vibrating like a cord: 'Rear ranks, wheel, fire, fire!' "The crowd before us yells, moves, and seems to stop. But behind them new ranks groan and approach. Anew the command is given, 'Fire, fire!' "Cries and groans answer the fusillade and a hand-to-hand struggle along the trenches ensues. "German shouts are heard: 'Help! Here, this way! Fall on their backs!' "But it is we who fall on their backs. We pry them out and clear the trenches. "In front of us all is quiet. On the right we hear the Germans struggling, growling, repeating the commands of the officers: 'Vorwärts! Vorwärts!' But nobody fires and nobody attacks our trenches. We fire in the general direction of the German voices, infrequent shots far apart answer us. The commands of 'Vorwärts' have stopped. They are at the foot of the trenches, but they do not storm them. 'After them with the bayonet,' our men cry, 'Finish them as we finished the others.' "'Halt, boys,' calls the sharp, vibrating voice of our commander. 'This may be only another German trick. They don't come on; we are firing and they do not answer. Shoot further and lower. Fire!'"
  • 79. II—"SO PERISHED A WHOLE BATTALION" "New cries and groans come from the Germans, followed by some isolated shots, which fly high above us. After five or six rounds silence settles upon the trenches and continues unbroken. 'What can this mean?' wonder our men. 'Have we exterminated them all?' "'Excellency, permit me to go and feel around,' offers S., chief scout, already decorated with the Cross of St. George. "'Wait, I am going to look into it myself.' "The officer lights a little electric lamp, and prudently sticks his arm above the rampart. The light does not draw a single shot. We peer cautiously over and see, almost within reach of our hands, the Germans lying in ranks, piled on top of one another. "'Excellency,' the soldiers marvel, 'they are all dead. They don't move, or are they pretending?' "The officer raises himself and directs the rays from his lamp on the heaps. We see that they are buried in the snow up to the waist, or to the neck, but none of them moves. The officer throws the light right and left, and shows us hundreds of Germans extended, their fallen rifles sticking up in the snow like planted things. "'I don't understand,' he mutters. "'Excellency, I am going to see,' says the chief scout. "'Go on,' the officer consents, 'and you, boys, have your rifles ready and fire at anything suspicious without waiting for orders from me.' "S. gets out of the trench and immediately disappears, swallowed by the soft snow up to the neck. He tries to get one leg out, but without success. He tries to lean on one hand, pushes it down into the snow, then pulls hard and swears. His hands are frightfully scratched; the blood tinges the snow with dark blotches. "'It's the barbed wire defenses,' he cries. 'Help me, little brothers. Alone I can do nothing.'
  • 80. Welcome to our website – the perfect destination for book lovers and knowledge seekers. We believe that every book holds a new world, offering opportunities for learning, discovery, and personal growth. That’s why we are dedicated to bringing you a diverse collection of books, ranging from classic literature and specialized publications to self-development guides and children's books. More than just a book-buying platform, we strive to be a bridge connecting you with timeless cultural and intellectual values. With an elegant, user-friendly interface and a smart search system, you can quickly find the books that best suit your interests. Additionally, our special promotions and home delivery services help you save time and fully enjoy the joy of reading. Join us on a journey of knowledge exploration, passion nurturing, and personal growth every day! ebookbell.com