ASP.NET 5 Console Application
Selamlar;
Bugün aşağıda görüldüğü gibi Visual Studio 2015 RC ile Web projesi altında bir Console Application yaratacağız.
Proje ilk oluşturulduğunda önceki sürümlere göre aşağıda görülen bir takım değişiklikler görülür:
- k ve klr artık DNX adını aldı..
- kvm ise dnvm yada diğer adı ile .NET Version Manager oldu.
- kpm ise bası özelliklerini dnu yani .NET Development Utility’e ve core NuGet’e devretti.
- ASP.NET 5.0 ve ASPNET Core.50 framework isimleri project.json dosyası içinde artık dnx451 ve dnxcore50 isimler ile anılmaya başlandı.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
"frameworks": { "dnx451": { "dependencies": { "System.Threading.Tasks": "4.0.10-beta-22816" } }, "dnxcore50": { "dependencies": { "System.Console": "4.0.0-beta-22816", "System.Collections": "4.0.10-beta-22816", "System.Linq": "4.0.0-beta-22816", "System.Threading": "4.0.10-beta-22816", "Microsoft.CSharp": "4.0.0-beta-22816" } } } |
global.json: Eklediğimiz tüm projeler global.json altında aşağıda görüldüğü gibi tanımlanır.
1 2 3 4 5 6 |
{ "projects": [ "src", "test" ], "sdk": { "version": "1.0.0-beta4" } } |
Kodlara geçmeden önce Web kategorisi altında Console Application yaratma fikrini tartışalım:
- İsmi aslında kafa karıştırıcı. Asp.Net Console application yerine Dnx Console Application olabilirdi.
- Öncelikle ilk amaç projeyi kolayca cross-compiling yapabilmektir. Aslında classic bir console application’dan farkı direk dnxcore 5.0 üzerinde çalşıp .Net framework’den bağımsız olmasıdır. Böylece işletim sistemi gözetmeksizin linux ve başka işletim sistemlerinde de uygulamamız çalışabilmekte yani platform bağımsız uygulama yazılabilmektedir.
- Gereksiz birçok paketin yüklenmesini engelleyerek çok daha az yer kaplayan bir proje yaratabiliriz. Böylece Martin Fowler’ın Microservices‘ler olarak bilinen design pattern’ına göre projemizin esas yapıcağı işleri farklı farklı küçük projelere mesala url’den sadece post eden yada get eden console applicationlara bölerek tek bir parça halinde olan projemizi yine bütün işi yapan küçük projelere bölebiliriz. Ve daha sonra bizim önceden kurduğumuz kendi makinamızda küçük bir sanal sunucu gibi çalışan Docker’a koyabiliriz. Servisi koyduğumuz bu yere Docker Container denir. Daha sonra azure üzerine bu Docker’ı publish edilip klonlayarak sayısını 500’e çıkarılabiliriz. Böylece scale yapmak gibi gelen yüke aynı işi yapan 500 küçük uygulama tarafından çok daha hızlı ve efektif olarak cevp vermiş oluruz. İşte bu yapıya Microservices diyoruz. Gerçekte Docker mantığı ilk olarak Linux sistemler için çıkmış ama daha sonra windows içinde geliştirilmiştir. Eğer biz Asp.Net console application yazarsak linux bir sisteme de ilgili kodumuzu publish edebiliriz. İşte normal Console Application’dan fark burada karşımıza çıkıyor. Docker aslında çok detaylı ve kapsamlı bir konudur.
Image Source: https://martinfowler.com/articles/microservices/images/sketch.png
Bugünkü örneğimizde basit bir oyun yazacağız. Console app’in arka rengini değiştirip istediğimiz yöne oklar ile cursor’u hareket ettireceğiz. Daha sonra space tuşuna bastığımız zaman dikdörgen çizdereceğiz.
Öncelikle Main() Methodunu yazalım. Console application’da da aşağıda görüldüğü gibi asenkron uygulama geliştirebiliriz.”async” ve “await” keywordleri bunun için yeterlidir. Main() methodu içinde basılan tuşa göre Fighter yani cursor yön tuşlarına göre MoveFighter() methodu ile hareket ettirilmektedir. ‘Esc’ tuşuna basılınca uygulama sonlanmaktadır. Ayrıca ‘space’ tuşuna basılınca dikdörgen çizilmektedir.
Değişkenler: Cursorun ve arka rengin tanımı, bir de cursorun kordinatlarının tutulduğu Fighter property’si bulunmaktadır.
1 2 3 4 |
const ConsoleColor fighterColor = ConsoleColor.Red; const ConsoleColor backgroundColor = ConsoleColor.DarkGreen; public static Coordinate Fighter { get; set; } //Hareket ettireceğimiz cursor'ın kordinatları.. |
Main():
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 |
static async Task Main(string[] args) { await InitGame(); ConsoleKeyInfo keyInfo; while ((keyInfo = Console.ReadKey(true)).Key != ConsoleKey.Escape) { switch (keyInfo.Key) { case ConsoleKey.UpArrow: await MoveFighter(0, -1); break; case ConsoleKey.RightArrow: await MoveFighter(1, 0); break; case ConsoleKey.DownArrow: await MoveFighter(0, 1); break; case ConsoleKey.LeftArrow: await MoveFighter(-1, 0); break; case ConsoleKey.Spacebar: await DrawBox(5, 5); break; } } } |
InitGame(): Arka rengin değiştirlmesi ve cursorun başlangıç pozisyonuna getirilmesi işlemleri yapılır.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
static async Task InitGame() { await Task.Factory.StartNew(() => { SetBackgroundColor(); Fighter = new Coordinate() { X = 0, Y = 0 }; }); } |
SetBackgroundColor(): Console application’ın arka rengi burdan değiştirilir.
1 2 3 4 5 |
static void SetBackgroundColor() { Console.BackgroundColor = backgroundColor; Console.Clear(); //Önemli! } |
MoveFighter(): Aşağıda görüldüğü gibi asenkron olarak çalıştırılan method’da belirtilen X ve Y kordinatlarında ilgili Fighter’ın yani cursorun kordinatları değiştirilir. Bu işlem sırasında CanMove() methodu ile cursorun hareket ettirilmek istenen noktanın açılan pencere sınırları içinde olup olmadığına bakılarak işlem tamamlanır. RemoveFighter() burada önemli bir method’dur. Amacı arka rengi tekrardan değiştirmekdir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
static async Task MoveFighter(int x, int y) { await Task.Factory.StartNew(() => { Coordinate newFighter = new Coordinate() { X = Fighter.X + x, Y = Fighter.Y + y }; if (CanMove(newFighter)) { RemoveFighter(); Console.BackgroundColor = fighterColor; Console.SetCursorPosition(newFighter.X, newFighter.Y); Console.Write(" "); Fighter = newFighter; } }); } |
CanMove(): Cursorun hareket ettirilmek istenen X ve Y kordinatlarının, açılan pencere sınırları içinde kalıp kalmadığına bakılır.
1 2 3 4 5 6 7 8 9 10 |
static bool CanMove(Coordinate c) { if (c.X < 0 || c.X >= Console.WindowWidth) return false; if (c.Y < 0 || c.Y >= Console.WindowHeight) return false; return true; } |
RemoveFighter(): Arka rengi tekrardan değiştirmesi sağlanır.
1 2 3 4 5 6 |
static void RemoveFighter() { Console.BackgroundColor = backgroundColor; Console.SetCursorPosition(Fighter.X, Fighter.Y); Console.Write(" "); } |
DrawBox(): ‘Space’e basılınca diktörtgen çizilmesi sağlanmıştı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 |
static async Task DrawBox(int w, int h) { await Task.Factory.StartNew(() => { int arg1 = w; int arg2 = h; Console.WriteLine(); for (int row = 1; row <= arg1; row++) { if (row == 1 || row == arg1) { for (int col = 1; col <= arg2; col++) { Console.Write("♫"); } Console.WriteLine(); } if (row < arg1 && row < arg1 - 1) { Console.Write("♫"); for (int i = 0; i < arg2 - 2; i++) { Console.Write(" "); } Console.Write("♫"); Console.WriteLine(); } } }); } |
Burada dikkat edilmesi gereken konulardan biri de dnxcore50 altında ConsoleKey ve birçok dll’in çalışmamasıdır. Burada dnx451’in çalışması ve dnxcore50’nin çıkarılması için aşağıdaki gibi project.json altındaki frameworks’lerden dnxcore50’inin kaldırılması gerekmektedir. Böylece sadece dnx451 altında uygulama derlenir. Böylece platformdan bağımsız olan uygulamamız .Net framework’e bağımlı hale getirilerek platform bağımsız özelliği yitirilmiştir. Kısaca Asp.Net Console application ile normal Console Application arasında hiçbir fark kalmamıştır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
"frameworks": { "dnx451": { "dependencies": { "System.Threading.Tasks": "4.0.10-beta-22816" } }/*, "dnxcore50": { "dependencies": { "System.Console": "4.0.0-beta-22816", "System.Collections": "4.0.10-beta-22816", "System.Linq": "4.0.0-beta-22816", "System.Threading": "4.0.10-beta-22816", "Microsoft.CSharp": "4.0.0-beta-22816" } }*/ } |
Program.cs: Tüm kodlar
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 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
using System; using System.Threading.Tasks; namespace ConsoleGame { class Program { const ConsoleColor fighterColor = ConsoleColor.Red; const ConsoleColor backgroundColor = ConsoleColor.DarkGreen; public static Coordinate Fighter { get; set; } //Hareket ettireceğimiz cursor'ın kordinatları.. static async Task Main(string[] args) { await InitGame(); ConsoleKeyInfo keyInfo; while ((keyInfo = Console.ReadKey(true)).Key != ConsoleKey.Escape) { switch (keyInfo.Key) { case ConsoleKey.UpArrow: await MoveFighter(0, -1); break; case ConsoleKey.RightArrow: await MoveFighter(1, 0); break; case ConsoleKey.DownArrow: await MoveFighter(0, 1); break; case ConsoleKey.LeftArrow: await MoveFighter(-1, 0); break; case ConsoleKey.Spacebar: await DrawBox(5, 5); break; } } } /// <summary> /// Yeni Fighter'ı boyar. /// </summary> static async Task MoveFighter(int x, int y) { await Task.Factory.StartNew(() => { Coordinate newFighter = new Coordinate() { X = Fighter.X + x, Y = Fighter.Y + y }; if (CanMove(newFighter)) { RemoveFighter(); Console.BackgroundColor = fighterColor; Console.SetCursorPosition(newFighter.X, newFighter.Y); Console.Write(" "); Fighter = newFighter; } }); } /// <summary> /// Eski Fighter'ı yani cursoru temizler. /// </summary> static void RemoveFighter() { Console.BackgroundColor = backgroundColor; Console.SetCursorPosition(Fighter.X, Fighter.Y); Console.Write(" "); } /// <summary> /// Yeni kordinatların ekran sınırları içinde kalmasını sağlar /// </summary> static bool CanMove(Coordinate c) { if (c.X < 0 || c.X >= Console.WindowWidth) return false; if (c.Y < 0 || c.Y >= Console.WindowHeight) return false; return true; } /// <summary> /// Arka rengi değiştirir. /// </summary> /// <remarks> /// Clear() methodu önemli. Arka rengin tekrardan boyanmasını sağlar. /// </remarks> static void SetBackgroundColor() { Console.BackgroundColor = backgroundColor; Console.Clear(); //Önemli! } /// <summary> /// Arka rengi belirler. /// fighter'ı başlangıç noktasına konumlandırır. /// </summary> static async Task InitGame() { await Task.Factory.StartNew(() => { SetBackgroundColor(); Fighter = new Coordinate() { X = 0, Y = 0 }; }); } static async Task DrawBox(int w, int h) { await Task.Factory.StartNew(() => { int arg1 = w; int arg2 = h; Console.WriteLine(); for (int row = 1; row <= arg1; row++) { if (row == 1 || row == arg1) { for (int col = 1; col <= arg2; col++) { Console.Write("♫"); } Console.WriteLine(); } if (row < arg1 && row < arg1 - 1) { Console.Write("♫"); for (int i = 0; i < arg2 - 2; i++) { Console.Write(" "); } Console.Write("♫"); Console.WriteLine(); } } }); } } /// <summary> /// Coordinate'leri tutan modeldir. /// </summary> class Coordinate { public int X { get; set; } //Left public int Y { get; set; } //Top } } |
Yukarıda görüldüğü gibi belli basit ve light uygulamalar için console applicationlar son derece uygun ve performanslıdır. Böylece geldik bir makalenin daha sonuna.
Yeni bir makalede görüşmek üzere hoşçakalın.
Source: https://martinfowler.com/articles/microservices.html
Asp.Net 5 yazıları ve Linux’da performans testlerini merakla bekliyoruz sizlerden :)
Selam Mustafa;
Asp.Net 5 için Webinarım aşağıdaki link’dedir:) Linux performans testi için önce linux bir makina yapmam lazım:)
Webinar: http://www.borakasmer.com/webinar-aspnet5/
Asp.Net 5.0 hakkında diğer makalelerim:
1-) http://www.borakasmer.com/asp-net-5-0-taghelpers/
2-) http://www.borakasmer.com/asp-net-mvc-5de-attribute-routing/
3-) http://www.borakasmer.com/asp-net-vnext-webapplication-ile-yeni-ozellikler/
İyi çalışmalar.