Sharing sessions between subdomains – Asp.Net Mvc Apps on IIS

Sometimes, you need to share sessions between different apps on different sub domains. There are some steps to achieve this behaviour and I will try to explain them today.

If we want apps to behave like single app on different subdomains, firstly they must use same cookies. With shared cookies, users won’t have to logged in for each app. They will be able to logged in / out only once for all apps.  In order to share cookies we need to add a setting under system.web section in webconfig for cookies:

<httpCookies domain=".yourmaindomain.com"/>

With this setting, any subdomain under yourmaindomain.com use the same cookies. But there is one more step here, all apps have to same machinekey setting on webconfig. Machinekey attribute is used while encrypting and decrypting the data for the webapplication in ASP.NET.

Before move further, Lets create two websites on our web server.

iis create web site

After creating two websites, for one, select MachineKey feature and click Generate Keys. Copy Validation Key and Decryption Key. Then open other app’s Machine Key feature and paste copied values to related fields.

These values will be pasted to a web config attribute too.

<machineKey validationKey="XXXXX" decryptionKey="XXXXX" validation="SHA1" decryption="AES" />

This attribute will be under system.web section in webconfig.

These changes helps us to use shared cookies without any problem. But to achieve our goal completely, we need to do one more thing. We have to store session state in database, so all applications will share same session data. By adding setting below to web config and editing to connection string, all session data will be shared.

<sessionState 
            mode="SQLServer"
            sqlConnectionString="data source=127.0.0.1;user id=username;password=strongpassword"
            cookieless="false" 
            timeout="20"/>

 

PHP Long Polling Örneği

Web ve mobil uygulamaların son zamanlardaki olmazsa olmazlarından birisi de bize olayları bildirimler ile iletmesi. Uygulamalar gelen mesajları, beğenileri vs. sayfanın bir yerinde bizim başka bir sayfaya gitmemize gerek kalmadan bize iletiyorlar. Ben de üzerinde çalıştığım bir uygulama+web sayfasında bildirimleri gösterme ihtiyacı hissettim. İlk etapta bunu web socketler ile yapmaya karar verdim. İlk denemem de gayet güzel bir şekilde çalıştı ama bir de mobil uygulama üzerinde denemeye karar verdiğimde hayal kırıklığına uğradım çünkü android WebView’de web socketler desteklenmiyordu. Bu nedenle daha az verimli, daha sorunlu ama yapması gereken işi platform ayırt etmeden yapan eski yöntem long polling ile yapmaya karar verdim. Belki ihtiyacı olanlar olabilir düşüncesiyle burada bir küçük örneğini paylaşmaya karar verdim, temel mantığı göstermekte faydalı olacaktır.  Öncelikle değişiklik olup olmadığını takip eden php dosyamızı yazalım.

polling.php

<?php
$gonderenId=$_POST["gonderenId"];
$pollMu=$_POST["poll"];
if (file_exists($gonderenId.'.txt') == false)
{
    file_put_contents($gonderenId.'.txt', time());
}

if (isset($pollMu))
{
    set_time_limit(150); // Zaman limitini beliliyoruz

    date_default_timezone_set('Europe/Istanbul');
    $time = time();
    $poll = true;
    while ($poll)
    {
        clearstatcache();
        $mtime = filemtime($gonderenId.'.txt');
        if ($mtime > $time) // Eğer dosyanın eklenme/güncellenme zamanı alınan zamandan büyük mü 
        {
            $poll = false;
            //burada veritabanından ilgili değerler çekilecek.
        }
        sleep(1); // Kaynakları tüketmemek için bir süre bekliyoruz
    }

    $arr = array ('mesaj'=>1,'begeni'=>2,'hediye'=>3); // Bunlar veritabanından alınan sonuçlar olacak
    echo json_encode($arr);
    exit;
}
?>

Bu dosyada öncelikle değişiklikleri takip edilecek kullanıcının idsini alıp, eğer bu idli bir dosya yoksa bir text dosyası oluşturuyoruz.  Daha sonra bir while loop’u içerisinde oluşturulan dosyanın tarihi, while’dan önce alınan tarihten büyük mü diye bakıyoruz. Eğer büyükse dosya güncellenmiştir, dosya güncellemesini ilgili kişiye yapılan işlemlerden önce yapıyoruz. Bir sonraki ekleyeceğimiz dosyada yapılan iş. Eğer bu koşulu sağlıyorsa, while döngüsünden çıkmak için değişkenimize false atıyoruz ve sonrasında veritabanından ilgili sorguları çekiyoruz. Ve bunlarsı json olarak dönüyoruz.

islem.php

<?php

$aliciId=$_POST["aliciId"];
$time = time();
file_put_contents($aliciId.'.txt', $time); // İlgili kullanıcının dosyasına o anı yazıyoruz ki server.php değişikliği yakalayabilsin.
//Burada veritabanında yapacağımız asıl işleri yapıyoruz.

?>

Kodumuzun bu kısmı ise kişileri mesaj attığımızda, beğeni gönderdiğimizde vs çalışacak olan veritabanı kodlarının bulunduğu kısım. Burada veritabanı işlemlerinden hemen önce alıcının idsi ile bulunan dosyaya tarih bilgisini atıyoruz ki dosyanın tarihi güncellensin ve az önce yazdığımız while döngüsündeki koşulu sağlasın.

Son olarak da client sayfamızı yazalım.

client.html

<html>
	<head>
		<title>
			Deneme
		</title>
		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1254">
	<script src="jquery-2.0.3.min.js"></script>
	<script>
		$(document).ready(function() {

			startPolling();

		$("#gonder").click(function(){
			$.ajax({
				type: "POST",
				url: 'islem.php',
				data: {
					aliciId: '123456789' // Diğer kullanıcının bilgisi
				},
				success: function(data) {
					alert("gönderildi.");
				}
			});				
		});	

		});

		function startPolling()
		{
			$.ajax({
				type: "POST",
				url: 'polling.php',
				data: {
					poll: 'evet',
					gonderenId: '123456789' // Login olan kullanıcının bilgisi
				},
				success: function(data) {
					displayNotifications(data);
					startPolling();
				}
			});		
		}

		function displayNotifications(data)
		{
			var obj;
			try {
				obj = jQuery.parseJSON(data);
				if(obj.mesaj > 0)
					$("#mesaj").html("Mesaj="+obj.mesaj);
				if(obj.hediye > 0)
					$("#hediye").html("Hediye="+obj.hediye);
				if(obj.begeni > 0)
					$("#begeni").html("Begeni="+obj.begeni);
			} 
			catch(err)
			{
				return true;
			}

		}
	</script>
	</head>
	<body>
	<div id="mesaj"></div>
	<div id="hediye"></div>
	<div id="begeni"></div>
	<br />
	<input type ="button" id="gonder" value="Etkileşim Gönder" />
	</body>
</html>

Burada öncelikle sayfamız ilk yüklediğinde ajax ile startPolling fonksiyonumuzu çağırıyoruz. gonderenId değişkeni login olan kullanıcıyı, aliciId de mesaj attığımız vs. kullanıcıyı gösterecek. Burada aynı olma sebebi test edebilme amaçlı. Eğer long polling başarı ile tamamlanırsa, yani bir bildirim gelmişse bildirim divlerimizi güncelliyoruz. Sonrasında tekrar startPolling fonksiyonumuzu çağırıyoruz ki dinlemeye devam edebilelim. İşte hepsi bu kadar. İlgili dosyaları lokalinizde oluşturup, kendiniz de deneyebilirsiniz. Jquery dosyasını da aynı dizine koymayı unutmayın.

Bugünlük bu kadar, Çevik Kalın 🙂

socket_create() hatası (PHP Socket)

Php ile bir uygulama geliştiriyorsunuz ve socketleri kullanmaya karar verdiniz. Bütün her şey hazır Command prompttan server uygulamanızı çalıştırıyorsunuz… derken çalıştıramıyorsunuz. Karşınızda bir hata

Fatal error: Call to undefined function socket_create()

Nasıl yani diyorsunuz. Halbuki php.ini dosyasında php_sockets’i enable etmiştiniz. Emin olamıyorsunuz tekrar kontrol ediyorsunuz ama evet işte orada enabled durumda. Durun, sizde herhangi bir sıkıntı yok. Sıkıntının tek sebebi  Command Prompt’un Apache server’dan farklı bir php.ini dosyasına bakması. Apache server Apache/bin/ altındaki php.ini dosyasına bakarken, Command Prompt php\ altındaki php.ini dosyasına bakar. Bu dosya içinde php_sockets extension’ına izin verirseniz hatasız bir şekilde istediğiniz işlemi yapabileceksiniz.

Composition ile Aggregation Arasındaki Fark

Uygulama geliştirirken OOP prensiplerine yaklaştıkça nesneler arasındaki ilişkilerin önemi de gitgide artıyor.  Ben de tasarım desenlerine verdiğim kısa arada çok karıştırılan iki kavramdan bahsetmek istiyorum. Nesneler arasındaki iki ilişki türü : Aggregation, Association

Aggregation : Bu tür ilişki de nesnelerin yaşam döngüleri birbirlerinden ayrıdır. Bir nesne diğerinden bağımsız olarak da yaşamını sürdürebilir. Yani aralarında bir sahiplik ilişkisi (has-a ) vardır. Örneğin Dizüstü Bilgisayarınız ile onun çantası arasında böyle bir ilişki vardır. Çantayı ayrı olarak ya da laptop’u ayrı olarak düşünebiliriz. Yaşam döngüleri ortak değildir. UML diagramında gösterimi ve koda dökülmüş bir örneği aşağıdaki gibidir.

public class Canta
{

}
public class Laptop {
private Canta _canta;
public Laptop(Canta canta)
{
_canta = canta;
}
}

Composition : Bu tür ilişki de nesnelerin yaşam döngüleri birbirleriyle bağlantılıdır. Bir nesne diğerinden bağımsız olarak kullanılamaz. Aralarındaki ilişki parçası olma(is-a-part-of ) ilişkisidir. Az önceki örneğimizden gidersek dizüstü bilgisayarımız ile ekranı arasında bu tarz bir ilişki vardır. UML diagramında gösterimi ve koda dökülmüş bir örneği aşağıdaki gibidir.

public class Ekran
{

}
public class Laptop
{

Ekran _ekran = new Ekran();
}

Regular Expressions – Gruplar

Bir regular expression’da parantez arasına alınmış ifadeler grupları oluştururlar. Örneğin

(\w+)\s\d*

ifadesinde (\w+) bir grup oluşturur. İfadenin tamamı varsayılan olarak 0 indisli ilk gruptur. Grupların sıralaması dıştan içe doğru ve soldan sağa doğrudur. Yani en kampsamlı grup varsayılan gruptan sonra gelecektir. Daha sonra iç gruplarda soldan sağa doğru artan indisler alacaktır. Bir gruba şu şekilde isim verebiliriz.

(?<firstWord>\w+)\s\d*

Düzenli ifademizdeki tüm grupların değerlerine ve indislerine Match tipinde bir nesne üzerinden aşağıdaki örnekteki gibi ulaşabiliriz.

Match match = Regex.Match(input, pattern);

string degeri = match.Groups[1].Value;

int indis = match.Groups[1].Index;

Grupların en çok işimize yarayacağı durum backreference’ların kullanımıdır. Backreference’ler bir regular expression içinde tekrar eden yapıların gruplar vasıtasıyla tekrar yazılmadan kullanılmasını sağlayan yapılardır. Temel de iki çeşit backreference vardır.

Numbered Backreference :

Numbered backreference’da daha önce belirttiğimiz grubu tekrar yazmak yerine bir sayı aracılığıyla refere ederiz. Bir örnek vermek gerekirse

(\w+)\s\1

Bu regular expression’da \1  (\w+) grubunu refere etmektedir. Yani ifade (\w+)\s(\w+) şeklinde düşünebilir.

Eğer örneğimizde \1 yerine \2 yazmış olsaydık, ikinci bir grubumuz olmadığı için compiler bir hata mesajı verecek ve uygulamamızı derlememize engel olacaktı.

Numbered backreference ile karşılaşacağımız bir sıkıntı kullandığımız rakamların gerçek değerler ile çakışması ihtimalidir. Yani kullandığımız rakam bir backreference da olabilir bir octal kod da. Bu yüzden rakamların yorumlanmasında bir takım kurallar mevcuttur.

  1. \1 ve \9 arasındaki değerler herzaman backreference olarak yorumlanır.
  2. Birden fazla basamaklı bir sayının ilk rakamı 8 veya 9 ise (\81, \90 vb) normal değer olarak yorumlanır.
  3. \10 dan büyük değerler grup var ise backreference yok ise octal kod olarak yorumlanır.

 

Named Backreference :

Named backreference yukarıda bahsettiğimiz rakam karmaşıklıklarından kurtulamamızı sağlar. Named Backreference’da grubumuza bir isim veririz ve önceki örnekde rakamla ulaştığımız gibi bu kez grubumuza grubun ismiyle ulaşırız. Bir önceki örneğin named backreference gösterimi aşağıdaki gibi olacaktır.

(?<grubum>\w+)\s\k<grubum>

bu kez gördüğümüz gibi grubum adını verdiğimiz gruba ulaşmak için \k<grubum> şeklinde bir yapı kullandık.

 


 

Regular Expressions – Lookaround

Önceki gönderimde bahsettiğim gibi bu aralar ciddi anlamda kafayı regular expression’larla bozmuş durumdayım. Ne kadar yetenekli olduklarını gördükçe daha da ayrıntısına girmeye başladım. Ama artık bu ifadelerle boğulmak üzere olduğumu farkedince durmam gerektiğini hissettim. Ama durmadan önce de sizlere yararlı olabileceğini düşündüğüm birşeylerden bahsetmek istiyorum.

Lookaround’a isminden de anlaşılacağı üzere özetle bir regular expression’ın öncesi ya da sonrasını da kontrol etmemizi sağlayan yapı diyebiliriz. Vereceğimiz örnekle kafanızda daha net şekilde canlanacaktır. 2 çeşit lookaround’dan bahsedebiliriz. Bunlar Lookahead ve Lookbehind.

Lookahead :

Lookahead verilen regular expression’dan sonra neyin gelmesini ya da gelmemesini belirlemek istediğimizde kullandığımız yapıdır.  Örneğin input string’imiz “Kara Kartal Karşınızda” olsun. Ben bu string içinde Kar kelimesini aramak istiyorum ama bu Kar kelimesinden sonra a harfi gelmesini istemiyorum. Bu durumda kullanacağım regular expression

Kar(?!a)

şeklinde olacak. Bu şekilde kurduğumuz yapıya negatif  lookahead diyoruz. Negatif lookahead yapısını ?! karakterleriyle oluşturuyoruz ve sonra a harfi gelmemesini istediğimizi belirtiyoruz. a harfi yerine başka bir regular expression’da kullanabilirdik. Örneğimizde gerçekleşecek olan eşleşmeler Kartal’daki ve Karşınızda’daki Kar kelimeleridir.

Bu örneğimiz negatif lookahead olduğuna göre bunun bir de pozitifi olması gerekir. Pozitif lookahead’de ise sonrasında ne gelmesini istediğimizi belirtiyoruz. Bunu ise ?= karakterleri ile yapıyoruz. Önceki input’umuzda bu kez aşağıdaki regular expression’ı kullanalım.

Kar(?=a)

Bu durumda sadece Kara kelimesindeki Kar kısmını eşleyecektir.

Lookbehind :

Lookbehind, lookaround ile aynı mantıkta olmakla beraber bu kez verdiğimiz yapının  öncesinde ne olup olmamasını belirlememize yardım eder.

Bu kez input string’imiz “Kandırdım Sandım” olsun. İlk olarak negatif lookbehind yapalım. Negatif lookbehind yapmak için ?<! karakterlerini kullanırız. Regular expression’ımızı aşağıdaki şekilde düzenleyelim.

(?<!K)an

Bu durumda sadece Sandım kelimesindeki an eşleşecektir. Aynı şekilde pozitif lookahead yapmak için ?<= karakterlerini kullanırız. Bu kez aynı input için regular expression’ımızı aşağıdaki şekilde belirleyelim.

(?<=K)an

Bu durumda ise sadece Kandırdım kelimesindeki an regular expression’ımız ile eşleşecektir.

Bundan sonraki yazılarımda Groups ve Balancing Groups konularından bahsetmeyi planlıyorum. Bu ve diğer konularda sorularınız varsa yorum kısmından elimden geldiğince yardımcı olmaya çalışırım. Şimdilik bol kodlu günler.

SEPOF

Epeydir yeni yazı girmemiştim günlüğe, bu suskunluğuma faydalı olduğunu düşündüğüm bir site için son veriyorum. www.sepof.com adresinden ulaşabileceğimiz Search Engine Position Finder’ın özellikle web geliştiricilerin ve SEO’ların işine yarayacağını düşünüyorum. Bu site aracılığıyla girdiğiniz kelimenin YAHOO, BING ve GOOGLE’da kaçıncı sırada oldığunu bulabilirsiniz. Ayrıca sitede bulunan son aramlar ve sitenizin arama geçmişi kısımları da benim oldukça hoşuma gitti.

ASP.NET Custom Server Control

ASP.Net ile web uygulamalarımız geliştirirken kimi zaman kontrollerin çalışma şekillerini
değiştirmek isteyebiliriz. Kontrollü biraz daha özelleştirmek isteyebiliriz. Bu işlemi kontrolü sayfamızın üstüne attıktan sonra sayfamızın koduna eklemeler yaparak gerçekleştirebiliriz. Ama peki başka bir sayfada daha aynı kontrolü kullanacaksak ne yapacağız. Böyle bir durumda kodları ilk sayfamızdan diğerine kopyalamamız gerekecek. Bu sorunu da böyle hallettikten sonra kontrolümüzü bir çok sayfada kullandık. Peki kontrolümüzün bir özelliğinde değişiklik yapacaksak ne olacak? Eklediğimiz bütün kodları teker teker değiştireceğiz. Daha sonra iş arkadaşınız kendi uygulamasında aynı özelleşmiş kontrolü kullanmak istediğinde ona kontrolün arkasına yazdığımız kodları göndermemiz
gerekecek. İşte bu ve buna benzer sorunlardan kurtulmak için kendi ASP.Net Server Kontrollerimizi yazarız.

Bu makalede uygularımızda kullanabilmek için Sayısal Textbox kontrolü oluşturucağım. Sayısal karakterlerin tesbitinde javascript kullanacağım için, javascript bilginiz olması bir avantaj olacaktır. Amacımız custom kontrolleri oluşturmayı anlamak olduğu için çok ayrıntılı bir kontrol yazmayacağım, ama siz bu başlangıcın üzerine eklemeler yaparak istediğiniz hale getirebilirsiniz. Bu konuda karşınıza çıkacak sorunlarda yardımcı olmaya çalışırım.
Continue…

ASPxPopUpControl Genişlik Problemi

DevExpress kontrollerinden ASPxPopUpControl kullanırken, bir yerde genişliğini 100% yapmam gerekti. Ama nedense bir türlü ayarlayamadım. Genişliği piksel olarak verdiğim de ise hiçbir sorun çıkmıyordu. Sonuçta biraz google’lama sonucunda çözümü buldum. Belki birilerine daha yardımı dokunabilir. Öncelikle şunu da söyleyeyim. Bu çözümü DevExpress Team önermiş yani bir nevi sorun olduğunu kabul ediyorlar.

Öncelikle bir javascript fonksiyonu yazıyoruz. (popup, kontrolümüzün ClientInstanceName’i)

    function GenislikAyarla(){
var width = _aspxGetDocumentWidth();
popup.SetWidth(width);
         }

Daha sonra kontrolün init client side event’inde bu fonksiyonu çağırıyoruz.

UpdatePanel Kullanırken…

Asp.Net ile uygulama geliştirirken hepimiz bir kere bile olsa updatepanel kullanmışızdır. Bazen bunu kullanılabilirlik için yaparken bazen de performans için yapabiliyoruz. Eğer updatepanel’i performans için kullanıyorsak dikkat etmemiz gereken bir nokta var. Örneğin bir web uygulaması yazdık. Bu uygulamada sol tarafta ağır sorgular sonucu getirilen bilgiler listeleniyor. Sağ tarafta ise basit kullanıcı işlemleri yapılıyor. Uygulamamızı çalıştırdığımızda sol taraftaki işlemler nedeniyle sayfadaki her postback’de sayfamız geç yükleniyor. Oysa biz sağ taraf güncellenirken sol tarafta işlemlerimize devam etmek istiyoruz. Hemen updatepanel aklımıza geliyor. İki tane updatepanel kullanıyoruz sağ ve sol taraf için. Tabii ki UpdateMode’u nu da conditional yapmamız gerektiğini biliyoruz. Evet tamam şimdi oldu. Mu? Uygulamamızı tekrar çalıştırdığımızda sağdaki updatepanel’de bir güncelleme yaptığımızda sayfamızın yine yavaş geldiğini görürüz. Bunun nedeni sadece bir updatepanel güncellenmesine rağmen ASP.Net sayfasının yaşam döngüsü nedeniyle sol taraftaki kodun bağlama işlemi de tekrar edilir. Bir de custom control ya da user control kullanırsanız, bunu farketmek daha da zor olacaktır. Bunu aşmak için belirli sayfanın yaşam döngüsünde postback’e neden olan kontrolleri takip ederek, belirli işlemlerin yapılmamasını sağlamalıyız. Mesela örneğimizdeki sol taraftaki databind işlemi için sadece bir timer ise yada belirli bir buton ise databind işlemini gerçekleştirmesini sağlayabiliriz.