Async Await Best Practices Cheat Sheet

Summary of Asynchronous Programming Guidelines

Name Description Exceptions
Avoid async void Prefer async Task methods over async void methods Event handlers
Async all the way Don’t mix blocking and async code Console main method
Configure context Use ConfigureAwait(false) when you can Methods that require con­text

The Async Way of Doing Things

To Do This … Instead of This … Use This
Retrieve the result of a background task Task.Wait or Task.Result await
Wait for any task to complete Task.WaitAny await Task.WhenAny
Retrieve the results of multiple tasks Task.WaitAll await Task.WhenAll
Wait a period of time Thread.Sleep await Task.Delay

Know Your Tools

There’s a lot to learn about async and await, and it’s natural to get a little disoriented. Here’s a quick reference of solutions to common problems.

Solutions to Common Async Problems

Problem Solution
Create a task to execute code Task.Run or TaskFactory.StartNew (not the Task constructor or Task.Start)
Create a task wrapper for an operation or event TaskFactory.FromAsync or TaskCompletionSource<T>
Support cancellation CancellationTokenSource and CancellationToken
Report progress IProgress<T> and Progress<T>
Handle streams of data TPL Dataflow or Reactive Extensions
Synchronize access to a shared resource SemaphoreSlim
Asynchronously initialize a resource AsyncLazy<T>
Async-ready producer/consumer structures TPL Dataflow or AsyncCollection<T>

Async and Await Guidelines

There are many new await-friendly techniques that should be used instead of the old blocking techniques. If you have any of these Old examples in your new async code, you’re Doing It Wrong(TM):

Old New Description
task.Wait await task Wait/await for a task to complete
task.Result await task Get the result of a completed task
Task.WaitAny await Task.WhenAny Wait/await for one of a collection of tasks to complete
Task.WaitAll await Task.WhenAll Wait/await for every one of a collection of tasks to complete
Thread.Sleep await Task.Delay Wait/await for a period of time
Taskconstructor Task.Run or TaskFactory.StartNew Create a code-based task

 

C# Yield Usage

You can use a yield return statement to return each element one at a time. It removes the need for an explicit extra class.
You can use a yield break statement to end the iteration.

public class PowersOf2
{
    static void Main()
    {
        // Display powers of 2 up to the exponent of 8:
        foreach (int i in Power(2, 8))
        {
            Console.Write("{0} ", i);
        }
    }

    public static System.Collections.Generic.IEnumerable<int> Power(int number, int exponent)
    {
        int result = 1;

        for (int i = 0; i < exponent; i++)
        {
            result = result * number;
            yield return result;
        }
    }

    // Output: 2 4 8 16 32 64 128 256
}
public static class GalaxyClass
{
    public static void ShowGalaxies()
    {
        var theGalaxies = new Galaxies();
        foreach (Galaxy theGalaxy in theGalaxies.NextGalaxy)
        {
            Debug.WriteLine(theGalaxy.Name + " " + theGalaxy.MegaLightYears.ToString());
        }
    }

    public class Galaxies
    {
        public System.Collections.Generic.IEnumerable<Galaxy> NextGalaxy
        {
            get
            {
                yield return new Galaxy { Name = "Tadpole", MegaLightYears = 400 };
                yield return new Galaxy { Name = "Pinwheel", MegaLightYears = 25 };
                yield return new Galaxy { Name = "Milky Way", MegaLightYears = 0 };
                yield return new Galaxy { Name = "Andromeda", MegaLightYears = 3 };
            }
        }
    }

    public class Galaxy
    {
        public String Name { get; set; }
        public int MegaLightYears { get; set; }
    }
}

Getting And Setting Property Attribute Value By Property Name

You can change property attribute value of an existing attribute at runtime. Below I created a helper class for getting and setting BrowsableAttribute value.

    public static class AttributeHelper
    {
        public static bool GetBrowsable(Type type, string propertyName)
        {
            PropertyDescriptor pd = TypeDescriptor.GetProperties(type)[propertyName];

            if (pd == null)
            {
                return false;
            }
            else
            {
                BrowsableAttribute ba = (BrowsableAttribute)pd.Attributes[typeof(BrowsableAttribute)];
                return (bool)ba.GetType().GetField("browsable", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(ba);
            }
        }

        public static void SetBrowsable(Type type, string propertyName, bool browsable)
        {
            PropertyDescriptor pd = TypeDescriptor.GetProperties(type)[propertyName];

            if (pd != null)
            {
                BrowsableAttribute ba = (BrowsableAttribute)pd.Attributes[typeof(BrowsableAttribute)];
                ba.GetType().GetField("browsable", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(ba, browsable);
            }
        }
    }

Yazılım Mühendisliği Ünvanları

Yazılım mühendisliği ünvanları firmadan firmaya değişen bir yapı göstermektedirler. Bana göre bir yazılım firmasında minimumda olması gereken ünvan basamakları aşağıdaki şekilde olabilir.

    1. Junior Software Engineer
    2. Software Engineer
    3. Senior Software Engineer
    4. Lead Software Engineer
    5. Principal Software Engineer

1. Junior Software Engineer:

  • Mesleğin ilk basamağıdır.
  • Sıradan işler için bile diğer yazılım mühendislerinden yardım alması gerekir.

2. Software Engineer:

  • Üst seviye görevlerin, iyi tanımlanmış daha küçük görevlere bölünmesine ihtiyaç duyar.
  • Yardım almadan çalışabilir.

3. Senior Software Engineer:

  • Üst seviye görevleri, iyi tanımlanmış daha küçük görevlere bölebilir.
  • Bir projeyi baştan sona kendi başına tamamlayabilir.
  • Bir çok problemi kendi başına çözebilir.

4. Lead Software Engineer:

  • Senior Software Engineer yeteneklerine sahiptir.
  • Küçük takımları yönetebilir. (3-7 kişilik)
  • Diğer yazılım mühendislerine, yeteneklerini arttırmaları için, öğretir ve akıl hocalığı yapar.
  • Diğer yazılım mühendislerinin daha üretken olmasını sağlar.

5. Principal Software Engineer:

  • Lead Software Engineer yeteneklerine sahiptir.
  • Çok kapsamlı başarıları vardır veya şirket için olmazsa olmaz bir anahtar pozisyondadır.

Dinamik Olarak ResourceDictionary, Model, ViewModel ve View Ekleme

Çalışma zamanında WPF uygulamalarımızda xaml dosyalarını XamlReader.Load fonksiyonu ile yükleyebiliyoruz. Bunun dışında cs dosyalarını yükleyip derleyebiliyoruz. Bu sayede sadece klasörlerdeki dosyaları değiştirerek aynı uygulamayı farklı şekillerde çalıştırabiliyoruz. Örnek bir proje oluşturdum. Bu projede ResourceDictionary, Model, ViewModel ve View dosyaları uygulama çalışırken ilgili klasörlerden yüklenmektedir. Projeye buradan ulaşabilirsiniz.

WPF ile Çok İşlemli Uygulama (Multi-Process Application)

Çok-işlemli uygulamalar aynı anda birden fazla uygulama arasında iletişim kurarak tek uygulama gibi çalışırlar. Uygulamaların direkt olarak birbirine bağlı olmaması sayesinde yüksek güvenlik, ana uygulama çalışırken diğer uygulamaları güncelleme, uygulamalardan biri çökse bile ana uygulamanın çökmemesi gibi bazı avantajları vardır.

WPF ile MPA mimarisinde çalışan bir uygulama geliştirdim. Uygulamalar arasındaki iletişimi Zyan Communication Framework ile IPC kullanarak sağladım. Buradan oluşturduğum projeyi indirebilirsiniz.

WSDL Değişiklikleri

Uyumlu Değişiklikler:

  • Yeni bir WSDL operasyon tanımı ve ilgili mesaj tanımları ekleme.
  • Yeni bir WSDL bağlantı noktası türü tanımı ve ilgili operasyon tanımları ekleme.
  • Yeni bir WSDL bağlayıcı ve servis tanımları ekleme.
  • Bir mesaj tanımına, yeni bir isteğe bağlı XML şeması elemanı veya nitelik tanımı ekleme.
  • Bir mesaj tanımı tipinin veya bir XML şema elemanının kural ayrıntı düzeyinin azaltılması.
  • Bir mesaj tanımı tipine yeni bir XML şeması jokeri ekleme.
  • Yeni bir isteğe bağlı WS-Policy belirteci ekleme.
  • Yeni bir WS-Policy alternatifi ekleme.

Uyumsuz Değişiklikler:

  • Mevcut bir WSDL operasyon tanımını yeniden adlandırma.
  • Mevcut bir WSDL operasyon tanımını kaldırma.
  • Mevcut bir WSDL operasyon tanımının MEP’ini değiştirme.
  • Mevcut WSDL operasyon tanımına bir hata mesajı ekleme.
  • Bir mesaj tanımına yeni bir gerekli XML şema öğesi veya nitelik beyanı ekleme.
  • Bir mesaj tanımının bir XML şema elemanının kısıt ayrıntı artan veya nitelik beyan.
  • Bir mesaj tanımının isteğe bağlı veya gerekli XML şema öğesi veya niteliği yeniden adlandırma.
  • Bir mesaj tanımından isteğe bağlı veya gerekli XML şema öğesi veya niteliği veya joker kaldırma.
  • Yeni gerekli WS-Policy savı ya da ifadesini ekleme.
  • Yeni göz ardı edilebilir WS-Policy ifadesini ekleme. (çoğu zaman)

BLAKE2 ile Hash Oluşturma

BLAKE2, MD5, SHA-1, SHA-2 ve SHA-3’ten daha hızlı bir kriptografik hash algoritması olmakla birlikte, en son standart olan SHA-3 kadar güvenlidir. BLAKE2, yüksek hız, güvenlik ve basitlik nedeniyle birçok projeyle kabul edilmiştir.

BLAKE2’nin iki çeşit algoritması vardır:

  • BLAKE2b (veya sadece BLAKE2) 64 bitlik platformlar (NEON etkinleştirilmiş ARM’lar da dahil olmak üzere) için optimize edilmiştir ve 1 ile 64 bayt arasında herhangi bir boyutta özet üretir.
  • BLAKE2s 8 ila 32 bitlik platformlar için optimize edilmiştir ve 1 ila 32 bayt arasında herhangi bir boyutta özet üretir.

Daha fazla bilgi için https://blake2.net/ adresini ziyaret edebilirsiniz.

Github’daki C# kütüphanesini kullanarak, BLAKE2b ile minimum 8 bit, maksimum 512 bit boyutunda hash üretebiliyoruz. Aşağıdaki örnekte boyut 512 bit verildi. Blake2Sharp kütüphanesini https://github.com/BLAKE2/BLAKE2 adresinden indirebilirsiniz.

private static string Blake2Hash(string text)
{
    return BitConverter.ToString(Blake2B.ComputeHash(Encoding.UTF8.GetBytes(text), 
                                 new Blake2BConfig { OutputSizeInBits = 512 })).Replace("-", "");
}

Ekran Görüntüsü Alma

Bazen uygulama içinden programatik olarak ekran görüntüsü almak gerekebilir. Aşağıdaki metot ile bir veya daha fazla ekrandan ekran görüntüsü alınıp kaydedilebilmektedir.

System.Drawing ve System.Windows.Forms referanslarını projeye eklemek gerekiyor.

public static void MultipleScreenCapture(string filename)
{
    var ss = new Bitmap(SystemInformation.VirtualScreen.Width,
                        SystemInformation.VirtualScreen.Height,
                        PixelFormat.Format32bppArgb);
 
    Graphics.FromImage(ss).CopyFromScreen(SystemInformation.VirtualScreen.X,
                                          SystemInformation.VirtualScreen.Y,
                                          0,
                                          0,
                                          SystemInformation.VirtualScreen.Size,
                                          CopyPixelOperation.SourceCopy);
 
    ss.Save(filename, ImageFormat.Png);
}