26 Kasım 2012 Pazartesi

TFS Boyut Yönetimi

Selamlar,
Tfs sunucunuzun boyutu 10larca Gb haline geldiyse temizlik için aşağıdaki maddeleri incelemenizi tavsiye ederim.
    Build icin yazilan joblar’ da retention policy ayarı.
Test, development ortamlarında cok gerekli degilse tarihce tutmayın. Canli ortam icin Keep All demeyin. Son 20 gun gibi yonetilebilir rakamlar belirleyin.

Build tanımlarinda sag click yapip edit build definition’a tıklanır. Acilan pencerede retention policy kısmında bahsettigim ayarlamalar yapılabilir.
   Tfs Default Collection Silinen Dosyalar/Projeler.
Tfs silinen bir dosyayi veya dizini gercekten silmiyor. Visual Studio Tools/Options kısmında yer alan Source Control ayarlarinda silinenleri goster kısmını sectigim zaman korkunc gercekle karsilastim. Onlarca proje muhtemelen isim degisikligi gordugunden veya baska bir yere tasindigindan dolayı silinmis. Bunlar database’te yer tutmaya devam ediyor.
Soyle bir goruntuyle karsilasirsaniz hemen mudahale edin.


Kalıcı olarak silmenin tek yontemi tf destroy komutu.
Komutun kullanimi su sekilde:
tf destroy $/”[TFS uzerindeki path]”  /collection:[Tfs adresi http://localhost:8080/tfs/defaultcollection] /startcleanup /keephistory /stopat:T

- Komut tfs kurulum dizinine konumlanildigi zaman calisiyor.
- Tfs uzerindeki path i ogrenmek icin klasorun uzerinde sag click ile properties’e basilir, $ ile baslayan path alinir.
- startcleanup yazilmadigi taktirde silme islemi scheduled job’a birakiliyor. Yazilirsa temizlik hemen basliyor.
- keephistory ve stopat:T ikilisi son versiyonun saklanmasini sagliyor. Digerleri siliniyor. Silinmis dosyalari detroy yaparken bunu eklemeye gerek yok. stopat yerine belirli bir tarih girilebiliyor (son 1 haftalık versiyonlari sakla kisminda isinize yarayabilir)
- tf destroy komutu ile ilgili detayli bilgi asagidaki linkten alinabilir.
http://msdn.microsoft.com/en-us/library/bb386005(v=vs.100).aspx
   Buyuk boyutlu dosyalar.
Tfs 16 mb’dan buyuk binary dosyalari versiyonlamiyor. Her degisimde eskisini ve yenisini ayrı satır olarak saklıyor.
Bu dosyalari tf destroy komutu ile temizleyin. Dll versiyonlari saklamaniz gerekiyorsa 1 haftayı gecmeyin.
Bu islemleri canlı sistemde denemeden once mutlaka test ortamı yaratın.
Canlidan verileri backup ile alıp test ortamında restore yapabilirsiniz. Su makaledeki adımları uygulayabilirsiniz.
İyi çalışmalar

23 Ağustos 2012 Perşembe

Radwindow VisibleOnPageLoad

Selamlar

RadWindow kullanımında dikkat edilmesi gereken onemli bir nokta var.
 
RadWindow’un gosterilmesini istedigimiz zaman VisibleOnPageLoad property’sini true olarak set edebiliyoruz.
Ancak bu degeri false’a geri cekmedigimiz zaman Postback’lerde Radwindow tekrar tekrar aciliyor (Ajax postbacklerde sorun olmuyor).
 
Konuyla ilgili 2 cozum var:
      VisibleOnPageLoad= false atamasini uygun zamanda yapmak.
      RadWindow acma islemini javascript ile yapmak.
Ornek:
   ScriptManager.RegisterStartupScript(this,this.GetType(), "key", "Sys.Application.add_load(showWindow);", true);

   <script type="text/javascript">
        function showWindow() {
            Sys.Application.remove_load(showWindow);
            var oWindowCust = $find('<%= RadWindow1.ClientID %>');
            oWindowCust.show();
        }  
    </script>
 
Bilginize
 
Serkan
 

17 Ağustos 2012 Cuma

Çok Sayfalı Raporlarda Performans Problemi

Selamlar,
Bizi baya uğraştıran bir hata hakkında kısaca bilgi verelim.

Uygulamamızda kullanılan bir raporun, tüm gemi bazında alınmaya çalışıldığı taktirde çok uzun sürdüğüne dair bir hata kaydımız vardı.
  • Öncelikle raporun yapısını ve sql’lerini inceledik ancak bir sonuca varamadık.
  • Sonrasında raporun ihtiyaç duyduğu tabloları dolduran, rapora parametre geçen kısımları didikledik, yine bir sonuca varamadık.
  • İşin ilginç yanı; Uygulamadan raporu çektğimizde gerçekten çok yavaş, ancak reporting service üzerinden aynı parametrelerle aynı işlemi yaptığımızda çok hızlı sonuç alıyorduk. Hatta reporting service logları da gayet temiz görünüyordu.
Bu işi bir de Mozilla’da deneyelim dedik ve ilk denememizde yüklü javascript gelmesinden dolayı IE’ın crash olduğunu anladık. Aslında rapor gayet hızlı çalışıyor, sonucu dönüyor ancak client’taki browser kendinden geçiyordu.
Toplam 173 sayfalık bir datayı render etmeye çalıştığından bu sorunun oluşması normal dedik ve rapora paging ekleyip konuyu kapattık J

6 Ağustos 2012 Pazartesi

Page, UserControl LifeCycle ve Veri Doldurma İşlemleri

Selamlar,

Asp.Net uygulaması geliştiren birçok developer mutlaka page ve user life cycle’larla ilgili bir dokuman, makale veya forum entry’leri okumuştur.

User control içerisinde yer alan dropdown list’e SelectedValue ataması yaparken, atamaya çalışılan nesne Items içerisinde yer almıyor hatası ile hemen hemen hepimiz karşılaşmısızdır.

 

Bu tarz hataları azaltmak ve developer’ın çözüm bulmakla vakit kaybetmesini engellemek için Bimar içerisinde geliştirdiğimiz projelerde temel prensiplerimiz şunlardır.

 

1)      Sayfada basit bir dropdownlist var.

a.       Sayfanın load metodunda dropdownlist itemlar doldurulur. Doldurma işlemi !IsPostBack if bloğu içerisinde yapılmalıdır. Böylelikle her postback’te gereksiz işlem yapılmaz.

b.      Itemlar doldurulduktan sonra istenirse selectedvalue set edilir.

2)      User control içerisinde dropdownlist var ve bu kontrol sayfada kullanılıyor (örnek kullanıcı seçim user controlu)

a.       User controlun init metodunda dropdownlist itemlar doldurulur. Doldurma işlemi !IsPostBack if bloğu içerisinde yapılmalıdır. Böylelikle her postback’te gereksiz işlem yapılmaz.

b.      Sayfanın load metodunda, istenirse usercontrol içerisindeki dropdown’ın selected value’su set edilir.

User controlun init metodu Page’in load metodundan önce, load metodu ise Page’in load metodundan sonra çalışır.

3)      User control içerisinde load on demand control (radcombo, autocomplete extender textbox vb. ) var ve bu kontrol sayfada kullanılıyor.

a.       User controlun init metodunda herhangi bir doldurma işlemi yapmaya gerek yok.

b.      Sayfa ilk açıldığı zaman bu kontrolde bir değer gösterilmek isteniyorsa, usercontrol’e ilgili PK değerini alan ve datayı saklandığı yerden getirip ekrana basan bir metot yazılmalı.

 

Biz bu işlemleri daha anlamlı metotlarda görebilmek için base classlar oluşturduk (Page ve UserControl’lerin). Bunların Load metotlarını override yaptık ve içerisinden ilgili metotların virtual signature’a sahip olanlarını çağırdık. Virtual metotların içlerini child Page ve UserControl’lerde doldurduk. Böylelikle developer’ın IsPostBack gibi kontrolleri yapmadan kod yazmasını sağladık.

 

İyi çalışmalar

 

Serkan

3 Ağustos 2012 Cuma

IIS'e WCF Servis Deploy'unda BaseAddress

Selamlar,

Bildiğiniz gibi WCF servislerini farklı ortamlarda host edebilirsiniz.
Biz şirket içinde yazdığımız wcf servisleri genelde IIS sunucularında yayınlıyoruz.
Hemen hemen her devreye alımda da endpoint’lerin URI’ları konusunda sorunlar yaşıyoruz J

Burada bilinmesi ve dikkat edilmesi gereken en önemli nokta; IIS servisin svc dosyasını base olarak kabul etmektedir.
Dolayısıyla web.config dosyasına baseaddress eklememeliyiz.
Örnek servis ve client configleri ile konu daha iyi anlaşılacaktır.

Hem netTcp hem de basicHttp binding destekleyen bir servisimiz olsun.
IIS’te basicHttp için 8018, netTcp için 8019 portlarını ayarladık. Svc dosyamızın ismi DistributedService.Wcf.ScheduledJobsService.svc şeklinde ve herhangi bir sub folder’ın altında değil.
Birden fazla endPoint tanımladığımız için bunların relative adreslerini de belirtmemiz gerekiyor. netTcp için address kısmına netTcpAdres diye bir giriş yaptım. Servis referans olarak eklenebilmesi için mexTcpBinding eklendi ve ona da özel bir adres atandı (mexTcpAdres).

<system.serviceModel>
    <services>
      <service behaviorConfiguration="Basic_Service_Behavior" name="DistributedService.Wcf.ScheduledJobsService">
        <endpoint address="netTcpAdres" binding="netTcpBinding" bindingConfiguration="ScheduledJobsServiceBinding" contract="DistributedService.Contracts.Interfaces.IScheduledJobsService"/>
        <endpoint address="mexTcpAdres" binding="mexTcpBinding" bindingConfiguration="" contract="IMetadataExchange"/>
        <endpoint address="" binding="basicHttpBinding" bindingConfiguration="ScheduledJobsServiceBindingHttp" contract="DistributedService.Contracts.Interfaces.IScheduledJobsService"/>
        <endpoint address="mex" binding="mexHttpBinding" bindingConfiguration="" contract="IMetadataExchange"/>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="Basic_Service_Behavior">
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <serviceMetadata/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <netTcpBinding>
        <binding name="ScheduledJobsServiceBinding" maxReceivedMessageSize="900000000" receiveTimeout="00:15:00" sendTimeout="00:15:00">
          <reliableSession inactivityTimeout="15:00:00"/>
        </binding>
      </netTcpBinding>
      <basicHttpBinding>
        <binding name="ScheduledJobsServiceBindingHttp" maxReceivedMessageSize="900000000" receiveTimeout="00:15:00" sendTimeout="00:15:00"/>
      </basicHttpBinding>
    </bindings>
</system.serviceModel>

Visual Studio’da bir test projesi yarattık ve service referans olarak ekleme yaptık.
Oluşan config dosyası şu şekilde:
<system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_IScheduledJobsService" closeTimeout="00:01:00"
          openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
          allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
          maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
          messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
          useDefaultWebProxy="true">
          <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
            maxBytesPerRead="4096" maxNameTableCharCount="16384" />
          <security mode="None">
            <transport clientCredentialType="None" proxyCredentialType="None"
              realm="" />
            <message clientCredentialType="UserName" algorithmSuite="Default" />
          </security>
        </binding>
      </basicHttpBinding>
      <netTcpBinding>
        <binding name="NetTcpBinding_IScheduledJobsService" closeTimeout="00:01:00"
          openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
          transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions"
          hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="524288"
          maxBufferSize="65536" maxConnections="10" maxReceivedMessageSize="65536">
          <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
            maxBytesPerRead="4096" maxNameTableCharCount="16384" />
          <reliableSession ordered="true" inactivityTimeout="00:10:00"
            enabled="false" />
          <security mode="Transport">
            <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
            <message clientCredentialType="Windows" />
          </security>
        </binding>
      </netTcpBinding>
    </bindings>
    <client>
      <endpoint address="net.tcp://testapp.bimar.com:8019/DistributedService.Wcf.ScheduledJobsService.svc/netTcpAdres"
        binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IScheduledJobsService"
        contract="ServiceReference1.IScheduledJobsService" name="NetTcpBinding_IScheduledJobsService">
        <identity>
          <servicePrincipalName value="host/ testapp.bimar.com" />
        </identity>
      </endpoint>
      <endpoint address="http:// testapp.bimar.com:8018/DistributedService.Wcf.ScheduledJobsService.svc"
        binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IScheduledJobsService"
        contract="ServiceReference1.IScheduledJobsService" name="BasicHttpBinding_IScheduledJobsService" />
    </client>
  </system.serviceModel>

Renkli kısımlarda gördüğünüz gibi;
Baseadress olarak svc dosyası görünüyor. BasicHttp için özel bir adres vermemiştik. netTcp için verdiğimiz özel adres (netTcpAdres) base adrese eklenmiş durumda.

Konuyla ilgili aşağıdaki linkleri de inceleyebilirsiniz.



İyi Çalışmalar

Serkan

1 Ağustos 2012 Çarşamba

Arayuz Validation Yetersizligi ve Session Kullanimi

Selamlar,
Yine guzel bir senaryo ile karsinizdayiz.

Arayuz validation’in yetersizligini kanıtlayan, dikkatli Session kullaniminin onemini gosteren super bir ornek.

Uygulamamızda Booking listesi isimli bir sayfamiz var. Bu sayfada arama yapiliyor, donen kayitlarin toplam adetlerini gosteren ekipman adetlerini goster isimli bir buton var. Bu buton kayit gelirse aktif, kayit gelmezse pasif gorunuyor. Kayit gelirse, bunlarin idleri Session’a aktariliyor. Ekipman adetlerini goster tıklaninca bir Dialog aciliyor ve bu dialog Session’daki bilgileri okuyup listeleme yapiyor.



Acilan Dialog’un calistirdigi kod su sekilde:
protected override void CustomExecute(BookingBaseRequest requestMessage, BookingBaseResponse responseMessage)
        {
            EkipmanAdetleriListeleRequest ekipmanAdetleriListeleRequest = (EkipmanAdetleriListeleRequest)requestMessage;
            EkipmanAdetleriListeleResponse ekipmanAdetleriListeleResponse = (EkipmanAdetleriListeleResponse)responseMessage;

            IPredicateExpression filtre = new PredicateExpression();
            if (ekipmanAdetleriListeleRequest.BookingIdList.Count > 0)
            {
                int count = ekipmanAdetleriListeleRequest.BookingIdList.Count;
                if (count >= 1000)
                {
                    int mod = count % 500;
                    count = count - mod;
                    int parcaSayisi = count / 500;
                    if (mod > 0)
                    {
                        parcaSayisi++;
                    }
                    IPredicateExpression idListFilter = new PredicateExpression();
                    for (int parIndex = 0; parIndex < parcaSayisi; parIndex++)
                    {
                        List<long> parcaList = new List<long>();
                        for (int index = parIndex * 500; index < count && index < ((500 * (parIndex + 1))); index++)
                        {
                            parcaList.Add(ekipmanAdetleriListeleRequest.BookingIdList[index]);
                        }
                        if (parcaList.Count != 0)
                        {
                            if (parIndex == 0)
                                idListFilter.Add(BkgBookingFields.Id == parcaList);
                            else
                                idListFilter.AddWithOr(BkgBookingFields.Id == parcaList);
                        }
                    }
                    filtre.Add(idListFilter);
                }
                else
                    filtre.AddWithAnd(BkgBookingFields.Id == ekipmanAdetleriListeleRequest.BookingIdList.ToArray());
            }
            filtre.AddWithAnd(DokKonsKonteynerYukuFields.AnaDokKonsKonteynerYukuId == DBNull.Value);

            #region Tip Tur Adet Hesaplama
            DataTable tipTurAdetDT = BkgDataTableFiller.FillBookingEkipmanTipTurAdetDetaylari(filtre);
            // BookingIdListesini içeren ekipmanlar dolu ve boş olanlar olarak iki
            // ayrı DataTable' a alınır.
            DataTable tipTurDoluAdetRow = (from tipTurAdetRow in tipTurAdetDT.AsEnumerable()
                                           where tipTurAdetRow.Field<bool>("DoluMu") == true
                                           group tipTurAdetRow by
                                                            new
                                                            {
                                                                Adet = tipTurAdetRow.Field<long?>("Adet"),
                                                                YukEkpBoyut = tipTurAdetRow.Field<short?>("YuklemeEkipmaniBoyutuKod"),
                                                                YukEkpTip = tipTurAdetRow.Field<string>("YuklemeEkipmaniTipiKod")
                                                            } into g
                                           select new
                                           {
                                               Adet = g.Key.Adet,
                                               YukEkpBoyut = g.Key.YukEkpBoyut,
                                               YukEkpTip = g.Key.YukEkpTip
                                           }).CustomCopyToDataTable();
            DataTable tipTurBosAdetRow = (from tipTurAdetRow in tipTurAdetDT.AsEnumerable()
                                          where tipTurAdetRow.Field<bool>("DoluMu") == false
                                          group tipTurAde

Arayuzden idlist gelirse filtreye ekliyor. Gelmezse eklemiyor, bunu validate’te kontrol de etmiyor. Nasil olsa arayuzden buton kapali diye dusunulmus.

Kullanici multi tab calissin.
Ilk actigi sayfada booking listesi dondu, Session’a data yazildi, buton aktif.
Ikinci actigi sayfada booking listesi donmedi, Session bosaltildi, buton pasif.
Ilk actigi sayfaya dondu, butona basti. Gümm. Bomba patladi, Tüm dbyi ayaga kaldirdi J)

Su an icin Cozum olarak Metodun validation’a ilave yapildi.

File Server - Db Lock

Merhaba,
Gecen hafta bir olay yasadik;

Bir anda dosya yazmalarda yavaşlık, database’te lock problemleri, geç connection alma gibi problemler yağmaya başladı.

Uzun ugraşlar sonucu sorun tespit edildi.
Yoğun dosya üreten bir uygulamamizın entegrasyon icin dosyalarini yazdigi file server kendinden geçmiş. Haliyle dosya yazma işlemlerinde müthiş bir yavaşlık yaşandı.

Lock’larin sebebine gelince;
Aşağıdaki kod for döngüsü içerisinde xml üretiyor ve bahsedilen file server’a yazıyor. Yazdıktan sonra da db’de bir alanı update ediyor. İşlem genel olarak transactional yapılmış.
Böyle olunca database dk’larca beklemeye geçiyor ve locklar oluşuyor.

Connection geç alma problemi de, db’ nin locklarla uğraşırken diğer işlere yeterli zaman ayıramamasından kaynaklanıyor J

Güzel bir örnek, umarım başınıza gelmez.


public void TopluAktarmaLimaniSefLokDegisiklikEntegrasyonu(List<long> bookingIdList, string islemYeri, long kullaniciId, string islemAdi)
        {
            TransactionHelper transaction = new TransactionHelper();
            transaction.BeginTransaction();
            try
            {
                foreach (long bookingId in bookingIdList)
                {
                    BkgBookingEntity bookingEntity = new BkgBookingEntity(bookingId);
                    DenizBookingKonsimentoEntity denizBookingKonsimentoEntity = new DenizBookingKonsimentoEntity(bookingEntity);
                    string entKod = "";
                    entKod = EntegrasyonKoduDondur(denizBookingKonsimentoEntity.DokDenizKonsimentosu.YuklemeLimaniLokasyonId);
                    if (BookingBusinessEntity.LimanXLimaniMi(denizBookingKonsimentoEntity.DokDenizKonsimentosu.YuklemeLimaniLokasyonId))
                    {
                        if (bookingEntity.GonderildiMi == true)
                        {
                            BookingBusinessEntity bookingBusinessEntity = new BookingBusinessEntity(bookingEntity);
                            List<long> ekpIdList = GonderilecekEkipmanlariBul(bookingEntity, transaction);
                            if (ekpIdList.Count > 0)
                            {
                                string dosyaDurumKodu = ((int)EntegrasyonEnumarations.DosyaDurumKodlari.Replace).ToString();
                                BookingAnaSchemaDoldur(bookingId, ekpIdList, null, entKod, dosyaDurumKodu, false, islemYeri, kullaniciId, islemAdi); //FILE SERVER ERISIMI
                            }
                        }
                        else
                        {
                            YuklemeLimaniXLimaninaDondugundeXeYeniGonderim(denizBookingKonsimentoEntity, islemYeri, kullaniciId, islemAdi);
                        }
                    }
                    else
                    {
                        if (bookingEntity.GonderildiMi == true)
                        {
                            BookingBusinessEntity bookingBusinessEntity = new BookingBusinessEntity(bookingEntity);
                            List<long> ekpIdList = GonderilecekEkipmanlariBul(bookingEntity, transaction);
                            string dosyaDurumKodu = ((int)EntegrasyonEnumarations. DosyaDurumKodlari.Cancellation).ToString();
                            BookingAnaSchemaDoldur(bookingId, ekpIdList, null, entKod, dosyaDurumKodu, false, islemYeri, kullaniciId, islemAdi);
                            bookingEntity.GonderildiMi = false;
                            bookingEntity.Save();
                        }
                    }
                }
                transaction.CommitTransaction();
            }
            catch (Exception a)
            {
                transaction.RollbackTransaction();               
                throw a;
            }
            finally
            {
                transaction.DisposeTransaction();
            }
        }