Makale Özeti

Bu yazıda Visual Studio .Net 2003 ile çalışma zamanında dinamik olarak VBScript veya Javascript kodu yaratıp çalıştırıp sonuçların .Netten okumasını sağlayacağız.

Makale

Giriş

Her zaman çalışma zamanında kod yaratıp, çalıştırmayı sevmişimdir. Pek çok kişi bunun yavaş olduğunu söyler, ancak günümüzün makinalarında bu pek sorun olmasa gerek. Gerçekten de performansın çok öncelikli olmadığı uygulamalarda dinamik kod çalıştırmak büyük esneklik sağlar. Hele Scripting yorumlanan yapısıyla, derlenen dillere göre daha da esnektir.

Bütün işi Microsoftun adından az bahsedilmiş, hakkında pek doküman bulamayacağınız "Microsoft Script Control 1.0" nesnesi yapmaktadır. En güzeli örnek bir uygulama yazmak.

  1. Visual Studioyu açın, C# ile yeni bir "Console Application" başlatın. İsterseniz Visual Basic olarak da başlatabilirsiniz. Benim tercihim C#. Bu makalede programla diline özel pek birşey yok. Hatta istersiniz Visual Basic veya Scripting bile kullanabilirsiniz.
  2. Solution Explorer tabından "References"i sağ tıklayarak "Add Reference" seçeneğini seçin,
  3. Açılan "Add Reference" diyalogunda "COM" tabını tıklayın,
  4. Ortalarda bir yerlerde "Microsoft Script Control 1.0" nesnesini bulana kadar aşağıya gidin (bir sürü Microsoft nesnesi var, neden acaba?) ve bu nesneyi tıklayın,
  5. Önce Select düğmesine sonra da OKe basın.
  6. Projenize "MSScriptControl" adında bir referansın eklendiğini göreceksiniz. (VB ile yazıyorsanız Project menüsünden Referencesi seçerek bu işlemi yapabilirsiniz.)
  7. Artık güç elimizde. "Main" metodunu aşağıdaki şekilde değiştirin ve F5e basın;
     
    using System;
    
    namespace ConsoleApplication2
    {
        /// &ltsummary>
        /// Summary description for Class1.
        /// </summary>
        class Class1
        {
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            [STAThread]
            static void Main(string[] args)
            {
                object[] oArrArguments = new object[] {};
                System.Text.StringBuilder sbCode = new System.Text.StringBuilder();
                sbCode.Append("Sub Main\n\r");
                sbCode.Append("MsgBox (\"Hello World\")\n\r");
                sbCode.Append("End Sub");
                MSScriptControl.ScriptControl script = new MSScriptControl.ScriptControlClass();
                script.Language = "VBScript";
                script.AddCode(sbCode.ToString());
                script.Run("Main", ref oArrArguments);
            }
        }
    }

Neler Oldu?

Yukarıdaki kod ile ilk önce sbCode adlı bir StringBuilder ile "Hello World" mesajı veren bir script tanımladık.
Daha sonra script adında bir adet "ScriptControl" nesnesi yarattık. Sonra da dili VBScript olarak seçtik. Burada ActiveScriptingi destekleyen herhangi bir dil seçebilirsiniz. Normalde bilgisayarınızda sadece VBScript, JScript/JavaScript mevcuttur. Ancak internetten birkaç dil daha bulabilirsiniz. Daha sonra script nesnemizin AddCode metodu ile sbCode değişkeninin içindeki değeri nesnemize ekleyip, Run metodunu boş bir parametre dizisiyle çağırdık. Ekranda "Hello World" yazan bir mesaj kutusu çıkmış olması lazım.

Olayı parametrik hale getirelim.

Normalde sbCodea eklediğimiz bloğumuzdaki Main metodu bir kaç parametre alabilir. Şimdi amacımız, Main Subını fonksiyon haline getirip, iki parametre geçirip, sonucu .Netten yazdırmak olsun. Aşağıdaki kodu gözönünde bulundurun;

static void Main(string[] args)
{
    object[] oArrArguments = new object[] {"Yaz", "Gelistir"};
    System.Text.StringBuilder sbCode = new System.Text.StringBuilder();
    sbCode.Append("Function Main(prm1, prm2)\n\r");
    sbCode.Append(  "Call MesajGoster(prm1, prm2)\n\r");
    sbCode.Append(  "Main = prm2 & \"mek iyidir!\"\n\r");
    sbCode.Append("End Function\n\r");
    sbCode.Append("Sub MesajGoster(p1, p2)\n\r");
    sbCode.Append(  "msgBox (");
    sbCode.Append(  "p1&p2&\"den sevgilerle\"");
    sbCode.Append(  ")\n\r");
    sbCode.Append("End Sub\n\r");
    MSScriptControl.ScriptControl script = new MSScriptControl.ScriptControlClass();
    script.Language = "VBScript";
    script.AddCode(sbCode.ToString());
    object result = null;
    try {
        result = script.Run("Main", ref oArrArguments);
        Console.WriteLine(result.ToString());
    } catch {
        Console.WriteLine(String.Format("Yazdığınız kodda {0}. satırda hata var.\n\r{1}", script.Error.Line, script.Error.Description ));
        Console.ReadLine();
    }

oArrArguments dizisini "Yaz" ve "Gelistir" diye iki eleman ile yarattık. sbCode değişkenimizi biraz değiştirdik. Artık sbCodedaki Main bir Sub değil, bir Function. Ayrıca "prm1" ve "prm2" adlı iki adet parametre alıyor. İşi biraz daha karıştırıp, "MesajGoster" diye bir Sub tanımladık. Main fonksiyonumuz, MesajGosteri, aldığı iki parametre ile çağırıyor, daha sonra da ikinci parametreyi (prm2) kullanarak bir değer geri döndürüyor.

Uygulamanın yapacağı şey; "YazGelistirden sevgilerle" diye bir mesaj kutusu çıkartmak, daha sonra da konsola "Geliştirmek iyidir!" yazmak oluyor.

Hata Kontrolü!!!

Ya scriptimizde hata varsa ne olacak? Yukarıdaki kodda bir try-catch bloğu göreceksiniz. Catch kısmında script değişkenin Run metodu çağrıldığında bir hata oluşursa, scriptteki bu hatayı nesnenin "Error" propertysi ile inceleyebiliriz. "MesajGoster" Subındaki "msgBox" komutunu "msgBx" olarak değiştirip programı tekrar çalıştırın. Şöyle bir çıktı görürsünüz;

Yazdığınız kodda 11.satırda hata var.
Type mismatch: msgBx

Daha neler var?

Eğer bu örnekleri Visual Studio .Net 2003 ile yaptıysanız, Main metodu içinde "script" yazıp noktaya basmanızı öneririm. MSScriptControl nesnesinde pek çok özellik bulunmaktadır. Bunlardan önemli olanları saymak gerekirse;

  1. script.Eval: Bir string parametre alır ve sonucu döndürür. AddCode ve Run metodunun yaptığı işleri bir kerede yapar, ancak parametre geçiremezsiniz.
  2. script.AddObject: Bu çok hoş bir özellik, bu metod ile script bloğunuza kullanabileceği, daha önceden sizin programınız tarafından yaratılmış bir COM nesnesi geçirebilirsiniz. Örneğin bir ADODB.RecordSet veya açılmış bir ADODB.Connection nesnesi. Ancak burada COM nesneleri ile sınırlısınız.
  3. script.Procedures: Bu bir collection nesnesidir. scriptteki kod bloğundaki Sub ve Functionların listesini barındırır. Bizim son örneğimizde, Main adlı bir fonksiyon ve MesajGoster adlı bir Sub var. Procedures collectionu bu iki metod hakkında bilgi barındırır. Procedure hakkında, Adını, kaç parametre aldığını ve geri dönen bir değer olup olmadığı (fonksiyon mu değil mi) bilgilerini tutar. Scriptingde sadece Variant tipleri tutulduğu için parametre adları ve tipleri hakkında bilgi tutulmasına gerek yoktur.

Neler yapılabilir / imkanlar

MSScriptControl nesnesi çok kuvvetli bir nesnedir, fakat dokümante edilmemiştir. Genelde, şu anda piyasadaki tüm Windows işletim sistemlerinde mevcuttur, o yüzden rahatlıkla kullanabilirsiniz.
Neler yapılabileceği ile aklıma ilk gelenler şunlar;

  • Script kodunuzu veritabanında saklayabilirsiniz (Object Oriented Database... Her kaydın kendine özel kodu var!!!),
  • Script kodunuzu dosyada saklayabilirsiniz,
  • XML içinde kodlar barındırıp, bu kodları gerektiğinde çağırabilirsiniz,
  • ActiveStateden Perl, TCL, PHP ve/veya Python indirip .Net kodunuzda sadece dili seçerek, yukarıdaki yöntemlerle kod çalıştırabilirsiniz.
  • VBS, JS, WSH dosyalarını açıp parse edip çalıştırabilirsiniz,
  • ASP/ASP.Net kodunuzda dinamik script oluşturup çalıştırabilirsiniz.

Mert Sakarya
Uygulama Mimarı
Doğan Online A.Ş.