https://www.buraksenyurt.com/Burak Selim Şenyurt - Windows Services2019-03-05T07:57:28+00:00Matematik Mühendisi Bir Bilgisayar Programcısının NotlarıBurak Selim SenyurtBlogEngine.Net Syndication Generatorhttps://www.buraksenyurt.com/opml.axdBurak Selim SenyurtMatematik Mühendisi Bir Bilgisayar Programcısının Notlarıtr-TRBurak Selim Şenyurt0.0000000.000000https://www.buraksenyurt.com/post/Debug-Edilebilir-Windows-Service-GelistirmekDebug Edilebilir Windows Service Geliştirmek2011-04-10T10:34:00+00:00bsenyurt<p><a href="https://www.buraksenyurt.com/pics/blg232_Giris.jpg"><img style="background-image: none; margin: 4px 0px; padding-left: 0px; padding-right: 0px; display: inline; float: right; padding-top: 0px; border: 0px;" title="blg232_Giris" src="/pics/blg232_Giris_thumb.jpg" alt="blg232_Giris" width="304" height="229" align="right" border="0" /></a>Merhaba Arkadaşlar,</p>
<p>Uzun süre önce dış kaynak(Outsource) olarak görev aldığım bir bankacılık uygulamasında <strong>Windows Service </strong>tabanlı entegrasyon işlemleri için görevlendirilmiştim. Herşeyden önce bu servislerin bankacılık uygulaması olması nedeniyle, farklı ve yabancı sistemleri de ilgilendiren iş adımları bulunmaktaydı. Bu sebepten söz konusu <strong>Windows Service </strong>uygulamalarının hem kod içerikleri hem de iş kuralları oldukça karışık olabiliyordu. İlgili <strong>Windows Service </strong>örneklerinin geliştirilmesi bir yana, bunların test ortamına atılması ve sonuçlarının takip edilmesi ise başlı başına bir dertti <img class="wlEmoticon wlEmoticon-confusedsmile" style="border-style: none;" src="/pics/wlEmoticon-confusedsmile_1.png" alt="Confused smile" /> </p>
<p>Genellikle servisin çalışma durumunu izlemek adına özellikle <strong>Exception </strong>bloklarında veya metod başlangıç ile bitiş noktalarında<em>(örneğin OnStart başında ve sonunda) </em>işletim sisteminin uygulamaya özel <strong>Event Log’</strong> larına bilgi atmaktaydım. Bu bilgileri atarken de durumun kritikliğine göre <strong>Warning, Exclamation, Error </strong>gibi hazır sistem ikonlarından yararlanıyor ve çalışma zamanındaki durumu analiz etmeye çalışıyordum.</p>
<p>Ancak bir developer için, kodun çalışma zamanındaki durumunu incelemenin sayısız yolu olduğu da bir gerçek. Öyleki, <strong>Debug</strong> etmek bence en güzel yollardan birisi. Lakin bir <strong>Windows Service </strong>uygulamasının <strong>Debug </strong>edilmesi de sanıldığı kadar kolay değil <img class="wlEmoticon wlEmoticon-thinkingsmile" style="border-style: none;" src="/pics/wlEmoticon-thinkingsmile.png" alt="Thinking smile" /> İşte bu yazımızda internet üzerinden yaptığım araştırmalar sonucu öğrendiğim ve bir <strong>Windows Service</strong> uygulamasının nasıl <strong>debug</strong> edilebeceğine dair uygulanabilen yöntemlerden birisini ele alıyor olacağız. Olabildiğince basit bir şekilde anlatmaya gayret edeceğim bu vaka çalışmamızda, adım adım ilerliyor olacağız<img class="wlEmoticon wlEmoticon-winkingsmile" style="border-style: none;" src="/pics/wlEmoticon-winkingsmile_2.png" alt="Winking smile" /> Öyleyse gelin şu metal entegre üzerindeki böcekleri ayıklamaya çalışalım.</p>
<p>İlk olarak <strong>Windows Service Application </strong>tipinden bir uygulama oluşturmamız gerekiyor. Bu uygulama içerisinde yer alan <strong>ControllerService</strong> isimli <strong>Windows Service </strong>tipinin içeriği başlangıçta aşağıdaki gibidir. Söz konusu servis içerisindeki <strong>Timer</strong> örneğinin <strong>10 </strong>saniyede bir çalıştırdığı olay metoduna göre, belirli bir klasördeki<em>(ki path bilgisi <strong>App.config </strong>dosyasından çekilmektedir)</em> dosyaların şifrelenmesi için bir akış çalıştırmaktadır ki aslında bunun konumuz için çok da büyük bir önemi yoktur <img class="wlEmoticon wlEmoticon-winkingsmile" style="border-style: none;" src="/pics/wlEmoticon-winkingsmile_2.png" alt="Winking smile" /></p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.Configuration;
using System.IO;
using System.ServiceProcess;
using System.Timers;
namespace FileControllerService
{
public partial class ControllerService
: ServiceBase
{
private string _path = null;
private Timer _timer = null;
public ControllerService()
{
InitializeComponent();
_path = ConfigurationManager.AppSettings["Path"];
_timer = new Timer(10000);
_timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
}
void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
string[] files=Directory.GetFiles(_path);
foreach (string file in files)
{
File.Encrypt(file);
}
}
protected override void OnStart(string[] args)
{
_timer.Start();
}
protected override void OnStop()
{
_timer.Stop();
}
}
}</pre>
<p>Bir <strong>Windows Service </strong>tipi temel olarak <strong>ServiceBase</strong> tipinden türemektedir. <strong>Windows Service Application </strong>proje şablonunda yer alan bu hazır uyarlamaya göre <strong>Program </strong>sınıfı içerisindeki <strong>Main </strong>metodunun kod yapısı da aşağıdaki gibi olacaktır.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Configuration;
using System.ServiceProcess;
using InvestigationLib;
namespace FileControllerService
{
static class Program
{
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new ControllerService()
};
ServiceBase.Run(ServicesToRun);
}
}
}</pre>
<p>Dikkat edileceği üzere Servisin çalıştırılması işini <strong>ServiceBase </strong>tipinin <strong>static Run </strong>metodu üstlenmektedir. Ne varki bu tip bir servisin varsayılan olarak <strong>Debug </strong>edilmesi mümkün değildir. Bir başka deyişle servise ait <strong>OnStart </strong>ve <strong>OnStop </strong>gibi metodların içerisine <span style="text-decoration: underline;">girilememektedir</span>. Bu, özellikle karmaşık iş kuralları ve modelleri içeren <strong>Windows Service </strong>örnekleri düşünüldüğünde, geliştirme sürecini zorlaştıran ve uzatan bir durumun oluşması anlamına gelmektedir. Elbette servisin pek çok noktasından örneğin işletim sistemi<strong> Event Log’</strong> larına bilgi gönderilebilir veya bir <strong>Text </strong>dosyası içerisine servisin çalışması sırasındaki sürecin önemli adımlarına ait bilgiler<em>(mesela Exceptipon mesajları) </em>yazdırılabilir. Ancak değişken, parametre ve metod sayılarının iyiden iyiye fazlalaştığı, referans edilen kütüphanelerin çok olduğu bir modelde bu içerikleri izlemekte, üretmekte zor olmaktadır.</p>
<p>Aslında bir geliştirici için kodun yazılması ve test ortamına alınması esnasında <strong>debug</strong> edilebilyor olması son derece önemlidir. Şimdi dilerseniz yazımıza konu olan bu basit <strong>Windows Service </strong>örneğinin <strong>debug </strong>edilebilir bir versiyonunu nasıl geliştirebileceğimize bir bakalım <img class="wlEmoticon wlEmoticon-openmouthedsmile" style="border-style: none;" src="/pics/wlEmoticon-openmouthedsmile_2.png" alt="Open-mouthed smile" /> Durumu anlamanın en kolay yolu bitmiş olan örneğin sınıf diagramına bakmak olacaktır<em>(Yani çözüme biraz tersten bakmamız gerekmektedir)</em> İşte çözümsel yaklaşıma ait sınıf diagramı görüntüsü.</p>
<p><a href="https://www.buraksenyurt.com/pics/blg232_ClassDiagram.gif"><img style="background-image: none; margin: 4px 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="blg232_ClassDiagram" src="/pics/blg232_ClassDiagram_thumb.gif" alt="blg232_ClassDiagram" width="563" height="557" border="0" /></a></p>
<p>Şimdi bu sınıf diagramını adım adım üretmeye başlayalım. İlk olarak bir <strong>arayüz sözleşmesi(Interface Contract)</strong> oluşturarak işe başlayacağız. Buradaki en büyük amacımız birden fazla <strong>Windows Service </strong>tipinin <strong>Debug </strong>edilebilir versiyonları için ortak bir sözleşme sunmaktır.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">namespace InvestigationLib
{
public interface IWindowsServiceContract
{
void OnStart(string[] args);
void OnStop();
}
}</pre>
<p><strong>IWindowsServiceContract</strong> arayüzünün içinde iki basit metod bildirimi olduğu görülmektedir. Örneğimizi çok basit tutmak istediğimizden <strong>OnPause, OnContinue, OnShutdown </strong>gibi metod bildirimlerini göz önüne almadık. Ancak siz kendi denemelerinizi yaparken veya bir ürün geliştirmesi sırasında bu tekniği uygularken mutlaka söz konusu diğer metodları da düşünmelisiniz. Aslında yaptığımız bir anlamda <strong>ServiceBase </strong>ile <strong>override </strong>edilen metodlara ait bir sözleşme bildiriminde bulunmaktan ibarettir.</p>
<p>Bu sözleşme bildiriminin ardından <strong>ServiceBase</strong> türevli olan ve <strong>IWindowsServiceContract</strong> arayüzünü implemente eden tiplerin fonksiyonelliklerini çağırabilen başka bir sınıf daha üretilir. <strong>WindowsServiceCaller</strong>…</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.ServiceProcess;
namespace InvestigationLib
{
public class WindowsServiceCaller
:ServiceBase
{
IWindowsServiceContract _winSrv;
public WindowsServiceCaller(IWindowsServiceContract winSrv)
{
_winSrv = winSrv;
}
protected override void OnStart(string[] args)
{
_winSrv.OnStart(args);
}
protected override void OnStop()
{
_winSrv.OnStop();
}
}
}</pre>
<p><strong>WindowsServiceCallar</strong> tipi için söylenebilecek iki önemli nokta vardır. Bunlardan ilki <strong>ServiceBase</strong> tipinden türemiş olması ve senaryomuza göre <strong>OnStart </strong>ile <strong>OnStop </strong>metodlarını <strong>override </strong>etmesidir. Diğer yandan ezilen <strong>OnStart </strong>ve <strong>OnStop </strong>metodları içerisinden yapılan çağrılar, tipin <strong>yapıcı metodu(Constructor) </strong>içerisinden alınan <strong>IWindowsServiceCaller </strong>arayüzünü implemente eden herhangibir nesne örneğine aittir. Bir başka deyişle bu tip, <strong>OnStart </strong>ve <strong>OnStop </strong>metod bildirimlerini sözleşme olarak sunan <strong>IWindowsServiceContract </strong>arayüzünü implemente eden bir tipin, çalışma zamanındaki asıl <strong>OnStart</strong> ve <strong>OnStop </strong>fonksiyonelliklerini kullanmaktadır<em>. (Oh oh ohhh!!! <strong>Including </strong>var, <strong>inheritance </strong>var, <strong>Polimorphysm </strong>var, <strong>overriding </strong>var <img class="wlEmoticon wlEmoticon-openmouthedsmile" style="border-style: none;" src="/pics/wlEmoticon-openmouthedsmile_2.png" alt="Open-mouthed smile" />… <strong>Nesne Yönelimli Programlama-Object Oriented Programming </strong>temellerini hatırlamanın zamanı )</em></p>
<p>Dolayısıyla bu tanımlamanın ardınan <strong>debug</strong> edilmesi gereken kod içeriğini taşıyan asıl servis tipi geliştirilir ki tesadüf bu olsa gerek bu tipte <strong>IWindowsServiceContract</strong> arayüzünü implemente etmektedir <img class="wlEmoticon wlEmoticon-openmouthedsmile" style="border-style: none;" src="/pics/wlEmoticon-openmouthedsmile_2.png" alt="Open-mouthed smile" /></p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.IO;
using System.Timers;
namespace InvestigationLib
{
public class DebugableControllerService
:IWindowsServiceContract
{
string path=String.Empty;
Timer timer = null;
public DebugableControllerService()
{
timer = new Timer(10000);
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
string[] files = Directory.GetFiles(path);
foreach (string file in files)
{
File.Encrypt(file);
}
}
catch (Exception excp)
{
//TODO:Handle Exception
// Eğer Windows Service projesinin özelliklerinden Output Type -> Console Application olarak seçilirse buradan Console penceresine de bilgi yazdırılabilir
}
}
#region IWindowsServiceContract Members
public void OnStart(string[] args)
{
path = args[0];
timer.Start();
}
public void OnStop()
{
timer.Stop();
}
#endregion
}
}</pre>
<p><strong>DebugableControllerService</strong> sınıfı aslında ilk başta <strong>debug</strong> <span style="text-decoration: underline;">edemediğimiz</span> <strong>ControllerService</strong> sınıfının asıl fonksiyonelliklerini içermektedir. Tabi <strong>ControllerService</strong> tipinin yaptığı gibi <strong>ServiceBase’</strong> den türemek yerine <strong>IWindowsServiceContract</strong> arayüzünü uygulamaktadır. Böylece <strong>WindowsServiceCaller</strong> tipinin kullanabileceği bir sınıf oluşturulmuştur. Ancak hazırlıklar bu tipleri yazmakla bitmez. Birde söz konusu <strong>debug</strong> edilecek tip örneğini <strong>başlatacak/yürütüecek</strong> bir başka sınıfın olmasında yarar vardır <img class="wlEmoticon wlEmoticon-cryingface" style="border-style: none;" src="/pics/wlEmoticon-cryingface.png" alt="Crying face" /> İşte başlatıcı tipimiz.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.Threading;
namespace InvestigationLib
{
public static class ServiceStarter
{
public static void Run(string[] args,IWindowsServiceContract winSrv)
{
winSrv.OnStart(args);
Thread.Sleep(45000);
winSrv.OnStop();
}
}
}</pre>
<p>Bu <strong>static</strong> sınıf içerisindeki <strong>Run</strong> metodu <strong>IWindowsServiceContract</strong> arayüzünü implemente eden her hangibir tip üzerinden <strong>OnStart</strong> ve <strong>OnStop</strong> metodlarını çağırabilir ve böylece simülasyon işlemini başlatabilir. Geriye yapılması gereken tek bir işlem kalmaktadır. <strong>Windows Service </strong>projesindeki <strong>Main </strong>metodu içeriğini aşağıdaki kod parçasında görüldüğü gibi değiştirmek.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Configuration;
using System.ServiceProcess;
using InvestigationLib;
namespace FileControllerService
{
static class Program
{
static void Main()
{
#region Debug Edilebilir Versiyon
DebugableControllerService implementation = new DebugableControllerService();
if (Environment.UserInteractive)
ServiceStarter.Run(
new string[]{
ConfigurationManager.AppSettings["Path"]
}
, implementation);
else
ServiceBase.Run(new WindowsServiceCaller(implementation));
#endregion
}
}
}</pre>
<p>Debug edilmek istenen kod içeriğini taşıyan <strong>DebugableControllerService</strong> örneğinin oluşturulmasından sonra <strong>ServiceStarter</strong> tipinin <strong>Run</strong> metodundan yararlanarak sürecin başlatılması sağlanır. Şu aşamada kod içerisinde <strong>breakpoint’</strong> ler yardımıyla ilerlenmesi mümkündür <img class="wlEmoticon wlEmoticon-laughingoutloud" style="border-style: none;" src="/pics/wlEmoticon-laughingoutloud.png" alt="Laughing out loud" /> Hatta örneğin olmayan bir klasör içeriğinin <strong>Directory</strong> tipinin <strong>GetFiles</strong> metodu yardımıyla okunmaya çalışılması sırasında oluşan <strong>Exception</strong> mesajları da, <strong>Visual Studio </strong>arabiriminin <strong>Output </strong>ekranına düşmektedir. Aynen aşağıdaki ekran çıktısında görüldüğü gibi.</p>
<p><a href="https://www.buraksenyurt.com/pics/blg231_DebugWindow.gif"><img style="background-image: none; margin: 4px 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="blg231_DebugWindow" src="/pics/blg231_DebugWindow_thumb.gif" alt="blg231_DebugWindow" width="527" height="504" border="0" /></a></p>
<p>Ancak istenirse işlemlerin daha kolay takip edilmesi adına <strong>Console</strong> penceresine bilgi yazdırılması da mümkün olabilir. Bunun için<strong> Windows Service</strong> projesinin <strong>Output</strong> tipinin <strong>Console Application</strong> olarak değiştirilmesi yeterlidir.</p>
<p><a href="https://www.buraksenyurt.com/pics/blg232_ConsoleOutput.gif"><img style="background-image: none; margin: 4px 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="blg232_ConsoleOutput" src="/pics/blg232_ConsoleOutput_thumb.gif" alt="blg232_ConsoleOutput" width="331" height="156" border="0" /></a></p>
<p>Buna göre <strong>Exception</strong> bloğunu aşağıdaki gibi değişitirsek <strong>debug</strong> işlemleri sırasında <strong>Console</strong> ekranına çıktı üretebilmeyi de sağlayabiliriz.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">void timer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
string[] files = Directory.GetFiles(path);
foreach (string file in files)
{
File.Encrypt(file);
}
}
catch (Exception excp)
{
Console.WriteLine(excp.Message);
}
}</pre>
<p><a href="https://www.buraksenyurt.com/pics/blg232_WriteToConsole.gif"><img style="background-image: none; margin: 4px 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="blg232_WriteToConsole" src="/pics/blg232_WriteToConsole_thumb.gif" alt="blg232_WriteToConsole" width="493" height="294" border="0" /></a></p>
<p>Elbette <strong>Debug</strong> işlemleri sonrasında hataları bertaraf edilen servis kodunun son hali asıl <strong>Windows Service </strong>kodu ile değiştirilmeli ve bu şekilde <strong>install</strong> edilmelidir. Örneğimiz bu haliyle artık <strong>Console</strong> penceresine bilgilendirme de bulunabilir. Ne <strong>Text</strong> dosyaya, ne işletim sistemindeki <strong>Event Log’</strong> lara ne veritabanı üzerindeki ilgili tablolara loglama işlemleri yapmak için gerekli atraksiyonlar ile uğraşmamıza gerek kalmamaktadır. Uygulamanın dışına çıkmadan, olduğumuz <strong>Visual Studio</strong> <strong>ortamı(Environment)</strong> içerisinden gerekli izleme ve <strong>Debug </strong>işlemleri yapılabilir. Doğrudan <strong>Console </strong>penceresinden gerekli izlemeler de yapılabilecektir. Bunu da unutmayalım <img class="wlEmoticon wlEmoticon-winkingsmile" style="border-style: none;" src="/pics/wlEmoticon-winkingsmile_2.png" alt="Winking smile" /> Böylece geldik bir yazımızın daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>
<p><a href="https://www.buraksenyurt.com/pics/2010%2f10%2fFileControllerService.rar">FileControllerService.rar (51,95 kb)</a></p>2011-04-10T10:34:00+00:00windows servicesdebugbsenyurtAncak bir developer için, kodun çalışma zamanındaki durumunu incelemenin sayısız yolu olduğu da bir gerçek. Öyleki, Debug etmek bence en güzel yollardan birisi. Lakin bir Windows Service uygulamasının Debug edilmesi de sanıldığı kadar kolay değil Thinking smile İşte bu yazımızda internet üzerinden yaptığım araştırmalar sonucu öğrendiğim ve bir Windows Service uygulamasının nasıl debug edilebeceğine dair uygulanabilen yöntemlerden birisini ele alıyor olacağız. Olabildiğince basit bir şekilde anlatmaya gayret edeceğim bu vaka çalışmamızda, adım adım ilerliyor olacağızWinking smile Öyleyse gelin şu metal entegre üzerindeki böcekleri ayıklamaya çalışalım.https://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=d535f709-b913-44a4-b64d-33efba5ba7544https://www.buraksenyurt.com/trackback.axd?id=d535f709-b913-44a4-b64d-33efba5ba754https://www.buraksenyurt.com/post/Debug-Edilebilir-Windows-Service-Gelistirmek#commenthttps://www.buraksenyurt.com/syndication.axd?post=d535f709-b913-44a4-b64d-33efba5ba754https://www.buraksenyurt.com/post/Windows-Servislerinin-Kontrolu-2-(-Sistemdeki-Servislerin-Kontrol-Edilmesi-)-bsenyurt-com-danWindows Servislerinin Kontrolü - 2 ( Sistemdeki Servislerin Kontrol Edilmesi )2004-05-12T06:00:00+00:00bsenyurt<p>Değerli Okurlarım, Merhabalar.</p>
<p>Bu makalemizde, sistemde yer alan windows servislerini bir windows uygulamasından nasıl elde edebileceğimizi ve nasıl kontrol edebileceğimizi incelemeye çalışacağız. Önceki makalelerimizden hatırlayacağınız gibi, sistemde yer alan servislerimiz, System.ServiceProcess isim alanında yer alan ServiceController sınıf nesneleri ile temsil edilmektedir. Eğer sistemde yer alan servisleri elde etmek istersek, aşağıda aşırı yüklenmiş iki prototipi olan, GetServices metodunu kullanabiliriz.</p>
<table id="table1" style="border-collapse: collapse; width: 100%;" border="1" cellpadding="5" bgcolor="#cccccc">
<tbody>
<tr>
<td bgcolor="#cccccc" width="350"><strong>GetServices Metodu Prototipleri</strong></td>
<td bgcolor="#cccccc"><strong>Açıklaması</strong></td>
</tr>
<tr>
<td bgcolor="#ffffff" width="350">public static ServiceController[] GetServices();</td>
<td bgcolor="#ffffff">Bu prototip ile, local makinede yer alan servisler elde edilir.</td>
</tr>
<tr>
<td bgcolor="#ffffff" width="350">public static ServiceController[] GetServices(string);</td>
<td bgcolor="#ffffff">Bu prototipte, parametre olarak verilen makine bilgisine ait servisler elde edilir.</td>
</tr>
</tbody>
</table>
<p><br />Burada görüldüğü gibi, GetServices metodu ServiceController sınıfı türünden bir diziyi geri döndürür. Ayrıca bu metod static bir metod oluduğundan, doğrudan ServiceController sınıfı üzerinden herhangibir nesne örneğine gerek duymadan çağırılabilir. Aşağıda örnek olarak sistemdeki servislerin elde ediliş tekniği gösterilmektedir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">ServiceController[] svc;
svc=ServiceController.GetServices();</pre>
<p>Elde edilen servislerin herbiri birer ServiceController nesnesi olarak, ele alınır. Elde ettiğimiz servislerin üzerinde bildiğiniz gibi, bir servisin temel davranışları olan Start,Stop,Pause,Contiune,ExecuteCommand vb.larını aşağıda prototipi verilen metodlar yardımıyla gerçekleştirebilmekteyiz.</p>
<table id="table3" style="border-collapse: collapse; width: 100%;" border="1" cellpadding="5" bgcolor="#ffffff">
<tbody>
<tr>
<td bgcolor="#cccccc" width="146"><strong>Metod</strong></td>
<td bgcolor="#cccccc" width="384"><strong> Prototip</strong></td>
<td bgcolor="#cccccc"><strong>Açıklama</strong></td>
</tr>
<tr>
<td width="146"><strong>Start</strong></td>
<td width="384">public void Start();<br /> public void Start(string[]);</td>
<td>Servisi çalıştırır.</td>
</tr>
<tr>
<td width="146"><strong>Stop</strong></td>
<td width="384"><strong>public </strong>void<strong> Stop();</strong></td>
<td>Servisi durdurur.</td>
</tr>
<tr>
<td width="146"><strong>Pause</strong></td>
<td width="384"><strong>public </strong>void<strong> Pause();</strong></td>
<td>Çalışan servisi duraklatır.</td>
</tr>
<tr>
<td width="146"><strong>Contiune</strong></td>
<td width="384"><strong>public </strong>void<strong> Continue();</strong></td>
<td>Duraklatılmış servisin çalışmasına devam etmesini sağlar.</td>
</tr>
<tr>
<td width="146"><strong>ExecuteCommand</strong></td>
<td width="384"><strong>public </strong>void<strong> ExecuteCommand(</strong>int <em> <a class="synParam">command</a></em><strong>);</strong></td>
<td>Servisin OnCustomCommand metodunu çalıştırır.</td>
</tr>
</tbody>
</table>
<p><br />Birazdan geliştireceğimiz örnek uygulamada, sistedemki servisler üzerinde yukarıda bahsettiğimiz metodları kullanarak, servislerin kontrolünü gerçekleştirmeye çalışacağız. Burada dikkat edilmesi gereken bir kaç nokta vardır. Öncelikle bir servis başlatılacaksa, bu servisin o an çalışmıyor olması başka bir deyişle Stopped konumunda olması gerekmektedir. Aynı durum bir servisi durdururkende geçerlidir. Böyle bir durumdada, Stop edilecek servisin, Running konumunda olması gerekmektedir. İşte bu nedenlerden dolayı, sistemdeki servislerin çalışmaya başlaması veya çalışanların durdurulması gibi hallerde, servisin o anki durumunu kontrol etmemiz gerekmektedir. Bu amaçla ServiceController sınıfının aşağıda prototipi verilen Status özelliğini kullanırız.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">public ServiceControllerStatus Status {get;}</pre>
<p>Burada görüldüğü gibi Status özelliği ServiceControllerStatus numaralandırıcısı türünden değerler alabilmektedir. Bu numaralandırıcının alacağı değerler servisin o anki durumu hakkında bilgi vermektedir. Status özelliği sadece get bloğuna sahip olduğundan, yanlızca servisin o anki durumu hakkında bilgi vermektedir. ServiceControllerStatus numaralandırıcısının alabileceği değerler aşağıdaki tabloda belirtilmektedir.</p>
<table id="table5" class="dtTABLE" style="border-collapse: collapse; width: 571px;" border="1" cellpadding="5">
<tbody>
<tr valign="top">
<th width="38%">ServiceControllerStatus Değeri</th>
<th width="51%">Açıklama</th>
</tr>
<tr valign="top">
<td width="38%"><strong>ContinuePending</strong></td>
<td width="51%">Duraksatılan servis devam ettirilmeyi beklerken.</td>
</tr>
<tr valign="top">
<td width="38%"><strong>Paused</strong></td>
<td width="51%">Servis duraksatıldığında.</td>
</tr>
<tr valign="top">
<td width="38%"><strong>PausePending</strong></td>
<td width="51%">Servis duraksatılmayı beklerken.</td>
</tr>
<tr valign="top">
<td width="38%"><strong>Running</strong></td>
<td width="51%">Servis çalışırken.</td>
</tr>
<tr valign="top">
<td width="38%"><strong>StartPending</strong></td>
<td width="51%">Servis çalıştırılmayı beklerken.</td>
</tr>
<tr valign="top">
<td width="38%"><strong>Stopped</strong></td>
<td width="51%">Servis durdurulduğunda.</td>
</tr>
<tr valign="top">
<td width="38%"><strong>StopPending</strong></td>
<td width="51%">Servis durdurulmayı beklerken.</td>
</tr>
</tbody>
</table>
<p><br />Burada en çok kafa karıştırıcı haller Pending halleridir. Bunu daha iyi anlamak için örnek olarak StopPending durumunu aşağıdaki şekil üzerinden incelemeye çalışalım.</p>
<p><img src="/makale/images/mk69_1.gif" alt="" width="629" height="198" border="0" /></p>
<p><em>Şekil 1. Pending Durumları.</em></p>
<p>Burada görüldüğü gibi çalışan bir servise, Stop emri verildiğinde, bu servisin durumu Stopped oluncaya kadar geçen sürede, servis StopPending durumundadır. Aynı mantık, StartPending, PausePending ve ContinuePending durumları içinde geçerlidir. Pending durumlarını daha çok, bu zaman sürelerinin tamamlanıp verilen emrin başarılı bir şekilde uygulandığının izlenmesinde kullanbiliriz. Bu amaçla, ServiceController sınıfı bize, aşağıda prototipleri verilen WaitForStatus metodunu sunmaktadır. Bu metod, parametre olarak aldığı ServiceControllerStatus değeri sağlanıncaya kadar uygulamayı duraksatmaktadır.</p>
<table id="table6" style="border-collapse: collapse; width: 100%;" border="1" cellpadding="5" bgcolor="#cccccc">
<tbody>
<tr>
<td width="337"><strong>Prototipler</strong></td>
<td><strong>Açıklama</strong></td>
</tr>
<tr>
<td bgcolor="#ffffff" width="337"><strong> public </strong>void<strong> WaitForStatus(</strong>ServiceControllerStatus <em> <a class="synParam">desiredStatus</a></em><strong>);</strong></td>
<td bgcolor="#ffffff">Servisin ServiceControllerStatus numaralandırıcısı ile belirtilen duruma geçmesi için, uygulamayı bekletir.</td>
</tr>
<tr>
<td bgcolor="#ffffff" width="337"><strong> public </strong>void<strong> WaitForStatus(</strong><br /> <strong> </strong>ServiceControllerStatus <em> <a class="synParam">desiredStatus</a></em><strong>,</strong><br /> <strong> </strong>TimeSpan <em> <a class="synParam">timeout</a></em><br /> <strong>);</strong></td>
<td bgcolor="#ffffff">Servisin ServiceControllerStatus numaralandırıcısı ile belirtilen duruma geçmesi için, TimeSpan ile belirtilen süre kadar uygulamanın beklemesini sağlar.</td>
</tr>
</tbody>
</table>
<p><br />Biz uygulamamızda WaitForStatus metodunu, bir servise Start,Stop,Pause ve Continue emirlerini verdiğimizde, pending işlemlerinin sona ermesi ile birlikte servisin başarılı bir şekilde istenen konuma geçtiğini anlamak amacıyla kullancağız. Bu aslında SCM yardımıyla bir servisin durdurulması veya başlatılmasında oluşan bekleme işlemi ile alakalı bir durumdur. Örneğin,</p>
<p><img src="/makale/images/mk69_2.gif" alt="" width="584" height="216" border="0" /></p>
<p><em>Şekil 2. Servisin çalıştırılması sırasındaki bekleme işlemi.</em></p>
<p>SCM yardımıyla bir servisi çalıştırdığımızda (Start) yukarıdaki gibi bir pencere ile karşılaşırız. Burada servis, StartPending konumundadır. Servis çalışmaya başladığında yani Running konumuna geldiğinde, artık StartPending konumundan çıkar. Lakin bu süre zarfında SCM uygulamasının bir süre duraksadığını görürüz. Bu duraksama servis Running halini alıncaya kadar sürer. İşte bunu sağlayan aslında WaitForStatus mekanizmasından başka bir şey değildir. Bu sayede servis Running moduna geçtiğinde, güncelenen listede servisin durumu Running olarak yazacaktır. Eğer WaitForStatus tekniği kullanılmamış olsaydı, bu durumda servis Start edildiğinde ve liste güncellendiğinde ilk aşamada Servisin durumu StartPending olucak ve ancak sonraki liste güncellemesinde Running yazacaktı. Bizde uygulamamızda WaitForStatus metodunu bu amaçla kullanacağız. Yani servis kesin olarak istediğimiz duruma ulaştığında, listemizi güncelliyeceğiz.</p>
<p>ServiceController sınıfı için kullanılacak diğer önemli bir özellikte CanPauseAndContinue özelliğidir. Bazı servislerin bu özellik değeri false olduğu için, bu servislerin Pause ve Continue emirlerine cevap vermesi olanaksızdır. İşte uygulamamızda bizde bir servisin bu durumunu kontrol edicek ve ona göre Pause ve Continue emirlerine izin vereceğiz. CanPauseAndContinue özelliğinin prototipi aşağıdaki gibidir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">public bool CanPauseAndContinue {get;}</pre>
<p>ServiceController sınıfı için kullanabilceğimiz diğer önemli bir özellik ise, bir servisin bağlı olduğu diğer servislerin listesini elde etmemizi sağlıyan, ServicesDependOn özelliğidir. Prototipi aşağıdaki gibi olan bu özellik ile, bir servisin çalışması için gerekli olan diğer servislerin listesini elde edebiliriz.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">public ServiceController[] ServicesDependedOn {get;}</pre>
<p>Prototipten de görüldüğü gibi bu özellik, ServiceController sınıfı türünden bir dizi geriye döndürmektedir. Dolayısıyla bu özellik yardımıyla sistemdeki servislerin bağlı oldukları servisleride elde etme imkanına sahibiz.</p>
<p>Şimdi dilerseniz buraya kadar işlediğimiz yanları ile, ServiceController sınıfını kullandığımız bir örnek geliştirmeye çalışalım. Bu örneğimizde, sistemimizdeki servislerin listesini elde edeceğiz. Seçtiğimiz bir servis üzerinde Start, Stop, Pause, Continue gibi emirleri yerine getireceğiz ve bir servise bağlı olan servislerin listesine bakabileceğiz. Bu amaçla öncelikle aşağıdakine benzer bir windows uygulama formu oluşturarak işe başlayalım.</p>
<p><img src="/makale/images/mk69_3.gif" alt="" width="616" height="352" border="0" /></p>
<p><em>Şekil 3. Uygulamamızın Form Görüntüsü.</em></p>
<p>Şimdide program kodlarımızı oluşturalım.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.ServiceProcess; /* ServiceController sınıfını kullanabilmek için bu isim alanını ekliyoruz.*/
namespace ServisBakim
{
public class Form1 : System.Windows.Forms.Form
{
.
.
.
/* Sistemde yüklü olan servislerin listesini elde edeceğimiz bir metod geliştiriyoruz. Bu metodu hem servis listesini alırken hemde bir servis ile ilgili Start,Stop,Pause,Continue emirleri verildikten sonra, ListView kontrolündeki listeyi güncel tutmak amacıyla kullanacağız.*/
private void ServisListeGuncelle()
{
ServiceController[] svc; /*ServiceController sınıfından bir dizi tanımlıyoruz.*/
svc=ServiceController.GetServices(); /* Bu diziye ServiceController sınıfının static GetServices metodu yardımıyla sistemde yüklü olan servisleri birer ServiceController nesnesi olarak aktarıyoruz.*/
lvServisler.Items.Clear(); /* ListView kontrolümüzün içeriğini temizliyoruz.*/
/* Elde ettiğimiz servisler arasında gezinmek için, Servis sayısı kadar ötelenecek bir for döngüsü oluşturuyoruz. Servis sayısını ise, svc isimli ServiceController tipinden dizimizin Length özelliği ile elde ediyoruz.*/
for(int i=0;i<svc.Length;i++)
{
lvServisler.Items.Add(svc[i].ServiceName.ToString()); /* ListView kontrolündeki ilk öğeye yani ServisAdı kısmına i indisli ServiceController tipinden svc nesnesinin ismini ekliyoruz. Bunun için ServiceName özelliğini kullanıyoruz.*/
lvServisler.Items[i].SubItems.Add(svc[i].Status.ToString()); /*ListView kontrolündeki alt öğeye, servisimizin durumunu Status özelliği yardımıyla ekliyoruz.*/
}
}
private void btnServisAl_Click(object sender, System.EventArgs e)
{
ServisListeGuncelle();
}
private void btnStart_Click(object sender, System.EventArgs e)
{
/* Öncelikle başlatmak istediğimiz servis bilgisini ListView kontrolünden almalıyız. Bunun için ListView kontrolünün FocusedItem özelliğini kullanıyoruz. Böylece kullanıcının ListView'da seçtiği servisin adını elde edebiliriz.*/
string servis;
servis=lvServisler.FocusedItem.Text;
/*Seçilen servis adını ele alarak bir ServiceController nesnesi oluşturuyoruz.*/
ServiceController curSer=new ServiceController(servis);
/* Servis başlatma işlemini eğer seçilen servisin durumu Stopped ise gerçekleştirebilmeliyiz. Bu amaçla, önce seçilen servise ait ServiceController nesnesinin Status özelliğine bakıyoruz. Değerin Stopped olup olmadığını denetlerken ServiceControllerStatus numaralandırıcısını kullanıyoruz.*/
if(curSer.Status==ServiceControllerStatus.Stopped)
{
curSer.Start(); /* Servisi çalıştırıyoruz.*/
curSer.WaitForStatus(ServiceControllerStatus.Running); /* Servisimiz Running konumunu alıncaya dek bir süre uygulamayı bekletiyoruz ve bu işlemin ardından servislerin listesini güncelliyoruz. Eğer WaitForStatus metodunu kullanmassak, servis listesini güncellediğimizde, ilgili servis için StartPending konumu yazılıcaktır.*/
ServisListeGuncelle();
}
else /* Servis zaten çalışıyorsa yani durumu(Status) Running ise bunu kullanıcıya belirtiyoruz.*/
{
MessageBox.Show(curSer.ServiceName.ToString()+" ZATEN CALISIYOR");
}
}
private void btnStop_Click(object sender, System.EventArgs e)
{
/* Bir servisi durdurmak için yapacağımız işlemler, başlatmak için yapacaklarımız ile aynı. Sadece bu kez, servisin Running konumunda olup olmadığını denetliyor ve öyleyse, Stop komutunu veriyoruz.*/
string servis;
servis=lvServisler.FocusedItem.Text;
ServiceController curSer=new ServiceController(servis);
if(curSer.Status==ServiceControllerStatus.Running)
{
curSer.Stop(); /* Servis durduruluyor. */
curSer.WaitForStatus(ServiceControllerStatus.Stopped);
ServisListeGuncelle();
}
else
{
MessageBox.Show(curSer.ServiceName.ToString()+" ZATEN CALISMIYOR");
}
}
private void btnPause_Click(object sender, System.EventArgs e)
{
/* Bir servisi duraksatacağımız zaman, bu servisin, CanPauseAndContinue özelliğinin değeri önem kazanır. Eğer bu değer false ise, servis üzerinde Pause veya Continue emirlerini uygulayamayız. Bu nedenle burada ilgili servise ati CanPauseAndContinue özelliğinin değeri kontrol edilir ve ona göre Pause emri verilir.*/
string servis;
servis=lvServisler.FocusedItem.Text;
ServiceController curSer=new ServiceController(servis);
if(curSer.CanPauseAndContinue==true) /* CanPauseAndContinue true ise, Pause işlemini uygulama hakkına sahibiz.*/
{
if(curSer.Status!=ServiceControllerStatus.Paused) /* Servis eğer Paused konumunda değilse Pause emri uygulanır. Bir başka deyişle servis çalışır durumdaysa.*/
{
curSer.Pause(); /* Servis duraksatılıyor.*/
curSer.WaitForStatus(ServiceControllerStatus.Paused); /* Servisin Paused konumuna geçmesi için bekleniyor. */
ServisListeGuncelle();
}
}
else
{
MessageBox.Show("SERVISIN PAUSE&CONTINUE YETKISI YOK");
}
}
private void btnContinue_Click(object sender, System.EventArgs e)
{
string servis;
servis=lvServisler.FocusedItem.Text;
ServiceController curSer=new ServiceController(servis);
if(curSer.CanPauseAndContinue==true) /* CanPauseAndContinue true ise, Continue işlemini uygulama hakkına sahibiz.*/
{
if(curSer.Status==ServiceControllerStatus.Paused) /* ServiceControllerStatus eğer Paused konumunda ise Continue işlemi uygulanır.*/
{
curSer.Continue(); /* Duraksatılan servis çalışmasına devam ediyor. */
curSer.WaitForStatus(ServiceControllerStatus.Running); /* Servisin Running konumuna geçmesi için bekleniyor. */
ServisListeGuncelle();
}
}
else
{
MessageBox.Show("SERVISIN PAUSE&CONTINUE YETKISI YOK");
}
}
private void btnBagliServisler_Click(object sender, System.EventArgs e)
{
string servis;
servis=lvServisler.FocusedItem.Text;
ServiceController curSer=new ServiceController(servis);
ServiceController[] bagliServisler=curSer.ServicesDependedOn; /* Bir servise bağlı servislerin listesini elde etmek için, güncel ServiceController nesnesinin, ServiceDependedOn özelliği kullanılır. */
lbBagliServisler.Items.Clear();
/* Bağlı servisler arasında gezinmek için foreach döngüsünü kullanıyoruz.*/
foreach(ServiceController sc in bagliServisler)
{
lbBagliServisler.Items.Add(sc.ServiceName.ToString());
}
}
}
}</pre>
<p>Uygulamamızı çalıştıralım , sistemdeki servisleri elde edelim ve örneğin Stopped konumunda olan servislerden Alerter servisini çalıştırıp, bu servise bağlı servis(ler) varsa bunların listesini tedarik edelim.</p>
<p><img src="/makale/images/mk69_4.gif" alt="" width="616" height="352" border="0" /></p>
<p><em>Şekil 4. Alerter Servisi Stopped konumunda.</em></p>
<p><img src="/makale/images/mk69_5.gif" alt="" width="616" height="352" border="0" /></p>
<p><em>Şekil 5. Alerter servisi çalıştırıldı ve bağlı olan servis elde edildi.</em></p>
<p>Geliştirmiş olduğumuz uygulamada olaşabilecek pek çok hata var. Örneğin listede hiç bir servis seçili değilken oluşabilecek istisnalar gibi. Bu tarz istisnaların ele alınmasını siz değerli okurlarıma bırakıyorum. Böylece geldik bir makalemizin daha sonuna. İlerleyen makalelerimizde görüşmek dileğiyle hepinize mutlu günler dilerim.</p>2004-05-12T06:00:00+00:00windows servicesbsenyurtBu makalemizde, sistemde yer alan windows servislerini bir windows uygulamasından nasıl elde edebileceğimizi ve nasıl kontrol edebileceğimizi incelemeye çalışacağız. Önceki makalelerimizden hatırlayacağınız gibi, sistemde yer alan servislerimiz, System.ServiceProcess isim alanında yer alan ServiceController sınıf nesneleri ile temsil edilmektedir.https://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=997bba2f-aba4-4a7b-bb89-381adbcb28c40https://www.buraksenyurt.com/trackback.axd?id=997bba2f-aba4-4a7b-bb89-381adbcb28c4https://www.buraksenyurt.com/post/Windows-Servislerinin-Kontrolu-2-(-Sistemdeki-Servislerin-Kontrol-Edilmesi-)-bsenyurt-com-dan#commenthttps://www.buraksenyurt.com/syndication.axd?post=997bba2f-aba4-4a7b-bb89-381adbcb28c4https://www.buraksenyurt.com/post/Windows-Servislerinin-Kontrolu-1-bsenyurt-com-danWindows Servislerinin Kontrolü -12004-05-05T09:00:00+00:00bsenyurt<p>Değerli Okurlarım, Merhabalar.</p>
<p>Bu makalemizde, windows servislerinin, bir windows uygulamasından nasıl kontrol edilebileceğini incelemeye çalışacağız. Bir önceki makalemizde, windows servislerinin nasıl oluşturulduğunu ve sisteme nasıl yüklendiklerini incelemiştik. Oluşturduğumuz windows servislerini(sistemdeki windows servislerini), SCM yardımıyla yönetibilmekteyiz. Ancak dilersek, bu yönetimi programlarımız içindende gerçekleştirebiliriz. Bunu sağlayabilmek için, System.ServiceProcess isim alanında yer alan ServiceController sınıfını ve üyelerini kullanmaktayız.</p>
<p>ServiceController sınıfı ile windows servislerine bağlanabilir ve onları kontrol edebiliriz. Örneğin servisleri başlatabilir, durdurabilir veya sistemdeki servisleri elde edebiliriz. Bu ve benzeri olanaklar dışında SCM ile yapamıyacağımız bir olayıda gerçekleştirebiliriz. Bu olay windows servislerinin OnCustomCommand metodu üzerinde işlemektedir. Bir windows servisinin OnCustomCommand metodu sayesinde servisimize standart işlevselliklerinin haricinde yeni işlevsellikler kazandırabiliriz. Prototipi aşağıdaki gibi olan OnCustomCommand metodu integer tipinden bir parametre almaktadır.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">protected virtual void OnCustomCommand(int command);</pre>
<p>OnCustomCommand metodunu herhangibir windows uygulamasından çağırabilmek için, ServiceController sınıfının ExecuteMethod metodu kullanılır. Integer tipindeki parametre 128 ile 256 arasında sayısal değerler alır. Metoda gönderilen parametre değerine göre, OnCustomCommand metodunun farklı işlevsellikleri yerine getirmesini sağlayabiliriz. ServiceController sınıfı ile yapabileceklerimiz aşağıdaki şekilde kısaca özetlenmiştir.</p>
<p><img src="/makale/images/mk68_1.gif" alt="" width="417" height="267" border="0" /></p>
<p><em>Şekil 1. ServiceController Sınıfı İle Yapabileceklerimiz.</em></p>
<p>Servislerimizi programatik olarak nasıl kontrol edebileceğimize geçmeden önce, konumuz ile ilgili basit bir windows servisi yazarak işe başlayalım. Bu servisimizde, kendi oluşturacağımız bir Event Log içerisinde, sistemdeki sürücülerinin boş alan kapasitelerine ait bilgileri tutacağız. Bu amaçlada, servisimize bir Performance Counter ekleyeceğiz. Ayrıca servisimize bir timer kontrolü koyacak ve bu kontrol ile belirli periyotlarda servisin, boş alan bilgilerini kontrol etmesini ve belli bir serviyenin altına inilirse Event Log'umuza bunu bir uyarı simgesi ile birlikte yazmasını sağlayacağız.</p>
<p>Bununla birlikte, OnCustomCommand metodunu uygulamamızdan çalıştıracak ve gönderdiğimiz parametre değerine göre servisin değişik işlevleri yerine getirmesini sağayacağız. Örneğin kullanıcının boş alan kontrol süresini ve alt sınır değerlerini programatik olarak belirleyebilmesini ve servisteki ilgili değerleri buna göre değiştirebilmesini sağlayacağız. Elbette bu değişiklikler servisin çalışma süresi boyunca geçerli olucaktır.</p>
<p>Şimdi dilerseniz servisimi oluşturalım. Öncelikle vs.net ortamında, yeni bir windows service projesi açıyoruz. Projemizin adı, BosAlanTakip olsun. Ardından servisimizin özelliklerinden adını ve servise ait kodlarda yer alan Service1'i , BosAlanTakipServis olarak değiştirelim. Bununla birlikte Soluiton Explorer'da Service1.cs kod dosyamızın adınıda BosAlanTakipServis.cs olarak değiştirelim. Sonraki adımımız ise, servisin özelliklerinden AutoLog özelliğine false değerini atamak. Nitekim biz bu servisimizde kendi yazacağımız Event Log'u kullanmak istiyoruz.</p>
<p><img src="/makale/images/mk68_2.gif" alt="" width="263" height="263" border="0" /></p>
<p><em>Şekil 2. Servisimizin özelliklerinin belirlenmesi.</em></p>
<p>Servisimizin kodlarını yazmadan önce, Custom Event Log'umuzu ekleyeceğiz. Bunun için, Components sekmesinden EventLog nesnesini servisimizin tasarım ekranına sürüklüyoruz.</p>
<p><img src="/makale/images/mk68_3.gif" alt="" width="179" height="295" border="0" /></p>
<p><em>Şekil 3. EventLog nesnesi.</em></p>
<p>Şimdi EventLog nesnemizin özelliklerini belirleyelim.</p>
<p><img src="/makale/images/mk68_4.gif" alt="" width="391" height="259" border="0" /></p>
<p><em>Şekil 4. EventLog nesnemizin özellikleri.</em></p>
<p>Artık log bilgilerini, servisimize eklediğimiz eventLog1 nesnesini kullanararak oluşturacağız. Sırada servisimize bir Performance Counter nesnesi eklemek var. Servislerimizde kullanabileceğimiz Performance Counter öğelerini, Solution Explorer pencersinde yer alan Performance Counter sekmesinden izleyebiliriz. Sistemde yüklü olan pek çok Performance Counter vardır.</p>
<p><img src="/makale/images/mk68_5.gif" alt="" width="299" height="353" border="0" /></p>
<p><em>Şekil 5. Sistemdeki Performance Counter'lardan bazıları.</em></p>
<p>Biz bu örneğimizde, LogicalDisk sekmesinde yer alan Free MegaBytes öğesini kullancağız. Bu sayaç yardımıyla, servisimizden, sistemdeki bir hardisk'in boş alan bilgilerini elde edebileceğiz. Bu amaçla buradaki C: sürücüsünü servisimiz üzerine sürüklüyoruz.</p>
<p><img src="/makale/images/mk68_6.gif" alt="" width="221" height="448" border="0" /></p>
<p><em>Şekil 6. Kullancağımız Performance Counter öğesi.</em></p>
<p>Diğer ihtiyacımız olan nesne bir Timer. Bunun için yine Components sekmesinden Timer nesnesini , servisimizin tasarım ekranına sürüklememiz yeterli. Daha sonra Timer nesnesinin interval özelliğinin değerini 600000 olarak değiştirelim. Bu yaklaşık olarak 10 dakikada (1000 milisaniye * 10 dakika * 60 saniye) bir, Timer nesnesinin Elapsed olayının çalıştırılılacağını belirtmektedir. Biz bu olay içerisinden C sürücüsündeki boş alan miktarını kontrol etmeyi planlıyoruz. Elbette süreyi başlangıçta 10 dakika olarak belirlememize rağmen geliştireceğimiz windows uygulamasında bu sürenin kullanıcı tarafından değiştirilebilmesini sağlıyacağız. Bu ayarlamaların ardından servisimiz için gerekli kodları yazmaya geçebiliriz.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
namespace BosAlanTakip
{
public class BosAlanTakipServis : System.ServiceProcess.ServiceBase
{
...
private long BosMiktar;
private long Sinir;
/* Servisimiz çalıştırıldığında(start),durdurulduğunda(stop), duraksatıldığında(pause) ve yeniden çalıştırıldığında(continue) , zaman bilgisini ve performanceCounter1 nesnesinin RawValue özelliğini kullanarak C sürücüsündeki boş alan miktarını, oluşturduğumuz Event Log'a WriteEntry metodu ile yazıyoruz. Servisin durum bilgisini ise metoda gönderdiğimiz string türünden parametre ile elde ediyoruz.*/
private void Bilgilendir(string durum)
{
eventLog1.WriteEntry(durum+" "+DateTime.Now.ToShortDateString()+ " C:"+performanceCounter1.RawValue.ToString()+" mb");
}
protected override void OnStart(string[] args)
{
Bilgilendir("START");
BosMiktar=performanceCounter1.RawValue; /* Servis çalıştırıldığında, C sürücüsündeki boş alan miktarını, BosMiktar isimli long türünden değişkenimize aktarıyoruz. performanceCounter'ımızın RawValue özelliği burada seçtiğimiz sayaç kriteri gereği sonucu megabyte cinsinden döndürmektedir.*/
Sinir=3300; // Yaklaşık olarak 3.3 GB.
timer1.Enabled=true; // Timer nesnemizi çalıştırıyoruz.
}
protected override void OnStop()
{
Bilgilendir("STOP");
}
protected override void OnPause()
{
Bilgilendir("PAUSE");
}
protected override void OnContinue()
{
Bilgilendir("CONTINUE");
}
/* Özel komutumuzu yazıyoruz. */
protected override void OnCustomCommand(int command)
{
/* if koşullarında OnCustomCommand'a gönderilecek parametre değerine göre, boş alan uyarısı için gerekli alt sınır değeri belirleniyor. Ayrıca, timer nesnemizin interval değeride gelen parametre değerine göre belirleniyor ve böylece timer nesnesinin Elapsed olayının çalışma aralığı belirlenmiş oluyor.*/
if(command==200)
{
Sinir=3000; // Yaklaşık olarak 3gb.
}
else if(command==201)
{
Sinir=2000; // Yaklaşık olarak 2gb.
}
else if(command==202)
{
Sinir=4000; // Yaklaşık olarak 4gb.
}
else if(command==203)
{
timer1.Enabled=false;
timer1.Interval=1800000; // 30 dakikada bir.
timer1.Enabled=true;
}
else if(command==204)
{
timer1.Enabled=false;
timer1.Interval=3600000; // Saatte bir.
timer1.Enabled=true;
}
else if(command==205)
{
timer1.Enabled=false;
timer1.Interval=3000; // 3 Saniyede bir.
timer1.Enabled=true;
}
}
private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if(BosMiktar<=Sinir)
{
/* Eğer C sürücüsündeki boş alan mikarı Sinir değişkeninin sahip olduğu değerin altına düşerse, bu bilgi Event Log'umuza bir warning singesi ile birlikte eklenecek. */
string bilgi=DateTime.Now.ToShortDateString()+ " C: Surucusu Bos Alan : "+performanceCounter1.RawValue.ToString();
eventLog1.WriteEntry(bilgi,EventLogEntryType.Warning);
}
else
{
Bilgilendir("");
}
}
}
}</pre>
<p>Servisimizin kodlarınıda böylece hazırlamış olduk. Şimdi servisimiz için gerekli olan installer'larımızı servisimizin tasarım ekranında sağ tuşla açtığımız menüden, Add Installer öğesini seçerek ekleyelim. Önce ServiceInstaller1'in özelliklerinden Display Name özelliğinin değerini, Bos Alan Takip olarak değiştirelim. Böylece servisimizin, services sekmesinde görünen ismini belirlemiş oluruz. Ardından ServiceProcessInstaller1 nesnemizin, Account özelliğinin değerini, LocalSystem olarak değiştirelim. Böylece sistemi açan herkes bu servisi kullanabilecek.</p>
<p>Diğer yandan oluşturduğumuz Custom Event Log içinde bir installer oluşturmamız gerekiyor ki installUtil tool'u ile servisimizi sisteme kurduğumuzda, sistedeki Event Log'lar içerisine, oluşturduğumuz Custom Event Log'da kurulabilsin. Bu amaçla, eventLog1 nesnemiz üzerinde sağ tuşa basıp çıkan menüden Add Installer'ı seçiyoruz. Bu sayede, Event Log'umuz için, bir adet eventLogInstaller'ın oluşturulduğunu görürüz. Bu işemlerin ardından windows servis uygulamamızı derleyelim ve servisimizi sisteme yükleyebilmek için installUtil, vs.net tool'unu aşağıdaki gibi kullanalım.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">installUtil BosAlanTakip.exe</pre>
<p>Bu işlemlerin ardından servisimiz başarı ile yüklendiyse, server explorer'daki services sekmesinde görünecektir. Servisimizi bu aşamada denemek amacı ile, başlatıp durdurmayı deneyelim. Ancak bu noktada servisimizin pause ve continue olaylarının geçersiz olduğunu görürüz. Bunun sebebi, servisimizin OnPauseContinue özelliğinin değerinin false olmasıdır. Şimdi bu değeri true yapalım. Servis uygulamamızı tekrar derleyelim. Ardından servisimizi sisteme yeniden yükleyelim. Şimdi server explorer'dan servisimizi çalıştırıp deneyelim.</p>
<p><img src="/makale/images/mk68_7.gif" alt="" width="397" height="383" border="0" /></p>
<p><em>Şekil 7. Servisin Çalışan Hali.</em></p>
<p>Ben servisi test etmek için, C sürücüsündeki boş alanı biraz daha düşürdüm. Görüldüğü gibi servis başarılı bir şekilde çalışıyor. Şu an için her 10 dakikada bir timer nesnesinin Elapsed olayı devreye giriyor ve C sürücüsündeki boş alan miktarının 3.3 gb'ın altına düşüp düşmediği kontrol ediliyor. Servisimiz bunu tespit ettiği anlarda Event Log'umuza bir uyarı işareti ekleyecektir.</p>
<p>Şimdi yazmış olduğumuz bu servisi başka bir windows uygulaması içerisinden nasıl yönetebileceğimizi incelemeye başlayalım. Burada bizim için anahtar nokta, windows uygulamamızda, System.ServiceProcess isim alanını kullanmak. Oluşturmuş olduğumuz servise ait OnCustomCommand metodunu çalıştırmak için, bu isim alanında yer alan ServiceController sınıfının ExecuteCommand metodunu kullanacağız. Öncelikle aşağıdaki gibi bir form tasarlayarak işe başlayalım.</p>
<p><img src="/makale/images/mk68_8.gif" alt="" width="312" height="248" border="0" /></p>
<p><em>Şekil 8. Form Tasarımımız.</em></p>
<p>Şimdi ServiceProcess isim alanını kullanabilmek için Add Referance kısmından uygulamamıza eklememiz gerekiyor.</p>
<p><img src="/makale/images/mk68_9.gif" alt="" width="566" height="446" border="0" /></p>
<p><em>Şekil 9. System.ServiceProcess isim alanının uygulamaya eklenmesi.</em></p>
<p>Öncelikle servisimizi temsil edicek ServiceController sınıfı türünden bir nesne oluşturacağız. ServiceController sınıfından nesnemizi oluştururken aşağıda prototipi verilen yapıcı metodu kullanıyoruz. Bu yapıcı, servisin tam adını parametre olarak string türünden almaktadır.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">public ServiceController(string serviceName);</pre>
<p>ServiceController sınıfına ait nesne örneğini kullanarak servisimize ilişkin pek çok bilgiyi elde edebiliriz. Örneğin, servisin görünen adını DisplayName özelliği ile , servisin çalıştığı makine adını MachineName özelliği ile elde edebiliriz. ServiceController sınıfının üyeleri yardımıyla sistemimizde kurulu olan servislere ait pek çok bilgiyi temin edebiliriz. Bu konuyu bir sonraki makalemizde incelemeye çalışacağız. Şimdi dilerseniz servisimizi kontrol ediceğimiz kısa windows uygulamamızın kodlarını yazalım.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">ServiceController sc; /* Servisimizi kontrol edicek olan ServiceController sınıf nesnemiz tanımlanıyor.*/
private void Form1_Load(object sender, System.EventArgs e)
{
sc=new ServiceController("BosAlanTakipServis"); /* ServiceController nesnemiz, kullanmak istediğimiz servisin adını parametre olarak almak suretiyle oluşturuluyor.*/
lblServisAdi.Text=sc.DisplayName.ToString()+"/"+sc.MachineName.ToString(); /* Servisimizin , sistemdeki services kısmında görünen ismi ve üzerinde çalıştığı makine adı elde ediliyor ve label kontrolümüze ekleniyor.*/
}
private void btnPeriyod_Click(object sender, System.EventArgs e)
{
if(lbPeriyod.SelectedIndex==0)
{
sc.ExecuteCommand(203); /* Servisimizdeki OnCustomCommand metodu çalıştırılıyor ve bu metoda parametre değeri olarak 203 gönderiliyor. Artık servisimiz, 203 parametre değerine göre bir takım işlevler gerçekleştirecek. 203 değeri karşılığında servisimizdeki OnCustomCommand metodu, log tutma süresini yarım saat olarak belirleyecektir.*/
}
else if(lbPeriyod.SelectedIndex==1)
{
sc.ExecuteCommand(204);
}
else if(lbPeriyod.SelectedIndex==2)
{
sc.ExecuteCommand(205);
}
}
private void btnAltSinirAyarla_Click(object sender, System.EventArgs e)
{
if(lbAltSinir.SelectedIndex==0)
{
sc.ExecuteCommand(201);
}
else if(lbAltSinir.SelectedIndex==1)
{
sc.ExecuteCommand(200);
}
else if(lbAltSinir.SelectedIndex==2)
{
sc.ExecuteCommand(202);
}
}</pre>
<p>Şimdi uygulamamızı çalıştıralım ve ilk olarak süreyi 3 saniyede 1 seçerek Event Log'ların tutuluşunu izleyelim. Windows uygulamamızı başlatmadan önce servisimizi manuel olarak başlatmayı unutmayalım. Diğer yandan bunu dilersek SCM yardımıyla otomatik hale getirebilir ve sistem açıldığında servisin otomatik olarak başlatılmasını sağlayabiliriz. Event Log süresini 3 saniye olarak belirleyip Ayarla başlıklı butona tıkladığımızda, servisimizi temsil eden ServiceController nesnesinin ExecuteCommand metodu devreye girerek, ListBox'tan seçilen öğenin indeksine göre bir değeri, temsil ettiği servis içindeki OnCustomCommand metoduna parametre olarak gönderir. Bunun sonucu olarak Event Log'umuzda 3 saniyede bir durum bilgisinin yazılıyor olması gerekir.</p>
<p><img src="/makale/images/mk68_10.gif" alt="" width="363" height="159" border="0" /></p>
<p><em>Şekil 10. Servisin Event Log tutma süresinin ayarlanması.</em></p>
<p>Görüldüğü gibi servisimiz bu yeni ayarlamadan sonra, kendi oluşturduğumuz Event Log'a 3 saniyede 1 bilgi yazmaktadır. Servisimizde, C sürücüsü için belli bir miktar kapasitenin altına düşüldüğünde, Event Log'a yazılan mesaj bir uyarı simgesi ile birlikte yazılıyor. Şu an için, belirtilen kapasitenin altında olduğumuzdan warning simgesi , servisin timer nesnesinin elapsed olayında değerlendiriliyor ve Event Log'umuza yazılıyor. Şimdi bu kapasiteyi 2 GB yapalım ve durumu gözlemleyelim.</p>
<p><img src="/makale/images/mk68_11.gif" alt="" width="365" height="128" border="0" /></p>
<p><em>Şekil 11. Alt Sinir değerinin değiştirilmesi.</em></p>
<p>Görüldüğü gibi, servisimizin alt sınıra göre Event Log'ların simgesini belirleyen davranışını değiştirmeyi başardık. Bu işlemi ExecuteCommand metodu ile servisimizdeki OnCustomCommand'a gönderdiğimiz parametrenin değerini ele alarak gerçekleştirdik.</p>
<p>Böylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde sistemimizde yer alan servisleri, ServiceController sınıfındaki metod ve özellikler ile nasıl kontrol edebileceğimizi incelemeye çalışacağız. Bu makalede görüşünceye dek hepinize mutlu günler dilerim.</p>2004-05-05T09:00:00+00:00windows servicesServiceControllereventlogbsenyurtBu makalemizde, windows servislerinin, bir windows uygulamasından nasıl kontrol edilebileceğini incelemeye çalışacağız. Bir önceki makalemizde, windows servislerinin nasıl oluşturulduğunu ve sisteme nasıl yüklendiklerini incelemiştik. Oluşturduğumuz windows servislerini(sistemdeki windows servislerini), SCM yardımıyla yönetibilmekteyiz. Ancak dilersek, bu yönetimi programlarımız içindende gerçekleştirebiliriz. Bunu sağlayabilmek için, System.ServiceProcess isim alanında yer alan ServiceController sınıfını ve üyelerini kullanmaktayız.https://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=84cf874a-6376-471d-9e90-7377aa7aefc60https://www.buraksenyurt.com/trackback.axd?id=84cf874a-6376-471d-9e90-7377aa7aefc6https://www.buraksenyurt.com/post/Windows-Servislerinin-Kontrolu-1-bsenyurt-com-dan#commenthttps://www.buraksenyurt.com/syndication.axd?post=84cf874a-6376-471d-9e90-7377aa7aefc6https://www.buraksenyurt.com/post/Windows-Servislerine-Giris-bsenyurt-com-danWindows Servislerine Giriş2004-04-28T15:00:00+00:00bsenyurt<p>Değerli Okurlarım, Merhabalar.</p>
<p>Bu makalemizde windows servislerine kısa bir giriş yapıcak ve en basit haliye bir windows servisinin, .net ortamında nasıl oluşturulacağını incelemeye çalışacağız. Öncelikle Windows Service nedir, ne amaçlarla kullanılır bunu irdelemeye çalışak daha sonra windows servislerinin mimarisini kısaca inceleyeceğiz.</p>
<p>Windows servisleri, işletim sisteminde arka planda çalışan, kullanıcı ile etkilişimde bulunduğu herhangibir arayüze sahip olmayan, kaynakların izlenmesi, system olaylarının log olarak tutulması, network erişimlerinin izlenmesi, veritabanları üzerindeki transaction'ların izlenmesi, sistem performansına ati bilgilerin toplanması, sistem hatalarının (system exceptions) , başarısız program denemelerin (failure) vb. gibi geri plan işlemlerinin takip edilmesinde kullanılan, sisteme kayıt edilmiş (register), çalıştırılabilir nesnelerdir.</p>
<p>Aslında, windows NT,2000,XP yada 2003 kullanıcısı iseniz, windows servisleri ile mutlaka ilgilenmişsinizdir. Sistemlerimizde çalışan pek çok servis vardır. Bu servislerin neler olduğuna, Administrative Tool bölümünde Services kısmından bakabiliriz. Örneğin aşağıda XP Professional sisteminde yüklü olan örnek servisler yer almaktadır.</p>
<p><img src="/makale/images/mk67_1.gif" alt="" width="591" height="391" border="0" /></p>
<p>Şekil 1. Win XP için Örnek Windows Servisleri</p>
<p>İşte biz, .net sınıflarını kullanarak, burada yer alacak windows servisleri yazma imkanına sahibiz. Windows Servislerinin mimari yapısı aşağıdaki şekilde görüldüğü gibidir.</p>
<p><img src="/makale/images/mk67_2.gif" alt="" width="576" height="165" border="0" /></p>
<p>Şekil 2. Windows Servis Mimarisi</p>
<p>Mimariden kısaca bahsetmek gerekirse; Service Application (Servis Uygulaması) , istenilen fonksiyonelliklere sahip bir veya daha fazla windows servisini içeren bir uygulamadır. Servis Kontrol Uygulaması (Service Controller Application) ise, servislerin davranışlarını kontrol eden bir uygulamadır. Son olarak, SCM, sistemde yüklü olan servislerin kontrol edilmesini sağlayan bir windows aracıdır. Dolayısıyla biz, bir windows servis uygulaması yazarken, bunun içerisine birden fazla servis koyabiliriz. Bu servis uygulaması ve başka servis uygulamalarının davranışlarını servis kontrol uygulamaları yardımı ile kontrol edebiliriz. Diğer yandan, yazmış olduğumuz tüm servis uygulamaları ile birlikte sistemdeki servisleri, SCM aracılığıyla yönetebiliriz.</p>
<p>.Net Framework, windows servislerini oluşturabilmemiz için gerekli sınıfları içeren System.ServiceProcess isim alanına (namespace) sahiptir. Bu isim alanındaki sınıfları kullanarak, bir servisi oluşturabilir, sisteme yükleyebilir, yürütebilir ve kontrol edebiliriz. Aşağıdaki şekil, basit olarak, ServiceProcess isim alanındaki sınıflar ile yapabileceklerimizi temsil etmektedir.</p>
<p><img src="/makale/images/mk67_3.gif" alt="" width="547" height="237" border="0" /></p>
<p>Şekil 3. System.ServiceProcess isim alanındaki sınıflar ile yapabileceklerimiz.</p>
<p>Buradaki sınıflar yardımı ile bir windows servisi oluşturmak istediğimizde izlememiz gereken bir yol vardır. Öncelikle, servisi oluşturmamız gerekir (Create) . Bunun için ServiceBase sınıfını kullanırız. ServiceBase sınıfında yer alan metodlar yardımıyla, bir windows servisini oluşturabiliriz. Oluşturulan bu servisin daha sonra, kullanılabilmesi için sisteme install edilmesi ve register olması gerekmektedir. Bu noktada devreye ServiceInstaller ve ServiceProcessInstaller sınıfları girer. Bir windows servis uygulamasını install etmeden önce, bu servis için bir iş parçacığı(process) oluşturulmalı ve yüklenmelidir. İşte bu noktada devreye ServiceProcessInstaller girer. ServiceInstaller ve ServiceProcessInstaller sınıfları aslında bir servisin sisteme yüklenebilmesi için gerekli metodları otomatik olarak sağlarlar. Ancak bu sınıfların uygulandığı bir windows servis uygulamasının tam olarak sisteme yüklenmesi ve Services kısmında görülebilmesi için, InstallUtil isimli .net aracı kullanılır ve oluşturulan windows servis uygulaması sisteme yüklenir.</p>
<p>Sisteme yüklenmiş olan servislerin kontrol edilebilmesi amacıyla, ServiceController sınıfındaki metodları kullanabiliriz. Yani, bir servisin Start, Stop, Pause, Continue gibi dabranışlarını kontrol edebiliriz. Bu amaçla SCM aracını kullanabileceğimiz gibi, ServiceController sınıfındaki metodlarıda kullanabilir ve böylece herhangibir uygulamdan bir servisi başlatabilir, durdurabilir vb. işlemlerini gerçekleştirebiliriz.</p>
<p>Bir windows servisinin oluşturulması, sisteme yüklenmesi , yürütülmesi ve kontrol edilmesi her nekadar karışık görünsede, vs.net burada gereksinimin duyduğumuz işlemlerin çoğunu bizim için otomatik olarak yapmaktadır. Windows servislerinin oluşturulmasında kullanılan System.ServiceProcess isim alanının yanında, servislerin durumunun izlenebilmesi, çeşitli performans kriterlerinin servis içerisinden kontrol edilebilmesi, sisteme ait logların servis içerisinde kullanılabilmesi gibi işlemleri gerçekleştirebileceğimiz sınıfları içeren System.Diagnostics isim alanıda vardır.</p>
<p><img src="/makale/images/mk67_4.gif" alt="" width="217" height="237" border="0" /></p>
<p>Şekil 4. System.Diagnostics isim alanı sınıfları.</p>
<p>Bir windows servis uygulaması ile normal bir vs.net uygulaması arasında belirgin farklılıklar vardır. Herşeyden önce bir windows servis uygulamasının kullanılabilmesi için, sisteme install edilmesi ve register olması gereklidir. Diğer önemli bir farkta, bir windows servis uygulaması arka planda çalışırken, bu servisin çalışması ile ilgili oluşabilecek hatalardır. Normal bir windows uygulamasında hatalar sistem tarafından kullanıcıya bir mesaj kutusu ile gösterilebilir yada program içerisindeki hata kontrol mekanizmaları sayesinde görsel olarak izlenebilir. Oysa bir windows servis uygulaması çalışırken meydana gelen hatalar, event log olarak sistemde tutulurlar.</p>
<p>Windows servisleri ile ilgili bu kısa bilgilerin ardından, dilerseniz birlikte basit bir windows servis uygulaması geliştirelim. Bunun için ilk yapmamız gereken vs.net ortamında, bir windows service applicaiton projesi açmaktır.</p>
<p><img src="/makale/images/mk67_5.gif" alt="" width="531" height="371" border="0" /></p>
<p>Şekil 5. Windows Servis Uygulaması Açmak.</p>
<p>Bu işlemi gerçekleştirdiğimizde, vs.net herhangibir kullanıcı arayüzü olmayan bir proje oluşturacaktır.</p>
<p><img src="/makale/images/mk67_6.gif" alt="" width="608" height="274" border="0" /></p>
<p>Şekil 6 . Windows Servis Uygulaması ilk oluşturulduğunda ekranın görnümü.</p>
<p>Servis uygulamasını geliştirmek için yazacağımız kodlara geçmek için, to switch to code windows linkine tıklamamız gerekiyor. Bu durumda vs.net tarafından otomatik olarak oluşturulmuş kodları görürüz. İlk dikkat çekici nokta, Service1 isimli sınıfın ServiceBase sınıfından türetilmiş olmasıdır.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">public class Service1 : System.ServiceProcess.ServiceBase</pre>
<p>ServiceBase sınıfı OnStart, OnStop, OnPause, OnContinue gibi bir takım metodlar içeren bir sınıftır. Bir windows servisi oluşturulurken bu servis sınıfının, ServiceBase sınıfından türetilmesinin sebebi, bahsetmiş olduğumuz metodların, servis sınıfı içerisinde override edilmeleridir. Bir servis SCM tarafından yada windows içinden başlatıldığında, servisin başlatıldığında dair start mesajı gelir. İşte bu noktada servisin OnStart metodundaki kodlar devreye girer. Aynı durum benzer şekilde, OnStop olayı içinde geçerlidir. Tüm bu metodlar ve başka üyeler temel sınıf olan ServiceBase sınıfı içerisinde toplanmıştır. Bunun sonucu olarak, bir sınıfı servis olarak tanımlamışsak, ServiceBase sınıfından türetir böylece servis başlatıldığında, durdurulduğunda vb. olaylarda yapılmasını istediğimiz işlemleri, türeyen sınıfta bu davranışların tetiklediği, OnStart, OnStop gibi metodları override ederek gerçekleştirebiliriz.</p>
<p>Sonuç itibariyle vs.net, bir servis uygulaması oluşturduğumuzda, buradaki varsayılan servisi, ServiceBase sınıfından türetir ve otomatik olarak OnStart ve OnStop metodlarını aşağıdaki şekilde ekler.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">protected override void OnStart(string[] args)
{
}
protected override void OnStop()
{
}</pre>
<p>Peki bu metodlar ne zaman ve ne şekilde çalışır. Bir windows servisinin, normal windows uygulamalarında olduğu gibi desteklediği olaylar vardır. Windows servisleri 4 olayı destekler. Bir windows servisinde meydana gelen olayların çalışma şekli aşağıdaki şekildeki gibidir.</p>
<p><img src="/makale/images/mk67_7.gif" alt="" width="331" height="462" border="0" /></p>
<p>Şekil 7. Servis Olaylarının Ele Alınış Mekanizması.</p>
<p>Buradan görüldüğü gibi, sistemde, yazmış olduğumuz windows servisi ile ilgili olarak 4 olay meydana gelebilir. Bunlar Start, Stop, Pause ve Continue olaylarıdır. Bir servis SCM tarafından başlatıldığında bu servis için Start olayı meydana gelir. Daha sonra SCM, servisin içinde bulunduğu Servis Uygulamasına Start komutunu gönderir. Buna karşılık servis uygulaması içindeki ilgili servis bu Start komutunu alır ve karşılığında, OnStart metodunda yazan kodları çalıştırır.</p>
<p>Diğer yandan bir servis durdurulduğunda, Stop olayı meydana gelir. Ancak bu noktada SCM Start tekniğinden farklı olarak hareket eder. SCM önce oluşan olayın sonucunda ilgili servis uygulaması içindeki servisin, CanStop özelliğine bakar. CanStop özelliği true veya false değer alabilen bir özelliktir ve servisin durdurulup durdurulamıyacağını dolayısıyla, bir Stop olayı meydana geldiğinde, servise ati OnStop metodunun çalıştırılıp çalıştırılamıyacağını belirtir. SCM bu nedenle Stop olayı meydana geldiğinde ilk olarak bu özelliği kontrol eder. Eğer özellik değeri true ise, servise Stop komutunu gönderir ve sonuç olarak OnStop metodundaki kodlar çalıştırılır.</p>
<p>Stop tekniğinde gerçekleşen özellik kontrol işlemi, Pause ve Continue olayları içinde geçerlidir. Bu kez SCM, servisin CanPauseAndContinue özelliğinin boolean değerine bakar. Eğer bu değer true ise, servise Pause komutunu veya Continue komutunu gönderir ve bunlara bağlı olan OnPause ve OnContinue metodlarındaki kodların çalıştırılmasını sağlar. Pause olayı bir servis duraklatıldığında oluşur. Continue olayı ise, pause konumunda olan bir servis tekrar çalışmasına devam etmeye başladığında oluşur.</p>
<p>Bir diğer önemli nokta oluşturulan service1 isimli sınıfın main metodundaki kodlardır.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">static void Main()
{
System.ServiceProcess.ServiceBase[] ServicesToRun;
ServicesToRun = new System.ServiceProcess.ServiceBase[] { new Service1() };
System.ServiceProcess.ServiceBase.Run(ServicesToRun);
}</pre>
<p>Burada görüldüğü gibi ServiceBase sınıfı tipinden bir nesne dizisi tanımlanmış ve varsayılan olarak bu nesne dizisinin ilk elemanı Service1 ismi ile oluşturulmuştur. Bu aslında bir servis uygulamasının birden fazla windows servisini içerebileceğinide göstermektedir. Burada ServiceBase sınıfı tipinden bir nesne dizisinin tanımlanmasının nedenide budur. Zaten oluşturduğumuz Service1 sınıfı, ServiceBase sınıfından türetildiği için ve sahip olduğu temel sınıf metodlarıda bu türeyen sınıf içerisinde override edildiği için, polimorfizmin bir gereği olarak, servis nesnelerini bir ServiceBase tipinden dizide tutmak son derece mantıklı ve kullanışlıdır.</p>
<p>Son satıra gelince. ServiceBase sınıfının Run metodu, parametre olarak aldığı serviseleri, SCM tarafından başlatılmış iseler, belleğe yüklemekle görevli bir metoddur. Elbette servislerin belleğe Run metodu ile yüklenebilmesi için, öncelikle Start komutu ile başlatılmaları gerekmektedir. ServiceBase.Run metodu aslında normal bir windows uygulamasındaki Application.Run metodu ile aynı işlevselliği gösterir.</p>
<p>Şu ana kadar oluşturduklarımız ile bir servisin omurgasını meydana çıkardık. Ancak halen servisimiz herhangibir işlem yapmamakta. Oysaki bir servis ile, örneğin, sistemdeki aygıt sürücülerine ait olay log'larını, düşük bellek kullanımı sonucu yazılım veya donanım ekipmanlarında meydana gelebilecek hata (error), istisna(exception), warning(uyarı) gibi bilgilere ait log'ları izleyebiliriz.</p>
<p>Şimdi dilerseniz ilk yazdığımız servis ile Uygulama Log'larının (Application Log) nasıl tutulduğunu incelemeye çalışalım. Aslında bizim izleyebileceğimiz üç tip log vardır. Bunlar, System Log'ları, Application Log'ları ve Security Log'larıdır.</p>
<p><img src="/makale/images/mk67_8.gif" alt="" width="410" height="225" border="0" /></p>
<p>Şekil 8. Olay Log'larının Türleri.</p>
<p>Normal şartlar altında, vs.net ortamında bir windows servis ilk kez oluşturulduğunda, servise ait AutoLog özelliği değeri true olarak gelir. Bu durumda Start,Stop,Pause ve Continue olayları meydana geldiğinde, servis sisteme kurulduğunda veya sistemden kaldırıldığında, servis uygulamasına ait loglar, Application Log'a otomatik olarak yazılırlar. Biz bu uygulamamızda kendi özel loglarımızı tutmak istediğimizden bu özelliğin değerini false olarak belirliyoruz.</p>
<p>Kendi olay loglarımızı yazabilmemiz için, EventLog nesnelerine ihtiyacımız vardır. EventLog nesneleri System.Diagnostics isim alanında yer alan EventLog sınıfı ile temsil edilirler. Bu nedenle uygulamızda öncelikle bir EventLog nesne örneği oluşturmalıyız.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">private System.Diagnostics.EventLog OlayLog;</pre>
<p>Bir EventLog nesnesi oluşturduktan sonra, bu nesne üzerinden CreateEventSource metodunu kullanarak servisimiz için bir event log oluşturabiliriz. Buna ilişkin kodları OnStart metodu içine yazarsak, servis başlatıldığında oluşturduğumuz log bilgilerininde otomatik olarak yazılmasını sağlamış oluruz.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">protected override void OnStart(string[] args)
{
OlayLog=new EventLog(); /* EventLog nesnemizi olusturuyoruz.*/
if(!System.Diagnostics.EventLog.SourceExists("Kaynak"))
{
System.Diagnostics.EventLog.CreateEventSource("Kaynak","Log Deneme"); /* Ilk parametre ile, Log Deneme ismi altinda tutulacak Log bilgilerinin kaynak ismi belirleniyor. Daha sonra bu kaynak ismi OlayLog isimli nesnemizin Source özelligine ataniyor.*/
}
OlayLog.Source="Kaynak";
OlayLog.WriteEntry("Servisimiz baslatildi...",EventLogEntryType.Information); /* Log olarak ilk parametrede belirtilen mesaj yazilir. Log'un tipi ise ikinci parametrede görüldügü gibi Information'dir.*/
}</pre>
<p>Bu işlemlerin ardından servisimiz için basit bir görevide eklemiş olduk. Şimdi sırada bu servisin sisteme yüklenmesi var. Bunun için, daha önceden bahsettiğimiz gibi, ServiceProcess.ServiceInstaller ve ServiceProcess.ServiceProcessInstaller sınıflarını kullanmamız gerekiyor. Servis uygulamamız için bir tane ServiceProcessInstaller sınıfı nesne örneğine ve servis uygulaması içindeki her bir servis içinde ayrı ayrı olamak üzere birer ServiceInstaller nesne örneğine ihtiyacımız var. Bu nesne örneklerini yazmış olduğumuz servis uygulamasına kolayca ekleyebiliriz. Bunun için, servisimizin tasarım penceresinde sağ tuşa basıyor ve Add Installer seçeneğini tıklıyoruz.</p>
<p><img src="/makale/images/mk67_9.gif" alt="" width="261" height="273" border="0" /></p>
<p>Şekil 9. Add Installer.</p>
<p>Bunun sonucu olarak vs.net, uygulamamıza gerekli installer sınıflarını yükler.</p>
<p><img src="/makale/images/mk67_10.gif" alt="" width="578" height="71" border="0" /></p>
<p>Şekil 10. Installer nesne örneklerinin yüklenmesi.</p>
<p>Bunun sonucu olarak aşağıda görülen sınıf uygulamamıza otomatik olarak eklenir. Bu aşamada buradaki kodlar ile fazla ilgilenmiyeceğiz.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Collections;
using System.ComponentModel;
using System.Configuration.Install;
namespace OrnekServis
{
[RunInstaller(true)]
public class ProjectInstaller : System.Configuration.Install.Installer
{
private System.ServiceProcess.ServiceProcessInstaller serviceProcessInstaller1;
private System.ServiceProcess.ServiceInstaller serviceInstaller1;
private System.ComponentModel.Container components = null;
public ProjectInstaller()
{
InitializeComponent();
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
private void InitializeComponent()
{
this.serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller();
this.serviceInstaller1 = new System.ServiceProcess.ServiceInstaller();
this.serviceProcessInstaller1.Password = null;
this.serviceProcessInstaller1.Username = null;
this.serviceInstaller1.ServiceName = "Service1";
this.Installers.AddRange(new System.Configuration.Install.Installer[] {this.serviceProcessInstaller1,this.serviceInstaller1});
}
}
}</pre>
<p>Ancak servisimizin, Sistemdeki service listesinde nasıl görüneceğini belirlemek için, ServiceInstaller nesne örneğinin, Display Name özelliğini değiştirebiliriz.</p>
<p><img src="/makale/images/mk67_12.gif" alt="" width="404" height="290" border="0" /></p>
<p>Şekil 11. Servisimizin görünen adını değiştiriyoruz.</p>
<p>Diğer taraftan yapmamız gereken bir işlem daha var. ServiceProcessInstaller nesne örneğinin Account özelliğinin değerini belirlemeliyiz. Bu özellik aşağıdaki şekilde görülen değerlerden birisini alır.</p>
<p><img src="/makale/images/mk67_13.gif" alt="" width="399" height="289" border="0" /></p>
<p>Şekil 12. Account Özelliğinin Alabileceği Değerler.</p>
<p>Biz bu uygulama için LocalSystem değerini veriyoruz. Bu, Servis Uygulamamızın sisteme yüklenirken, sistemdeki kullanıcıların özel haklara sahip olmasını gerektirmez. Dolayısıyla sisteme giren her kullanıcının servisi yükleme hakkı vardır. Eğer User seçeneğini kullanırsak, servisin sisteme yüklenebilmesi için geçerli bir kullanıcı adı ve parolanın girilmesi gerekmektedir.</p>
<p>Artık yazmış olduğumuz servis uygulamsı için installer'larıda oluşturduğumuza göre uygulamamız derleyip, sisteme InstallUtil aracı ile yükleyebilir ve register edebiliriz. Bunun için, servis uygulamamızın exe dosyası ile, InstallUtil aracını aşağıdaki gibi kullanırız.</p>
<p><img src="/makale/images/mk67_11.gif" alt="" width="639" height="470" border="0" /></p>
<p>Şekil 13. InstallUtil aracı yardımıyla bir servisin sisteme yüklenmesi.</p>
<p>İşte InstallUtil aracı servisimizi sisteme yüklerken, servis uygulamamıza eklediğimiz ServiceProcessInstaller ve ServiceInstaller sınıflarını kullanır. Bu işlemin ardından vs.net ortamında, Server Explorer'dan servislere baktığımızda, AServis isimli servisimizin yüklendiğini ancak henüz çalıştırılmadığını görürüz.</p>
<p><img src="/makale/images/mk67_14.gif" alt="" width="347" height="148" border="0" /></p>
<p>Şekil 14. Servis sisteme yüklendi.</p>
<p>Eğer servisin otomatik olarak başlatılmasını istiyorsak, ServiceInstaller nesnesinin StartType özelliğini Automatic olarak ayarlamamız yeterli olucaktır.</p>
<p><img src="/makale/images/mk67_15.gif" alt="" width="397" height="339" border="0" /></p>
<p>Şekil 15. Servisin Başlatılma Şeklinin Belirlenmesi.</p>
<p>İstersek servisimizi, yine Server Explorer'dan servis adına sağ tıklayıp açılan menüden start komutuna basarak çalıştırabiliriz. Servisimizi çalıştırdıktan sonra, yine Server Explorer pencersinden Event Logs sekmesine bakarsak, bahsetmiş olduğumuz olay logları haricinde kendi yapmış olduğumuz olay logununda eklendiğini görürüz.</p>
<p><img src="/makale/images/mk67_16.gif" alt="" width="382" height="128" border="0" /></p>
<p>Şekil 16. Servisin çalışmasının sonucu.</p>
<p>Burada görüldüğü gibi Log Deneme ismi ile belirttiğimiz Event Log oluşturulmuş, Source olarak belirttiğimiz Kaynak nesnesi oluşturulmuş ve OnStart metoduna yazdığımız kodlar yardımıyla, mesaj bilgimiz information(bilgi) olarak yazılmıştır. Buraya kadar anlattıklarımız ile bir windows servisinin nasıl yazıldığını ve sisteme yüklendiğini en temek hatları ile görmüş olduk. İlerleyen makalelerimizde, windows servisleri ile ilgili daha farklı uygulamlar geliştirmeye çalışacağız. Hepinize mutlu günler dilerim.</p>2004-04-28T15:00:00+00:00windows serviceshello worldc#windowsbsenyurtBu makalemizde windows servislerine kısa bir giriş yapıcak ve en basit haliye bir windows servisinin, .net ortamında nasıl oluşturulacağını incelemeye çalışacağız. Öncelikle Windows Service nedir, ne amaçlarla kullanılır bunu irdelemeye çalışak daha sonra windows servislerinin mimarisini kısaca inceleyeceğiz. Windows servisleri, işletim sisteminde arka planda çalışan, kullanıcı ile etkilişimde bulunduğu herhangibir arayüze sahip olmayan, kaynakların izlenmesi, system olaylarının log olarak tutulması, network erişimlerinin izlenmesi, veritabanları üzerindeki transaction'ların izlenmesi, sistem performansına ati bilgilerin toplanması, sistem hatalarının (system exceptions) , başarısız program denemelerin (failure) vb. gibi geri plan işlemlerinin takip edilmesinde kullanılan, sisteme kayıt edilmiş (register), çalıştırılabilir nesnelerdir.https://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=825c4120-652e-4c87-9a24-c0d8cd8f1e0a7https://www.buraksenyurt.com/trackback.axd?id=825c4120-652e-4c87-9a24-c0d8cd8f1e0ahttps://www.buraksenyurt.com/post/Windows-Servislerine-Giris-bsenyurt-com-dan#commenthttps://www.buraksenyurt.com/syndication.axd?post=825c4120-652e-4c87-9a24-c0d8cd8f1e0a