Faydalı Visual Studio Kısayolları

Diğer IDE’lerde olduğu gibi Visual Studio’da da çok çeşitli kısayollar mevcuttur. Üretkenliği arttırmak için çok kullanılan kısayolları bilmek gerekir. Yazılım geliştirirken sık kullandığım kısayollar aşağıdaki gibidir.

Edit.CompleteWord ALT+RIGHT ARROW or CTRL+SPACEBAR or CTRL+K, W
Edit.FindAllReferences CTRL+K, R veya SHIFT+F12
Edit.GoToDefinition F12
View.PropertiesWindow F4
View.ViewCode F7
View.ViewDesigner SHIFT+F7
Debug.Start F5
Debug.StepInto F11
Debug.StepOver F10

Kısayolların tam listesi için aşağıdaki sayfayı ziyaret edebilirsiniz.
Visual Studio Kısayolları

Custom Attribute Oluşturma

TC kimlik numarası ve cep telefonu için alan doğrulama amaçlı yazdığım attribute’ler aşağıdadır.

Tckn.cs

using System;
using System.ComponentModel.DataAnnotations;
using System.Globalization;

namespace WpfValidation.CustomAttibutes
{
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
    sealed public class Tckn : ValidationAttribute
    {
        public override bool IsValid(object value)
        {
            if (value == null)
            {
                return true;
            }

            bool result = false;

            try
            {
                if (value.ToString().Length == 11)
                {
                    long tcNo = Int64.Parse(value.ToString());

                    long atcno = tcNo / 100;
                    long btcno = tcNo / 100;

                    long c1 = atcno % 10; atcno = atcno / 10;
                    long c2 = atcno % 10; atcno = atcno / 10;
                    long c3 = atcno % 10; atcno = atcno / 10;
                    long c4 = atcno % 10; atcno = atcno / 10;
                    long c5 = atcno % 10; atcno = atcno / 10;
                    long c6 = atcno % 10; atcno = atcno / 10;
                    long c7 = atcno % 10; atcno = atcno / 10;
                    long c8 = atcno % 10; atcno = atcno / 10;
                    long c9 = atcno % 10; atcno = atcno / 10;
                    long q1 = ((10 - ((((c1 + c3 + c5 + c7 + c9) * 3) + (c2 + c4 + c6 + c8)) % 10)) % 10);
                    long q2 = ((10 - (((((c2 + c4 + c6 + c8) + q1) * 3) + (c1 + c3 + c5 + c7 + c9)) % 10)) % 10);

                    result = ((btcno * 100) + (q1 * 10) + q2 == tcNo);
                }

                return result;
            }
            catch (Exception)
            {
                return false;
            }   
        }

        public override string FormatErrorMessage(string name)
        {
            return String.Format(CultureInfo.CurrentCulture, ErrorMessageString, name);
        }
    }
}

MobilePhone.cs

using System;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Text.RegularExpressions;

namespace WpfValidation.CustomAttributes
{
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
    sealed public class MobilePhone : ValidationAttribute
    {
        public override bool IsValid(object value)
        {
            if (value == null)
            {
                return true;
            }

            try
            {
                var number = value.ToString();

                return Regex.IsMatch(value.ToString(), "^[0-9]{1" + (number.StartsWith("0") ? "1" : "0") + "}$");
            }
            catch (Exception)
            {
                return false;
            }
        }

        public override string FormatErrorMessage(string name)
        {
            return String.Format(CultureInfo.CurrentCulture, ErrorMessageString, name);
        }
    }
}

WPF’de Data Annotations ile Veri Doğrulaması

Ekrandan veri girişi yapılan uygulamalarda verilerin doğrulanması kaçınılmazdır. WPF üzerinde bu işi kolay bir yoldan halletmek için .NET’teki “System.ComponentModel.DataAnnotations” kütüphanesini kullanacağız. Öncelikle ekrana alanları ve gönder tuşunu ekliyoruz. Ekranın arka tarafında “Datacontext”‘i ayarlayarak ekranı daha önce oluşturduğumuz modele bağlıyoruz. Ekrandaki alanları da “Binding” yardımı ile modeldeki “Property”‘lere bağlıyoruz. Alanların kısıtlarını “Property”‘lerin üzerinde tanımladığımız “Data Annotations” ile belirliyoruz. “Submit” tuşuna basıldığında ise yazdığımız kodla doğrulama gerçekleşiyor ve mesaj kutusunda gösteriliyor.

MainWindow.xaml

<Window x:Class="WpfValidation.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="150"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition Height="30"/>
            <RowDefinition Height="30"/>
            <RowDefinition Height="30"/>
            <RowDefinition Height="30"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        
        <TextBlock Text="Name:" Grid.Column="0" Grid.Row="0"/>
        <TextBox Text="{Binding Name}" Grid.Column="1" Grid.Row="0"/>

        <TextBlock Text="Age:" Grid.Column="0" Grid.Row="1"/>
        <TextBox Text="{Binding Age}" Grid.Column="1" Grid.Row="1"/>
        
        <TextBlock Text="Birth Date:" Grid.Column="0" Grid.Row="2"/>
        <TextBox Text="{Binding BirthDate}" Grid.Column="1" Grid.Row="2"/>

        <TextBlock Text="TCKN:" Grid.Column="0" Grid.Row="3"/>
        <TextBox Text="{Binding Tckn}" Grid.Column="1" Grid.Row="3"/>
        
        <Button Content="Submit" Grid.Column="0" Grid.Row="4" Grid.ColumnSpan="2" Click="Button_Click"/>
    </Grid>
</Window>

MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Windows;
using WpfValidation.ViewModels;

namespace WpfValidation
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            DataContext = new MainWindowViewModel();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var validationResults = new List<ValidationResult>();

            bool isValid = Validator.TryValidateObject(DataContext,
                                                       new ValidationContext(DataContext), 
                                                       validationResults, 
                                                       true);

            if (isValid)
            {
                MessageBox.Show("Validation success.");
            }
            else
            {
                var strErr = String.Empty;

                foreach (var item in validationResults)
                {
                    strErr += item.ErrorMessage + "\n";
                }

                MessageBox.Show(strErr);
            }
        }
    }
}

MainWindowViewModel.cs

using System;
using System.ComponentModel.DataAnnotations;

namespace WpfValidation.ViewModels
{
    public class MainWindowViewModel
    {
        public MainWindowViewModel()
        {
            // Default values
            Name = "Test";
            Age = 67;
            BirthDate = new DateTime(1980, 02, 10);
            Tckn = "11009797396";
        }

        [Required(ErrorMessage = "Name is required.")]
        [StringLength(10, MinimumLength = 3, ErrorMessage = "The name must be between 3 and 10 characters long.")]
        [RegularExpression(@"^[a-zA-Z]+$", ErrorMessage = "The name must only contain letters (a-z, A-Z).")]
        public string Name { get; set; }

        public int Age { get; set; }

        public DateTime BirthDate { get; set; }

        [Required(ErrorMessage = "Tckn is required.")]
        [StringLength(11, MinimumLength = 11, ErrorMessage = "The tckn must be 11 characters long.")]
        public string Tckn { get; set; }
    }
}

SHA-2 Hesaplama

SHA-2(Secure Hash Algorithm) ABD Ulusal Güvenlik Ajansı tarafından tasarlanan kriptografik hash fonksiyonları (SHA-224, SHA-256, SHA-384, SHA-512) kümesidir. Bir hash fonksiyonu rastgele dizilimli bir veri elemanı kümesinden, metin dosyası gibi, sabit uzunluklu bir değer hesaplayan algoritmadır. Bulunan bu değer daha sonra kopyalanan orjinal verinin bütünlüğünü kontrol etmek için kullanılabilir. MD5 algoritmasının güvenlik konusunda bazı sıkıntıları olduğundan yeni uygulamalarda SHA-256 ve SHA-512 kullanılması tavsiye edilmektedir. Aşağıdaki kod ile 256 veya 512 bit uzunluğunda hash oluşturabiliriz.

static string GetSha(string text, int bitLength)
{
    switch (bitLength)
    {
        case 256:
            return BitConverter.ToString(new SHA256Managed().ComputeHash(Encoding.UTF8.GetBytes(text))).Replace("-", "").ToLower();
        case 512:
            return BitConverter.ToString(new SHA512Managed().ComputeHash(Encoding.UTF8.GetBytes(text))).Replace("-", "").ToLower();
        default:
            return null;
    } 
}

Tekil Bilgisayar Id’si Üretme

Aşağıdaki metot yardımı ile tekil bilgisayar id’si üretip, bunu bilgisayarı tanımlamak için kullanabiliriz. Aşağıdaki kod işlemci, anakart ve sabit disk üzerinden id’yi oluşturmaktadır. Bu numaraları birleştirip SHA-512 hashini hesaplıyoruz ve bu şekilde oluşan id’nin her zaman 128 karakter olmasını garantilemiş oluyoruz. Donanım numaralarını basit bir şekilde birleştirmek yerine byte[] dönüşümü yapıp, toplama, and, or, xor, bit kaydırma gibi daha karmaşık yöntemler kullanılırsa güvenlik daha da artacaktır.

public static string GenerateHardwareId()
{
     // gets processor id
     string pId = "";
     var mos = new ManagementObjectSearcher("select * from Win32_Processor");

     foreach (ManagementObject m in mos.Get())
     {
         pId = m["ProcessorId"].ToString();
         break;
     }

     // gets motherboard id
     string mbId = "";
     mos = new ManagementObjectSearcher("select * from Win32_BaseBoard");

     foreach (ManagementObject m in mos.Get())
     {
         mbId = m["SerialNumber"].ToString();
         break;
     }

     // gets logical disk volume serial number
     string ldvSerialNumber = "";
     mos = new ManagementObjectSearcher("select * from Win32_LogicalDisk");

     foreach (ManagementObject m in mos.Get())
     {
         if (m["DeviceID"].ToString() == "C:")
         {
             ldvSerialNumber = m["VolumeSerialNumber"].ToString();
             break;
         }
     }

     var hwIdJoined = ldvSerialNumber + pId + mbId;

     byte[] hash = new SHA512Managed().ComputeHash(Encoding.UTF8.GetBytes(hwIdJoined));

     return BitConverter.ToString(hash).Replace("-", "").ToLower();      
}