Happy 15th Birthday .NET!

Happy-Birthday-Microsoft-DotNet

Today marks the 15th anniversary since .NET debuted to the world. On February 13th, 2002, the first version of .NET was released as part of Visual Studio.NET. It seems just like yesterday when Microsoft was building its “Next Generation Windows Services” and unleashed a new level of productivity with Visual Studio.NET.

Since the beginning, the .NET platform has allowed developers to quickly build and deploy robust applications, starting with Windows desktop and web server applications in 2002. You got an entire managed framework for building distributed Windows applications, ASP.NET was introduced as the next generation Active Server Pages for web-based development, and a new language, C# (pronounced “see sharp” :-)) came to be.

Over the years, .NET and it’s ecosystem has grown and expanded to meet the needs of all kinds of developers and platforms. As the technology landscape has changed, so has .NET. You can build anything with .NET including cross-platform web apps, cloud services, mobile device apps, games and so much more. We have a vibrant open-source community where you can participate in the direction of .NET.

Announcing Microsoft ASP.NET WebHooks V1

WebHooks provide a simple pub/sub model for wiring together Web APIs and services with your code. A WebHook can be used to get notified when a file has changed in Dropbox, a code change has been committed to GitHub, a payment has been initiated in PayPal, a card has been created in Trello, and much more — the possibilities are endless! When subscribing, you provide a callback URI where you want to be notified. When an event occurs, an HTTP POST request is sent to your callback URI with information about what happened so that your Web app can act accordingly. WebHooks happen without polling and with no need to hold open a network connection while waiting for notifications.

Receiving WebHooks

Dealing with WebHooks depends on who the sender is. Sometimes there are additional steps registering a WebHook verifying that the subscriber is really listening. Often the security model varies quite a bit. Some WebHooks provide a push-to-pull model where the HTTP POST request only contains a reference to the event information which is then to be retrieved independently.

The purpose of Microsoft ASP.NET WebHooks is to make it both simpler and more consistent to wire up your API without spending a lot of time figuring out how to handle any WebHook variant:

WebHoks-Receiving

A WebHook handler is where you process the incoming WebHook. Here is a sample handler illustrating the basic model. No registration is necessary – it will automatically get picked up and called:

public class MyHandler : WebHookHandler
{
    // The ExecuteAsync method is where to process the WebHook data regardless of receiver
    public override Task ExecuteAsync(string receiver, WebHookHandlerContext context)
    {
        // Get the event type          
        string action = context.Actions.First();
 
        // Extract the WebHook data as JSON or any other type as you wish
        JObject data = context.GetDataOrDefault();
 
        return Task.FromResult(true);
    }
}

Finally, we want to ensure that we only receive HTTP requests from the intended party. Most WebHook providers use a shared secret which is created as part of subscribing for events. The receiver uses this shared secret to validate that the request comes from the intended party. It can be provided by setting an application setting in the Web.config file, or better yet, configured through the Azure portal or even retrieved from Azure Key Vault.

For more information about receiving WebHooks and lots of samples, please see these resources:

More detail on Microsoft Blog.

It’s a Good Day to Be a C# Developer

great_time_csharp_header

Recently at Connect(), Microsoft made a slew of new announcements. First, the public availability of Visual Studio 2017 Release Candidate. This just isn't a new version of the signature developer tool, it also includes the latest bits for C# 7.0. Second, Google announced they were joining the .NET Foundation. This means that Google, technically a competitor of Microsoft, wants to be actively involved in the evolution of .NET (and indirectly C#). Third, the first public release of Visual Studio for Mac. As a native environment, Visual Studio for Mac will provide the same world class tooling support for Xamarin applications, using C# and F#.

We could go on, but there is a common thread that runs between many of these announcements. As a developer, choosing C# as a part of your technology stack is an excellent decision! But what if you are not a C# developer already? How does C# compare to other popular languages such as JavaScript, Java, Python, etc?

Dijkstra's Algorithm in C# with Generics

I recently needed to to implement a shortest-path algorithm (to identify preferred domain controllers using site link costs) and I found Dijkstra's Algorithm

Path class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DijkstraAlgorithm {
   public class Path<T> {
      public T Source { get; set; }

      public T Destination { get; set; }

      /// <summary>
      /// Cost of using this path from Source to Destination
      /// </summary>
      /// 
      /// Lower costs are preferable to higher costs
      /// </remarks>
      public int Cost { get; set; }
   }
}

ExtensionMethods class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DijkstraAlgorithm {
   public static class ExtensionMethods {
      /// <summary>
      /// Adds or Updates the dictionary to include the destination and its associated cost 
      /// and complete path (and param arrays make paths easier to work with)
      /// </summary>
      public static void Set<T>(this Dictionary<T, KeyValuePair<int, LinkedList<Path<T>>>> Dictionary, 
                                T destination, int Cost, params Path<T>[] paths) {
         var CompletePath = paths == null ? new LinkedList<Path<T>>() : new LinkedList<Path<T>>(paths);
         Dictionary[destination] = new KeyValuePair<int, LinkedList<Path<T>>>(Cost, CompletePath);
      }
   }
}

Engine class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DijkstraAlgorithm {
   /// <summary>
   /// Calculates the best route between various paths, using Dijkstra's algorithm
   /// </summary>
   public static class Engine {
      public static LinkedList<Path<T>> CalculateShortestPathBetween<T>(T source, T destination, IEnumerable<Path<T>> Paths) {
         return CalculateFrom(source, Paths)[destination];
      }

      public static Dictionary<T, LinkedList<Path<T>>> CalculateShortestFrom<T>(T source, IEnumerable<Path<T>> Paths) {
         return CalculateFrom(source, Paths);
      }

      private static Dictionary<T, LinkedList<Path<T>>> CalculateFrom<T>(T source, IEnumerable<Path<T>> Paths) {
         // validate the paths
         if (Paths.Any(p => p.Source.Equals(p.Destination)))
            throw new ArgumentException("No path can have the same source and destination");

         // keep track of the shortest paths identified thus far
         Dictionary<T, KeyValuePair<int, LinkedList<Path<T>>>> ShortestPaths = new Dictionary<T, KeyValuePair<int, LinkedList<Path<T>>>>();

         // keep track of the locations which have been completely processed
         List<T> LocationsProcessed = new List<T>();

         // include all possible steps, with Int.MaxValue cost
         Paths.SelectMany(p => new T[] { p.Source, p.Destination })           // union source and destinations
                 .Distinct()                                                  // remove duplicates
                 .ToList()                                                    // ToList exposes ForEach
                 .ForEach(s => ShortestPaths.Set(s, Int32.MaxValue, null));   // add to ShortestPaths with MaxValue cost

         // update cost for self-to-self as 0; no path
         ShortestPaths.Set(source, 0, null);

         // keep this cached
         var LocationCount = ShortestPaths.Keys.Count;

         while (LocationsProcessed.Count < LocationCount) {
            T _locationToProcess = default(T);

            //Search for the nearest location that isn't handled
            foreach (T _location in ShortestPaths.OrderBy(p => p.Value.Key).Select(p => p.Key).ToList()) {
               if (!LocationsProcessed.Contains(_location)) {
                  if (ShortestPaths[_location].Key == Int32.MaxValue)
                     return ShortestPaths.ToDictionary(k => k.Key, v => v.Value.Value); //ShortestPaths[destination].Value;

                  _locationToProcess = _location;
                  break;
               }
            } // foreach

            var _selectedPaths = Paths.Where(p => p.Source.Equals(_locationToProcess));

            foreach (Path<T> path in _selectedPaths) {
               if (ShortestPaths[path.Destination].Key > path.Cost + ShortestPaths[path.Source].Key) {
                  ShortestPaths.Set(
                      path.Destination,
                      path.Cost + ShortestPaths[path.Source].Key,
                      ShortestPaths[path.Source].Value.Union(new Path<T>[] { path }).ToArray());
               }
            }

            //Add the location to the list of processed locations
            LocationsProcessed.Add(_locationToProcess);
         } // while

         return ShortestPaths.ToDictionary(k => k.Key, v => v.Value.Value);
         //return ShortestPaths[destination].Value;
      }
   }
}

Test

using System.Linq;
using DijkstraAlgorithm;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace UnitTestProject1 {
   [TestClass]
   public class UnitTest1 {
      [TestMethod]
      public void Calculate_A_to_D_given_AB_BC_CD__should_be__ABCD() {
         var Results = Engine.CalculateShortestPathBetween(
             "A",
             "D",
             new Path<string>[] {
                new Path<string>() { Source = "A", Destination = "B", Cost = 3 },
                new Path<string>() { Source = "B", Destination = "C", Cost = 3 },
                new Path<string>() { Source = "C", Destination = "D", Cost = 3 }
             });

         Results.Sum(r => r.Cost).Should().Be(9);
         Results.Count.Should().Be(3);

         Results.First().Cost.Should().Be(3);
         Results.First().Source.Should().Be("A");
         Results.First().Destination.Should().Be("B");

         Results.Skip(1).First().Cost.Should().Be(3);
         Results.Skip(1).First().Source.Should().Be("B");
         Results.Skip(1).First().Destination.Should().Be("C");

         Results.Skip(2).First().Cost.Should().Be(3);
         Results.Skip(2).First().Source.Should().Be("C");
         Results.Skip(2).First().Destination.Should().Be("D");
      }

      [TestMethod]
      public void Calculate_A_to_D_given_AB_BC_CD_DE__should_be__ABCD() {
         var Results = Engine.CalculateShortestPathBetween(
             "A",
             "D",
             new Path<string>[] {
                new Path<string>() { Source = "A", Destination = "B", Cost = 3 },
                new Path<string>() { Source = "B", Destination = "C", Cost = 3 },
                new Path<string>() { Source = "C", Destination = "D", Cost = 3 },
                new Path<string>() { Source = "D", Destination = "E", Cost = 3 }
             });

         Results.Sum(r => r.Cost).Should().Be(9);
         Results.Count.Should().Be(3);

         Results.First().Cost.Should().Be(3);
         Results.First().Source.Should().Be("A");
         Results.First().Destination.Should().Be("B");

         Results.Skip(1).First().Cost.Should().Be(3);
         Results.Skip(1).First().Source.Should().Be("B");
         Results.Skip(1).First().Destination.Should().Be("C");

         Results.Skip(2).First().Cost.Should().Be(3);
         Results.Skip(2).First().Source.Should().Be("C");
         Results.Skip(2).First().Destination.Should().Be("D");
      }

      [TestMethod]
      public void Calculate_A_to_D_given_AB_AC_AD_AE_BC_CD_DE__should_be__ACD() {
         var Results = Engine.CalculateShortestPathBetween(
             "A",
             "D",
             new Path<string>[] {
                new Path<string>() { Source = "A", Destination = "B", Cost = 3 },
                new Path<string>() { Source = "A", Destination = "C", Cost = 3 },
                new Path<string>() { Source = "A", Destination = "D", Cost = 7 }, // set this just above ABC (3+3=6)
                new Path<string>() { Source = "A", Destination = "E", Cost = 3 },
                new Path<string>() { Source = "B", Destination = "C", Cost = 3 },
                new Path<string>() { Source = "C", Destination = "D", Cost = 3 },
                new Path<string>() { Source = "D", Destination = "E", Cost = 3 }
             });

         Results.Sum(r => r.Cost).Should().Be(6);
         Results.Count.Should().Be(2);

         Results.First().Cost.Should().Be(3);
         Results.First().Source.Should().Be("A");
         Results.First().Destination.Should().Be("C");

         Results.Skip(1).First().Cost.Should().Be(3);
         Results.Skip(1).First().Source.Should().Be("C");
         Results.Skip(1).First().Destination.Should().Be("D");
      }

      [TestMethod]
      public void Calculate_A_to_D_given_AB_AC_AD_AE_BC_CD_DE__should_be__AD() {
         var Results = Engine.CalculateShortestPathBetween(
             "A",
             "D",
             new Path<string>[] {
                new Path<string>() { Source = "A", Destination = "B", Cost = 3 },
                new Path<string>() { Source = "A", Destination = "C", Cost = 3 },
                new Path<string>() { Source = "A", Destination = "D", Cost = 5 }, // set this just below ABC (3+3=6)
                new Path<string>() { Source = "A", Destination = "E", Cost = 3 },
                new Path<string>() { Source = "B", Destination = "C", Cost = 3 },
                new Path<string>() { Source = "C", Destination = "D", Cost = 3 },
                new Path<string>() { Source = "D", Destination = "E", Cost = 3 }
             });

         Results.Sum(r => r.Cost).Should().Be(5);
         Results.Count.Should().Be(1);

         Results.Single().Cost.Should().Be(5);
         Results.Single().Source.Should().Be("A");
         Results.Single().Destination.Should().Be("D");
      }
   }
}

You can find the code on GitHub.

Happy coding!

DistinctBy in Linq (Find Distinct object by Property)

Linq-Distinct-Screenshot1

public class Size {
   public string Name { get; set; }
   public int Height { get; set; }
   public int Width { get; set; }
}

Consider that we have Size Class for advertisement which is having Heigth, Width and Name as property in it. Now Requirement is I have to find out the all product with distinct Name values.

Size[] adv = { 
    new Size { Name = "Leaderboard", Height = 90, Width = 728 }, 
    new Size { Name = "Large Rectangle", Height = 280, Width = 336 }, 
    new Size { Name = "Large Mobile Banner", Height = 100, Width = 320 }, 
    new Size { Name = "Large Skyscraper", Height = 600, Width = 300 },
    new Size { Name = "Medium Rectangle", Height = 250, Width = 300 },
    new Size { Name = "Large Skyscraper", Height = 300, Width = 600 },
};

var lst = adv.Distinct();

foreach (Size p in lst) {
   Console.WriteLine(p.Height + " : " + p.Name);
}

It returns all the size event though two size have same Name value. So this doesn't meet requirement of getting object with distinct Name value.

Way 1: Implement Comparable

First way to achieve the same functionality is make use of overload Distinct function which support to have comparator as argument.

Here is MSDN documentation on this : Enumerable.Distinct<TSource> Method (IEnumerable<TSource>, IEqualityComparer<TSource>).

So for that I implemented IEqualityComparer and created new SizeComparare which you can see in below code.

class SizeComparare : IEqualityComparer<Size> {
   private Func<Size, object> _funcDistinct;
   public SizeComparare(Func<Size, object> funcDistinct) {
      this._funcDistinct = funcDistinct;
   }

   public bool Equals(Size x, Size y) {
      return _funcDistinct(x).Equals(_funcDistinct(y));
   }

   public int GetHashCode(Size obj) {
      return this._funcDistinct(obj).GetHashCode();
   }
}

So in SizeComparare constructor I am passing function as argument, so when I create any object of it I have to pass my project function as argument. In Equal method I am comparing object which are returned by my projection function. Now following is the way how I used this Comparare implementation to satisfy my requirement.

Way 2: Implement Comparable

The second and most eaisest way to avoide this I did in above like using Comparare implementation is just make use of GroupBy like as below

List<Size> list = adv
                     .GroupBy(a => a.Name)
                     //.GroupBy(a => new { a.Name, a.Width })
                     .Select(g => g.First())
                     .ToList();

foreach (Size p in list) {
   Console.WriteLine(p.Height + "x" + p.Width + " : " + p.Name);
}

So this approach also satisfy my requirement easily and output is similar to above two approach. If you want to pass more than on property than you can just do like this .GroupBy(a => new { a.Width, a.Code }).

Linq-Distinct-Screenshot2

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using System.Threading;

namespace DistinctBy {
   public class Size {
      public string Name { get; set; }
      public int Height { get; set; }
      public int Width { get; set; }
   }

   class SizeComparare : IEqualityComparer<Size> {
      private Func<Size, object> _funcDistinct;
      public SizeComparare(Func<Size, object> funcDistinct) {
         this._funcDistinct = funcDistinct;
      }

      public bool Equals(Size x, Size y) {
         return _funcDistinct(x).Equals(_funcDistinct(y));
      }

      public int GetHashCode(Size obj) {
         return this._funcDistinct(obj).GetHashCode();
      }
   }

   class Program {
      static void Main(string[] args) {

         Console.WriteLine("Linq Distinct");
         Size[] adv = { 
                        new Size { Name = "Leaderboard", Height = 90, Width = 728 }, 
                        new Size { Name = "Large Rectangle", Height = 280, Width = 336 }, 
                        new Size { Name = "Large Mobile Banner", Height = 100, Width = 320}, 
                        new Size { Name = "Large Skyscraper", Height = 600, Width = 300 },
                        new Size { Name = "Medium Rectangle", Height = 250, Width = 300},
                        new Size { Name = "Large Skyscraper", Height = 300, Width = 600 },
                      };

         var lst = adv.Distinct();

         foreach (Size p in lst) {
            Console.WriteLine(p.Height + "x" + p.Width + " : " + p.Name);
         }

         Console.WriteLine("\nCompare Distinct");

         var list2 = adv.Distinct(new SizeComparare(a => new { a.Name, a.Height }));
         //var list2 = adv.Distinct(new SizeComparare(a => a.Name));

         foreach (Size p in list2) {
            Console.WriteLine(p.Height + "x" + p.Width + " : " + p.Name);
         }

         Console.WriteLine("\nGroup By way");
         List<Size> list = adv
                              .GroupBy(a => a.Name)
                              //.GroupBy(a => new { a.Name, a.Width })
                              .Select(g => g.First())
                              .ToList();

         foreach (Size p in list) {
            Console.WriteLine(p.Height + "x" + p.Width + " : " + p.Name);
         }

         Console.ReadLine();
      }
   }
}

Happy coding!

Data and data access technologies

In my previous post I spoke about key layers of distributed applications. Now we will go through the most crucial layer of any distributed application, the data layer. In this part, you will be introduced to various database technologies, along with .NET-related technologies.

Data can be stored in a wide range of data sources such as relational databases, files on the local filesystems, on the distributed filesystems, in a caching system, in storage located on the cloud, and in memory.

  • Relational databases (SQL server): This is the traditional data source that is designed to store and retrieve data. Queries are written in languages such as T-SQL-utilized Create, Retrieve, Update, and Delete (CRUD) operations model.
  • The filesystem: The filesystem is used to store and retrieve unstructured data on the local disk system in the files. One of the simplest options to store and retrieve data, it has many functional limits and is not distributed by its nature.
  • The Distributed File System (DFS): The DFS is the next level of file system that solves the size and other limitations introduced by local disks. In a nutshell, DFS is a pool of networked computers that store data files.
  • NoSQL databases: NoSQL databases are a new way of storing data in a non-relational fashion. Often, NoSQL databases are used to store large or very large volumes of data, and the biggest difference between these databases and relational database is that NoSQL data stores are schema-free. However, data can be organized by one or more different models, such as key-value stores and document stores, among others.
  • Cloud storage: Any infrastructure located on the cloud solves many issues, such as security, reliability, resilience, and maintenance. Cloud offerings such as Microsoft Azure Storage provide many ways of storing the data in different formats, which can be structured or unstructured. As with many other cloud storage offerings, Microsoft Azure Storage exposes the HTTP REST API, used by any application and client running on any platform that supports HTTP.
  • In-memory stores: In-memory stores are the fastest data stores that are limited in size, not persistent, and cumbersome to use in a distributed multi-server environment. In-memory stores are used to store temporary and volatile data.

ADO.NET and ADO.NET Entity Framework

.NET Framework has several database access options, and the foundation of most of them is ADO.NET. ADO.NET can be called a foundation for every other data access technology on Microsoft stacks. In a nutshell, ActiveX Data Objects .NET (ADO.NET) is a collection of classes that implement program interfaces to simplify the process of connecting to data stores without depending on the structure and implementation of a concrete data store and its location. The challenge that it offers is that most developers must write complex data access code (between the application and the database) that requires them to have a good understanding of the database itself, of raw tables, views, stored procedures, the database schema, table definitions and parameters, results, and so on.

This is mostly solved by the Object-relational mapping (ORM) approach. Programmers create a conceptual model of the data and write their data access code against that model, while an additional layer provides a bridge between the entity-relationship model and the actual data store. Entity Framework generates database entities according to database tables and provides the mechanism for basic CRUD operations, managing 1-to-1, 1-to-many, and many-to-many relationships, and the ability to have inheritance relationships between entities among others.

Basically, you have the ability to "talk" about your model not with the database but with the class model you wrote or generated from a database using Entity Framework. This is achieved by the creation of a combination of XML schema files, code generation, and the ADO.NET Entity Framework APIs. The schema files are used to define a conceptual layer, to be used as a map between the data store and the application. The ADO.NET Entity Framework allows you to write the application that uses classes that are generated from the conceptual schema. Entity Framework then takes care of the rest.

Another important component of Entity Framework that is often used by developers is Language Integrated Query (LINQ). It adds data querying capabilities to .NET languages and extends the language with SQL-like query expressions.

There are three approaches to working with Entity Framework in the project:

  • Database-first: This approach is used when you already have a database that is going to be used as a data source.
  • Model-first: This approach is used when you have no database. First, you draw the model in the Visual Designer and then instruct it to create the database for you with all the tables.
  • Code-first: This approach is used often as it provides a way to write your model in code as classes and instruct Entity Framework to generate the database with objects described in the code.

Key layers of distributed applications

Every application that is going to be used by end users should be designed appropriately as users are expecting to process information from various data sources that might be geographically distributed. They are also expecting this information to be up-to-date and capable of being inflected very fast. Designing such applications is not an easy task and involves integration among different groups of components. Let's review the layers that form a typical distributed application.

The responsibilities in a distributed system can be divided into four layers:

  • The data layer
  • The business logic layer
  • The server layer
  • The user interface layer

The data layer

The data layer is responsible for storing and accessing data and for querying, updating, or deleting this data. This layer includes the logic of data access and store performance that can be a complicated task, especially dealing with a large volume of data distributed among different data sources.

The business logic layer

The business logic layer is responsible for the crucial part of the application: logic that is executed between the client and data layers. Basically, the business logic layer contains the logic of the application. It is the "brain" that coordinates the integration between the data layer that is used for reading and storing the data and the user interface layer that interacts with the client.

The server layer

The server layer is sometimes called a services layer, and that is an accurate term as well. The server layer is responsible for exposing some of the capabilities of the application that can be consumed by other services and used as a data source, for example. This layer works as the interface between our application and the world of other services, which is different from that of the end users.

The server layer is an extremely important part of every distributed application; its proper design can impact the overall performance of the system as it is responsible for the defining of the collaboration principles between parts of applications and the distribution of load and data. It contains security mechanisms that validate requests as well.

The user interface layer

The user interface layer is the layer that is used by clients interacting with the application. This layer must contain only that part of the system that is responsible for rendering the interface consisting of the data, user interface components, and other things important in the process of interacting between the user and the application.

This layer also has the logic that can be used in the process of adapting the application user interface layer for different form factors, people, cultures, interfaces (such as touchscreens), screen sizes, and resolutions. At the same time, it must be simple and effective and must provide a smooth user experience.

Properly designed user interface design is important; if the user interface is not friendly and experience is not smooth or if the user does not understand how the system works and how it should be used, the application will not be used.

Remove line numbers from code

Often you copy from a site some code but it has line numbers and you have to spend some times to remove them. With my simple tool on line, you can remove them quickly.

Try it!

Throw vs Throw e

Some people asked me the different between those two following code:

Code 1

try
{
    ...
}
catch (Exception ex)
{
   throw ex;
}

Code 2

try
{
    ...
}
catch (Exception ex)
{
    throw;
}

I don't think there is ever a good reason to write catch (Exception e) { throw e; }. This loses the original stacktrace. When you use throw; the original stacktrace is preserved. This is good because it means that the cause of the error is easier to find.

Beware of the stopwatch

In my previous post I showed how to measure with stopwatch an execution time for a method. There are several mechanisms, I will explain 3 of them and point out their strengths and weaknesses.

DateTime.UtcNow

DateTime begin = DateTime.UtcNow;

...

DateTime end = DateTime.UtcNow;
Console.WriteLine("Measured time: " + (end-begin).TotalMilliseconds + 
                  " ms.");

This is the fastest mechanism because under the hood it only reads a counter from memory (the code above takes only 76 nanoseconds to execute on my machine). However the resolution is not so great: only 10 milliseconds on recent version of Windows. If you want to measure a piece of code that takes shorter to execute, you will have to execute it e.g. 1000 times and measure how long this takes, then divide the result by 1000.

Another disadvantage is that this is not reliable if the system-time changes. This should be a very rare situation, but could for instance happen through synchronization with a time server.

Stopwatch

Stopwatch watch = new Stopwatch();
watch.Start();

...

watch.Stop();
Console.WriteLine("Measured time: " + watch.Elapsed.TotalMilliseconds + 
                  " ms.");

This mechanism is a bit slower than the previous one (10 times slower on my machine) so for short intervals this may have an impact on the result. However there are some serious issues:

  • This can be unreliable on a PC with multiple processors. Due to a bug in the BIOS, Start() and Stop() must be executed on the same processor to get a correct result.
  • This is unreliable on processors that do not have a constant clock speed (most processors can reduce the clock speed to conserve energy). This is explained in detail here.

I suspect that you can get a reliable result if you run it on a single-processor machine and disable any power-saving options in the BIOS. I haven’t tested this though.

On the upside, it has the hightest possible resolution (which depends on the hardware it runs on).

Process.TotalProcessorTime

TimeSpan begin = Process.GetCurrentProcess().TotalProcessorTime;

...

TimeSpan end = Process.GetCurrentProcess().TotalProcessorTime;
Console.WriteLine("Measured time: " + (end - begin).TotalMilliseconds + 
                  " ms.");

This mechanism is different from the previous ones because it does not measure how much time has passed, but it measures how long your process has kept the CPU busy. This is great for performance measurements:

  • The timings are not distorted by other processes that consume a lot of CPU.
  • You can measure the impact that your code has on the overall performance of the system. On laptops, this also gives an indication towards the battery-power that is consumed by your process. This can be important for applications that run for a long time (such as services and other background tasks).

To interpret the measured time correctly, you should realize that time that is spent while your code is waiting (e.g. in a Sleep) will not be counted. On the other hand, if your process is keeping multiple processors busy, the time of each processor will be added (if a dual-core processor is kept 100% busy, the ‘TotalProcessorTime’ will increment with 2 each second!).

Note that this mechanism has the worst performance: the code above takes 19264 nanoseconds on my PC. This is 250 times slower than using DateTime.UtcNow!

So there is not one-size-fits-all solution to measure a time interval. Personally, if I want to measure how long a piece of code takes to execute, I run it in a loop (e.g. one million times) and measure it using DateTime.UtcNow.

Advertsing

125X125_06

Planet Xamarin

Planet Xamarin

Calendar

<<  July 2017  >>
MonTueWedThuFriSatSun
262728293012
3456789
10111213141516
17181920212223
24252627282930
31123456

View posts in large calendar

Month List