Regex Replace

Xml dönüşümleri için regex kullanabiliriz. Aşağıdaki örnekte Regex.Replace metodu ile old.xml, new.xml’e dönüştürülmektedir. Her “Row” etiketine “E” özelliği eklenmektedir.

old.xml

<Rows>
  <Row A="73" B="2" C="0" D="3" />
  <Row A="140" B="3" C="1" D="2" />
  <Row A="129" B="2" C="2" D="2" />
  <Row A="255" B="4" C="3" D="10" />
  <Row A="334" B="2" C="4" D="48" />
</Rows>

new.xml

<Rows>
  <Row A="73" B="2" C="0" E="0" D="3" />
  <Row A="140" B="3" C="1" E="0" D="2" />
  <Row A="129" B="2" C="2" E="0" D="2" />
  <Row A="255" B="4" C="3" E="0" D="10" />
  <Row A="334" B="2" C="4" E="0" D="48" />
</Rows>

Program.cs

using System;
using System.IO;
using System.Text.RegularExpressions;

namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            var oldXml = File.ReadAllText("old.xml");

            var newXml = Transform(oldXml);

            File.WriteAllText("new.xml", newXml);

            Console.WriteLine("Done.");

            Console.ReadKey();
        }

        private static string Transform(string xml)
        {
            var newXml = Regex.Replace(xml,
                                      "C=\"(?<td>.*?)\"",
                                      (m) =>
                                      {
                                          var td = m.Groups["td"].Value.Trim();

                                          return "C=\"" + td + "\" E=\"0\"";
                                      });

            return newXml;
        }
    }
}

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();      
}

Yerel Wsdl Dosyasından Web Servis Bağlantısı İçin Kod Üretme

Wsdl.exe aracı ile XML web servislerini kullanmak için kod üretebiliriz.

Wsdl adresi tarayıcıda açılır. Doküman bir dizine x.wsdl olarak kaydedilir.
Dokümandaki xsd adresi alınır. Tarayıcıda açılır ve önceki dizine x.xsd olarak kaydedilir.
Visual Studio komut satırı yönetici olarak başlatılır. Aşağıdaki komut çalıştırılır.

wsdl /verbose <wsdl dosya yolu> <xsd dosya yolu>

Aynı dizinde cs uzantılı dosyamız oluşacaktır. Projeye ekleyip kullanabiliriz.

Windows Makinelerde Program Yüklü mü Kontrolü

Aşağıdaki methot ile Windows işletim sisteminde herhangi bir programın yüklü olup olmadığını kontrol edebiliriz. Sadece “Program Ekle Kaldır” da görünen adı ile veya isteniyorsa sürüm numarasını da parametre olarak girip sorgulama yapabiliyoruz.


private bool IsProgramInstalled(string displayName, string displayVersion = null)
 {
 var uninstallKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";

using (var registryKey = Registry.LocalMachine.OpenSubKey(uninstallKey))
 {
 foreach (var subKeyName in registryKey.GetSubKeyNames())
 {
 using (var subKey = registryKey.OpenSubKey(subKeyName))
 {
 var dn = subKey.GetValue("DisplayName");

if ((dn != null) && (dn.ToString() == displayName))
 {
 if (displayVersion != null)
 {
 var dv = subKey.GetValue("DisplayVersion");

return (dv != null) && (dv.ToString() == displayVersion);
 }

return true;
 }
 }

}
 }

return false;
 }

Küçük Bellek Dökümü(MiniDump) Alma

Aşağıdaki sınıf ile kod içinde herhangi bir anda küçük bellek dökümü alıp dosyaya kaydedebilirsiniz.

using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;

namespace MiniDumper
{
    public class MiniDumper
    {
        internal enum MINIDUMP_TYPE
        {
            MiniDumpNormal = 0x00000000,
            MiniDumpWithDataSegs = 0x00000001,
            MiniDumpWithFullMemory = 0x00000002,
            MiniDumpWithHandleData = 0x00000004,
            MiniDumpFilterMemory = 0x00000008,
            MiniDumpScanMemory = 0x00000010,
            MiniDumpWithUnloadedModules = 0x00000020,
            MiniDumpWithIndirectlyReferencedMemory = 0x00000040,
            MiniDumpFilterModulePaths = 0x00000080,
            MiniDumpWithProcessThreadData = 0x00000100,
            MiniDumpWithPrivateReadWriteMemory = 0x00000200,
            MiniDumpWithoutOptionalData = 0x00000400,
            MiniDumpWithFullMemoryInfo = 0x00000800,
            MiniDumpWithThreadInfo = 0x00001000,
            MiniDumpWithCodeSegs = 0x00002000
        }

        [DllImport("dbghelp.dll")]
        static extern bool MiniDumpWriteDump(IntPtr hProcess, 
                                             Int32 ProcessId,
                                             IntPtr hFile,
                                             MINIDUMP_TYPE DumpType,
                                             IntPtr ExceptionParam,
                                             IntPtr UserStreamParam,
                                             IntPtr CallackParam);

        public static void MiniDumpToFile(string fileToDump)
        {
            FileStream fs = null;

            if (File.Exists(fileToDump))
            {
                fs = File.Open(fileToDump, FileMode.Append);
            }
            else
            {
                fs = File.Create(fileToDump);
            }

            var thisProcess = Process.GetCurrentProcess();

            MiniDumpWriteDump(thisProcess.Handle, 
                              thisProcess.Id, 
                              fs.SafeFileHandle.DangerousGetHandle(), 
                              MINIDUMP_TYPE.MiniDumpNormal, 
                              IntPtr.Zero, 
                              IntPtr.Zero, 
                              IntPtr.Zero);
            
            fs.Close();
        }
    }
}

Dinamik Olarak Dll Yükleme ve Kullanma

.NET ile yazılmış bir dll’i projeye eklemeden, dosya yolunu göstererek kullanabiliriz. Aşağıdaki örnek için çağırılacak sınıf ve metot statik olmalıdır.

using System;
using System.IO;
using System.Reflection;

namespace DynamicLoadTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var result = CallMethod(@&quot;C:\SampleDll.dll&quot;, &quot;Add&quot;, new object[] { 5, 4 });

            if (result is Exception)
            {
                Console.WriteLine(&quot;Some errors occured!&quot;);

                Console.ReadKey();
            }

            Console.WriteLine(result);

            Console.ReadKey();
        }

        private static object CallMethod(string assemblyFile, string methodName, object[] parameters)
        {
            try
            {
                var a = Assembly.LoadFrom(assemblyFile);

                var mi = a.GetTypes()[0].GetMethod(methodName);

                return mi.Invoke(null, parameters);
            }
            catch (Exception ex)
            {
                return ex;
            }
        }
    }
}

Yukarıdaki yöntem çok esnek bir yöntem değil. Methot adlarını bilmek gerekiyor. Bunun yerine .NET kütüphanesinde bulunan MEF(Managed Extensibility Framework) kütüphanesini kullanabiliriz. Bu kütüphane System.Composition altında bulunmaktadır.

Bir interface oluşturulur.

namespace CompositionTest
{
    public interface IOperation
    {
        int Add(int a, int b);

        int Subtract(int a, int b);

        double Divide(int a, int b);

        int Multiply(int a, int b);
    }
}

Interface’de kullanmak için modül tipi metadata’sı oluşturulur.

namespace CompositionTest
{
    public interface IOperationMetadata
    {
        ModuleTypes ModuleType { get; }
    }
}

MEF kütüphanesini kullanmak için yardımcı bir sınıf oluşturulur.

using DynamicLoadTest;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.IO;
using System.Reflection;

namespace CompositionTest
{
    public class MefHelper
    {
        [ImportMany]
        public IEnumerable&lt;Lazy&lt;IOperation, IOperationMetadata&gt;&gt; operations;

        public void Setup()
        {
            try
            {
                operations = new List&lt;Lazy&lt;IOperation, IOperationMetadata&gt;&gt;();

                var aggregate = new AggregateCatalog();
                //aggregate.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
                aggregate.Catalogs.Add(new DirectoryCatalog(Path.GetDirectoryName(Assembly.GetAssembly(typeof(Program)).Location)));

                var parts = new CompositionBatch();
                parts.AddPart(this);

                var container = new CompositionContainer(aggregate);
                container.Compose(parts);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
            }
        }
    }
}

Modül tipleri enum’u oluşturulur.

namespace CompositionTest
{
    public enum ModuleTypes
    {
        None, AnotherModule, SampleModule
    }
}

Aşağıdaki gibi kullanabiliriz.

using CompositionTest;
using System;
using System.Linq;

namespace DynamicLoadTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var mh = new MefHelper();

            mh.Setup();

            Console.WriteLine(mh.operations.First(f =&gt; f.Metadata.ModuleType == ModuleTypes.AnotherModule).Value.Add(10, 4));

            Console.WriteLine(mh.operations.First(f =&gt; f.Metadata.ModuleType == ModuleTypes.SampleModule).Value.Add(10, 4));

            Console.ReadKey();

            Console.WriteLine(mh.operations.First(f =&gt; f.Metadata.ModuleType == ModuleTypes.AnotherModule).Value.Add(10, 4));

            Console.WriteLine(mh.operations.First(f =&gt; f.Metadata.ModuleType == ModuleTypes.SampleModule).Value.Add(10, 4));

            Console.ReadKey();
        }
    }
}

Örnek dll sınıfı.

using CompositionTest;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AnotherModule
{
    [Export(typeof(IOperation))]
    [ExportMetadata(&quot;ModuleType&quot;, ModuleTypes.AnotherModule)]
    public class Operation : IOperation
    {
        public int Add(int a, int b)
        {
            return -1;
        }

        public int Subtract(int a, int b)
        {
            return -2;
        }

        public double Divide(int a, int b)
        {
            return -3;
        }

        public int Multiply(int a, int b)
        {
            return -4;
        }
    }
}

Örnek projeyi buradan indirebilirsiniz.