Aracılığıyla paylaş


Güvenilirlik En İyi Uygulamalar

Aşağıdaki güvenilirlik kuralları SQL Server'a yöneliktir; ancak, bunlar herhangi bir konak tabanlı sunucu uygulaması için de geçerlidir. SQL Server gibi sunucuların kaynak sızdırmaması ve kapatılmaması son derece önemlidir. Ancak bu, bir nesnenin durumunu değiştiren her yöntem için geri çıkış kodu yazılarak yapılamaz. Hedef, geri alma koduyla her konumdaki hatalardan kurtarılacak yüzde 100 güvenilir yönetilen kod yazmak değildir. Bu, başarı şansı az olan göz korkutucu bir görev olurdu. Ortak dil çalışma zamanı (CLR), mükemmel kod yazmayı mümkün hale getirmek için yönetilen kod için yeterince güçlü garantiler sağlamaz. SQL Server'ın, ASP.NET aksine, kabul edilemez derecede uzun bir süre boyunca bırakılamadan geri dönüştürülemeyecek tek bir süreci kullandığını unutmayın.

Daha zayıf olan bu garantiler ve tek bir işlemde çalışılması sebebiyle, güvenilirlik, gerektiğinde iş parçacıklarının sonlandırılmasına veya uygulama etki alanlarının geri dönüştürülmesine bağlıdır ve işletim sistemi kaynaklarının, örneğin tanıtıcılar ya da belleğin, sızdırılmamasını sağlamak için önlemler alınır. Bu daha basit güvenilirlik kısıtlamasıyla bile önemli bir güvenilirlik gereksinimi vardır:

  • İşletim sistemi kaynaklarını asla sızdırmayın.

  • CLR'deki tüm formlarda bulunan yönetilen kilitleri tanımlayın.

  • Uygulamalar arası etki alanında paylaşılan durumu asla bozmamak, AppDomain geri dönüşüm süreçlerinin sorunsuz çalışmasını sağlar.

Uygulamanın tamamında ThreadAbortException, StackOverflowException, ve OutOfMemoryException özel durumlarını işlemek için yönetilen kod yazmak teorik olarak mümkün olsa da geliştiricilerin bu kadar sağlam kod yazmasını beklemek mantıksızdır. Bu nedenle bant dışı özel durumlar yürütme iş parçacığının sonlandırılmasıyla sonuçlanır; ve sonlandırılan iş parçacığı paylaşılan durumu düzenliyorsa, bu durum iş parçacığının bir kilit barındırıp tutmadığı tarafından belirlenebilir, sonra AppDomain kaldırılır. Paylaşılan durumu düzenleyen bir yöntem sonlandırıldığında, paylaşılan duruma güncelleştirmeler için güvenilir geri alma kodu yazmak mümkün olmadığından durum bozulur.

.NET Framework sürüm 2.0'da güvenilirlik gerektiren tek konak SQL Server'dır. Derlemeniz SQL Server'da çalıştırılacaksa, veritabanında çalıştırılırken devre dışı bırakılan belirli özellikler olsa bile bu derlemenin her bölümü için güvenilirlik çalışması yapmanız gerekir. Kod çözümleme altyapısı kodu derleme düzeyinde incelediğinden ve devre dışı bırakılmış kodu ayırt edemeyeceğinden bu gereklidir. Sql Server programlamada dikkat edilmesi gereken bir diğer nokta da SQL Server'ın her şeyi tek bir işlemde çalıştırması ve AppDomain geri dönüştürmenin bellek ve işletim sistemi tanıtıcıları gibi tüm kaynakları temizlemek için kullanılmasıdır.

Geri çıkış kodu için sonlandırıcılara, yıkıcılara veya try/finally bloklara bağımlı olamazsınız. Bunlar kesintiye uğrayabilir veya çağrılmayabilir.

Zaman uyumsuz özel durumlar beklenmeyen konumlarda, büyük olasılıkla her makine yönergesinde oluşturulabilir: ThreadAbortException, StackOverflowException, ve OutOfMemoryException.

SQL'deki yönetilen iş parçacıkları her zaman Win32 iş parçacıkları olmak zorunda değildir; bunlar lifler olabilir.

İşlem genelinde veya uygulama alanı arasında değiştirilebilir paylaşılan durumun güvenli bir şekilde değiştirilmesi son derece zordur ve mümkün olduğunda bundan kaçınılmalıdır.

SQL Server'da yetersiz bellek koşulları nadir değildir.

SQL Server'da barındırılan kitaplıklar paylaşılan durumlarını doğru güncelleştirmezse, veritabanı yeniden başlatılana kadar kodun kurtarılmama olasılığı yüksektir. Buna ek olarak, bazı aşırı durumlarda, bu SQL Server işleminin başarısız olmasına ve veritabanının yeniden başlatılmasına neden olabilir. Veritabanını yeniden başlatmak bir Web sitesini çökertebilir veya şirket operasyonlarını etkileyerek kullanılabilirliği olumsuz etkileyebilir. Bellek veya tanıtıcılar gibi işletim sistemi kaynaklarının yavaş sızması, sunucunun kurtarma olasılığı olmayan tanıtıcıları ayırmada başarısız olmasına neden olabilir veya sunucunun performansı yavaş yavaş düşebilir ve müşterinin uygulama kullanılabilirliğini azaltabilir. Bu senaryolardan kaçınmak istediğimiz açıktır.

En iyi yöntem kuralları

Giriş bölümü, sunucuda çalışan yönetilen kodun çerçevenin kararlılığını ve güvenilirliğini artırmak için kod incelemesinde tespit etmesi gereken unsurlara odaklanıyordu. Tüm bu denetimler genel olarak iyi bir uygulamadır ve sunucuda mutlak bir uygulama olmalıdır.

Kilitlenme veya kaynak kısıtlaması karşısında, SQL Server bir iş parçacığını durduracak veya bir AppDomainöğesini yok edecektir. Bu durumda, yalnızca kısıtlanmış yürütme bölgesindeki (CER) geri çıkış kodunun çalıştırılması garanti edilir.

Kaynak sızıntılarını önlemek için SafeHandle kullanma

Kaldırma durumunda, AppDomain blokların veya sonlandırıcıların yürütülmesine bağımlı olamazsınız; bu nedenle, tüm işletim sistemi kaynak erişimini finally, SafeHandle veya benzeri sınıflar yerine IntPtr sınıfı aracılığıyla soyutlamak önemlidir. Bu, CLR'nin yırtılma durumunda bile kullandığınız tutamaçları izlemesine ve kapatmasına AppDomain olanak tanır. SafeHandle , CLR'nin her zaman çalıştıracağı kritik bir sonlandırıcı kullanacaktır.

İşletim sistemi tanıtıcısı, oluşturulduğu andan yayınlandığı ana kadar güvenli tanıtıcıda depolanır. ThreadAbortException oluştuğunda bir tutamacın sızabileceği bir fırsat yoktur. Buna ek olarak, platform çağrısı, tanıtıcının ömrünü yakından takip etmek için tanıtıcıya referans sayımı yapar ve şu anda tanıtıcıyı kullanan bir yöntem ile Dispose arasındaki yarış durumuna bağlı bir güvenlik sorununu önler.

Şu anda bir işletim sistemi tutamacını temizlemek için sonlandırıcı kullanan sınıfların çoğu artık sonlandırıcıya ihtiyaç duymayacak. Bunun yerine, SafeHandle sonlandırıcı türetilmiş sınıfta olacaktır.

SafeHandle öğesinin IDisposable.Dispose yerine geçmediğini unutmayın. İşletim sistemi kaynaklarını açıkça serbest bırakırken kaynak kullanımı çatışması ve performans avantajları hala mevcut olabilir. Kaynakları açıkça elden çıkaran finally blokların, tamamlanamadan yürütülmeyebileceğini fark edin.

SafeHandle, bir işletim sistemi işleme serbest bırakma rutinine durumu aktarma veya bir döngüdeki tanıtıcı kümesini serbest bırakma gibi, tanıtıcıyı serbest bırakma işlemini gerçekleştiren kendi ReleaseHandle yönteminizi uygulamanıza olanak tanır. CLR, bu yöntemin çalıştırılmasını garanti eder. Uygulamanın ReleaseHandle yazarının sorumluluğu, tanıtıcının her koşulda serbest bırakılmasını sağlamaktır. Bunu yapmamak kolun sızmasına neden olur, bu da genellikle kolla ilişkili yerel kaynakların sızmasına yol açar. Bu nedenle, SafeHandle türetilmiş sınıflar, ReleaseHandle uygulamasının çağrı zamanında kullanılamayabilecek kaynakların ayrılmasını gerektirmemesi için yapılandırılması kritik öneme sahiptir. Kodunuz bu tür hataları işleyebilir ve yerel tanıtıcıyı serbest bırakma sözleşmesini tamamlayabilirse, ReleaseHandle uygulamanızda başarısız olabilecek yöntemleri çağırmanın izinli olduğunu unutmayın. Hata ayıklama amacıyla, kaynağın serbest bırakılmasını engelleyen bir yıkıcı hatayla karşılaşılırsa ReleaseHandle olarak ayarlanabilecek bir dönüş değeri vardır Booleanfalse. Bunu yaptığınızda, sorunun tanımlanmasına yardımcı olması için releaseHandleFailed MDA etkinleştirilir. Çalışma süresini başka bir şekilde etkilemez; ReleaseHandle aynı kaynak için yeniden çağrılmaz ve sonuç olarak tanıtıcı boşa harcanır.

SafeHandle belirli bağlamlarda uygun değildir. ReleaseHandle yöntemi bir sonlandırıcı iş parçacığında çalıştırılabildiği için, belirli bir GC iş parçacığında serbest bırakılması gereken tüm tanıtıcılar SafeHandle içine sarılmamalıdır.

Çalışma zamanı çağrılabilen sarmalayıcılar (RCW) ek kod olmadan CLR tarafından temizlenebilir. Platformsal çağrıyı kullanan ve bir COM nesnesini bir IUnknown* veya IntPtr olarak değerlendiren kod için, kod RCW kullanarak yeniden yazılmalıdır. SafeHandle yönetilen koda geri çağrı yapabilecek bir kontrolsüz sürüm yöntemi olasılığı nedeniyle bu senaryo için yeterli olmayabilir.

Kod analizi kuralı

İşletim sistemi kaynaklarını kapsüllemek için kullanın SafeHandle . HandleRef veya IntPtr türünde alanları kullanmayın.

İşletim sistemi kaynaklarının sızmasını önlemek için sonlandırıcıların çalıştırılması gerekmediğinden emin olun

Çalışmasalar bile kritik bir işletim sistemi kaynağının sızdırılmadığından emin olmak için sonlandırıcılarınızı dikkatle gözden geçirin. Uygulama sabit bir durumda yürütülürken veya SQL Server gibi bir sunucu kapatıldığında normal AppDomain bir yüklemeden farklı olarak, nesneler ani AppDomain bir kaldırma işlemi sırasında sonlandırılmaz. Ani bir kaldırma durumunda kaynakların sızdırılmadığından emin olun, çünkü uygulamanın doğruluğu garanti edilemez, ancak kaynakların sızdırılmamasıyla sunucunun bütünlüğü korunmalıdır. tüm işletim sistemi kaynaklarını boşaltmak için kullanın SafeHandle .

İşletim sistemi kaynaklarının sızmasını önlemek için finally yan tümcelerinin çalışmak zorunda kalmamasını sağlayın.

finally yan tümcelerinin CER'lerin dışında çalıştırılması garanti edilemez ve kitaplık geliştiricilerinin yönetilmeyen kaynakları serbest bırakmaları için bir finally blok içindeki koda güvenmemesi gerekir. Önerilen çözüm SafeHandle kullanmaktır.

Kod analizi kuralı

İşletim sistemi kaynaklarını temizlemek için SafeHandle kullanın; Finalize yerine. kullanmayın IntPtr; kaynakları kapsüllemek için kullanın SafeHandle . finally yan tümcesinin çalışması gerekiyorsa, bunu bir CER'ye yerleştirin.

Tüm kilitler mevcut yönetilen kilitleme kodundan geçmelidir

CLR kodun ne zaman bir kilit içinde olduğunu bilmeli, böylece iş parçacığını iptal etmek yerine AppDomain öğesini yıkabileceğini bilmelidir. İş parçacığının sonlandırılması tehlikeli olabilir, çünkü iş parçacığı tarafından işlenen veriler tutarsız bir durumda bırakılabilir. Bu nedenle, tüm AppDomain geri dönüştürülmek zorunda. Bir kilidin tanımlanamamasının sonuçları kilitlenmeler veya yanlış sonuçlar olabilir. Kilit bölgelerini BeginCriticalRegion tanımlamak için ve EndCriticalRegion yöntemlerini kullanın. Bunlar, Thread sınıfındaki ve sadece mevcut iş parçacığı için geçerli olan statik yöntemlerdir ve bir iş parçacığının başka bir iş parçacığının kilit sayısını düzenlemesini önlemeye yardımcı olur.

Enter ve Exit bu CLR bildirimini yerleşik olarak kullandığınızdan, kullanımlarının yanı sıra bu yöntemleri kullanan lock Deyiminin kullanılması önerilir.

Diğer kilitleme mekanizmaları olan döndürme kilitleri ve AutoResetEvent, kritik bir bölüm girildiğini CLR'ye bildirmek için bu yöntemleri çağırmalıdır. Bu yöntemler herhangi bir kilit almaz; CLR'ye kodun kritik bir bölümde yürütüldüğünü ve iş parçacığını durdurmanın paylaşılan durumu tutarsız bırakabileceğini bildirir. Özel ReaderWriterLock sınıf gibi kendi kilit türünüzü tanımladıysanız, bu kilit sayısı yöntemlerini kullanın.

Kod analizi kuralı

İşaretleyin ve BeginCriticalRegion ve EndCriticalRegion kullanarak tüm kilitleri tanımlayın. Bir döngüde CompareExchange, Increment ve Decrement kullanmayın. Bu yöntemlerin Win32 varyantlarını platform çağrısı olarak çağırmayın. Döngüde Sleep kullanmayın. Volatile alanlar kullanmayın.

Temizleme kodu, bir finally veya catch bloğunda olmalıdır, bir catch bloğunu takip etmemelidir.

Temizleme kodu hiçbir zaman bir catch bloğunu takip etmemelidir; bir finally bloğunda veya catch bloğunun içinde olmalıdır. Bu normal bir iyi uygulama olmalıdır. Blok finally genellikle tercih edilir çünkü hem özel durum oluştuğunda hem de bloğun try sonuna normalde karşılaşıldığında aynı kodu çalıştırır. Beklenmeyen bir özel durum oluştuğunda, örneğin bir ThreadAbortExceptiontemizleme kodu çalışmaz. finally öğesinde temizleyeceğiniz yönetilmeyen kaynaklar, sızıntıları önlemek için ideal olarak SafeHandle içine sarmalanmalıdır. C# using anahtar sözcüğünün, tanıtıcılar da dahil olmak üzere nesneleri bertaraf etmek için etkili bir şekilde kullanılabileceğini unutmayın.

Geri dönüşüm, sonlandırıcı iş parçacığındaki kaynakları temizleyebilir, ancak AppDomain temizleme kodunu doğru yere yerleştirmek yine de önemlidir. Bir iş parçacığı kilit tutmadan zaman uyumsuz bir özel durum alırsa, CLR'nin geri dönüşüme gerek kalmadan iş parçacığının kendisini sonlandırmaya çalıştığına AppDomaindikkat edin. Kaynakların daha sonra değil daha önce temizlenmesini sağlamak, daha fazla kaynağın kullanılabilir olmasını sağlayarak ve kullanım ömrünü daha iyi yöneterek yardımcı olur. Bazı hata kodu yollarında bir dosya tanıtıcısını açıkça kapatmıyorsanız ve sonlandırıcının SafeHandle temizlemesini bekliyorsanız, sonlandırıcı henüz çalışmadıysa kodunuzun bir sonraki çalıştırmasında tam olarak aynı dosyaya erişme girişimi başarısız olabilir. Bu nedenle, temizleme kodunun mevcut olduğundan ve düzgün çalıştığından emin olmak, kesinlikle gerekli olmasa bile hatalardan daha temiz ve hızlı bir şekilde kurtulmaya yardımcı olur.

Kod analizi kuralı

Temizleme kodu catch sonrasında, finally bloğunda olmalıdır. Çağrıları bir finally bloğuna koyarak dispose edin. catch blokları bir throw veya rethrow ile sona ermelidir. Çok sayıda özel durumdan herhangi birini alabileceğiniz bir ağ bağlantısının kurulup kurulamayacağını algılayan kod gibi özel durumlar olsa da, normal koşullarda bir dizi özel durumun yakalanmasını gerektiren tüm kodlar, kodun başarılı olup olmadığını görmek için test edilmesi gerektiğini belirtmelidir.

Uygulama etki alanları arasındaki Process-Wide değişken paylaşımlı durum ya ortadan kaldırılmalı ya da kısıtlanmış yürütme bölgesi kullanılmalıdır.

Giriş bölümünde açıklandığı gibi, uygulama etki alanları arasında işlem genelinde paylaşılan durumu güvenilir bir şekilde izleyen yönetilen kod yazmak çok zor olabilir. İşlem genelinde paylaşılan durum, Win32 kodunda, CLR'nin içinde veya uzaktan iletişim kullanan yönetilen kodda uygulama etki alanları arasında paylaşılan her tür veri yapısıdır. Herhangi bir değiştirilebilir paylaşılan durumun yönetilen kodda doğru yazılması çok zordur ve statik paylaşılan durum yalnızca büyük bir dikkatle yapılabilir. İşlem genelinde veya makine genelinde paylaşılan durumunuz varsa, bunu ortadan kaldırmanın veya kısıtlanmış yürütme bölgesi (CER) kullanarak paylaşılan durumu korumanın bir yolunu bulun. Kimliği belirlenmeyen ve düzeltilmeyen paylaşılan duruma sahip herhangi bir kütüphanenin, temiz AppDomain kaldırma gerektiren SQL Server gibi bir konağın kilitlenmesine neden olabileceğini göz önünde bulundurun.

Kod bir COM nesnesi kullanıyorsa, bu COM nesnesini uygulama etki alanları arasında paylaşmaktan kaçının.

Kilitler işlem genelinde veya uygulama etki alanları arasında çalışmaz.

Geçmişte, Enter ve lock Deyimi genel işlem kilitleri oluşturmak için kullanılmıştır. Örneğin, AppDomain çevik sınıflara kilitleme işlemi yapıldığında, paylaşılan olmayan derlemelerden gelen örnekler, nesneler, iç paylaşıma alınmış dizeler ve uzaktan iletişim kullanılarak uygulama etki alanları arasında paylaşılan bazı dizeler söz konusu olduğunda, bu durum meydana gelir. Bu kilitler artık işlem genelinde değildir. İşlem genelinde bir uygulama etki alanı kilidinin varlığını belirlemek için, kilit içindeki kodun disk üzerindeki bir dosya veya büyük olasılıkla bir veritabanı gibi dış, kalıcı bir kaynak kullanıp kullanmadığını belirleyin.

Korumalı kod bir dış kaynak kullanıyorsa bir AppDomain içinde kilit almanın sorunlara neden olabileceğini unutmayın çünkü bu kod birden çok uygulama etki alanı arasında aynı anda çalıştırılabilir. Bu, bir günlük dosyasına yazarken veya işlemin tamamı için bir yuvaya bağlanırken sorun olabilir. Bu değişiklikler, adlandırılmış Mutex veya Semaphore örnek kullanmak dışında işlem genel kilidi almak için yönetilen kodu kullanmanın kolay bir yolu olmadığı anlamına gelir. İki uygulama etki alanında aynı anda çalışmayan kod oluşturun veya Mutex veya Semaphore sınıflarını kullanın. Mevcut kod değiştirilemiyorsa, bu eşitlemeyi gerçekleştirmek için mutex adlı bir Win32 kullanmayın çünkü fiber modunda çalıştırmak, aynı işletim sistemi iş parçacığının bir mutex alıp serbest bırakacağını garanti edemeyeceğiniz anlamına gelir. Kod kilidini yönetilmeyen kod kullanarak eşitlemek yerine, CLR'nin farkında olduğu şekilde eşitlemek için yönetilen Mutex sınıfını veya adlandırılmış ManualResetEvent, AutoResetEvent veya Semaphore sınıflarını kullanmanız gerekir.

Lock(typeof(MyType)) kullanmaktan kaçının

Tüm uygulama etki alanlarında paylaşılan kodun yalnızca bir kopyasına sahip paylaşılan derlemelerdeki özel ve genel Type nesneler de sorun sunar. Paylaşılan derlemeler için işlem başına yalnızca bir Type örnek vardır ve bu da birden çok uygulama etki alanının aynı Type örneği paylaştığı anlamına gelir. Bir Type örneğine kilit almak, yalnızca AppDomain'i değil, tüm süreci etkileyen bir kilit alır. AppDomain Bir nesne kilitlenirseType, bu iş parçacığı aniden durdurulur, kilidi serbest bırakmaz. Bu kilit daha sonra diğer uygulama etki alanlarının kilitlenmesine neden olabilir.

Statik yöntemlerde kilitleri almak için iyi bir yol, koda statik iç eşitleme nesnesi eklemeyi içerir. Bu, varsa sınıf oluşturucusunda başlatılabilir, ancak değilse şu şekilde başlatılabilir:

private static Object s_InternalSyncObject;
private static Object InternalSyncObject
{
    get
    {
        if (s_InternalSyncObject == null)
        {
            Object o = new Object();
            Interlocked.CompareExchange(
                ref s_InternalSyncObject, o, null);
        }
        return s_InternalSyncObject;
    }
}

Daha sonra kilitleme sırasında, kilitlemek için üzerine nesne elde etmek amacıyla InternalSyncObject özelliğinden yararlanın. Sınıf oluşturucunuzda iç eşitleme nesnesini başlatmışsanız özelliğini kullanmanız gerekmez. Çift denetim kilidi başlatma kodu şu örnekteki gibi görünmelidir:

public static MyClass SingletonProperty
{
    get
    {
        if (s_SingletonProperty == null)
        {
            lock(InternalSyncObject)
            {
                // Do not use lock(typeof(MyClass))
                if (s_SingletonProperty == null)
                {
                    MyClass tmp = new MyClass(…);
                    // Do all initialization before publishing
                    s_SingletonProperty = tmp;
                }
            }
        }
        return s_SingletonProperty;
    }
}

Kilitle ilgili bir not(bu)

Genel olarak erişime açık olan tek bir nesne üzerinde kilit almak kabul edilebilir. Ancak, nesne bir alt sistemin tamamının kilitlenmesine neden olabilecek tek bir nesneyse, yukarıdaki tasarım desenini de kullanmayı göz önünde bulundurun. Örneğin, bir SecurityManager nesnesindeki bir kilit, AppDomain içinde bir tıkanıklığa neden olarak tüm AppDomain nesnesini kullanılamaz hale getirebilir. Bu türdeki genel olarak erişilebilir bir nesneye kilitlenmemek iyi bir uygulamadır. Ancak tek bir koleksiyon veya dizideki kilit genel olarak bir sorun oluşturmamalıdır.

Kod analizi kuralı

Uygulama etki alanları arasında kullanılabilecek veya güçlü bir kimlik hissine sahip olmayan türlerde kilit oluşturmayın. Enter öğesini Type, MethodInfo, PropertyInfo, String, ValueType, Thread veya MarshalByRefObject öğesinden türetilmiş herhangi bir nesne üzerinde çağırmayın.

GC.KeepAlive çağrılarını kaldırın

Mevcut kodun önemli bir kısmı, gerektiğinde KeepAlive'yi kullanmaz veya uygun olmadığında kullanır. Dönüştürdükten sonra SafeHandle, sınıfların sonlandırıcıya sahip olmadığı varsayıldığında, işletim sistemi tanıtıcılarının sonlandırılması için KeepAlive kullanıldığı sürece SafeHandle çağrılmasına gerek yoktur. KeepAlive çağrısını tutmanın performans maliyeti göz ardı edilebilir olsa da, KeepAlive çağrısının artık mevcut olmayabilecek bir ömür sorununu çözmek için gerekli veya yeterli olduğu algısı, kodun bakımını daha zor hale getirir. Ancak, COM birlikte çalışabilen CLR tarafından çağrılabilen sarmalayıcılar (RCW'ler) kullanıldığında, KeepAlive kod için hala gereklidir.

Kod analizi kuralı

"Bu öğeyi kaldırın KeepAlive."

HostProtection Özniteliğini Kullanma

HostProtectionAttribute (HPA), Exit veya Show gibi SQL Server için uygun olmayan yöntemleri çağırmasını engelleyerek, konak koruma gereksinimlerini belirlemek için deklaratif güvenlik eylemlerinin kullanılmasını sağlar; bu sayede konak, tamamen güvenilen kodun dahi çağrı yapmasını önleyebilir.

HPA yalnızca ortak dil çalışma zamanını barındıran ve SQL Server gibi konak koruması uygulayan yönetilmeyen uygulamaları etkiler. Uygulandığında, güvenlik işlemi, sınıfın veya yöntemin erişime sunduğu sunucu kaynaklarına göre bir bağlantı talebi oluşturulmasına yol açar. Kod bir istemci uygulamasında veya konak korumalı olmayan bir sunucuda çalıştırılıyorsa, "buharlaşır" özniteliği; algılanmaz ve bu nedenle uygulanmaz.

Önemli

Bu özniteliğin amacı, güvenlik davranışını değil konağa özgü programlama modeli yönergelerini zorunlu kılmaktır. Programlama modeli gereksinimlerine uyumluluğu denetlemek için bir bağlantı talebi kullanılsa da, HostProtectionAttribute bu bir güvenlik izni değildir.

Konağın programlama modeli gereksinimleri yoksa, bağlantı talepleri gerçekleşmez.

Bu öznitelik aşağıdakileri tanımlar:

  • Konak programlama modeline uymayan, ancak aksi takdirde zararsız olan yöntemler veya sınıflar.

  • Konak programlama modeline uymayan ve sunucu tarafından yönetilen kullanıcı kodunun istikrarsızlaştırılmasına neden olabilecek yöntemler veya sınıflar.

  • Ana programlama modeline uymayan ve sunucu sürecinin kendisinde istikrarsızlığa yol açabilen yöntemler veya sınıflar.

Uyarı

İçine alıcı korumalı bir ortamda çalışabilecek uygulamalar tarafından erişilecek bir sınıf kütüphanesi oluşturuyorsanız, bu özniteliği kaynak kategorilerini ifşa eden üyelere uygulamanız gerekir. Bu özniteliğe sahip .NET Framework sınıf kitaplığı üyeleri yalnızca hemen çağıranın denetlenmesini tetikler. Kütüphane öğeniz doğrudan çağıranı kontrol etmesini de aynı şekilde sağlamalıdır.

Lütfen HostProtectionAttribute içinde HPA hakkında daha fazla bilgi bulabilirsiniz.

Kod analizi kuralı

SQL Server için, eşitleme veya iş parçacığı oluşturma amacıyla kullanılan tüm yöntemlerin HPA ile tanımlanması gerekir. Bu, durumu paylaşan, eşitlenen veya dış işlemleri yöneten yöntemleri içerir. SQL Server'ı etkileyen değerler HostProtectionResource, SharedState, Synchronization ve ExternalProcessMgmt şeklindedir. Ancak, yalnızca SQL'i etkileyen kaynakları kullanan yöntemler değil, herhangi bir HostProtectionResource içeren tüm yöntemler bir HPA tarafından tanımlanmalıdır.

Yönetilmeyen kodda süresiz olarak engellemeyin

Yönetilen kod yerine yönetilmeyen kodda engelleme yapmak, CLR'nin iş parçacığını durduramaması nedeniyle hizmet reddi saldırısına yol açabilir. Engellenen iş parçacığı, CLR'nin, en azından bazı son derece güvensiz işlemler yapmadan AppDomain öğesini kaldırmasını engeller. Windows eşitleme temel öğesini kullanarak engelleme, izin veremediğimiz bir şeyin açık bir örneğidir. Bir sokette ReadFile çağrısının engellenmesinden mümkün olduğunca kaçınılmalıdır; ideal olarak, Windows API'nin böyle bir işlemi zaman aşımına uğratacak bir mekanizma sağlaması gerekir.

Yerel kod çağıran herhangi bir yöntem, ideal olarak, makul ve sonlu bir zaman aşımı ile Win32 çağrısı kullanmalıdır. Kullanıcının zaman aşımını belirtmesine izin veriliyorsa, kullanıcının belirli bir güvenlik izni olmadan sonsuz bir zaman aşımı belirtmesine izin verilmemelidir. Kılavuz olarak, bir yöntem yaklaşık 10 saniyeden uzun süre engellenecekse, zaman aşımlarını destekleyen bir sürüm kullanıyor olmanız veya ek CLR desteğine ihtiyacınız vardır.

Sorunlu API'lere bazı örnekler aşağıda verilmiştir. Kanallar (hem anonim hem de adlandırılmış) zaman aşımı ile oluşturulabilir; ancak kodun, hiçbir zaman CreateNamedPipe veya WaitNamedPipe'i NMPWAIT_WAIT_FOREVER ile çağırmadığından emin olunmalıdır. Ayrıca, zaman aşımı belirtilse bile beklenmeyen engellemeler olabilir. Anonim bir boru hattında WriteFile çağrısı yapmak, tüm baytlar yazılana kadar bekler, yani arabellekte okunmamış veri varsa, WriteFile çağrısı okuyucu borunun arabelleğinde yer açana kadar bekler. Soketler her zaman bir zaman aşımı mekanizmasını dikkate alan bir API kullanmalıdır.

Kod analizi kuralı

Yönetilmeyen kodda zaman aşımı olmadan engelleme bir hizmet reddi saldırısıdır. WaitForSingleObject, WaitForSingleObjectEx, WaitForMultipleObjects, MsgWaitForMultipleObjects ve MsgWaitForMultipleObjectsEx için platform çağırma çağrıları gerçekleştirmeyin. NMPWAIT_WAIT_FOREVER kullanmayın.

tüm STA-Dependent özelliklerini tanımlama

COM tek iş parçacıklı yapılandırmaları (STA) kullanan herhangi bir kodu belirleyin. STA'lar SQL Server işleminde devre dışı bırakılır. CoInitialize öğesine bağlı olan performans sayaçları veya clipboard gibi özellikler, SQL Server içinde devre dışı bırakılması gerekmektedir.

Sonlandırıcıların senkronizasyon sorunlarından arındırılmış olduğundan emin olun

.NET Framework'ün gelecek sürümlerinde birden çok sonlandırıcı iş parçacığı olabilir, yani aynı türün farklı örnekleri için sonlandırıcılar aynı anda çalıştırılır. Tam anlamıyla iş parçacığı güvenli olması gerekmez; çöp toplayıcı, belirli bir nesne örneği için sonlandırıcıyı yalnızca bir iş parçacığının çalıştıracağını garanti eder. Ancak, birden çok farklı nesne örneğinde aynı anda çalışırken yarış koşullarını ve kilitlenmeleri önlemek için sonlandırıcıların kodlanması gerekir. Sonlandırıcıda, günlük dosyasına yazma gibi herhangi bir dış durum kullanılırken iş parçacığı sorunları ele alınmalıdır. İş parçacığı güvenliği sağlamak için bitirme işlemine güvenmeyin. Sonlandırıcı iş parçacığında durumu depolamak için yönetilen veya yerel iş parçacığına özgü depolama kullanmayın.

Kod analizi kuralı

Sonlandırıcılar senkronizasyon sorunlarından tamamen arındırılmalıdır. Sonlandırıcıda statik bir değiştirilebilir durum kullanmayın.

Mümkünse yönetilmeyen bellekten kaçının

Yönetilmeyen bellek, işletim sistemi tutamacı gibi sızdırılabilir. Mümkünse stackalloc veya fixed ifadesi gibi sabitlenmiş yönetilen bir nesne ya da GCHandle bayt[] kullanarak yığıtta bellek kullanmayı deneyin. Sonunda GC bunları temizler. Ancak, yönetilmeyen belleği ayırmanız gerekiyorsa, bellek ayırma işlemine uygun bir yapı oluşturmak için SafeHandle öğesinden türetilen bir sınıf kullanmayı düşünün.

Yeterli olmayan en az bir durum SafeHandle olduğunu unutmayın. COM yöntemi çağrılarında bellek ayırma veya boşaltma söz konusu olduğunda, bir DLL'nin belleği CoTaskMemAlloc kullanarak ayırması ve ardından başka bir DLL'nin CoTaskMemFree ile bu belleği boşaltması yaygın bir durumdur. SafeHandle'yi bu yerlerde kullanmak, belleğin ömrünü kontrol etmesi gereken diğer DLL yerine SafeHandle'nin ömrüne bağlamaya çalışacağı için uygun olmayacaktır.

Catch(Exception) tüm kullanımlarını gözden geçirin.

Belirli bir özel durum yerine tüm özel durumları yakalayan catch blokları artık zaman uyumsuz özel durumları da yakalar. Her catch(Exception) bloğunu inceleyin; atlanan önemli kaynak serbest bırakma veya geri alma kodlarının yanı sıra ThreadAbortException, StackOverflowException veya OutOfMemoryException işlemek için catch bloğunun kendi içinde potansiyel olarak hatalı davranışları arayın. Bu kodun günlüğe kaydediyor veya bazı varsayımlar yapıyor olabileceğini ve yalnızca bazı özel durumları görebileceğini ya da bir özel durum gerçekleştiğinde tam olarak belirli bir nedenden dolayı başarısız olduğunu unutmayın. Bu varsayımlar ThreadAbortException'ü içerecek şekilde güncellenebilir.

Dize biçimlendirme yöntemleri gibi, tüm özel durumları yakalayan tüm yerleri, oluşturulacağını beklediğiniz belirli bir FormatException özel durum türünü yakalayacak şekilde değiştirmeyi göz önünde bulundurun. Bu, catch bloğunun beklenmeyen özel durumlarda çalışmasını engeller ve kodun beklenmeyen özel durumlar yakalayarak hataları gizlememesini sağlamaya yardımcı olur. Genel bir kural olarak hiçbir zaman kitaplık kodundaki bir özel durumu işlemez (bir özel durumu yakalamanızı gerektiren kod, çağırdığınız kodda tasarım kusurunu gösterebilir). Bazı durumlarda bir özel durum yakalamak ve daha fazla veri sağlamak için farklı bir özel durum türü oluşturmak isteyebilirsiniz. Bu durumda iç içe özel durumları kullanın ve hatanın gerçek nedenini yeni özel durumun özelliğinde InnerException depolar.

Kod analizi kuralı

Yönetilen koddaki tüm nesneleri yakalayan veya tüm özel durumları yakalayan tüm yakalama bloklarını gözden geçirin. C# dilinde bu, hem catch{} hem de catch(Exception){} işaretleme anlamına gelir. Özel durum türünü çok özel hale getirebilirsiniz veya beklenmeyen bir özel durum türü yakalarsa kötü bir şekilde davranmadığından emin olmak için kodu gözden geçirin.

Yönetilen iş parçacığının win32 iş parçacığı olduğunu varsaymayın – Fiber

Yönetilen iş parçacığı yerel depolamayı kullanmak işe yarayabilir, ancak yönetilmeyen iş parçacığı yerel depolama alanı kullanmayabilir veya kodun geçerli işletim sistemi iş parçacığında yeniden çalıştırılacağını varsayabilirsiniz. Dil ayarı gibi ayarları değiştirmeyin. InitializeCriticalSection veya CreateMutex'yi platform çağrısı ile çağırmayın çünkü bir kilit içine giren işletim sistemi iş parçacığının aynı zamanda kilitten çıkması gerekmektedir. Fiber kullanılırken bu durum söz konusu olmadığından Win32 kritik bölümleri ve muteksleri doğrudan SQL'de kullanılamaz. Yönetilen Mutex sınıfın bu iş parçacığı benzimliği sorunlarını işlemediğini unutmayın.

Yönetilen iş parçacığı yerel depolama alanı ve iş parçacığının geçerli kullanıcı arabirimi kültürü de dahil olmak üzere yönetilen bir Thread nesnedeki durumun çoğunu güvenle kullanabilirsiniz. Ayrıca, mevcut bir statik değişkenin değerini yalnızca geçerli yönetilen iş parçacığı tarafından erişilebilir hale getiren öğesini de kullanabilirsiniz ThreadStaticAttribute(bu, CLR'de fiber yerel depolama yapmanın başka bir yoludur). Programlama modeli nedenleriyle, SQL'de çalışırken iş parçacığının geçerli kültürünü değiştiremezsiniz.

Kod analizi kuralı

SQL Server fiber modunda çalışır; yerel iş parçacığı depolamasını kullanmayın. Platform çağrılarını TlsAlloc, TlsFree, TlsGetValue, ve TlsSetValue. için kullanmaktan kaçının.

SQL Server'ın kimliğe bürünme işlemlerini işlemesine izin ver

Kimliğe bürünme iş parçacığı düzeyinde çalıştığından ve SQL fiber modunda çalışabildiğinden, yönetilen kod kullanıcıların kimliğine bürünmemeli ve RevertToSelf çağrılmamalıdır.

Kod analizi kuralı

Kimliğe bürünme işlemlerini SQL Server'ın işlemesine izin verin. RevertToSelf, ImpersonateAnonymousToken, DdeImpersonateClient, ImpersonateDdeClientWindow, ImpersonateLoggedOnUser, ImpersonateNamedPipeClient, ImpersonateSelf, RpcImpersonateClient, RpcRevertToSelf, RpcRevertToSelfEx veya SetThreadToken kullanmayın.

Thread::Suspend'i çağırmayın.

Bir iş parçacığını askıya alma özelliği basit bir işlem gibi görünebilir, ancak kilitlenmelere neden olabilir. Kilit tutan bir iş parçacığı ikinci bir iş parçacığı tarafından askıya alınırsa ve ikinci iş parçacığı aynı kilidi almayı denerse, kilitlenme oluşur. Suspend şu anda güvenlik, sınıf yükleme, uzaktan iletişim ve yansımayı etkileyebilir.

Kod analizi kuralı

çağrısı Suspendyapma. Bunun yerine Semaphore veya ManualResetEvent gibi gerçek bir eşitleme yapı taşını kullanmayı göz önünde bulundurun.

Kısıtlanmış yürütme bölgeleri ve güvenilirlik sözleşmeleriyle kritik işlemleri koruma

Paylaşılan durumu güncelleştiren veya kesin olarak tamamen başarılı veya tamamen başarısız olması gereken karmaşık bir işlem gerçekleştirirken, bunun kısıtlanmış yürütme bölgesi (CER) tarafından korunduğundan emin olun. Bu, kodun her durumda, ani bir iş parçacığı iptali veya AppDomain ani bir kaldırma işlemi ile bile çalışmasını garanti eder.

CER, çağrısından hemen önce gelen belirli try/finally bir bloktur PrepareConstrainedRegions.

Bunu yapmak, bloğu çalıştırmadan önce just-in-time derleyicisinin finally bloğundaki tüm kodu hazırlamasını sağlar. Bu, finally bloğundaki kodun derlendiğini ve her durumda çalıştırılacağını garanti eder. Cer'de boş try bir bloğun olması sık karşılaşılan bir durum değildir. CER kullanmak, eşzamanlı olmayan iş parçacığı iptallerine ve bellek yetersizliği durumlarına karşı koruma sağlar. Aşırı derin kod için yığın taşmalarını ek olarak işleyen bir CER biçimi için bkz ExecuteCodeWithGuaranteedCleanup .

Ayrıca bakınız