Introduction
It has been almost a year since .NET 4.5 got released. But the
problems with most of the recent Microsoft releases have been
communication with .NET developers. Only one or two features are known
to developers and other features just stay on MSDN and end up becoming
simple documents.
For example, the time you ask a .NET developer what is new in the core framework .NET 4.5 most of them will just say
async
and
awaitt
(at least with people whom I have interacted have just talked about those features).
Again it’s very difficult to run through all the new features.
Because the features may not sound interesting depending on what you are
working currently on..
So in this article I have picked my five favorite features introduced
in .NET 4.5 core. Again it’s possible my favorites cannot be your
favorites. But what I have done is while choosing these features I kept
in mind the larger .NET community and I hope I have met that
expectation.
Note: This article does not discuss the new features in ASP.NET,
WCF, WPF, WWF etc. It only talks about new features related to the core.
Feature 1: async and await (code markers)
This feature has been oversold and every .NET evangelist has talked
about it. But this is still my favorite and you will come to know why in
a few lines from here.
async
and await
are markers which mark code positions from where control should resume after a task (thread) completes.
Let us try to make sense of the above statement by understanding the below code. If you see the flow of the below code:
Method()
gets called from the Static void main()
entry point.
Method()
spawns a Task
(thread) LongTask
which waits for 10 seconds.
- At the same time the control comes back to
Method()
to execute the remaining code after the task was called. In other words as the invocation is multi-threaded (Task.Run
…), LongTask
is also running i.e., waiting for 10 seconds and the remaining code of your Method()
is also executed.
Now in certain scenarios we want step 3 to behave differently. We want that after
LongTask()
finishes execution, the control should go back to
Method
to execute the remaining code. The
async
and
await
keywords help to achieve the above behavior.
Now there are three important points to remember about the
async
and
await
keywords:
async
and await
are pair keywords. You cannot use them in a standalone manner.
async
is marked on a method. This keyword is just an indicator saying that this method will have the await
keyword.
- The
await
keyword marks the position from where the task should resume. So you will always find this keyword in conjunction with Task
.
Below is a modified version of the previously discussed code where we have applied
async
and
await
.
All the other steps remain the same but “Step 3” is executed after
“Step 2” completes. In simple words the control comes back to
Method()
after the task has finished operation.
Now that you have read about “async” and “await”, let me put a cross question. The above behavior can be also achieved by using
Task.Wait
or
Task.ContinueWith
, so how do they differ? I am leaving this question as a home work for you.
Feature 2: Zip facility (Zip compression)
Zip is one of the most accepted archive file formats. Zip format is
supported in almost all operating systems with some built-in name.
- In Windows operating system it’s implemented by the name “Compressed folders”.
- In MAC OS it’s implemented by the name “Archive utility”.
Now in .NET we did not have built-in support for implementing Zip
compression. Many developers where using third party components like
“DotnetZip”. In .NET 4.5, the Zip feature is baked in the framework
itself, inside the namespace
System.IO.Compression
.
The first step is you need to reference two namespaces:
System.IO.Compression.FileSystem
System.IO.Compression
The next step is to import the below two namespaces:
using System.IO.Compression;
If you want to Zip files from a folder you can use the
CreateFromDirectory
function as shown below.
ZipFile.CreateFromDirectory(@"D:\data",@"D:\data.zip");
If you wish to unzip, you can use the
ExtractToDirectory
function as shown in the below code.
ZipFile.ExtractToDirectory(@"D:\data.zip", @"D:\data\unzip");
Feature 3: Regex timeout (TimeOut)
“Regex” has been the most preferred way of doing validations. In case you are new to Regex, please see the Regex video
where I have explained how regex is implemented. But because of the
typical parsing logic of regex it is exposed to DOS attacks. Let us try
to understand in detail what I mean by that.
For instance consider this regular expression - “^(\d+)$”. This regex
expression says that it can have only numbers. You can also see the
regex symbolic diagram which shows how the regex will be evaluated .Now
let’s say if we want to validate “123456X”. It will have six paths as
shown in the below figure.
But if we add one more number to it, it will take seven paths. In
other words as the length increases a regex takes more time to evaluate.
In other words the time taken to evaluate is linearly proportional to
the length of the characters.
Now let’s complicate the previously defined regex from “^(\d+)$” to
“^(\d+)+$” . If you see the regex symbolic diagram it’s pretty complex.
If we now try to validate “123456X”, it will run through 32 paths. If
you add one more character the number pf paths become 64.
In other words for the above regex, the time taken to evaluate rises exponentially with the number of characters.
Now the question you would ask is, how does it matter? This linear
rise of evaluation time can be exploited by hackers to do a DOS (Denial
of Service) attack. They can put a long, a really long string and make
your application hang forever.
The proper solution for this would be to have a timeout on the regex
operation. Good news, in .NET 4.5 you can now define a timeout property
as shown in the below code. So if you get any kind of malicious string,
the application will not go in a loop forever.
try
{
var regEx =
new Regex(@”^(\d+)+$”, RegexOptions.Singleline, TimeSpan.FromSeconds(
2));
var match = regEx.Match(“123453109839109283090492309480329489812093809x”);
}
catch (RegexMatchTimeoutException ex)
{
Console.WriteLine(“Regex Timeout”);
}
Feature 4: Profile optimization (Improved startup performance)
We all know .NET code is in a half compiled format. During runtime,
the JIT (Just-in-Time) compiler runs and translates this half compiled
IL code to native machine code. One of the big complaints about JIT is
that when a .NET applications runs the first time, it runs slow as JIT
is busy translating IL code to machine code.
In order to bring down this startup time, in .NET 4.5, we have
something called “profile optimization”. Profile is nothing but a simple
file which has a list of methods which the application will need during
startup. So when the application starts, a background JIT runs and
starts translating IL code for those methods into machine / native code.
This background JIT compilation of startup methods happens across
multiple processors thus minimizing the start up time further. Also note
you need to have a multicore box to implement profile optimization. In case you do not have a multicore box then this setting is ignored.
In order to create the “profile” file, you first need to import the
System.Runtime
namespace. You can then call the
SetProfileRoot
and
StartProfile
methods of the static class
ProfileOptimization
.
Now when the application starts the background JIT it will read from
the profile file and compile your start up methods in the background
thus reducing your startup time.
using System.Runtime;
ProfileOptimization.SetProfileRoot(
@"D:\ProfileFile");
ProfileOptimization.StartProfile(
"ProfileFile");
One important note:
Profileoptimization
is enabled by
default for ASP.NET 4.5 and Silverlight 5 applications. So the above
code need not be written for these technologies.
Feature 5: Garbage collector (GC background cleanup)
Garbage collector is one real heavy task in a .NET application. And
it becomes heavier when it is an ASP.NET application. ASP.NET
applications run on the server and a lot of clients send requests to the
server thus creating loads of objects, making the GC really work hard
for cleaning up unwanted objects.
In .NET 4.0, when the GC runs for cleanup, all the application
threads are suspended. You can see in the above figure we have three
application threads running. We have two GCs running on separate
threads. One GC thread for one logical processor. Now the application
threads run and do their work. Now as these application threads are
performing their task they also create managed objects.
At some point of time the background GC runs and starts clean up.
When these background GCs start cleanup, they suspend all the
application threads. This makes the server/application less responsive
for that moment.
To overcome the above problem, server GC was introduced. In server GC
there is one more thread created which runs in the background. This
thread works in the background and keeps cleaning generation 2 (see this video for GC generation 0, 1, and 2)objects
thus minimizing the load on the main GC thread. Due to double GC
threads running, the main application threads are less suspended, thus
increasing application throughput. To enable server GC, we need to use
the
gcServer
XML tag and enable it to
true
.
<configuration>
<runtime>
<gcServer enabled="true"/>
</runtime>
</configuration>
Three more features worth exploring
Set default culture to App Domain
In the previous versions of .NET if I needed to set culture I needed
to do it in every thread. Below is a sample code which demonstrates the
pain of setting culture at thread levels. That was a real pain when we
had heavily multi-threaded applications.
Collapse | Copy Code
CultureInfo cul =
new CultureInfo(strCulture);
Thread.CurrentThread.CurrentCulture = cul;
Thread.CurrentThread.CurrentUICulture = cul;
In 4.5 we can set culture at the app domain level and all the threads
inside that appdomain will inherit that culture. Below is a sample code
of how to implement
DefaultThreadCurrentCulture
.
Collapse | Copy Code
CultureInfo culture = CultureInfo.CreateSpecificCulture(
"fr-FR");
CultureInfo.DefaultThreadCurrentCulture = culture;
Array support more than two gigabyte size
I am not sure in what kind of a scenario we would need a 2 GB
collection. So I personally do not see where we would need this feature.
If I ever need such a big collection I would break it into parts. But I
am sure there should be a good reason for this feature to be enabled in
the framework.
Unicode support for console
I left this feature out from the discussion as very less people work
with console applications. I have seen people using consoles for
academic purposes. All said and done we now have Unicode support for
console apps also.
References