Bir İş Görüşmesinde Detaylı İstenen Proje Bölüm2
Selamlar;
Bugün bir önceki makaleden, bir iş görüşmesinde detaylı istenen bir projedeki geri kalan maddeleri tamamlıyacağız:
- Basit bir UI form hazırlayıp gelen “Kur İsmlerini” Türkçeden İngilizceye çevirerek gösteriniz. TUR->ENG. Örnek(ABD DOLAR->USA Dollar İNGİLİZ STERLİNİ -> Great Britain Pound)
- Dataları sürekli Database’den dinleyip güncellenenleri, Jquery kullanarak Mvc bir sayfada gösteriniz.
- Dataları sürekli Database’den dinleyip güncellenenleri, SignalR kullanarak Mvc bir sayfada gösteriniz.
İlk projemiz 2.Madde olan Jquery ile timer kullanılıp dataların çekilip ekrana basılmasıdır. Öncelikle “CurrencyRates“yeni bir Empty Mvc Projesi yaratılır.
Views/Home/JqueryCurrency.cshtml(Full): Aşağıda görüldüğü gibi ilgili view bir önceki makalede bahsettiğimiz “CurrencyReport” adında bir @model beklemektedir. “CurrencyRate” id’li div’in içine “CurrencyList” adında partial view ilgili model ile birlikte aşağıdaki gibi basılmaktadır. Son olarak her dakikada bir (60000) “RefreshData()” function’ı çağrılarak “CurrencyList()” methoduna post yapılmakta ve geri dönen PartialView “CurrencyList” div’inin içine sayfa post olmadan basılmaktadır. Böylece güncel data 1/dak bir yenilenerek client’a gösterilmektedir.
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 |
@model List<DAL.CurrencyReport> @{ Layout = null; } <!DOCTYPE html> <html> <head> <script src="~/Scripts/jquery-2.1.4.min.js"></script> <meta name="viewport" content="width=device-width" /> <title>JqueryCurrency</title> <script> (function () { var int = self.setInterval(RefreshData, 60000); })(); function RefreshData() { $.post("/Home/CurrencyList", function (currencyData) { console.log("Post Data"); $("#CurrencyList").html(currencyData); }); } </script> </head> <body> <div id="CurrencyList"> @{Html.RenderPartial("CurrencyList", Model);} </div> </body> </html> |
HomeController.cs/JqueryCurrency(): Sıra geldi ekrana bastığımız JqueryCurrency View’ına ait Action’a. Aşağıda görüldüğü gibi bir önceki makalede yazılan “CurrencyService” adlı WebApi servisinden, ilgili datalar asenkron olarak çekilmektedir. Öncelikle performance amaçlı “CurrencyData” adlı cache kullanılmış, ilgili datalar “30sn” süre ile ilgili cache’e atılıp çekilmiştir. İlgili cache’in 30sn sonunda null olması durumunda gerekli data WebApi servisinden çekilip ilgili cache tekrardan 30sn süre için doldurulmaktadır. WebApi servisinin yolu her zaman değişebileceği ve dışarıya bağımlı bir durum olduğu için web.config altına “baseApiAddress” ismi ile tanımlanmıştır. Böylece sayfa derlenmeden ilgili yol değiştirilebilmektedir.
Not: Controller kısmında hiçbir bussines işlem yapılmamış ve bu işlem webservisine bırakılmıştır. Böylece hem entityframework gibi sınıflar burada tanımlanmamış hem de bussines’da bir değişiklik olduğu zaman kullanıcıya gösterilen portal durdurulmadan bir başka proje üzerinde derleme işlemi kolaylıkla yapılabilmiştir. Ayrıca bu dağıtık mimari ile farklı projelerde farklı kişilerin kolaylıkla çalışması sağlanmıştır.
Son olarak çekilen data “JqueryCurrency” view’ı ile birlikte döndürülmektedir.
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 |
public async Task<ActionResult> JqueryCurrency() { //Performans amaçlı 30sn cache yapılmıştır if (HttpContext.Cache["CurrencyData"] == null) { using (var client = new HttpClient()) { List<CurrencyReport> currencyData = null; client.BaseAddress = new Uri(ConfigurationManager.AppSettings["baseApiAddress"]); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); HttpResponseMessage response = await client.GetAsync("api/Currency"); if (response.IsSuccessStatusCode) { currencyData = await response.Content.ReadAsAsync<List<CurrencyReport>>(); HttpContext.Cache.Insert("CurrencyData", currencyData, null, DateTime.UtcNow.AddSeconds(30), System.Web.Caching.Cache.NoSlidingExpiration, CacheItemPriority.High, null); } return View(currencyData); } } else { var data = (List<CurrencyReport>)HttpContext.Cache["CurrencyData"]; return View(data); } } |
Web.config: Tanımlanan web.config aşağıdaki gibidir.
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 |
<?xml version="1.0" encoding="utf-8"?> <!-- For more information on how to configure your ASP.NET application, please visit http://go.microsoft.com/fwlink/?LinkId=301880 --> <configuration> <appSettings> <add key="webpages:Version" value="3.0.0.0"/> <add key="webpages:Enabled" value="false"/> <add key="ClientValidationEnabled" value="true"/> <add key="UnobtrusiveJavaScriptEnabled" value="true"/> <add key="baseApiAddress" value="http://localhost:4071/"/> </appSettings> <system.web> <compilation debug="true" targetFramework="4.6"/> <httpRuntime targetFramework="4.6"/> </system.web> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35"/> <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0"/> </dependentAssembly> <dependentAssembly> <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35"/> <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0"/> </dependentAssembly> <dependentAssembly> <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35"/> <bindingRedirect oldVersion="1.0.0.0-5.2.3.0" newVersion="5.2.3.0"/> </dependentAssembly> </assemblyBinding> </runtime> <system.codedom> <compilers> <compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:6 /nowarn:1659;1699;1701"/> <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\"Web\" /optionInfer+"/> </compilers> </system.codedom> </configuration> |
JqueryCurrency.cshtml sayfasının görünümü aşağıdaki gibidir.
Views/Home/CurrencyList.aspx(Partial View)(Full): Jquery Currency sayfasında ilgili div’in içinde, çekilen kur değerlerinin gösterildiği partial viewdır. Css olarak bootstrap kullanılmıştır. Bu neden ile “bootstrap.min.css” ve “bootstrap.min.js” kütüpahaneleri eklenmiştir. View Engine olarak Razor kullanılmıştır. İlgili “List<DAL.CurrencyReport>” model tek tek gezilip ekrana bir table içinde basılmıştır. Tablo tasarımında bootstrap css’leri(table table-hover table-bordered table-striped table condensed) yukarıda görüldüğü gibi kullanılmıştır.
Not: Buradaki en önemli kısım türkçe gelen datanın custom olarak yazılan “@Html.Translate()” html helper’ı ile ingilizceye çevrilmesidir.
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 |
@model List<DAL.CurrencyReport> @using CurrencyRates.Models <script src="~/Scripts/jquery-2.1.4.min.js"></script> <script src="/Scripts/bootstrap.min.js"></script> <link href="/Content/bootstrap.min.css" rel="stylesheet" /> <div class="container"> <h2>Jquery Currency</h2> <p>This page is using Jquery and get All datas with timer..</p> <div class="table-responsive"> <table class="table table-hover table-bordered table-striped table-condensed"> <thead> <tr> <th>CurrencyName</th> <th>ForexBuying</th> <th>ForexSelling</th> <th>BanknoteBuying</th> <th>BanknoteSelling</th> <th>CrossRateUSD</th> </tr> </thead> <tbody> @foreach (var item in Model) { <tr> <td>@Html.Translate(@item.CurrencyName)</td> <td>@item.ForexBuying</td> <td>@item.ForexSelling</td> <td>@item.BanknoteBuying</td> <td>@item.BanknoteSelling</td> <td>@item.CrossRateUSD</td> </tr> } </tbody> </table> </div> </div> |
Model/Helper.cs: Aşağıda görüldüğü gibi “Helper” static sınıfının “Translate()” adında yine static bir methodu vardır. “expression” değişekeni çevrilecek kelimeyi temsil etmekte ve parametre olarak alınmaktadır. İlgili kelime karşılığı “key”,”value” pair olarak “switch-case” yapısı ile kontrol edilmekte ve ingilizce karşılığı atanmaktadır.
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 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web.Mvc; namespace CurrencyRates.Models { public static class Helper { public static string Translate(this HtmlHelper html, string expression) { switch (expression) { case "ABD DOLARI": { expression = "USA DOLLAR"; break; } case "AVUSTRALYA DOLARI": { expression = "AUSTRALIAN DOLLAR"; break; } case "BULGAR LEVASI": { expression = "BULGARIAN LEV"; break; } case "ÇİN YUANI": { expression = "CHINESE RENMINBI"; break; } case "DANİMARKA KRONU": { expression = "DANISH KRONE"; break; } case "İSVİÇRE FRANGI": { expression = "SWISS FRANK"; break; } case "İSVEÇ KRONU": { expression = "SWEDISH KRONA"; break; } case "İNGİLİZ STERLİNİ": { expression = "GREAT BRITAIN POUND"; break; } case "İRAN RİYALİ": { expression = "IRANIAN RIAL"; break; } case "JAPON YENİ": { expression = "JAPENESE YEN"; break; } case "KANADA DOLARI": { expression = "CANADIAN DOLLAR"; break; } case "KUVEYT DİNARI": { expression = "KUWAITI DINAR"; break; } case "NORVEÇ KRONU": { expression = "NORWEGIAN KRONE"; break; } case "PAKİSTAN RUPİSİ": { expression = "PAKISTANI RUPEE"; break; } case "RUMEN LEYİ": { expression = "NEW LEU"; break; } case "RUS RUBLESİ": { expression = "RUSSIAN ROUBLE"; break; } case "SUUDİ ARABİSTAN RİYALİ": { expression = "SAUDI RIYAL"; break; } } return expression; } } } |
Sıra geldi 2. sayfamız olan signalR ve anglarjs kullanan SignalrCurrency.cshtml sayfamıza. Öncelikle aşağıdaki paketler Nuget’den indirilir.
HomeController.cs/SignalrCurrency(): Aşağıda görüldüğü gibi herhangi bir data gönderilmemiş sadece view dönülmüştür.
1 2 3 4 |
public ActionResult SignalrCurrency() { return View(); } |
Views/Home/SignalrCurrency.cshtml: Sayfanın başlangıcında eklenen script kütüpahaneleri aşağıdaki gibidir.
- Sayfa içinde AngularJs framework’ünün kullanılabilmesi için “angular.min.js” eklenmiştir.
- Bu sayfada dil desteği Angularjs ile verilecektir. Bu neden ile “angular-translate.min.js” sayfaya eklenmiştir.
- “signalR” jquery’e ihtiyaç duyduğu için “jquery-2.1.4.min.js” tanımlanmıştır.
- Sayfada verilerin real time olarak gösterilebilmesi için signalR WebSocket teknolojisi kullanılmıştır. Bu yüzden “jquery.signalR-2.2.0.min.js” kullanılmıştır.
- SignalR runtime’da kendisi için gerekli ilgili endpointleri oluşturup sayfa içine gömdüğü magic script “signalr/hubs”‘dır. Gerçekte böyle bir script yoktur. Buna “Magic Script” denir.
- Bootstrap’in sayfada kullanılabilmesi için ilgili css ve script kütüpahaneleri “bootstrap.min.js ve bootstrap.min.css” sayfaya eklenmiştir.
- Son olarak AngularJS yardımı çoklu dil desteğinin sağlanabilmesi için “key” “value” pair olarak türkçe kelimelerin ingilizce karşılğının ve AngularJS içerisinde ilgili modellerin doldurulup, güncellendiği script “SignalRCurrency.js” sayfaya eklenmiştir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
@{ Layout = null; } <!DOCTYPE html> <html ng-app="app"> <head> <script src="~/Scripts/angular.min.js"></script> <script src="~/Scripts/angular-translate.min.js"></script> <script src="~/Scripts/jquery-2.1.4.min.js"></script> <script src="~/Scripts/jquery.signalR-2.2.0.min.js"></script> <script src="~/signalr/hubs"></script> <script src="/Scripts/bootstrap.min.js"></script> <link href="/Content/bootstrap.min.css" rel="stylesheet" /> <meta name="viewport" content="width=device-width" /> <title>SignalrCurrency</title> <script src="~/Scripts/SignalRCurrency.js"></script> </head> |
a) SignalRCurrency.js: Aşağıda görüldüğü gibi SignalrCurrency.cshtml’de signalR ilgili hub sınıfı olan “Currency”‘e bağlanıp connect edilmiştir. Ayrıca “disconnect” durumunda 3sn beklenip tekrar connect işlemi yapılmıştır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
(function (angular) { function Controller($scope, $http) { var hubProxy = $.connection.currency; $.connection.hub.logging = true; $.connection.hub.start().done(function () { console.log("hub.start.done"); }).fail(function (error) { console.log(error); }); $.connection.hub.disconnected(function () { setTimeout(function () { $.connection.hub.start(); }, 3000); // Restart connection after 1 seconds. }); } |
b) SignalRCurrency.js(getAllData): SignalR’ın OnConnected durumunda aşağıdaki “getAllData()” signalR function’ı server side taraftan tetiklenip AngularJS’in “$scope.currencyDatas” property’si doldurulmuştur.
1 2 3 4 5 |
hubProxy.client.getAllData = function (data) { console.log(JSON.stringify(data)); $scope.currencyDatas = data; $scope.$apply(); } |
a) HomeController.cs/Currency(OnConnected):Hub : Aşağıda görüldüğü gibi signalR sınıfı “onConnected()” durumunda sadece bağlanan client için bunu “Clients.Caller“‘dan anlayabiliriz, ilgili data önceden yazılan WebApi servisinden asenkron olarak Json data şeklinde çekilir. Daha sonra client side üzerindeki “getAllData()” function’ı ilgili data ile birlikte tetiklenir. Böylece sayfaya yeni bir client geldiğinde signalR sınıfına bağlanılıp ilgili datalar çekilir ve ekrana basılır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public class Currency : Hub { public override async Task OnConnected() { using (var client = new HttpClient()) { List<CurrencyReport> currencyData = null; client.BaseAddress = new Uri(ConfigurationManager.AppSettings["baseApiAddress"]); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); HttpResponseMessage response = await client.GetAsync("api/Currency"); if (response.IsSuccessStatusCode) { currencyData = await response.Content.ReadAsAsync<List<CurrencyReport>>(); } Clients.Caller.getAllData(currencyData); } } } |
b) HomeController.cs/Currency(FillData():Hub : Önceki makaleden hatırlayacağınız gibi TCMB’den ilgili kur bilgisini çeken Windows Service eğer database’de hiçbir kayıt yok ise signalR sınıfındaki FillData() methodunu aşağıdaki gibi tetiklemekte ve çekilen tüm data o an bağlı olan tüm clientlara real time olarak gösterilmektedir.
- Windows Services (Insert): Windows servisden remote olarak Hub sınıfındaki ilgili methodun çağrılması.
1 2 3 4 |
HubConnection hubConnection = new HubConnection("http://localhost:1646"); IHubProxy hubProxy = hubConnection.CreateHubProxy("Currency"); await hubConnection.Start(new LongPollingTransport()); hubProxy.Invoke("FillData", NewDatas); |
- Currency/FillData(): Aşağıda görüldüğü gibi signalR’ın connected olduğu durumda çağrılan client side tarafdaki “getAllData()” function’ı burda da aynı şekilde çekilen datalar ile birlikte tetiklenir.
1 2 3 4 |
public async Task FillData(List<CurrencyReport> datas) { await Clients.All.getAllData(datas); } |
c) HomeController.cs/Currency(UpdateData()):Hub : Önceki makaleden hatırlanacağı gibi TCMB ‘den ilgili kur bilgisini çeken Windows Service eğer database’de kayıt var ve sadece bir kısım data güncellenmiş ise ilgili değişikliğin tüm clientlarda real time gözükmesi için Hub sınıfına ait “UpdateData()” methodu değişen datalar ile birlikte tetiklenir.
- Windows Services (Update): Windows servisden remote olarak Hub sınıfındaki ilgili methodun güncellenen datalar ile birlikte çağrılması.
1 2 3 4 |
HubConnection hubConnection = new HubConnection("http://localhost:1646"); IHubProxy hubProxy = hubConnection.CreateHubProxy("Currency"); await hubConnection.Start(new LongPollingTransport()); hubProxy.Invoke("UpdateData", changeDatas); |
- Currency/UpdateData(): Aşağıda görüldüğü gibi windows services’den gönderilen değişmiş datalar(datas), o an connect olan tüm clientlara “UpdateData()” function’ı ile güncellenerek real time olarak gösterilir.
1 2 3 4 |
public async Task UpdateData(List<CurrencyReport> datas) { await Clients.All.UpdateData(datas); } |
c) SignalRCurrency.js(UpdateData): “$scope.currencyDatas”‘daki tüm kayıtlar tek tek gezilerek “isUpdate()” function ile değişen datalar içinde olup olmadığına bakılır. Değişen bir data ise ilgili data gelen güncellenmiş data ile değiştirilir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
hubProxy.client.UpdateData = function (data) { console.log("Update Data: " + JSON.stringify(data)); for (var i = 0; i < $scope.currencyDatas.length; i++) { var index = isUpdated(data, $scope.currencyDatas[i]); if (index != -1) { $scope.currencyDatas[i] = data[index]; } }; $scope.$apply(); } function isUpdated(UpdatedList, currencyItem) { for (var i2 = 0; i2 < UpdatedList.length; i2++) { if (UpdatedList[i2].CurrencyName.indexOf(currencyItem.CurrencyName) >= 0) { return i2; } } return -1; } |
Views/Home/SignalrCurrency.cshtml(Full): Aşağıda görüldüğü gibi bootstrap bir tabloya AngularJS ile çekilen kurlar bilgisi “$scope.currencyDatas” içinde tek tek “ng-repeat” ile gezilerek ekrana basılmaktadır. Burada dikkat edilecek en önemli kısım “| translate” custom directive’i dir. Türkçe olarak gelen kur isminin “CurrencyName”‘inin key-value pair olarak ingilizce karşılığı ekrana basılır.
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 |
@{ Layout = null; } <!DOCTYPE html> <html ng-app="app"> <head> <script src="~/Scripts/angular.min.js"></script> <script src="~/Scripts/angular-translate.min.js"></script> <script src="~/Scripts/jquery-2.1.4.min.js"></script> <script src="~/Scripts/jquery.signalR-2.2.0.min.js"></script> <script src="~/signalr/hubs"></script> <script src="/Scripts/bootstrap.min.js"></script> <link href="/Content/bootstrap.min.css" rel="stylesheet" /> <meta name="viewport" content="width=device-width" /> <title>SignalrCurrency</title> <script src="~/Scripts/SignalRCurrency.js"></script> </head> <body> <div class="container"> <h2>Real Time SignalR Currency</h2> <p>This page using SignalR socket. Soo all the datas are live and dynamic..</p> <div ng-controller="Controller" class="table-responsive"> <table class="table table-hover table-bordered table-striped table-condensed"> <thead> <tr> <th>CurrencyName</th> <th>ForexBuying</th> <th>ForexSelling</th> <th>BanknoteBuying</th> <th>BanknoteSelling</th> <th>CrossRateUSD</th> </tr> </thead> <tbody> <tr ng-repeat="data in currencyDatas"> <td>{{data.CurrencyName | translate}}</td> <td>{{data.ForexBuying}}</td> <td>{{data.ForexSelling}}</td> <td>{{data.BanknoteBuying}}</td> <td>{{data.BanknoteSelling}}</td> <td>{{data.CrossRateUSD}}</td> </tr> </tbody> </table> </div> </div> </body> </html> |
SignalRCurrency.cshtml sayfasının görünümü aşağıdaki gibidir.
Aşağıda Kur isimlerinin Türkçede=> İngilizce karşılıklarının yazıldığı “$.translateProvider” tanımlanmaktadır.
d) SignalRCurrency.js(app.config)$translateProvider:
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 |
var app = angular.module("app", ['pascalprecht.translate']).controller("Controller", ["$scope", "$http", Controller]); app.config(['$translateProvider', function ($translateProvider) { $translateProvider.translations('en', { 'ABD DOLARI': 'USA DOLLAR', 'AVUSTRALYA DOLARI': 'AUSTRALIAN DOLLAR', 'BULGAR LEVASI': 'BULGARIAN LEV', 'ÇİN YUANI': 'CHINESE RENMINBI', 'DANİMARKA KRONU': 'DANISH KRONE', 'İSVİÇRE FRANGI': 'SWISS FRANK', 'İSVEÇ KRONU': 'SWEDISH KRONA', 'İNGİLİZ STERLİNİ': 'GREAT BRITAIN POUND', 'İRAN RİYALİ': 'IRANIAN RIAL', 'JAPON YENİ': 'JAPENESE YEN', 'KANADA DOLARI': 'CANADIAN DOLLAR', 'KUVEYT DİNARI': 'KUWAITI DINAR', 'NORVEÇ KRONU': 'NORWEGIAN KRONE', 'PAKİSTAN RUPİSİ': 'PAKISTANI RUPEE', 'RUMEN LEYİ': 'NEW LEU', 'RUS RUBLESİ': 'RUSSIAN ROUBLE', 'SUUDİ ARABİSTAN RİYALİ': 'SAUDI RIYAL', }); $translateProvider.preferredLanguage('en'); $translateProvider.useSanitizeValueStrategy('escape'); }]); |
Scripts/SignalRCurrency.js(Full):
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 |
(function (angular) { function Controller($scope, $http) { var hubProxy = $.connection.currency; hubProxy.client.getAllData = function (data) { //console.log(JSON.stringify(data)); $scope.currencyDatas = data; $scope.$apply(); } hubProxy.client.UpdateData = function (data) { console.log("Update Data: " + JSON.stringify(data)); for (var i = 0; i < $scope.currencyDatas.length; i++) { var index = isUpdated(data, $scope.currencyDatas[i]); if (index != -1) { $scope.currencyDatas[i] = data[index]; } }; $scope.$apply(); } //angular.forEach($scope.currencyDatas, function (currency) { // var index = isUpdated(data, currency); // if (index != -1) { // currency = data[index]; // } //}); //$scope.$apply(); //} $.connection.hub.logging = true; $.connection.hub.start().done(function () { console.log("hub.start.done"); }).fail(function (error) { console.log(error); }); $.connection.hub.disconnected(function () { setTimeout(function () { $.connection.hub.start(); }, 3000); // Restart connection after 1 seconds. }); } var app = angular.module("app", ['pascalprecht.translate']).controller("Controller", ["$scope", "$http", Controller]); app.config(['$translateProvider', function ($translateProvider) { $translateProvider.translations('en', { 'ABD DOLARI': 'USA DOLLAR', 'AVUSTRALYA DOLARI': 'AUSTRALIAN DOLLAR', 'BULGAR LEVASI': 'BULGARIAN LEV', 'ÇİN YUANI': 'CHINESE RENMINBI', 'DANİMARKA KRONU': 'DANISH KRONE', 'İSVİÇRE FRANGI': 'SWISS FRANK', 'İSVEÇ KRONU': 'SWEDISH KRONA', 'İNGİLİZ STERLİNİ': 'GREAT BRITAIN POUND', 'İRAN RİYALİ': 'IRANIAN RIAL', 'JAPON YENİ': 'JAPENESE YEN', 'KANADA DOLARI': 'CANADIAN DOLLAR', 'KUVEYT DİNARI': 'KUWAITI DINAR', 'NORVEÇ KRONU': 'NORWEGIAN KRONE', 'PAKİSTAN RUPİSİ': 'PAKISTANI RUPEE', 'RUMEN LEYİ': 'NEW LEU', 'RUS RUBLESİ': 'RUSSIAN ROUBLE', 'SUUDİ ARABİSTAN RİYALİ': 'SAUDI RIYAL', }); $translateProvider.preferredLanguage('en'); $translateProvider.useSanitizeValueStrategy('escape'); }]); })(angular); function isUpdated(UpdatedList, currencyItem) { for (var i2 = 0; i2 < UpdatedList.length; i2++) { if (UpdatedList[i2].CurrencyName.indexOf(currencyItem.CurrencyName) >= 0) { return i2; } } return -1; } |
Controllers/HomeController.cs(Full):
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 |
using Microsoft.AspNet.SignalR; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Threading.Tasks; using DAL; using System.Configuration; using System.Net.Http; using System.Net.Http.Headers; using System.Web.Caching; namespace CurrencyRates.Controllers { public class HomeController : Controller { // GET: Home public async Task<ActionResult> JqueryCurrency() { //Add 30 seconds cache for performance if (HttpContext.Cache["CurrencyData"] == null) { using (var client = new HttpClient()) { List<CurrencyReport> currencyData = null; client.BaseAddress = new Uri(ConfigurationManager.AppSettings["baseApiAddress"]); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); HttpResponseMessage response = await client.GetAsync("api/Currency"); if (response.IsSuccessStatusCode) { currencyData = await response.Content.ReadAsAsync<List<CurrencyReport>>(); HttpContext.Cache.Insert("CurrencyData", currencyData, null, DateTime.UtcNow.AddSeconds(30), System.Web.Caching.Cache.NoSlidingExpiration, CacheItemPriority.High, null); } return View(currencyData); } } else { var data = (List<CurrencyReport>)HttpContext.Cache["CurrencyData"]; return View(data); } } public ActionResult SignalrCurrency() { return View(); } //Url'den erişilememesi için yapılmıştır.. [HttpPost] public async Task<PartialViewResult> CurrencyList() { //Add 30 seconds cache for performance if (HttpContext.Cache["CurrencyData"] == null) { using (var client = new HttpClient()) { List<CurrencyReport> currencyData = null; client.BaseAddress = new Uri(ConfigurationManager.AppSettings["baseApiAddress"]); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); HttpResponseMessage response = await client.GetAsync("api/Currency"); if (response.IsSuccessStatusCode) { currencyData = await response.Content.ReadAsAsync<List<CurrencyReport>>(); HttpContext.Cache.Insert("CurrencyData", currencyData, null, DateTime.UtcNow.AddSeconds(30), System.Web.Caching.Cache.NoSlidingExpiration, CacheItemPriority.High, null); } return PartialView(currencyData); } } else { var data = (List<CurrencyReport>)HttpContext.Cache["CurrencyData"]; return PartialView(data); } } } public class Currency : Hub { public override async Task OnConnected() { using (var client = new HttpClient()) { List<CurrencyReport> currencyData = null; client.BaseAddress = new Uri(ConfigurationManager.AppSettings["baseApiAddress"]); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); HttpResponseMessage response = await client.GetAsync("api/Currency"); if (response.IsSuccessStatusCode) { currencyData = await response.Content.ReadAsAsync<List<CurrencyReport>>(); } Clients.Caller.getAllData(currencyData); } } public async Task UpdateData(List<CurrencyReport> datas) { await Clients.All.UpdateData(datas); } public async Task FillData(List<CurrencyReport> datas) { await Clients.All.getAllData(datas); } } } |
Böylece 2 bölümlük bir iş görüşmesinde istenen bir projeyi kodladık. Bu bölümde 2 farklı sayfa oluşturduk. Biri AngularJS ile dataların ekrana basıldığı ve SignalR WebSocket ile real time olarak güncellendiği bir sayfa. Diğeri Mvc Partial view ile bir div içine Razor engine kullanılarak basılan ve Jquery Timer ile her dakikada bir action’a post yapılıp ilgili son datayı partial view olarak ilgili div içine basan bir view yarattık. Çoklu dil desteği için Partial view sayfası için gene mvc’nin gücü kullanılarak @Html.Helper yazdık. AngularJS sayfası için ise bir çeşit custom directive olan “AngularTranslate” kullandık. Böylece Windows Services ve WebApi servisi kullanan 2 farklı Mvc sayfa yapısının real time data binding üzerine karakteristik davranışını hep beraber inceledik. Tabi tüm bu işlemler için database katmanında EntitiyFramework ve Codefirst kullandık.
Geldik bir makalenin daha sonuna. Yeni bir makalede görüşmek üzere hoşçakalın.
Source Code: http://www.borakasmer.com/projects/CurrencyRates.rar
CurrencyRates Solution’ın genel yapısı aşağıdaki gibidir:
Merak ettiğim kırk konu bir arada. ELine sağlık…
Teşekkür ederim Mustafa,
Sanırım iş veren de merak ediyormuş. Yazdırdı hepsini:)
Yine çok başarılı bir çalışma.
Emekleriniz için çok teşekkürler…
Ben teşekkür ederim Cem…
Sitenize sans eseri denk geldim. Konulari derleyip toparlamaniz, ozellikle de gercek hayatta bunlarin nasil bir araya getirilip building block lari olusturmaniz…mutluluktan gozlerim yasardi ne diyeyim, iyi ki boyle bir site kurup bilgilerinizi bizimle paylasmissiniz. Bundan sonra sitenizi olabildigince takip edicem. Ingiltere den selamlar efendim :)
Selamlar Elif,
Teşekkürler.
Paylaşım için teşekkürler. Burada bahsi geçen mülakatla ilgili 2 hususta bilgi almak istiyorum.
1) Tüm bu mülakat için toplam ne kadar süre verdiler?
2) Tüm kodları ezbere yazdırmadılar ve internetten yardım almak serbestti değil mi? :) Konu hakkında bilgisi olmayan zaten bişey yapamaz ama yine de işverenin beklentisini öğrenmek istedim. Teşaekkürler.
Selamlar,
1 haftasonu verilmişti. Zaten proje uzaktan yapıldığı için, kitap açmak serbest idi :)