28 Ocak 2011 Cuma

Cin Fikir: No Client WCF !

Merhaba Arkadaşlar;

Bugünden itibaren, "Cin Fikir" diye ifade ettiğim; kodlamaktan da oldukça hoşlandığım bir kaç sıradışı fikrimi sizlerle paylaşmaya karar verdim. Cin Fikir'lerim genelde bir sorun görüp, bunu nasıl bir "Cin"lik ile çözebilirim ana fikrinden ortaya çıkan fikirler oluyor. Bugünkü fikrimiz WCF ile ilgili:

Problemin Tanımı: Outsource olarak bulunduğum bir iş yerinde, her şeyin olabildiğince servislere yıkılmasını ve gerektiğinde de farklı server ya da uygulamalara geçirilmesi; "Yazılım Geliştirme Stratejisi" olarak belirlenmişti. Ancak bu durum; küçük bir veri çekme işleminde dahi yazılan servislere bir client oluşturulması zorunluluğu getiriyordu. Üstelik de servis sayısı arttıkça; development için kullandığınız PC her servis çağrısı için TCP portlarına veri göndermek zorunda kalıyordu ve performansı çok düşük oluyordu. Üstelik geliştirilen uygulama gerçek ortama alınıp da servisler aynı PC'ye kurulursa, gereksiz olarak performans kaybına uğranıyordu.

Cin Fikir ! : Servis çağrılarını bir Façade sınıf üzerinden, interface üzerinden çekersek; concrete sınıfı da bir konfigurasyona göre ürettirirsek Bussiness kodlarını DLL üzerinden ya da WCF üzerinden çağırmamızı  bilmeden kod yazabiliriz. Bir de bu interface'i Servis sınıfına implemente ettirip, Client sınıfını da bu inteface'i implenmente edecek bir proxy nesnesiyle oluşturursak deymeyin keyfimize :D Daha fazla beklemeden kodlamaya geçelim...

Kodlama:
İlk olarak Service Interface'imize ve implemetasyonuna göz atalım.
[ServiceContract]
public interface IComplexService
{
    [OperationContract]
    int Sum(int x, int y);
}

public class ComplexService : IComplexService
{
    public int Sum(int x, int y)
    {
        return x + y;
    }
}
Karşınızda çok komplex bir servis :)
Şimdi de methodu çağıran sınıftaki kod'a göz atalım. Bu bir Console uygulaması..


class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(
           Core.ComplexService.Sum(2, 5)
        );
        Console.ReadLine();
    }
}
Burası sistemin can alıcı noktalarından birisi; Core sınıfı üzerindeki ComplexService static property'si IComplexService tipindedir. Bu property içinde Configuration içinden aldığımız değere göre gerçek nesneyi ya da WCF üzerinden çağrıyı gerçekleştirecek proxy sınıfını geri döndürüyoruz.

public static class Core
{
    public static IComplexService ComplexService
    {
        get
        {
            if (ConfigurationManager.AppSettings["userService"] == "1")
                return new ComplexService();

            return new ChannelFactory<IComplexService>("BasicHttpBinding_ComplexService")
                               .CreateChannel();
        }
    }
}
Burada belirtilen ChannelFactory sınıfı; Visual Studio'nun WCF Client kod üreticisinin ürettiği koda benzer şekilde verilen konfigurasyona ve service interface'ine göre, verilen interface tipinde WCF client nesnesi üretmekte.. Yani bir tür proxy nesnesi.. Buradaki sıkıntımız, bizim WCF method çağrımlarında her method'dan önce ve sonra işlem yapmak zorunda olduğumuzu varsaydığımızda sıkıntı çıkartması..

Bu durumda kendi proxy nesnelerimiz üretebileceğimiz bir yapıya ihtiyaçımız var. Bunun için bir çok çözüm var; biz burada RealProxy nesnesini kullanıyor olacağız. (Konu hakkında ayrıntılı bilgi için Sefer Algan Hocam'ın yazdığı CSharpNedir'deki şu makalesine göz atabilirsiniz).


internal class ProxyFactory<TObject> : RealProxy
{
    public TObject RealObject { get; private set; }

    public ProxyFactory(TObject realObject)
        : base(typeof(TObject))
    {
        this.RealObject = realObject;
    }


    private Func<Func<object>, object> _surroundDelegate;
    public TObject GetProxy(Func<Func<object>, object> surroundDelegate)
    {
        this._surroundDelegate = surroundDelegate;
        return (TObject)this.GetTransparentProxy();
    }

    public override IMessage Invoke(IMessage msg)
    {
        //Bu örnek gelen çağrımın bir metot olduğu varsayımı altında yapılmıştır.
        //Eğer çağrım bir Property ise ona göre bu kodu değiştirmek gerekir.Yani set_ ve get_ önekleri ile metodu dinamik bir şekilde çağırmak gerekir.

        IMethodCallMessage message = (IMethodCallMessage)msg;

        if (message != null)
        {
            //MessageBox.Show(message.MethodName + " metodu çağrılmak üzere. Biz araya girdik çağrılmadan önce");

            object methodRetval = _surroundDelegate(() => message.MethodBase.Invoke(RealObject, message.InArgs));

            ReturnMessage retVal = new ReturnMessage(methodRetval, null, 0, message.LogicalCallContext, message);

            return retVal;
        }
        return null;
    }
}

Burada göz atılacak 3 önemli satır var.

  1. 5 numaralı satır'da; bir nesnenin proxy'ini üretmek için ProxyGenerator sınıfını üretirken; gerçek nesneyi de vermeyi zorunlu tutuyoruz.
  2. 13 numaralı satırda method parametresi :"Func<Func<object>, object>". Yani içerisine object tipinde değer döndüren; verilen Delegate'i çalıştırıp, dönen değeri geri bize veren bir Delegate istenmektedir. Biliyorum cümle çok karmaşık oldu ama kod yeterince açık değil mi zaten :D
  3. 30 numaralı satırda ise; proxy nesne üzerinden çağrılan, gerçek sınıfın methodlarını çağırdığında GetProxy nesnesinde aldığımız delegate; içerisine gerçek nesnenin ilgili methodunu barındıran delegate verilerek çalıştırılıyor.
Son olarak da: Core Sınıfımızın son hali :
public static class Core
{
    public static IComplexService ComplexService
    {
        get
        {
            if (ConfigurationManager.AppSettings["useService"] == "0")
                return new ComplexService();
            //return new ChannelFactory<IComplexService>("BasicHttpBinding_ComplexService").CreateChannel();

            var proxyCreater = new ProxyFactory<IComplexService>(
                            new ChannelFactory<IComplexService>("BasicHttpBinding_ComplexService")
                                .CreateChannel()
                            );

            return proxyCreater.GetProxy(fnc =>
                {
                    using (OperationContextScope scope = new OperationContextScope(proxyCreater.RealObject as IContextChannel))
                    {
                        return fnc.Invoke();
                    }
                });
        }
    }
}
Proxy methodunu alırken Lambda Expression'lar gerçek methodu, OperationScope içerisinde gerçeklemiş oldum. İstersek, kendi case'lerimize özel çalışmalar da yapabiliriz.

Artık istediğimiz an basit bir konfigurasyon ayarıyla sistemimizi WCF üzerinden çalışır hale getirebiliriz. Üstelik servis method'larını çalıştırıken tekrar etmek zorunda kaldığımız kodları da merkezi noktalara çekebilmiş olduk.

Çalışan örneğin kaynak kodlarını buradan indirebilirsiniz.

Umarım fikrimi yeterince "Cin" bulumuşsunuzdur :)

Sıradışı günler, sıradışı başarılar dilerim.

[Tips & Tricks] İleri Visual Studio Teknikleri

sMerhaba Arkadaşlar;

Şimdiye kadar Visual Studio ile yazılım geliştirdik. Peki nimetlerinden ne kadar yararlanıyoruz? Daha doğrusu ne kadar farkındayız? Bu makalede sizlerle çok fazla seslendirilmeyen Visual Studio kullanım teknikleri ve VS Macro'lar üzerine konuşacağız.

Hızlı kod yazabilmek için temel gereksinim; editörü hızlı kullanabilmektir. Ne kadar hızlı mouse kulanırsak kullanalım, hiç bir zaman klavyede eriştiğimiz hızlara erişemeyiz( en azından benim ve çevremdeki arkadaşlar için böyle :). Bu da bizi Visual Studio kullanımında da klavye'ye yönelmemiz gerektiği gerçeğiyle karşılaştırır. O zaman hemen sık kullanılan Visual Studio Klavye Kısayollarına bakalım. Bunların broşür halinin şuradan da indirebilirsiniz.

  • Ctrl+. (Shift+Alt+F10un yaptığını yapıyor; using eklemek, gerektiğinde method oluşturmak vb. işlemlerde)
  • F12 - Go to Definiton
  • Alt+F12 - Find Symbol
  • Shift+Alt+F12 - Quick Find Symbol(Seçtiğin bir string'i Symbol olarak direk arar. En çok Web.Config gibi yerlerde işe yarıyor.)
  • Ctrl+Shift+F - Find In Files - Tüm bulduğu eşleşenleri liste halinde gösterir.
  • Shift+F12 - Find All References
  • Ctrl+Shift+A - Add New Item
  • Shift+Alt+C - Add New Class
  • Ctrl+W,S - Solution Explorer
  • Ctrl+W,E - Error List
  • Ctrl+F4 - Close Current Tab
  • Ctrl+Tab - Açık pencereler arasında dolaşmanı sağlıyor
  • Ctrl+ - : Bir kod satırından uzak bir satıra atladıysan Geri gelmeni sağlıyor. "Go to Definition" gibi atlamalarında da sayfalar arası atlama falan da yapabiliyorsun.(Navigate Backward)
  • Ctrl+Shift+ - : Navigate Forward
  • F7 - View Code  : Shift+F7 - View Designer
  • Ctrl+K, S  - Surround with (Snippet'le sorrund etmek için(#region,foreach,if vb.))
  • Ctrl+M,M - Bulunduğun bölümü collapse eder
  • Ctrl+M,O - Tüm bölümleri(region, method ne varsa) collapse eder.
  • Shift+F9 - Quick Watch
  • F9 - Toggle Break Point - Break point koyar.
  • Debug işlemlerinde F10,F11,Shift+F11,Shift+F5,F5 gibi bildiğiniz şeyler...

İhtiyaçlarınıza göre bu kısayolları ezberleyin derim. Kısa sürede kod yazma hızınızdaki artışı fark edeceksiniz. Çünkü mouse kullanımı etkileşimli(mouse'in ekranın neresine gittiğini görüp hızını ayarlamanız gerekmekte); ancak klavye kullanımı otonom(klavyeye bakmadan tuşlara basar ve istediğiniz sonucu alırsınız) bir harekettir. Klavye kullanımındaki otonom hareket, zihinizi kod yazarken mouse'den kurtarıp daha etkili kod yazmanızı sağlayacaktır.

Visual Studio'da Regular Expressions

Visaul Studio'nun çok fazla kullanılmayan nimetlerinden biri de Regular Expression'lar. Arama işlemlerinde işlerinizi ne kadar kolaylaştırdığını fark ettiğiniz de bilmeden geçirdiğiniz günlere acıyacaksınız.

Mesela kodlarınızdaki tüm tek satırda yazılan int propertyleri bulmak istiyorsunuz. Arama penceresinde "Use Regular Expressions" seçtikten sonra "int.*{.*}" yazmanız  yeterli :) Nasıl ama kolay değil mi? Ya da sık kullanabileceğimiz boş satırları silme işlemi için "\n:b*\n" aratıp, "\n" ile replace edebilirsiniz.":b" burada özel bir karakter kısmını ifade eder, tab ya da space.. * ise RegEx'den bildiğimiz şekilde çalışır: 0 ya da sonsuz tane tekrar..

Özellikle HTML ve XML kullanımlarında işinizi oldukça kolaylaştıracaktır. Find & Replace özelliğinde daha özel işler yapabilirsiniz de.. Mesela seçtiğiniz bir XML taginin başına ve sonuna özel bir tag ekleyebilirsiniz.

Burada önemli nokta Özel karakterlere hızlı erişim için arama textbox'ının yanındaki ">" butonunu kullanabilirsiniz. Diğer tüm anahtar karakterlere adresinden erişebilirsiniz.

Visual Studio Macros

Macro'lar tekrarlanan işler yaparken işlerimizi kolaylaştırmak için elimiz ayağımız oluyor. Visual Basic olması bir dezavantaj olsa da, online C#2Vb Code Converter'lar oldukça işinize yarayabilir.

2 türlü kullanabilirsiniz. Ctrl+Shift+R kısayolu ile geçici(temporary) Macro kaydedip, Ctrl+Shift+P ile de bu Macro'yu çalıştırabilirsiniz. Aynı zamanda bu kaydettiğiniz macroları Visual Basic kodu olarak da Macro Explorer üzerinden görüntüleyebilirsiniz. Sık kullandığım, ve bu kaydedilmiş Macro'lara bakarak oluşturduğum bir kaç Macro örneğini sunayım size:

 

IIS Worker Process'e Attach olmanızı sağlayan Macro Kodu

 

Sub AttachToW3wp()
Dim attached As Boolean = False
Dim proc As EnvDTE.Process

For Each proc In DTE.Debugger.LocalProcesses
If (Right(proc.Name, 8) = "w3wp.exe") Then
proc.Attach()
attached = True
Exit For
End If
Next

If attached = False Then
MsgBox("w3wp.exe çalışmıyor")
End If
End Sub


 



Aktif dosyayı sadce çalıştırıldığı anda göstern Macro Kodu(Bu özellik zaten Visual Studio'da var ama sürekli aktif olması dez avantaj olduğu için böyle bir çözüm güdülmüş. Ben de bu kodu başka bir yerde gördüm :)



 



Public Sub LocateFileInSolutionExplorer()
DTE.ExecuteCommand("View.TrackActivityinSolutionExplorer")
DTE.ExecuteCommand("View.TrackActivityinSolutionExplorer")
DTE.ExecuteCommand("View.SolutionExplorer")
End Sub


 



 



Açık olan tüm dökümanlara Format Document komutunu veren kod bloğu



 



Sub FormatEachOpenedPage()
For Each doc As Document In DTE.Documents
doc.Activate()
DTE.ExecuteCommand("Edit.FormatDocument")
doc.Save()
Next
End Sub


 



 



 



DB'de bir alandaki değeri çekip, bu veriyi bir dosya olarak Solution'a ekleyen Macro kodu.. Mail templateini DB'de tutan bir kod bloğu gördüm. HTML editör olmadığı için oldukça zor değiştiriliyordu. Bende Visual Studio üzerine çalışabileceğim bir ortam oluşturdum.



 



Sub LoadAllMail()
'Dim selectedfileName As String = DTE.ActiveDocument.Selection.Text
Dim adap As New OracleDataAdapter("SELECT * FROM CC_MAILTEMPLATE where ISACTIVE=1 MAILCODE IN (' + selectedfileName + ') ", Helpers.RealConStr)
Dim commandWin As EnvDTE.CommandWindow
commandWin = DTE.Windows.Item(EnvDTE.Constants.vsWindowKindCommandWindow).Object

Dim dTable As New DataTable()
adap.Fill(dTable)

For Each row As DataRow In dTable.Rows
DTE.Windows.Item(Constants.vsWindowKindSolutionExplorer).Activate()
DTE.ActiveWindow.Object.GetItem("DBSources\" + Helpers.DefaultProject + "\MailTemplate").Select(vsUISelectionType.vsUISelectionTypeSelect)
Try
DTE.ItemOperations.AddNewItem("Visual C# Items\General\Text File", row("MAILCODE").ToString() + ".html")

DTE.ActiveDocument.Selection.SelectAll()
DTE.ActiveDocument.Selection.Delete()

DTE.ActiveDocument.Selection.Insert(row("BODY_TR_TR").ToString())
Catch ex As Exception
commandWin.OutputString("Yüklenemedi " + row("MAILCODE").ToString())
End Try

Next
End Sub


 



Alttaki de bu dosyadan tekrar veritabanına gönderen kod bloğudur.










Sub SaveMail()
DTE.ActiveDocument.Selection.SelectAll()
Dim name As String = DTE.ActiveDocument.Name.Split(".")(0)
Dim con As New OracleConnection(OttoHelpers.ConStr)
Dim cmd As New OracleCommand()
cmd.Connection = con
'
cmd.CommandText = "UPDATE CC_MAILTEMPLATE SET BODY = :MAILBODY WHERE MAILCODE='" + name + "' AND ISACTIVE=1"
cmd.Parameters.AddWithValue("MAILBODY", DTE.ActiveDocument.Selection.Text.ToString())
Try
con.Open()
cmd.Transaction = con.BeginTransaction()
Dim affectedRows As Int32 = cmd.ExecuteNonQuery()
If affectedRows = 1 Then
cmd.Transaction.Commit()
MsgBox("Güncellenen kayıt sayısı:" + affectedRows.ToString())
End If
Catch ex As Exception
cmd.Transaction.Rollback()
MsgBox("Transaction Geri Alındı (Rollback) !")
Finally
If con.State = ConnectionState.Open Then
con.Close()
End If
End Try
DTE.ActiveDocument.Selection.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstText)
End Sub


Bu kodlar size de neler yapılabileceği ile ilgil oldukça iyi fikirler vermiştir diye düşünüyorum.




Umarım bu İp Uçları( [Tips & Tricks] ) işinize yarar ve size kolaylık sağlar.





Herkese iyi çalışmalar dilerim.

Verimlilik Teknolojileri Ne Kadar Verimli?

Merhaba Arkadaşlar,
Bugün sizlerle farklı bir konudaki fikirlerimi paylaşacağım.. Avrupa Birliği Enerji Verimliliği Etiket'leri.. Nam-ı diğer; 'Yeşil Teknoloji' reklamlarıyla alfabenin ilk bir harflerini yarıştıran reklamcılık malzemesi..

Geçen hafta aileme bir kurutma makinesi almaya karar verdik. Ünlü bir markanın üst sınıf diye tabir edilen modellerinde ikisini beğenmişler. Karar vermek için benim de fikrimi almaya karar vermişler. Tabi kısa süre sonra evlenecek biri olarak hemen incelemeye daldım :D
Öncelikle özelliklerine göz attım. Karşılaştırma matrisi genel olarak şöyleydi.

  • A Enerji sınıfı ürün
    • Orta-Üst sınıf teknik özellikler
    • Yaklaşık 120dk süren bir programı 1,5 kWh enerji harcıyor
    • Fiyat 1530 TL
  • B Enerji sınıfı ürün
    • Üst sınıf teknik özellikler(Daha geniş hacim ve daha çok teknoloji)
    • Yaklaşık 120dk süren bir programı 4,5 kWh enerji harcıyor
    • Fiyat 1180 TL
B sınıfı olan ürün daha çok imkan sunuyordu, üstelik ucuzdu da; ancak 3 kat daha fazla elektrik faturasına yansıması olacaktı. Düşündüm, ve kağıdı kalemi alıp hesaplamam gerektiğini anladım :) Biraz mühendislik yapmak gerekiyordu :P

Bizim evde haftada 2 kez cihazın çalıştırılacağını tahmin ettik. Yılın ortalama 6 ayı çamaşırları makinede kurutacaktık. Yıllık (26 Hafta x 2 Defa) = 52 kez cihaz çalıştırlacaktı. İnternet yaptığım kısa araştırma sonun 1 kWh saat elektriğin de 19,5 Krş yani 0,195 TL olduğunu öğrendim. Bu durumda cihazların elektrik faturasına yıllık ağırlığı aşağıdaki gibi olacak:

A Sınıfı Kurutma Makinası: 1,5 kWh * 2 saat * 52 kez * 0,195 TL = 30,42 TL
B Sınıfı Kurutma Makinası: 4,5 kWh * 2 saat * 52 kez * 0,195 TL =  91,26 TL

Yıllık masraf farkı yaklaşık 60 TL oluyor. 2 cihaz arasındaki fiyat farkının da 1530 TL - 1180 TL=350 TL olduğunu da dikkate alırsak A Enerji sınıfı cihaz daha düşük teknik özelliklerine rağmen, aradaki farkı ancak 6 yılda ödeyebiliyor ve sizi kâra geçirmeye başlıyor.

Bu durum A enerji sınıfı cihazın çok da tercih edilmesinin mantıklı olamayacağını görebiliyoruz.
Yukardaki hesaplamalar sizin diğer beyaz eşya tercihlerinizde de fikir verici olacağını umuyorum..

İnsan böyle bakınca; "Keşke hayat da matematiğe dökülebilseydi" diyor içinden :)

Hayatınızda "Akıllıca seçimler" dilerim..