Azure Cloud Service Worker Role ile Sql Db’den Kurlara Göre TL Karşılığını Bulma Part1
Selamlar;
Bugün bir şirketin farklı kurlardaki sql db kayıtlarına, belirli bir zaman aralığında bakarak o an ki güncel kur ile TL karşılığını bulacağız. Bunun için Azure tarafındaki Cloud Service çözümüne gideceğiz.
1-)Öncelikle Visual Studio 2015 Preview’de aşağıda görüldüğü gibi Azure Cloud Service uygulaması yaratılır.
2-)Bu cloud service için Worker Role seçilir.
3-)Solution’ın son hali aşağıda görüldüğü gibidir.
Şimdi gelin BorsoftCompany adında bir database oluşturalım. Yaratılan tablolar aşağıdadır.
[dbo].[ExportProductDetail] [dbo].[ExchangeType]
Yukarıda [dbo].[ExportProductDetail].ExchangeType ile [dbo].[ExchangeType].ID arasında Foreign Key vardır.
Solution’a yeni bir DAL adında Class Library ekleyelim.
Şimdi yeni DAL projemize Entity Data Model ekleyelim.
Var olan database den Code First ile DbContext yani Data Model’i oluşturalım.
İlgili database ve tablo aşağıdaki gibi seçilir:
Oluşan Data Model ExportProductDetail.cs: Ayrıca DbContext de ProductContext adında aşağıda görüldüğü gibi oluşturulur.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
namespace DAL { using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Data.Entity.Spatial; [Table("ExportProductDetail")] public partial class ExportProductDetail { public int ID { get; set; } [StringLength(50)] public string ProductName { get; set; } [Column(TypeName = "money")] public decimal? Price { get; set; } public int? ExchangeType { get; set; } public decimal? ExchangeRate { get; set; } [Column(TypeName = "money")] public decimal? PriceTL { get; set; } public DateTime? CreatedDate { get; set; } public DateTime? UpdateDate { get; set; } } public class ProductContext : DbContext { public DbSet<ExportProductDetail> ExportProductDetail { get; set; } } } |
DAL projesindeki connection string WorkerRole1 projesindeki app.config dosyasına aşağıdaki gibi kopyalanır.
1 2 3 |
<connectionStrings> <add name="ProductContext" connectionString="data source=.;initial catalog=BorsoftCompany;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" /> </connectionStrings> |
Kurlar için aşağıdaki gibi Enum class yaratılır. Böylece gelen kur tipine göre işlem yapılır.
1 2 3 4 5 6 |
public enum Exchange { Dollar = 1, Euro = 2, Pound = 3 } |
Şimdi sıra geldi ilgili database’i her 30sn bir kontrol edip ExchangeRate’i yani kur değeri olmayan kayıtları çekip, kur tipinin enum karşılığına göre TL fiyatını bulmaya. İlgili kod aşağıdadır. Linq ile products.ExchangeRate ==null olan kayıtlar çekildikten sonra eğer kayıt var ise Xpath kullanılarak [@Kod=’USD’] gibi ilgili kur değerleri tcmb.gov.tr‘den alınmıştır. Daha sonra fiyat ile kur Switch Case yapısı kullanılarak girilen kur tipinini enum karşılığına göre çarpılır. Böylece ürünün TL fiyatı bulunur.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
private async Task RunAsync(CancellationToken cancellationToken) { // TODO: Replace the following with your own logic. while (!cancellationToken.IsCancellationRequested) { Trace.TraceInformation("Working"); //iŞLEM YAPILMAMIŞ KAYITLAR ÇEKİLİR. using (ProductContext dbcontext = new ProductContext()) { IEnumerable<ExportProductDetail> data = (from products in dbcontext.ExportProductDetail where products.ExchangeRate ==null select products).ToList(); string USD = string.Empty; string EURO = string.Empty; string POUND= string.Empty; //KAYIT VAR ISE GÜNCEL KURLAR ÇEKİLİR. if (data.Any()) { var m_strFilePath = " http://www.tcmb.gov.tr/kurlar/today.xml"; string xmlStr; using (var wc = new WebClient()) { xmlStr = wc.DownloadString(m_strFilePath); } var xmlDoc = new XmlDocument(); xmlDoc.LoadXml(xmlStr); USD = xmlDoc.SelectSingleNode("Tarih_Date/Currency[@Kod='USD']/BanknoteSelling").InnerXml.Replace(",","").Replace(".",","); EURO = xmlDoc.SelectSingleNode("Tarih_Date/Currency[@Kod='EUR']/BanknoteSelling").InnerXml.Replace(",", "").Replace(".", ","); POUND = xmlDoc.SelectSingleNode("Tarih_Date/Currency[@Kod='GBP']/BanknoteSelling").InnerXml.Replace(",", "").Replace(".", ","); } //İŞLEM YAPILACAK ÜRÜNÜN KUR TİPİNE GÖRE TL KARŞILIĞI BULUNUR... foreach(ExportProductDetail product in data) { switch(product.ExchangeType) { case (int)Exchange.Dollar: { product.ExchangeRate = decimal.Parse(USD); product.PriceTL=product.Price* decimal.Parse(USD); product.UpdateDate = DateTime.Now; dbcontext.SaveChanges(); break; } case (int)Exchange.Euro: { product.ExchangeRate = decimal.Parse(EURO); product.PriceTL = product.Price * decimal.Parse(EURO); product.UpdateDate = DateTime.Now; dbcontext.SaveChanges(); break; } case (int)Exchange.Pound: { product.ExchangeRate = decimal.Parse(POUND); product.PriceTL = product.Price * decimal.Parse(POUND); product.UpdateDate = DateTime.Now; dbcontext.SaveChanges(); break; } }; } } //30sn BEKLENDİKTEN SONRA İŞLEM TEKRARLANIR. await Task.Delay(30000); } } } |
Servis çalışmadan önceki ve sonraki örnek kayıdın durumu aşağıdadır. Böylece windows service yerine Azure üzerinde asenkron çalışan cloud bir service ile ilgili dataların fiyatının TL karşılığını bulduk.
WokerRole1:cs (Tüm Kod): WorkerRole ilk çalıştırıldığı zaman OnStart methodu devreye girer ve Trace’e mesaj yazılır. Daha sonra Run() methodu çalıştırılır ve RunAsync() methodu asenkron olarak çağrılır. Daha sonra bu asenkron method kendini her 30snde bir çağırır. Ve yeni kayıt olup olmadığı kontrol edilir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.Diagnostics; using Microsoft.WindowsAzure.ServiceRuntime; using Microsoft.WindowsAzure.Storage; using DAL; using System.Xml; namespace WorkerRole1 { public class WorkerRole : RoleEntryPoint { private readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); private readonly ManualResetEvent runCompleteEvent = new ManualResetEvent(false); public override void Run() { Trace.TraceInformation("WorkerRole1 is running"); try { this.RunAsync(this.cancellationTokenSource.Token).Wait(); } finally { this.runCompleteEvent.Set(); } } public override bool OnStart() { // Set the maximum number of concurrent connections ServicePointManager.DefaultConnectionLimit = 12; // For information on handling configuration changes // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357. bool result = base.OnStart(); Trace.TraceInformation("WorkerRole1 has been started"); return result; } public override void OnStop() { Trace.TraceInformation("WorkerRole1 is stopping"); this.cancellationTokenSource.Cancel(); this.runCompleteEvent.WaitOne(); base.OnStop(); Trace.TraceInformation("WorkerRole1 has stopped"); } private async Task RunAsync(CancellationToken cancellationToken) { // TODO: Replace the following with your own logic. while (!cancellationToken.IsCancellationRequested) { Trace.TraceInformation("Working"); using (ProductContext dbcontext = new ProductContext()) { IEnumerable<ExportProductDetail> data = (from products in dbcontext.ExportProductDetail where products.ExchangeRate ==null select products).ToList(); string USD = string.Empty; string EURO = string.Empty; string POUND= string.Empty; if (data.Any()) { var m_strFilePath = " http://www.tcmb.gov.tr/kurlar/today.xml"; string xmlStr; using (var wc = new WebClient()) { xmlStr = wc.DownloadString(m_strFilePath); } var xmlDoc = new XmlDocument(); xmlDoc.LoadXml(xmlStr); USD = xmlDoc.SelectSingleNode("Tarih_Date/Currency[@Kod='USD']/BanknoteSelling").InnerXml.Replace(",","").Replace(".",","); EURO = xmlDoc.SelectSingleNode("Tarih_Date/Currency[@Kod='EUR']/BanknoteSelling").InnerXml.Replace(",", "").Replace(".", ","); POUND = xmlDoc.SelectSingleNode("Tarih_Date/Currency[@Kod='GBP']/BanknoteSelling").InnerXml.Replace(",", "").Replace(".", ","); } foreach(ExportProductDetail product in data) { switch(product.ExchangeType) { case (int)Exchange.Dollar: { product.ExchangeRate = decimal.Parse(USD); product.PriceTL=product.Price* decimal.Parse(USD); product.UpdateDate = DateTime.Now; dbcontext.SaveChanges(); break; } case (int)Exchange.Euro: { product.ExchangeRate = decimal.Parse(EURO); product.PriceTL = product.Price * decimal.Parse(EURO); product.UpdateDate = DateTime.Now; dbcontext.SaveChanges(); break; } case (int)Exchange.Pound: { product.ExchangeRate = decimal.Parse(POUND); product.PriceTL = product.Price * decimal.Parse(POUND); product.UpdateDate = DateTime.Now; dbcontext.SaveChanges(); break; } }; } } await Task.Delay(30000); } } } public enum Exchange { Dollar = 1, Euro = 2, Pound = 3 } } |
2.Bölümde AngularJs javascript framework’ü kullanılan bir ekranda yeni ürün girişi yapıcağız. Ve girilen tüm ürünleri aşağısında sıralayacağız. Daha sonra Azure Cloud Services devreye girip ürünün TL karşılığını bulunca signalR ile aşağıda listelediğimiz bu ürünü yenileyeceğiz.
Kodları 2.Bölümün sonunda alabilirsiniz.
Makalenin devamında görüşmek üzere hoşçakalın.
Merhaba Hocam,
await Task.Delay(30000);
bölümünde gösterdiğim sürenin iki katını bekliyor, yani 10 saniye dediysem, 20 saniyede bir yapıyor. Neden olabilir?
Selam Kemal,
Sanırım O bölüme 2 kere giriyor. Yani uygulama da RunAsync 2 kere çalıştırılıyor olabilir. Ya da farklı yerlerde yanlışlıkla 2 tane “Task.Delay(30000)” yazmış olabilirmisin ?
Bunları bir kontrol et derim.
İyi çalışmalar.
Hocam sadece bir değil birçok sorunuma ayna tuttunuz. Sayenizde
Azure CloudKit server nasıl bağlanacağımı
Nasıl Worker Role oluşturacağımı
Class Library kullanımını
Code first ile nasıl ilişkilendirme yapılacağını
Asenkron yaklaşımın nasıl kullanılacağını
Using kullanımını
Parse kullanımını
Taskın tekrarlayan işlemleri gerçekleştirebileceğini
Benim için altın değerinde olan ufak bir kod dizisiyle göstermişsiniz.
Aslında siz bir yazılım geliştiricinin nasıl temiz çalışması gerektiğini ifade etmişsiniz. Teşekkür ediyorum.
Selamlar Hakan,
İşine bu denli yaraması, beni çok sevindirdim. Bu tarz güzel yorumlar ile daha bir şevkli yazıyorum :) Teşekkürler.
Hoşçakal..