paint-brush
Eşzamansız EventHandler'lar İçin Basit Bir Güvenlik Ağıby@devleader
750
750

Eşzamansız EventHandler'lar İçin Basit Bir Güvenlik Ağı

Dev Leader8m2023/02/14
Read on Terminal Reader
Read this story w/o Javascript

Async void, korkunç async EventHandlers kurulumuna izin verdiğimiz tek istisnadır. Bu yazımda kendi kodunuzda deneyebileceğiniz başka bir çözüm sunacağım. Nasıl kullanılabileceğine ilişkin olarak benim bakış açımdan artılarını ve eksilerini ele alacağız, böylece mantıklı olup olmadığına karar verebilirsiniz.
featured image - Eşzamansız EventHandler'lar İçin Basit Bir Güvenlik Ağı
Dev Leader HackerNoon profile picture

Eşzamansız EventHandler'ları tartıştığımızda çoğumuzun aklına gelen ilk şey, bunun izin verdiğimiz tek istisna olduğudur. korkunç eşzamansız geçersiz kurulum .


Bunun hakkında daha önce yazdığımda, asenkron boşluğun var olmasına izin veren (saçımın geri kalanını yolmak istemeden) bir çözümü araştırdığım için heyecanlanmıştım.


Benim için bu, sorunu tamamen ortadan kaldıracak çözümler sunmaktan çok, eşzamansız EventHandler'ların üstesinden gelmek için kullanabileceğimiz bazı akıllı hilelerle ilgiliydi.


Bununla birlikte, makale üzerinde çok fazla ilgi vardı, buna çok müteşekkirim ve bazı kişiler async EventHandlers'ı farklı bir şekilde çözmeyi tercih edecekleri yönünde görüşlerini ifade ettiler.


Bunun harika bir nokta olduğunu düşündüm, bu yüzden eşzamansız boşluğu düzeltmeyen alternatif bir yaklaşım bulmak istedim, ancak bu, bazı zorlukları çözerken tamamen geçersiz kılmanıza (orada ne yaptığımı gördünüz mü?) olanak tanıyor eşzamansız EventHandlers ile.


Bu yazımda kendi kodunuzda deneyebileceğiniz başka bir çözüm sunacağım. Nasıl kullanılabileceğine ilişkin olarak artılarını ve eksilerini benim bakış açımdan ele alacağız, böylece kullanım durumunuz için anlamlı olup olmadığına karar verebilirsiniz.


Ayrıca .NET keman sağında bazı etkileşimli kodlar da bulabilirsiniz. buraya . Aksi takdirde şunları yapabilirsiniz: GitHub'daki kodu kontrol edin denemek için yerel olarak klonlamak istiyorsanız.

Bir Yardımcı Video!

buraya tıklayın Videoya göz atmak için!

Sorun

Eşzamansız EventHandlers ile karşılaştığımız sorun, C#'ta abone olabileceğimiz olayların imzasının varsayılan olarak şöyle görünmesidir:


 void TheObject_TheEvent(object sender, EventArgs e);


Ve fark edeceksiniz ki, bu imzanın ön yüzünü geçersiz kılarak, etkinliğe abone olmak için kendi işleyicilerimizde void kullanmak zorunda kalıyoruz.


Bu, eğer işleyicinizin eşzamansız/beklemede kod çalıştırmasını istiyorsanız, geçersiz yönteminizin içinde beklemeniz gerektiği anlamına gelir… Bu, veba gibi kaçınmamız söylenen büyük, korkutucu eşzamansız boşluk modelini ortaya çıkarır.


Ve neden? Çünkü async void, istisnaların düzgün bir şekilde ortaya çıkma yeteneğini bozar ve sonuç olarak bir sürü baş ağrısına neden olabilir.


Önceki makale Olayların çağırma tarafında yaratıcı olmamızı sağlayarak bu konuyu ele aldık ama…


  • Olayların çağrılmasını kontrol etmediğimiz nesnelerde bunun için desteğe ihtiyacımız olabilir (örneğin, favori kullanıcı arayüzü çerçevenizde bir düğmenin tıklama olayına bağlanıyorsunuz)


  • Bazı insanlar bu çözümün içindeki bağlamın kullanımını bir hack olarak görüyor (ben de buna katılmıyorum).


  • … Özellikle, olay işleyicileri söz konusu olduğunda, eşzamansız EventHandler'ları desteklemek için yapabileceğimiz başka basit hilelerimiz de var!


Bana göre basit olan daha iyidir… yani eşzamansız geçersizlik hakkındaki önceki makalemi okursanız ve amacınız gerçekten sadece EventHandlers ile uğraşmaksa, bu size yardımcı olacaktır.

Async EventHandler'ları Try/Catch ile Çözme

Daha önce belirtilen koşullara bağlı olarak, istisna işleme, zaman uyumsuz boşluğun sınırlarını aşarak bozulur. Bu sınırı aşması gereken bir istisna varsa, o zaman eğlenceli vakit geçireceksiniz.


Eğlence derken, eğer bir şeyin neden çalışmadığını tespit etmekten hoşlanıyorsanız ve neyin bozulduğuna dair net bir fikriniz yoksa, o zaman gerçekten harika vakit geçireceksiniz.


Peki bunu düzeltmenin en kolay yolu nedir?


Erişebildiğimiz basit bir aracı kullanarak istisnaların bu sınırı aşmasını ilk etapta önleyelim: dene/yakala.


 objectThatRaisesEvent.TheEvent += async (s, e) => { // if the try catch surrounds EVERYTHING in the handler, no exception can bubble up try { await SomeTaskYouWantToAwait(); } catch (Exception ex) { // TODO: put your exception handling stuff here } // no exception can escape here if the try/catch surrounds the entire handler body }


Yukarıdaki kodda belirtildiği gibi, olay işleyicinizin ENTIRE gövdesinin etrafına bir try/catch bloğu yerleştirirseniz, bu zaman uyumsuz boşluk sınırı boyunca herhangi bir istisnanın ortaya çıkmasını önleyebilirsiniz. Görünüşte oldukça basittir ve bunu uygulamak için süslü bir şey gerektirmez.


Artıları:

  • Son derece basit. Anlaşılması gereken karmaşık mekanizmalar yok.


  • Paket gerekmez.


  • Bunun işe yaraması için olayı başlatan sınıfın sahibi olmanıza gerek yok. Bu, bu yaklaşımın WinForms ve WPF UI bileşenleri de dahil olmak üzere mevcut tüm olay yaratan nesneler için çalışacağı anlamına gelir.


Eksileri:

  • Bunu her yerde yapmayı hatırlamanız gerekir.


  • Kodunuz zaman içinde geliştikçe, birisinin yanlışlıkla olay işleyicisinin try-catch dışında istisnalar oluşturabilecek bir mantık yazması mümkündür.


Bununla birlikte, bu çözüm gerçekten basit, ancak biraz daha iyisini yapabileceğimizi düşünüyorum.

Eşzamansız EventHandler'ları İyileştirmeye (Biraz) Daha Meraklı Bir Yaklaşım

Başlangıçta önerilen çözümün üzerine yapabileceğimizi düşündüğüm bir gelişme, istisnaların oluşmasına karşı güvenli olması gereken eşzamansız bir EventHandler'a sahip olduğumuzu biraz daha açık hale getirebilmemizdir.


Bu yaklaşım aynı zamanda zaman içinde kod kaymasının sorunlu kodun olay işleyicinin dışında çalışmasına neden olmasını da önleyecektir. Ancak bunu manuel olarak eklemeyi hatırlamanız gerektiği gerçeğini ele almayacaktır!


Kodu kontrol edelim:

 static class EventHandlers { public static EventHandler<TArgs> TryAsync<TArgs>( Func<object, TArgs, Task> callback, Action<Exception> errorHandler) where TArgs : EventArgs => TryAsync<TArgs>( callback, ex => { errorHandler.Invoke(ex); return Task.CompletedTask; }); public static EventHandler<TArgs> TryAsync<TArgs>( Func<object, TArgs, Task> callback, Func<Exception, Task> errorHandler) where TArgs : EventArgs { return new EventHandler<TArgs>(async (object s, TArgs e) => { try { await callback.Invoke(s, e); } catch (Exception ex) { await errorHandler.Invoke(ex); } }); } }


Yukarıdaki kod, istisnaların eşzamansız boşluk sınırını geçmesini önlemek için kelimenin tam anlamıyla aynı yaklaşımı kullanır. Biz sadece olay işleyicisinin gövdesini yakalamaya çalışıyoruz, ancak şimdi bunu yeniden kullanıma özel bir yöntemle bir araya getirdik.


Bunu uygulamanın nasıl görüneceği aşağıda açıklanmıştır:


 someEventRaisingObject.TheEvent += EventHandlers.TryAsync<EventArgs>( async (s, e) => { Console.WriteLine("Starting the event handler..."); await SomeTaskToAwait(); Console.WriteLine("Event handler completed."); }, ex => Console.WriteLine($"[TryAsync Error Callback] Our exception handler caught: {ex}"));


Artık birlikte çalışabileceğimiz eşzamansız Görev imzasına sahip bir temsilcimiz olduğunu ve içine koyduğumuz her şeyin, daha önce gördüğümüz yardımcı yöntem dahilinde bir deneme/yakalama işlemine sahip olacağından emin olduğumuzu görebiliriz.


Aşağıda, istisnayı düzgün bir şekilde yakalayan hata işleyici geri aramasını gösteren bir ekran görüntüsü verilmiştir:


Eşzamansız EventHandlers için örnek programın çıktısı

Artıları:


  • Yine de çok basit. Sarma işlevi *biraz* daha karmaşıktır, ancak yine de çok basittir.


  • Paket gerekmez.


  • Bunun işe yaraması için olayı başlatan sınıfın sahibi olmanıza gerek yok. Bu, bu yaklaşımın WinForms ve WPF UI bileşenleri de dahil olmak üzere mevcut tüm olay yaratan nesneler için çalışacağı anlamına gelir.


  • İşleyiciyi olaya bağlarken söz dizimi nedeniyle eşzamansız EventHandlers ile çalışmanın amacı daha açıktır.


  • Sonunda daha fazla istisna atan kod kayması yine de try/catch'in içine sarılacak


Eksileri:


  • Hala bu şeyi bağlamayı hatırlaman gerekiyor!

Async EventHandlers Üzerine Düşünceleri Kapatmak

Başlangıçta keşfetmeye çıktığımda asenkron boşlukla başa çıkmanın ilginç yolları , örneklerin eşzamansız EventHandlers'a odaklandığı için okuyucu geri bildirimi geçerliydi ve kesinlikle daha basit bir yol olmalı.


Bu makalede, async EventHandler'larınızın düzgün davranmasını sağlamanın en basit yolunun ne olduğunu tartışabileceğimi araştırdık ve geliştirilmiş çözümün (bence) yalnızca onu kullanmayı hatırlamanız gereken dezavantajı var.


Bir yorumcu kişinin keşfedebileceğini önermişti Yön Odaklı Programlama (AoP) bu tür davranışları uygulamanıza enjekte etmenizi sağlar, böylece bunu yapmayı hatırlamanıza gerek kalmaz.


Bazı derleme zamanı AoP çerçeveleri mevcut, ancak bunu okuyucu olarak size bir alıştırma olarak bırakacağım (çünkü bu aynı zamanda benim için de takip etmem gereken bir alıştırmadır).