Production Ortamındaki .NET Core Uygulamasında Publish Sorunu

Merhaba,

IIS Server üzerinde publish edilmiş bir .NET Core uygulamasının dll’lerini değiştirmek, üstüne yazmak istediğinizde lock’lı olmasından dolayı “The process cannot access the file because it is being used by another process” hatası alırsınız. Bunu aşmak için kullandığınız application pool’u durdurmak ya da publish dosyanızın içeriğini değiştirmek iki ayrı yöntemdir.

İlk seçenek powershell üzerinden komut yardımıyla yapabilirsiniz;
C:\Users\Administrator> Stop-WebAppPool -Name "DotNetCorePool"
— deploy işlemi —
C:\Users\Administrator> Start-WebAppPool -Name "DotNetCorePool"

Diğer seçenek olarak da uzantısı pubxml olan publish dosyanıza aşağıdaki satırı ekleyebilirsiniz.

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<WebPublishMethod>FileSystem</WebPublishMethod>
<EnableMSDeployAppOffline>true</EnableMSDeployAppOffline>
<PublishProvider>FileSystem</PublishProvider>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<SiteUrlToLaunchAfterPublish />
<LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
<ExcludeApp_Data>False</ExcludeApp_Data>
<ProjectGuid>f9ab3eb9-187f-4e8e-bc03-5fa7fc70821d</ProjectGuid>
<publishUrl>bin\Release\PublishOutput</publishUrl>
<DeleteExistingFiles>False</DeleteExistingFiles>
</PropertyGroup>
</Project>

AWS Lambda ile Serverless ASP.NET Core Uygulaması Geliştirme

Merhaba, bu yazımızda AWS’in sunucusuz uygulama mimarisi (serverless architecture) sunan Lambda hizmeti ile ASP.NET Core web uygulaması nasıl geliştirilir, deploy edilir ve çalışma mantığı neye dayanır gibi soruları kısaca cevaplamaya çalışacağız.

Öncelikle sunucusuz mimariye kısaca göz atarsak, bu kavramın aslında sunuculara ihtiyacı n olmadığı, hatta sunucunun olmadığı bir dünya değil; sunucular üzerindeki yük dağıtımı, konfigürasyonlar, ölçeklendirme, deployment, test gibi konuları yönetme zor(unlu)luğunu ortadan kaldıran bir yaklaşım olarak ortaya çıkıyor. Aşırı yük altında çalışan, yüksek network trafiğine sahip web uygulamalarında, yazılan iş mantığı ile birlikte bu tip konuların da önemi artıyor. Özetle sunucusuz mimari; geliştiriciye, uygulamanın iş mantığını ortaya çıkaracak fonsiyonları yaz, run-time konusuna kadar her şeyi soyutlayıp kendi tarafımda yöneteceğim diyor. Bunu popüler bir kısaltma olarak FaaS (Function as a Service) şeklinde adlandırabiliriz.

Peki neden AWS Lambda vb. servisler tercih edilebilir? FaaS yaklaşımının geliştiriciden yukarıda bahsedilen konuları soyutlaması, verim ve maliyet olarak geri dönüyor. Aynı zamanda kullanım başına ödeme (pay-per-use-pricing) yaklaşımı, fonksiyon çağırımlarına kadar inmiş durumda. Bu durum maliyet açısından, kullanılan ram ve işlemci seviyesine göre ücretlendirmeyle kıyaslandığında oldukça avantajlı.

Mevcut bir ASP.NET Core uygulamasının çalışma mantığına baktığımızda, clienttan gelen requestin, IIS ya da Nginx gibi bir web sunucu üzerinden Kestrel’e ve oradan Web API controllerlarına ulaştığını görüyoruz.

Ancak uygulamamızı, AWS Lambda üzerinde yayınlarsak durum değişiyor. Gelen istekler, AWS API Gateway üzerinden geçip daha sonra Lambda tarafından karşılanıyor.

 

AWS Lambda hizmetini kullanmaya karar verdik ve ASP.NET Core ile bir web uygulaması geliştirmek istiyoruz. İlk olarak AWS Toolkit Visual Studio kuruyor ve AWS Explorer üzerinden profil bilgilerini giriyoruz. (Bu sonraki deployment aşamasında işe yarayacak.)

Daha sonra yeni bir AWS Serverless Application oluşturuyoruz.

Oluşturulan proje şablonunda, klasik Web API şablonundan farklı olarak S3ProxyController, entry pointleri içeren sınıflar ve serverless.template dosyası göreceksiniz. Aslında önemli fark, uygulamanın Main() fonksiyonu içeren Program.cs üzerinden başlaması değil; LambdaEntryPoint.cs sınıfı ile ASP.NET Core frameworkünün ayağa kaldırılmasından başlıyor. Bu sınıf aynı zamanda, uygulamanın AWS kaynaklarını nasıl kullanacağını belirten serverless.template dosyasında da Handler olarak yazıyor.

"Get" : {
      "Type" : "AWS::Serverless::Function",
      "Properties": {
        "Handler": "AWSServerless2::AWSServerless2.LambdaEntryPoint::FunctionHandlerAsync",
        "Runtime": "dotnetcore1.0",
        "CodeUri": "",
        "MemorySize": 256,
        "Timeout": 30,
        "Role": null,
        "Policies": [ "AWSLambdaFullAccess" ],
        "Environment" : {
          "Variables" : {
            "AppS3Bucket" : { "Fn::If" : ["CreateS3Bucket", {"Ref":"Bucket"}, { "Ref" : "BucketName" } ] }
          }
        },
        "Events": {
          "PutResource": {
            "Type": "Api",
            "Properties": {
              "Path": "/{proxy+}",
              "Method": "ANY"
            }
          }
        }
      }
    }

Bununla birlikte LocalEntryPoint.cs sınıfını Handler olarak varsayabilir ve localde çalışabilirsiniz. Controllers klasörü içinde gelen S3ProxyController, GET, POST gibi HTTP metotlarının, deploy edilmiş projenin konfigürasyon dosyasını içerecek S3 bucket’a AWS SDK.NET tarafından nasıl çağrıda bulunulduğunu gösteriyor. Localde çalışırken appsetting.json dosyasından farklı bir bucket adı verebiliyoruz.

{
  "Lambda.Logging": {
    "LogLevel": {
      "Default": "Debug",
      "Microsoft": "Information"
    }
  },
  "AppS3Bucket": ""
}

Şimdi mevcut uygulamamızı, toolkit yardımıyla deploy etmeye çalışalım. Bu noktada yardımımıza proje için oluşturulmuş serverless.template koşuyor. AWS’in bir diğer toolu olan Cloud Formation, bir uygulamanın çalıştırılmadan önce hangi AWS kaynaklarını (EC2, DynamoDB, S3, Cache, VPC vs.) nasıl kullanacağını json ya da YAML formatında tasarlamamızı sağlıyor. Yapmamız gereken AWS Explorer -> AWS Cloud Formation -> Create Stack -> Select a file yolunu izleyerek serverless.template dosyasını göstermek ve oluşturacağımız stacke yeni bir isim vermek. 

Publish to AWS Lambda kısmını başarıyla geçtikten sonra domain adınız yoksa AWS, Serverless URL oluşturacaktır.

Linkler:

https://aws.amazon.com/blogs/compute/container-reuse-in-lambda/
https://read.acloud.guru/how-to-keep-your-lambda-functions-warm-9d7e1aa6e2f0
https://start.jcolemorrison.com/aws-lambda-vs-the-world/

AWS S3 Storage ile Dosya İşlemleri

Bu yazımızda, AWS’nin storage hizmeti olan Amazon S3 Storage ve .NET SDK’sını kullanarak dosyalarımızı nasıl yöneteceğimizi inceleyeceğiz.

Bir web uygulamasında, sıklıkla dosya yükleme kullanılıyorsa, sunucuda tutulan bu dosyaların saklama, arşivleme ve hatta yükleme işlerinin bir süre sonra baş ağrıtan bir problem haline gelme ihtimali epey yüksektir. Amazon’un S3 Storage hizmeti ya da benzeri ürünler, scalability, arşivleme ve analitik konularında pratik ve kolay uygulanabilir çözümleri güvenli bir yolla kullanıma sunuyor. Bu yüzden, web uygulamalarının deploy edildiği klasörler içinde yazma – okuma işini, S3 bucket’larına devredebiliriz.

AWS Console üzerinden S3 servisine gidiyoruz ve yeni bir bucket oluşturuyoruz. Bucket adımız, AWS üzerindeki tüm bucketlar içinde tekil olmalıdır.

createbucket[0]

AWS, bize bir sonraki kısımda versiyonlama, loglama ve tag kullanıp kullanmayacağımızı soruyor, şimdi her birinin ne işe yaradığına kısaca bakalım;

Versiyonlama

Versiyonlamayı aktif etmek demek,  bucket içinde tuttuğumuz bir objenin farklı versioning_Enabledçeşitlerinin bir versionID ile birlikte tutulması anlamına gelir. Bu özellik ile aynı objenin tekrar yüklenmesi ve silinmesi durumunda ilk haline dönüşü sağlanabilir. Aşağıdaki görselde “h0721u2562x0134v3959” keyName’e sahip bir fotoğrafın ilk haline ulaşacağımız link, version ID ve son değiştirilme tarihi görülmektedir.

createbucket[1]

Loglama

Yüklenen dosyaların daha detaylı bilgilerine erişmek isteniyorsa loglama özelliği ücretsiz bir şekilde aktif edilebilir. (Ancak AWS log dosyalarını başka bir yere taşımak isterseniz data transfer ile bir tutarak ücret kesiyor.)

Bucket Owner Id
79
a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be
Bucket Name
mybucket
Create Date
[06/Feb/2014:00:00:38 +0000]
Remote IP
192.0.2.3
Requester
79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be
Request Id (Amazon tarafından her request için oluşturulur.)
3E57427F3EXAMPLE
File Name
keyname
Operation
REST.GET.VERSIONING –
Key
“GET /mybucket?versioning
HTTP/1.1”

200
Bytes Sent
113
Total Time
7
Error Message
“-”
“S3Console/0.4”

Tag Ekleme

Dosya yükleme esnasında, dosyayla bir ya da daha fazla tag ilişkilendirilerek kategorize edilebilir.

3. adımda kullanıcıların bucket içindeki dosyalara olan erişim kurallarını belirlememiz gerekiyor. Bu kısım varsayılan olarak geçilerek bucket’ı oluşturuyoruz ve içine girip Permissions sekmesindeki Bucket Policy alanına giriyoruz. Burada yer alan Policy Generator aracından faydalanarak erişim kurallarımızı belirleyebiliriz.

createbucket[12].PNG

Burada oluşturduğumuz JSON formatındaki kural setini, Bucket Policy içine kopyalayaıp kaydediyoruz. Artık bucket’ımızı kullanmaya hazırız.

Bu örnekte stream ve path kullanarak fotoğraf yükleme ve silme işlemlerini yapacağız. İlk olarak projemize AWSSDK.S3 paketini yükleyerek başlayabiliriz. Byte dizisi şeklindeki bir fotoğrafı yüklemek istiyorsak, MemoryStream sınıfı ile basit bir şekilde gerçekleştirebiliriz.

public static string UploadImageToAws(string keyName, string bucketName, byte[] imageArray)
        {
            try
            {
                using (var ms = new MemoryStream())
                {
                    client = new AmazonS3Client(ConfigurationManager.AppSettings["AWSAccessKey"],
                    ConfigurationManager.AppSettings["AWSSecretAccessKey"], RegionEndpoint.EUWest1);
                    var tu = new Amazon.S3.Transfer.TransferUtility(client);

                    ms.Write(imageArray, 0, imageArray.Length);
                    ms.Position = 0;
                    var req = new Amazon.S3.Transfer.TransferUtilityUploadRequest();
                    req.BucketName = bucketName;
                    req.Key = keyName;
                    req.InputStream = ms;
                    tu.Upload(req);

                    return "https://s3.amazonaws.com/" + bucketName + "/" + keyName;
                }
            }
            catch (AmazonS3Exception amazonS3Exception)
            {
                Console.WriteLine(amazonS3Exception.Message);
            }
            catch (Exception ex)
            {
                throw (ex);
            }
            return string.Empty;
        }

Mevcut bir fotoğrafı silmek içinse aşağıdaki gibi DeleteObject() metodunu çağırmak yeterli.

public static bool DeleteImageToAws(string keyName, string bucketName)
        {
            using (client = new AmazonS3Client(ConfigurationManager.AppSettings["AWSAccessKey"],
                   ConfigurationManager.AppSettings["AWSSecretAccessKey"], RegionEndpoint.EUWest1))
            {
                DeleteObjectRequest dor = new DeleteObjectRequest() { BucketName = bucketName, Key = keyName };
                client.DeleteObject(dor);
            }

            return true;
        }

 

C# – Extension Metot Kullanımı

Extension metotlar, mevcut sınıf ve struct yapılarının orjinalliklerini bozmadan yeni metotlar ve özellikler yazarak fonksiyonelliklerini genişletme ihtiyacından doğmuştur. Bu ihtiyacı var olan çözümlerle de (kalıtım, mevcut sınıfa metot ekleme, partial sınıf vs.) giderebiliriz. O halde neden extension metotları kullanıyoruz?

* .NET içinde yazılmış çok sayıda sealed olarak tanımlanmış tip ve sınıf mevcuttur. Bu durumu kendilerinden türeterek yazamayacağımız tip ve metotları extension metot kavramı ile aşabiliriz.

* Çalışılan projede çok sayıda sınıf var, yeni bir metot eklenmesi production ortamı için risk içeriyor olabilir. Bir metot için oluşturulacak partial sınıf mantığının bakımı da zorlaşabilir. Yine böyle bir durumda extension metotlar pratik bir yaklaşım olarak karşımıza çıkıyor.

Bir extension metot tanımlamak için;

* Statik bir sınıf içinde statik metot olarak tanımlanmalıdır.

* Extension metotta, genişletilecek sınıfın türü this anahtar sözcüğü ile parametre olarak alınmalıdır. Bu sınıf türü, this ile ele alınmazsa hiç bir zaman çağrılmayacaktır. Aynı zamanda bir metodu, kendi ismiyle genişletirseniz, yazılan extension metot yerine yine kendisi çağrılır.

internal static class StringExtensions
    {
        public static int CountWords(this string s)
        {
            var collection = Regex.Matches(s, @"[\S]+");
            return collection.Count;
        }
    }

Bu extension metot ile int sınıfını genişletmiş olduk, artık bu sınıftan türetilen objeler için kullanabiliriz.

Extension metotların IEnumerable objeler için kullanım örneklerini aşağıda bulabilirsiniz. Buna benzer faydalı extension metotları extensionmethod.net sitesinde bulabilir, siz de ekleyebilirsiniz. :)

public static class Extensions
{
    //listelerin null kontrolüne alternatif.
    public static IEnumerable<T> ToSafeList<T>(this List<T> source)
    {
        if (source != null)
            return source;
        return new T[0];
    }

    //ToList()'i belli bir sayı ile kullanmak için.
    public static List<T> ToList<T>(this IEnumerable<T> source, int count)
    {
        if (source == null)
            throw new ArgumentNullException("source");
        if (count < 0)
            throw new ArgumentOutOfRangeException("count");

        var list = new List<T>(count);
        list.AddRange(source);

        return list;
    }

    //ToArray()'i belli bir sayı ile kullanmak için.
    public static T[] ToArray<T>(this IEnumerable<T> source, int count)
    {
        if (source == null)
            throw new ArgumentNullException("source");
        if (count < 0)
            throw new ArgumentOutOfRangeException("count");

        var array = new T[count];
        var i = 0;

        foreach (var item in source)
        {
            array[i++] = item;
        }

        return array;
    }

}

C# ve MongoDB ile MapReduce Kullanımı

MapReduce, kısaca Google’ın veri işleme, indexleme gibi işlemlerinin arka planında yer alan algoritmasıdır. Çok sayıda makina barındıran kümelerle oluşturulan dağıtık mimari ile verilerin toplanması ve analiz edilmesi sağlanır.

Dağıtık mimari dediğimiz yapıda tüm veriyi alan ana düğüm (master node), alt düğümlere (worker node) veri toplama işini dağıtır. Toplanan veriler birleştirilerek ana düğüme tekrar gönderilir. Reduce aşamasında ise veri analiz edilir. İlişkisel veritabanları mantığı ile düşünürsek; map, select ifadesini, reduce ise count, having, avg gibi ‘data-aggreagation- işlemlerine karşılık geliyor. NoSQL sistemlerinde bu işlemlerin biraz daha karmaşık olması sebebiyle MapReduce işimizi gerçekten kolaylaştırıyor. MongoDB’nin dökümantasyonundan aldığım aşağıdaki görsel durumu daha açıklayıcı hale getirebilir.

map-reduce

MapReduce yapısının Google’ın bir algoritması olduğunu söylemiştik. C# ile MapReduce yapısını kullanmak istiorsanız MongoDB üzerinde entegre olarak geliyor. MongoDB C# driver ı her versiyonda biraz farklılaşıyor. Aşağıdaki örnekte 1.9.2 sürümünü kullandığımı belirteyim. Siz de projede kullanmak için Package Manager Console üzerinden dahil edebilirsiniz.

PM> Install-Package mongocsharpdriver -Version 1.9.2

Örnek senaryomuzda Products adında basit bir koleksiyon üzerinde bazı işlemler yapacağız. Aşağıdaki sınıfla veritabanından çekeceğimiz veri için model oluşturuyoruz.

class Product
    {
        public string name { get; set; }
        public string category { get; set; }
        public double price { get; set; }
        public DateTime enterTime { get; set; }
    }

Oluşturduğumuz koleksiyon içine ürün eklemek için MongoCollection sınıfından bir liste oluşturup Insert ya da  InsertBatch metodunu kullanabiliriz. InsertBatch() birden fazla verinin eklenmesini sağlar. AddProducts() içinde localhost‘a bağlanmak için gereken işlemlere de yer verdim. Uri‘ye veritabanı isminizi (bu örnekte test) verdikten sonra koleksiyonlarınıza GetCollection() metodu ile ulaşabilirsiniz.

static void AddProducts()
        {
            const string uri = "mongodb://localhost/test";
            var client = new MongoClient(uri);
            var db = client.GetServer().GetDatabase(new MongoUrl(uri).DatabaseName);

            var collection = db.GetCollection<Product>("Products");

            var products = new List<Product>{
                new Product {   name = "potato", 
                                category = "vegetables",
                                price = 5.32, 
                                enterTime = new DateTime(2015, 09, 14) },

                new Product {   name = "eggplant", 
                                category = "vegetables", 
                                price = 3, 
                                enterTime = new DateTime(2015, 09, 14) },
            };

            collection.InsertBatch(products);
        }

Bu kısımdan sonra asıl işlemlere yani map – reduce – finalize fonksiyonlarına geçebiliriz. Bu fonksiyonların MongoDB için Javascript ile yazıldığını hatırlatalım. Verilerin analizini price değeri üzerinden yapmayı seçersek fonksiyonlarımız aşağıdaki gibi şekillenecektir.

string map = @"
               function() {
               var product = this;
               emit(product.category, { count: 1, price: product.price });
                            }";

map işleminde, emit fonksiyonu kendisine gelen parametreleri key - value şeklinde toplamaktadır. Burada key, veriyi neye göre gruplayacağımıza karar verdiğimiz değerken (bu örnekte product) diğer parametre olan value, ürünün fiyatı ve sayısı (1 olmak durumunda) olmaktadır. Farklı düğümler üzerinde topladığımız veriyi ana düğüme aktardıktan sonra reduce fonksiyonuna geçebiliriz.

string reduce = @"        
                            function(key, values) {
                                var result = {count: 0, price: 0 };

                                values.forEach(function(value){               
                                    result.count += value.count;
                                    result.price += value.price;
                                });

                                return result;
                            }";

Map işleminden sonra bir bütün halinde gönderilen veri analiz edilerek tekrar toplanarak result adında tek bir veri haline getiriliyor. Burada her ürünün fiyatları toplanıyor. Buraya kadar yaptığımız işlemleri daha görsel bir örnekle açıklamaya çalışalım.

apple 3.25
orange 5
melon 2
—————

cucumber 2
eggplant 3
potato 5,32
—————

PC 4000
TV 3400

Yukarıda kategorilerine göre (fruits, vegetables, electronics..) key – value şeklinde sıralanmış veriler görüyoruz. Bu veri yapısı aynı zamanda toplanmış verinin reduce işlemine hazır olduğu anlamına geliyor. Reduce işlemi sonrası ise şöyle bir yapı ile karşılaşıyoruz;

reduce

 

 

 

 

Görüldüğü gibi ürünler kategorilerine göre gruplanmış ve fiyatlarının toplamı da alınmış bir şekilde gözüküyor. count, price değerlerinin yanısıra average değeri de gözünüze çarpmış olabilir.

string finalize = @"
                                function(key, value){
      
                                  value.average = value.price / value.count;
                                  return value;

                                }";

 

finalize fonksiyonu isteğe bağlı kullanılan ve reduce işleminden geçen veri üzerinde başka işlemler yapılmak istendiğinde kullanılabilir. Burada her kategorinin fiyat ortalamasını almış oluyoruz. Map, reduce ve finalize fonksiyonlarını yazarak verilerin nasıl toplanacağını ve analiz edeceğini belirtmiş olduk. Ancak neye göre gruplanacağı sorusuna henüz cevap vermedik. Örneğin toplanan fiyat değerinin 100’den büyük olduğu verileri, sadece fruits kategorisindeki verileri ya da giriş tarihi (bu örnekte enterTime) geçen ay ve bugüne kadar olan ürünleri listelemek istediğimizde ne yapacağız?

var mapReduceQuery = Query.GT("price", 100);

var options = new MapReduceOptionsBuilder();
options.SetFinalize(finalize);
options.SetOutput(MapReduceOutput.Inline);
options.SetQuery(mapReduceQuery);
var results = collection.MapReduce(map, reduce, options);


foreach (var result in results.GetResults())
{
    Console.WriteLine(result.ToJson()+"\n");
}

 

mapReduceQuery nesnesi ile çok çeşitli kombinasyonlar yapıp sonuçları değerlendirebilirsiniz. Bu basit uygulama dışında MapReduce işlemlerinin kullanıldığı örneklere Facebook’un kullanıcı davranışı analizlerinde, Amazon’un sunduğu web servis hizmetlerinden Amazon Elastic MapReduceu ve Linkedin, Twitter, Yahoo gibi çok büyük verilerle uğraşan şirketlerin yoğun olarak kullandığını verebiliriz. Daha fazla bilgi için MapReduce algoritmasını kullanan açık kaynak kodlu Hadoop platformunu inceleyebilirsiniz.

Online Check-in ve Overbooking Üzerine

Türkiye’de sivil havacılık sektörünün son yıllarda inanılmaz yol kat etmesiyle birlikte havayolu şirketlerinin günlük yolcu taşıma kapasitesinde de büyük artış oldu. Rakamlarla konuşursak Atatürk Havalimanı’ndan (AHL) 2005 yılında uçan yolcu sayısı 19.3 milyonken, 2015 yılında bu sayı 61.3 milyona yükselmiştir. AHL, bugün günde 1300’den fazla uçağa ve 160 binden fazla yolcuya hizmet vermektedir.

Karlılık rekorları kıran havayolu şirketlerinin kaynaklarında yolcu ve uçuş sayılarının yanısıra az bilinen overbooking kuralı da yer alıyor. IATA standartlarına göre yasal hak olan overbooking, bazı uçuşlarda koltuk kapasitesinin üzerinde bilet satma anlamına geliyor. Uçuş dolu olsa bile no-show olarak belirtilen bazı yolcuların uçuşa gelmemesini göz önüne alınarak overbook satışlar yapılabiliyor.

Havalimanlarında büyük stres yaşayan overbook olmuş yolcuların tartışmaları nadir görülen bir olay değil üstelik. Özellikle bayram, hac, tatil gibi yoğun dönemlerde sık rastlanan bu durumda yolcu mutlaka uçuş yapmak isterse, diğer yolculara danışılıyor. Uçamayan yolcu için, iç hat uçuşlarında 100 Euro, dış hat uçuşlarında ise uzaklığa bağlı olarak 250 – 600 Euro tazminat ödenerek bir adet ücretsiz uçuş sağlanıyor. Farklı bir saat/gün seçiminde ise otel ve CIP salonu imkanı sunuluyor.

Havayolu firmaları, mağduriyeti gidermek adına güzel imkanlar sunsa da bu aksiliği yaşamamanızın yolu online check-inden geçiyor. Aşağıda belirtilen süre aralıklarında online check-in yaparak hem overbook olma riskini kaldırır hem de havalimanında uzun kuyruklar beklemezsiniz. Üstelik bazı firmalar, online check-in yapan yolcularına bazı kampanyalar düzenliyor.

Havayolu En erken En geç
THY 24 sa önce 90 dk önce
Anadolujet 24 sa önce 90 dk önce
Atlasglobal 48 sa önce 90 dk önce
Pegasus 72 sa önce 45 dk önce
Borajet 24 sa önce 2 sa önce

Windows 8 ve Windows Server 2012’de ASP.NET 4.5 Kullanımı

Windows’un önceki versiyonlarında Default Web Site altındaki bir uygulamanın framework değerini komut satırından aspnet_regiis.exe ve gerekli parametreleriyle uygun hale getirmek mümkündü. Siz de Windows 8 ve üzeri bir versiyona geçtiyseniz ve örneğin uygulamanız .NET 4.5 kullanıyorsa küçük bir işlem yapmalısınız. Bunun sebebi aspnet_regiis.exe’nin Windows 8 sonrasında install ve uninstall işlemleri için emekliye ayrılması diyebiliriz, en azından .NET 4.5 için. Yapılması gereken, Denetim masasından Windows özellikleri aç veya kapat seçeneğinde bulunan Internet Information Services altındaki ASP.NET 4.5 seçeneğini işaretlemek.

blog

Eğer Windows Server 2012 kullanıyorsanız, Server Manager altında bulunan şu yolu takip edebilirsiniz;
“Web Server (IIS) -> Web Server ->Application Development -> ASP.NET 4.5”.

SQL Server’da Bulunan Stored Procedure ve View İçinde Arama Yapma

Stored procedure, view ve tabloların sayısı arttıkça hangi tablonun nerede kullanıldığını incelemek zorlaşabiliyor. Örneğin bir tablo üzerinde yapılan değişikliği kullanıldığı her noktayı bulmak ve değişikliği işlemek isteyebiliriz. MS SQL Server için konuşursak bunun aşağıdaki gibi bir yolu bulunmaktadır. Tablo adınızı yazdığınızda aşağıdaki sorgu hangi stored procedure’lerde yer aldığını listeler.

SELECT o.name,o.create_date,o.modify_date
FROM sys.sql_modules sm
INNER JOIN sys.objects o ON o.object_id = sm.object_id
WHERE o.type = 'P' AND sm.definition LIKE '%tablo_adi%'
ORDER BY o.name

Aşağıdaki sorgu da view’lerin içinde arama yapmamızı sağlar.

SELECT o.name, o.create_date, o.modify_date
FROM sys.objects o
WHERE o.type IN ('V') AND 
OBJECT_DEFINITION(object_id) LIKE '%tablo_adi%'
ORDER BY o.name

LINQ Sorgularında Left/Right Join İşlemleri

Bu yazıda outer join işlemlerini Linq sorgularıyla nasıl gerçekleştirebileceğimize bakacağız. Inner join işleminde birden fazla tablonun sadece istenen kolonlarının eşleştiği bilgileri getirilmesi sağlanır. Ancak bazı durumlarda tabloların alınacak kesişim kümesini biz belirlemek isteyebiliriz. Bunu iki basit veri tipi ile açıklayalım. Kitap ve SatisTipi adlı iki sınıf olsun.

public class Kitap
    {
        public int KitapNo { get; set; }
        public string KitapAdi { get; set; }
    }
    public class SatisDetay
    {
        public int SatisNo { get; set; }
        public int KitapNo { get; set; }
        public string SatisTipi { get; set; }
    }

 

Örnek verilerimiz de aşağıdaki gibi olsun.

List<Kitap> ktpListe = new List<Kitap>
                {
                    new Kitap{KitapNo=1, KitapAdi="Kaiken"},
                    new Kitap{KitapNo=2, KitapAdi="Satori"},
                    new Kitap{KitapNo=3, KitapAdi="Şibumi"},
                    new Kitap{KitapNo=4, KitapAdi="Kişisel Bir Sorun"},
                    new Kitap{KitapNo=5, KitapAdi="Kappa"}
                };

            List<SatisDetay> stsListe = new List<SatisDetay>
                {
                    new SatisDetay{SatisNo=1, KitapNo=1, SatisTipi="Internet"},
                    new SatisDetay{SatisNo=2, KitapNo=2, SatisTipi="Magaza"},
                    new SatisDetay{SatisNo=3, KitapNo=3, SatisTipi="Internet"},
                    new SatisDetay{SatisNo=4, KitapNo=3, SatisTipi="Internet"}
                };

 

Eğer satışı gerçekleşen kitapların adını listelemek isteseydik inner join işlemini şu şekilde kullanabiliriz.

var kitaplar = (from k in ktpListe
                            join s in stsListe on k.KitapNo equals s.KitapNo
                            select k.KitapAdi
                                    ).Distinct();

 

Ancak satışı gerçekleşmeyen kitapları da aynı liste de görüntülemek isteseydik bu kez left join işlemi yapmamız gerekir. Satışı gerçekleşmeyen kitaplar için satış tipi NULL gelecektir. Burada DefaultIfEmpty() metodu dikkatinizi çekmiştir. a olarak ifade ettiğimiz tablodan b olarak ifade ettiğimiz SatisDetay tablosunda karşılığı boş olan kolonları da getirmesini sağladık.

var kitaplar = (from k in ktpListe
                            join s in stsListe on k.KitapNo equals s.KitapNo
                            into a from b in a.DefaultIfEmpty(new SatisDetay())
                            select k.KitapAdi
                                    ).Distinct();

 

Eğer mevcut tüm satış tiplerini getirmek istersek right join işlemi yapabiliriz.

var satisTipleri = (from s in stsListe
                            join k in ktpListe on s.KitapNo equals k.KitapNo
                            into a from b in a.DefaultIfEmpty(new Kitap())
                            select s.SatisTipi
                                   ).Distinct();

 

 

 

VQ5XP

LINQ Sorgularında If Kontrolü

Bazı durumlarda LINQ sorgularını çalıştırırken if durumu ile kontrol gerekebilir. Örneğimizde DataModel adlı bir model sınıftan LINQ ile OrnekData tablosundan 3 adet bilgi çekelim.

IQueryable<DataModel> q = (from od in OrnekData
                        where od.FirmaId != null
						select new DataModel
                               {
                                CalisanAdi = od.CalisanAdi,
                                Id = od.Id,
                                KullaniciAdi = od.KullaniciAdi.HasValue ? od.KullaniciAdi : null,
                                Sifre = od.Sifre.HasValue ? od.Sifre : 0
                                });

public class DataModel
        {
            public string CalisanAdi { get; set; }
            public int? Sifre { get; set; }
            public string KullaniciAdi { get; set; }
        }

 

Kullanıcının kullanıcı adı ve şifresinin olup olmadığını HasValue özelliğiyle kontrol ettik eğer yoksa null ve 0 değerlerinin kullanılmasını sağladık.