Erhan Ballıeker

Asp.Net Core 2.0’a Giriş – Bölüm 2 (Program.cs, WebHostBuilder, Kestrel hakkında)

Selamlar Arkadaşlar, bu yazımda geçen yazıda başladığımız AspNet Core Web Application oluşturma ve solution structer ına bir göz gezdirmeden sonra, Program.cs e ve içeriğindeki metodlara değineceğiz. Sonrasında sırası ile, Startup.cs dosyasına, bakıp AspNetCore Dependency Injection, Middleware yapısı vb konulara değinerek bu seriyi tamamlayacağız.

Öncelikle klasik AspNet ten hatırladığımız System.Web assembly sinden ve ne yaptığından bahsedip Core tarafına o şekilde geçelim.

Klasik Asp.Net projelerinde, bir web projesinin ayağa kalkma süreci System.Web assembly sindeki kodlar tarafından sağlanırdı ve sizin buna müdahele şansınız sadece size Global.asax dosyasında müdahele etmeniz, konfigürasyonlar yapmanız için verilen bazı metodları editlemekle kısıtlıydı. Artık yeni AspNet Core tarafında, application ın tümüyle başlatılma kısmı sizin elinizde. Nasıl olduğuna biraz daha derinlemesine değinelim.

Asp.Net Core projelerinde solution içerisinde bir adet Program.cs dosyası mevcut.  Bu dosya içerisindeki Main() metodu artık sizin application nınızın entry point i. Uygulumanızı başlattığınızda, Runtime uygulama içerisinde ki bu metodu arar ve çalıştırır. Şu aşamada Asp.Net Core Web App projeniz aslında bir Command Line Application olarak yaşamına başlar.

public class Program
{
     public static void Main(string[] args)
     {
         CreateWebHostBuilder(args).Build().Run();
     }

     public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
          WebHost.CreateDefaultBuilder(args)
         .UseStartup();
}

Uygulama çalıştığında Main() metodunuz, CreateWebHostBuilder Metodunu çağırır ve geri dönen IWebHostBuilder interface i üzerindeki Build() ve Run() metodlarını tetikler. Bu IWebHostBuilder metodu üzerindeki Run() metodu tetiklendiği andan itibaren artık uygulamanız gerçekten bir Asp.Net Core Web Application a dönüşür 🙂

Asp.Net Core un open source olmasından faydalanalım ve bu CreateDefaultBuilder(args) metodu arka planda ne yapıyor bir bakalım.

Buradan gördüğümüz gibi CreateDefaultBuilder(args) metodu aşağıdaki işleri yapıyor. Tek tek ne olduklarına değinmeye çalışalım.

public static IWebHostBuilder CreateDefaultBuilder(string[] args)
        {
            var builder = new WebHostBuilder();

            if (string.IsNullOrEmpty(builder.GetSetting(WebHostDefaults.ContentRootKey)))
            {
                builder.UseContentRoot(Directory.GetCurrentDirectory());
            }
            if (args != null)
            {
                builder.UseConfiguration(new ConfigurationBuilder().AddCommandLine(args).Build());
            }

            builder.UseKestrel((builderContext, options) =>
                {
                    options.Configure(builderContext.Configuration.GetSection("Kestrel"));
                })
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    var env = hostingContext.HostingEnvironment;

                    config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                          .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);

                    if (env.IsDevelopment())
                    {
                        var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
                        if (appAssembly != null)
                        {
                            config.AddUserSecrets(appAssembly, optional: true);
                        }
                    }

                    config.AddEnvironmentVariables();

                    if (args != null)
                    {
                        config.AddCommandLine(args);
                    }
                })
                .ConfigureLogging((hostingContext, logging) =>
                {
                    logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
                    logging.AddConsole();
                    logging.AddDebug();
                    logging.AddEventSourceLogger();
                })
                .ConfigureServices((hostingContext, services) =>
                {
                    // Fallback
                    services.PostConfigure(options =>
                    {
                        if (options.AllowedHosts == null || options.AllowedHosts.Count == 0)
                        {
                            // "AllowedHosts": "localhost;127.0.0.1;[::1]"
                            var hosts = hostingContext.Configuration["AllowedHosts"]?.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                            // Fall back to "*" to disable.
                            options.AllowedHosts = (hosts?.Length > 0 ? hosts : new[] { "*" });
                        }
                    });
                    // Change notification
                    services.AddSingleton(
                        new ConfigurationChangeTokenSource(hostingContext.Configuration));

                    services.AddTransient<IStartupFilter, HostFilteringStartupFilter>();
                })
                .UseIIS()
                .UseIISIntegration()
                .UseDefaultServiceProvider((context, options) =>
                {
                    options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
                });

            return builder;
        }

Burada aslına bir takım kontroller ve konfigürasyonların dışında değinmek istediğim yerler şimdilik şunlar ;

  • builder.UseContentRoot
  • builder.UseConfiguration
  • builder.UseKestrel
  • .UseIIS()
  • .UseIISIntegration()
  • .ConfigureServices((hostingContext, services)
  • .UseDefaultServiceProvider((context, options)

bu metodlar ile initialize edilen WebHostBuilder için aşağıdaki ayarlar default olarak yapılıyor.

  • builder.UseContentRoot(Directory.GetCurrentDirectory());
    • Burada projenin content root konfigürasyonu yapılıyor. Project Directory si Content Root olarak set ediliyor.
  •  builder.UseConfiguration(new ConfigurationBuilder().AddCommandLine(args).Build());
    • Burada projenin settings konfigürasyonu yapılıyor. Default olarak appsettings.json dosyasında konfigürasyonlar okunup initiate ediliyor.
  • builder.UseKestrel((builderContext, options) => { … }
    • Kestrel AspNet Core için yazılmış olan internal bir Web Server. Tabii ki bir IIS, Nginx, Apache gibi donanımlı ve yetenekli değil, ama oldukça lightweight ve performanslı çalışan bir web server. Bunun detaylarına daha sonra gireceğiz ama özetle burada Asp.Net Core Web App projesinin internal olarak Kestrel i kullanması söyleniyor ve Kestrel in bazı konfigürasyonları yapılıyor.
  • .UseDefaultServiceProvider((context, options)
    • Burada WebHostBuilder a söylenen Asp.Net Core projesinin internal Dependency injection container ını kullanması. Dependency injection artık Core ile birlikte built-in gelen bir support. Object Creation lar, ve onların lifetime managementları için bunu doğrudan kullanabiliriz. Yada kendi istediğimiz IoC Containerları kullanmasını söyleyebiliriz. Burada Default olarak built-in gelen container ın kullanılması söyleniyor.
  • .ConfigureServices((hostingContext, services)
    • Burada, Builder a kullanması için verilen IoC Container a, Proje ile alakalı bazı type ların register edilmesi sağlanıyor.
    • örneğin;  services.AddTransient<IStartupFilter, HostFilteringStartupFilter>(); Transient (obje container dan her istendiğine yenisi oluşturulup veriliyor) olarak IStartupFilter istendiğinde, HostFilteringStartupFilter ın proje içerisinde kullanılması ayarları yapılıyor.
  • .UseIIS()
  • .UseIISIntegration()
    • Burada, Web uygulamasının external web server olarak IIS kullanması söyleniyor. Gelen  requestler önce IIS den geçip, internal olan Kestrel e ulaşacak, sonrasında da middleware lerin eklenme sırasına göre her bir middleware de ilgili process ler gerçekleşip, aynı şekilde önce Kestrel e sonra da IIS e response iletilecek, ve response client tarafına dönecek.

 

Bu yazımıza da burada son verelim. Bir uygulamanın hayatına bir command line application olarak başlayıp, nasıl bir Asp.Net Core Web App e dönüştüğünü yüzeysel olarak source kodları inceleyerek anlamaya çalıştık. Bir sonraki yazımızda da Startup.cs dosyasını inceleyip artık bir Asp.Net Core Web Application ın, nasıl oluştuğunu, solution un neler içerdiğini ve konfigürasyonlarının yapılıp hayatına nasıl başladığını tamamen anlamış olacağız.

Bir sonraki yazımda görüşmek üzere.

Asp.Net Core 2.0’a Giriş – Bölüm 1 (NewProject, Solution Structure, Solution File hakkında)

Selamlar. Bu yazı serimizde AspNet Core’a bir girizgah yapacağız. Basit bir örnekle biraz yüzeysel olarak AspNet Core‘a  aşina olmuş, AspnetCore tarafında kod yazmaya başlayarak işin daha derinine inmeden önce biraz ellerimizi ısıtmış, AspnetCore tarafında biraz teorik bilgi sahibi olmuş olmak bu yazı serisinin temel amacı olacak. Sonraki yazılarda kısım kısım daha teknik detaylara girmeye çalışacağım.

Bu seri ve sonraki tüm yazılarda Visual Studio 2017 kullanacağım. Bu yüzden herhangi  birşeye başlamadan önce, daha sağlık ilerlemek adına Visual Studio 2017 yi ve Asp.Net Core 2‘yi download edip pc nize yüklerseniz sorunsuz bir şekilde blogları takip edebilirsiniz.

  • .NetCore un engüncel SDK sını şuradan indirebilirsiniz. Sadece SDK yı indirip kurmanız yeterli olucaktır, zaten Core Runtime, SDK içerisinde gelecek.
  • Visual Studio 2017 yi download etmek ve kurulum ile ilgili detaylı bilgi almak için buradan faydalanabilirsiniz.

Asp.Net Core Microsoft tarafından en baştan geliştirildi. Bizde şimdi Visual Studio 2017 mizi açıp sıfırdan bir Asp.Net Core projesi oluşturalım ve her şeye sıfırdan bakıp anlamaya çalışalım.

Klasik olarak başlangıç noktamız File -> New Project seçtikten sonra, ister VisualC# altından, ister .NetCore altından isterseniz de Web sekmeleri altında Asp.Net Core Web Application proje tipini seçip, projemize bir isim verdikten sonra Template seçme adımına geliyoruz.corenewprj

Yukarıdaki gibi projemizin tipini seçip, ismini verip, pc de saklayacağımızı yeri belirledikten sonra aşağıdaki Template seçme adımına geliyoruz. Herşeye sıfırdan bakmak istediğimiz için WebApplication veya WebApplication (Model-View-Controller) gibi birçok hazır dosya ve kodlar ile gelen template i değil de Empty template i seçerek yolumuza devam edelim. emtpyproj

Empty Template i seçip, herhangi bir authentication mekanizması seçmeden projemizi oluşturuyoruz. Şu ana kadar yaptımız tüm bu adımları Visual Studio yerine .NetCore CLI‘dan da yapmak mümkün biliyorsunuz. Ama CLI(Command Line Interface) detaylarına sonra gireceğiz. Yine de basitçe CLI dan nasıl proje oluşturulup, birbirine referans verilip, çalıştırılır abakmak isterseniz, önceki yazımda anlanttığım, .NetStandard 2.0 proje oluşturup bir Web app den kullanma örneği yaptığım yazıma bakabilirsiniz.

Peki, projemizi oluşturduk gelelim Solution Structer ın nasıl değiştiğine, düzenlendiğine. Yeni ve sıfırdan oluşturduğumuz projemizin structure ı aşağıdaki gibi görünüyor.

solstructs

Eğer daha önceki .NetCore versiyonları ile çalıştıysanız, ilk fark edeceğiniz şey project.json doyasının artık olmadığı. Bunun sebebi bu dosyanın MSBuild ile uyumlu çalışmaması, ve MSBuild in birçok DevOps Environment‘ı tarafından kullanılıyor olması. Bunun yerine artık doğrudan, hiç projeyi unload etmeden, csproj (VB ile yazıyorsanız vbproj) dosyasını editleyebiliyor olmamız. proje dosyası (csproj-vbproj) herhangi bir folder veya file referansı içermiyor artık. Solution File Explorer da açıp içerisi boş bir txt dosyası ekleyelim ve bakalım ne olacak.

Gördüğünüz gibi proje klasörüne eklenen text dosyası doğrudan proje içerisine included edilmiş şekliyle geldi. Bunun sebebi Asp.Net Core, Solution Explorer ın pc deki Disk ile birebir map lenmiş olması. Yani bir dosyayı projeye eklemek istediğimizde doğrudan Solution klasörüne atmak artık yeterli, Folder veya File referansları ile alakamız yok. Bu da aslında bir Source Control mekinizması kullanırken ki sıkça karşımıza çıkan, projeye yeni bir şeyler eklendiğinde, ilgili klasörün folder-file referanslarının da projeye eklenmesi yüzünden yaşadığımız conflict lerden bizi kurtarıyor.

Birde proje dosyamızın içine bakalım.

csprojfl

görmüş olduğunuz gibi proje dosyası gayet net ve temiz. En üstte projeyi oluştururken seçmiş olduğumuz Asp.Net Core framework ünün takma ismi (tüm platformların kendi takma ismi var, ör: netstandard2.0, netcoreapp2.1, net461, net471 vb..)

Bir sonraki Item a bakalım. wwwroot klasörü. Classic AspNet projelerinde Root Folder daki tüm dosyalar sunulmaya hazır halde olurdu. Browserdan ilgili folder ve file a gittiğinizde eğer o dosyaı Blacklist e alıp blocklamadıysak, WebConfig, Global.asax gibi hassas dosyalarda browserdan ulaşılabilir oluyordu.

Asp.Net Core da ise bu Blacklisting bakış açısı değişti ve WhiteListing e döndü. Artık bu wwwroot klasörü altında olmayan hiçbir şey doğrudan ulaşılmaz halde. Css, Javascript dosyaları, resimler gibi, browser ın ulaşması gerken tüm dosyalarımı koyacağımız yeni yer artık bu wwwroot klasörü olacak. Proje klasörüne gidip wwwroot ltında img  diye bir klasör oluşturup içine bir adet resim atalım.

imgroot

 

Solution kalsöründe wwwroot altında img klasörümüz ve içerisindeki resim anında Solution Explorer da görünür oldu. Şimdi bunu browserdan test etmek için projeyi çalıştıralım. Ama şöyle ekstra bir adım atmamı lazım, Sıfırdan bir template dosyası oluşturduğumuz için, Startup.cs içerisinde nerdeyse hiçbir built-in gelen middleware eklenmemiş halde. Startup dosyasından, Middleware yapısından ilerde detaylıca bahsedeceğiz ama şuan bu projeye eklediğimiz resmi görmemiz için Startup.cs doyasına gidip, Configure metodunun içerisine şu satırı eklememiz gerekiyor.

app.UseStaticFiles();

Şimdi Browserdan ilgili klasöre gidelim ve resim karşımızda.

coreimg.PNG

Peki proje dosyasındaki son item a bakalım.

<PackageReference Include=”Microsoft.AspNetCore.App” />

Normalde bir projeye nuget ten bir paket indirdiğinizde referansı buraya eklenirdi. Asp.Net Core 1.0 dan da hatırlarsanız, herbir paket ayrı ayrı projeye indiriliyordu, bu ilk başta güzel gibi gözüksede sonradan sorun çıkarmaya başladığı görüldü. Bu yüzden artık yeni bir proje oluşturduğunuzda içeriye versiyon numarası olmayan bu paket yükleniyor. Versiyon numarası yok çünkü siz .makinanızda NetCore her update ettiğinizde bu paket te güncelleniyor.

Microsoft.AspNetCore.App paketinde neler var?

  • Asp.Net Core un kullandığı tüm paketler
  • Entity Framework Core a ait paketler
  • Asp.Net Core ve Entity Framework Core un kullandığı tüm 3rd party paketler

Dolasyısı ile projenize neredeyse başka paket eklemeden geliştirmeye başlamaya hazırsınız. Peki bu kadar paket deploy zamanı ne oluyor? 🙂 Tabii ki bunu da düşünmüşler, yeni .NetCore Runtime Store fetarure ile kullanılmayan paketler deploy edilmeden ayıklanıyor.

Bu yazıyı burada tamamlayalım ve bir sonraki yazımızda, Program.cs ve Startup.cs dosyalarından devam edelim. Yeni bir Asp.Net Core Web Application nasıl oluşur ve Solution structer ı nasıldır öğrenmiş olduk. Serinin diğer yazılarında biraz daha aktif kod yazmaya başlayıp, yine biraz teoriğe değineceğiz.

Bir sonraki yazımda görüşmek üzere.

Xamarin.Workbook ile UrhoSharp Örnekleri Bölüm 1.

Herkese Merhaba,

Bundan önce UrhoSharp’ın temellerinden, Xamarin Workbook‘tan bahsetmiştim. Bu yazıdan önce UrhoSharp Giriş ve Xamarin Workbook Giriş yazılarımı okumanızda fayda var. Bu yazımda biraz daha yoğun görsellik içeren bir örnek yapacağım. UrhoSharp’ta Shapes, Actions ve Physics namespace’lerinden bahsedeceğim. Yeni bir workbook açıp (Console .Net Framework) UrhoSharp paketini nuget package manager’dan indiriyoruz.

Önce örneğimizde kullanacağımız namespacelerimizi workbook’umuza ekliyoruz.

using Urho;
using Urho.Shapes;
using Urho.Actions;
using Urho.Physics;

Şimdi daha önceki örneklerimizde görmüş olduğumuz SimpleApplication sınıfı yardımı ile 3D canvas’ımızı oluşturuyoruz.

 var app = SimpleApplication.Show(new ApplicationOptions{
             Width = 750,
             Height = 750
           });

Canvas’ımız oluştuktan sonra, SimpleApplication nesnesinin bizim için oluşturduğu CameraNode’unun Position ve Direction property’lerini değiştirelim.

app.CameraNode.Position = new Vector3(0, 0, -5);
app.CameraNode.SetDirection(new Vector3(0, 0, 1));

SimpleApplication’ın oluşturduğu RootNode’un Position değerinin default’da nasıl oluştuğuna bakalım.

possss

Gördüğünüz gibi RootNode (0,-2,8) koordinatlarına eklenmiş. Bunu Origine taşıyalım.

 app.RootNode.Position = new Vector3(0,0,0);

Şimdi SimpleApplication’ın oluşturduğu CameraNode ve bu node’a eklediği light’ı silip biz kendimiz oluşturalım. Light component’imi direk Scene’e tanımlamak istiyorum. Hatırlatayım Light tipi default olarak Point tanımlanırdı ama biz bunu Directional olarak tanımlayalım.

// Camera Node a ait tüm child node ları siliyoruz
app.CameraNode.RemoveAllChildren();

// directional light'ı Scene'e eklemeden önce kaldırıyoruz. Hatırlarsanız bu işlemleri workbook taki her bir hücrenin birden çok kez çalışması sebebi ile, duplicate node'lar oluşturmamak için yapıyorduk.
app.Scene.RemoveChild(app.Scene.GetChild("directionalLight"));
Node lightNode = app.Scene.CreateChild("directionalLight");

// Light Node'uma Light Componenti ekliyorum.
Light light = lightNode.CreateComponent();
light.LightType = LightType.Directional;
light.Color = new Color(0.65f, 0.65f, 0.65f);

// 3D sahnelerde genellikle ışık, oyuncunun sol omzunun üzerinden geliyormuş gibi bir yönde set edilir. Bunun için,aşağıdaki şekilde bir Vector3 tanımlıyorum.
lightNode.SetDirection(new Vector3(2, -3, 1));

// Simple Application tarafından oluşturulan Zone nesnesinin Ambient color rengini veriyorum. Bunun light componentinin Color değeri ile toplamının 1'i geçmemesine dikkat edin. Aksi halde normalden fazla parlak bir sahneniz olacaktır.
app.Zone.AmbientColor = new Color(0.35f, 0.35f, 0.35f);

Oluşan 3D canvas’da mouse ile kamerayı hareket ettirebilme özelliği vardır. Mouse’ın sol tuşuna basılı tutarak hareket ettirirseniz camera’nın oynadığını farkedeceksiniz. Ben cameranın oynamasını değil, Mouse’u hareket ettirdiğimde 3D ortamı daha iyi anlamak için RootNode nesnemi Rotate etmek istiyorum.

//Önce Mouse hareketiyle cameranın oynamaması için aşadağıki SimpleApplication nesnesinde aşağıdaki değişikliği yapıyorum
app.MoveCamera = false;

Şimdi mouse’un sol tuşuna basılı halde hareket ettiğimde, RootNode’u hareket ettirecek event handler’ı oluşturacağım. Sonrasında da bu event handler SimpleApplication objesinin Update event’ine atayacağım. Bu update metodu, UrhoSharp’ın Game Loop’unda tetiklenen event’dir. Normal bir UrhoSharp application’da OnUpdate metodunu override ederek de ilerleyebilirsiniz. Bu metot sahnedeki obje ve animasyon yoğunluğuna bağlı olarak saniyede pek çok kere çalışabilmektedir.

//Update event ine atayacağım event handler ı tanımlıyorum.
void ProcessMouseMovement(UpdateEventArgs args)
{
    //Gelen input Mouse un sol tuşu ise..
    if (app.Input.GetMouseButtonDown(MouseButton.Left))
    {
        //Mouse un X ve Y koordinatları ile 2 boyutlu bir vektör tanımlıyorum. Y değerine, mouse un Y değerinin negatifini set ediyorum, çünkü mouse u yukarı oynattığımda aşağıyı, aşağı oynattığımda yukarıyı göstermek istiyorum.
        Vector2 mouseMove = new Vector2(app.Input.MouseMove.X, -app.Input.MouseMove.Y);
        
        //Her bir piksel için 1 derece kabul ediyorum
        float angle = mouseMove.Length; 

        if (angle > 0)
        {
            //Aşağıda bir vector3 tanımlıyorum, Z her zaman 0, fakat RootNode a döndürme hareketi yaptıracağım için, X ekseninde mouse u hareket ettirdiğim Y ekseni etrafında döndürüyor olucam bu yüzden X değerine mouse hareketinin Y değerini veriyorum, aynı şekilde de Y değeri yerine mouse hareketinin negatifi X değerini veriyorum.
            Vector3 axis = new Vector3(mouseMove.Y, -mouseMove.X, 0);
            app.RootNode.Rotate(Quaternion.FromAxisAngle(axis, angle), TransformSpace.Parent);
        }
    }
}

Tekrar workbook’taki her bir hücrenin tekrar tekrar çalışabilir olmasından dolayı biraz reflection ile SimpleApplication’ın Update event’ini kaldırıyorum.

using System.Reflection;
FieldInfo field = typeof(Application).GetField("Update", BindingFlags.Instance | BindingFlags.NonPublic);
field.SetValue(app, null);

//Event i kaldırdıktan sonra tekrar Upadte event ine hazırldağım event handler set ediyorum.
app.Update += ProcessMouseMovement;

Peki, Canvas’ımızı oluşturduktan sonra oldukça hazırlık kodu yazdık. Birkaç farklı şeyi de irdelemiş olduk. Artık düz bir çizgiden fazlasını yapmaya başlayalım. Önce kod ile ekrana bir üçgen çizelim. Scene’deki 3 boyutu daha iyi algılamamız için tüm eksenler yönünde farklı renklerde çizgiler çizelim. Sonrasında da Urho.Shapes namespace’i ile neleri daha kolay yapabiliriz bir bakalım.

 //üçgenin noktalarını bir VertexBuffer.PositionNormalColor dizi olarak tanımlayalım.
VertexBuffer.PositionNormalColor[] vertices = {
 new VertexBuffer.PositionNormalColor{
 Position = new Vector3(-3,0, 5),
 Color = Color.Blue.ToUInt()
 },
 new VertexBuffer.PositionNormalColor{
 Position = new Vector3(0 ,3, 5),
 Color = Color.Yellow.ToUInt()
 },
 new VertexBuffer.PositionNormalColor{
 Position = new Vector3(3, 0, 5),
 Color = Color.Red.ToUInt()
 },
};
// Z eksenine göre 5 değerinde, yani ekrandan 5 birim uzaklıkta, Tabanı X ekseninde ve yüksekliği Y eksenin 3. birimde olacak şekilde 3 vertex tanımladım.

Şimdi VertexBuffer objemizi oluşturalım.

 var vertexBuffer = new VertexBuffer(Application.CurrentContext, false);
vertexBuffer.SetSize((uint)vertices.Length, ElementMask.Position | ElementMask.Normal | ElementMask.Color);
vertexBuffer.SetData(vertices);
//Bu sefer oluşturduğum vertex in Color değerinide kullandığım için, Position ve Normal flag leri yanında ElementMask.Color flag ini de vertexBuffer ın Size ını set ederken, eklemem gerekiyor.

Şimdi Geometry objemizi oluşturup bu üç vertex’i, üçgen olarak birleştirmek istediğimi söyleyeceğim.

 var geometry = new Geometry();
geometry.SetVertexBuffer(0, vertexBuffer);
geometry.SetDrawRange(PrimitiveType.TriangleList, 0, 0, 0, (uint)vertices.Length, true);
//SetDrawRange metodu ile bu iç noktayı TriangleList olarak birleştirmek istediğimi söyledim. Yani vertices dizimde 9 vertex im olsa idi, her bir üçlü bir üçgen oluşturacaktı.

Sırada bu geometriyi kullanacak Model objemizi oluşturmak var.

 var model = new Model();
model.NumGeometries = 1;
model.SetGeometry(0, 0, geometry);
model.BoundingBox = new BoundingBox(new Vector3(0,0,0), new Vector3(1,1,1));

Şimdi Material objemi zioluşturucağım. Bunu yaparken yine bir bitmap kullanmayıp sadece bir renkten türeyen Material nesnesi oluşturacağım.

 var material = Material.FromColor(Color.Green);

Artık bu model ve material objelerini birleştireceğim static model nesnemizi yaratmam ve bu nesneyi ekranda bir node’a eklemem gerek. Şimdi bunu yapalım. Node’u eklemeden önce silmeyi unutmayalım.

app.RootNode.RemoveChild(app.RootNode.GetChild("triangleNode"));
//GetChild metodu ilgili node u bulamazsa null dönecek ama bu RemoveChild metodu için sorun değil, işlem doğrudan ignore edilir.

//Node u oluşturuyorum.
var triangleNode = app.RootNode.CreateChild("triangleNode");

//Static Model componentimi oluşturuyorum.
var triangle = triangleNode.CreateComponent();

//model i set edelim.
triangle.Model = model;

//material ı set edelim.
triangle.SetMaterial(material);

tşranglecolor
Tüm bu işlemlerden sonra ekranda yeşil bir üçgen gördük. İstersek mouse’un sol tuşuna basılı tutarak RootNode’un rotate edip üçgenimizin etrafını gezebiliriz. Fakat bir şeye dikkat ettiniz mi? Vertex’leri tanımlarken her birine birer Color atamıştım, fakat en sonunda Material oluştururken verdiğim Yeşil renk bu değerleri ezmiş oldu. Bunu ortadan kaldırmak için yapmam gereken Material bir Technique set etme olacak.

//NoTextureVCol değerindeki NoTexture bir bitmap kullanma demek, VCol kısmı ise Vertex Color kullan demek.  
material.SetTechnique(0, CoreAssets.Techniques.NoTextureVCol, 1, 1);

//Bu kodu çalıştırdığımda vertexlerin renklerininde olaya dahil olduğunu göreceğim.Fakat yeşil rengi ortadan kaldırmak için Material'ı oluştururken renksiz bir instance oluşturmak gerek. Yukarıda Materail ı tanımlarken bu değişikliği yapıp tekrar deneyip görmenizi öneririm.Bunu yaptığınızda tamamen Kırmızı sarı ve mavi renklerinin karışımı resimdeki gibi bir üçgen göreceksiniz.

Şimdi yukarıda bahsettiğimiz gibi, tüm eksenler boyunca farklı renklerde çizgiler çizelim ki RootNode u hareket ettirdikçe 3D sahneyi daha rahat algılayabilelim. Bunun için her bir eksen yönünde -50, +50 aralığında çizgiler çizmemiz yeterli olacaktır.

//Tüm vertexleri ekleyeceğim listeyi oluştuyorum...
var lineVertices = new List();

-50, + 50 aralığında eksenleri çizelim demiştik. Şimdi bu döngüyü kurup vertex’lerimizi yukarıda tanımladığımız listeye ekleyelim ama bunun da öncesinde tüm eksenleri tanımladığım basit bir dizi oluşturalım. Sonuçta her bir eksen için, bu -50 +50 döngüsü çalışmalıdır. Döngünün sonunda elimde her bir eksen 100 tane totalde 300 adet vertices olmalı.

Vector3[] unitLineVertices = {Vector3.UnitX, Vector3.UnitY, Vector3.UnitZ};

Satırın çıktısında gördüğünüz gibi, her bir eksen bir birim vektör tanımlamak için oluşturulmuş UnitX, UnitY,  UnitZ field’larından yararlandım. Bu birazdan vector oluştururken de işimize yarayacak.

foreach(var unitVector in unitLineVertices)
{
    for(int i = -50; i < 50; i++)     
     {         
            //yeni bir vertex oluşturuyorum.        
            var lineVertex = new VertexBuffer.PositionNormalColor   
            {            
                 Position = i * unitVector, //int * birim vector = Vector3.. ör: i = 5 için Position = (1,0,0) * 5 => (5,0,0) olacak. 

            //X eksenindeysem kırmızı, Y eksenindeysem Yeşil, Z eksenindeysem mavi bir çizgi istiyorum.
            Color = unitVector == Vector3.UnitX ? Color.Red.ToUInt() : (unitVector == Vector3.UnitY ? Color.Green.ToUInt() : Color.Blue.ToUInt())
        };

        lineVertices.Add(lineVertex);
    }
}

Şimdi yukarıdaki sırayla gidelim (VertexBuffer -> Geometry -> Model -> Material -> Static Model -> Node). Bu sefer dikkat etmemiz gereken tek şey: Geometry objemizi oluştururken PrimitiveType olarak LineList kullanmak olacak.

var lineVertexBuffer = new VertexBuffer(Application.CurrentContext,false);
lineVertexBuffer.SetSize((uint)lineVertices.Count, ElementMask.Position |ElementMask.Normal |ElementMask.Color, false);
lineVertexBuffer.SetData(lineVertices.ToArray());

var lineGeometry = new Geometry();
lineGeometry.SetVertexBuffer(0, lineVertexBuffer);
lineGeometry.SetDrawRange(PrimitiveType.LineList, 0, 0, 0, (uint)lineVertices.Count, true);

var lineModel = new Model();
lineModel.NumGeometries = 1;
lineModel.SetGeometry(0, 0, lineGeometry); 
lineModel.BoundingBox = new BoundingBox(new Vector3(0,0,0), new Vector3(1,1,1));

var lineMaterial = new Material();
lineMaterial.SetTechnique(0, CoreAssets.Techniques.NoTextureVCol, 1, 1);

app.RootNode.RemoveChild(app.RootNode.GetChild("lineNode"));
var lineNode = app.RootNode.CreateChild("lineNode");

var line = lineNode.CreateComponent();
line.Model = lineModel;
line.SetMaterial(lineMaterial);

Yukarıda farklı birşey yapmadık. Bu kodu çalıştırdığımızda, istediğimiz 100 birimlik tüm eksenlerimizde farklı renklerde çizgiler çizmiş olduk. Üçgenimizin tam olarak Z eksenin +5 değerinde olduğunu daha rahat görebiliriz. Mouse ile biraz oynayarak sahnemizi gezebiliriz.

triangle2

Biraz da Urho’nun kendi Shape namespace’inden faydalanıp daha az kod ile daha fazla şey yapma vakti geldi. Şimdi origin’e bir adet küre ekleyelim. Bunun için Urho.Shapes namespace’in altındaki Sphere Component’ini kullanacağız. Sphere gibi 8 adet hazır shape mevcut. Biz bu örnekte hepsini görmeyeceğiz ancak sizin hepsini ekrana ekleyip görmenizde, el alışkanlığı kazanmanız fayda var.

//Direk olarak küremi koyacağım Node u üreterek işe başlıyorum.
app.RootNode.RemoveChild(app.RootNode.GetChild("sphereNode"));
var sphereNode = app.RootNode.CreateChild("sphereNode");

//StaticModel componenti yerine, bu component ten türeyen ama farklı özelliklere de sahip olan Sphere Componentini ekliyorum node'uma
var sphere = sphereNode.CreateComponent();
sphere.Color = Color.Blue;
//Bu componentin Color propertysi sayesinde direk renk set edebiliyorum. StaticModel Componentinde normalde böyle bir property yok. Material kullanıyordum renk bitmap vb set etmek için.

Vee bu kadar. Tam olarak orijinde, 1 birim çapında, mavi bir kürem oluştu bile.
Şimdi birde küp ekleyelim ve ona biraz animasyon katalım.

app.RootNode.RemoveChild(app.RootNode.GetChild("boxNode"));

var boxNode = app.RootNode.CreateChild("boxNode");
var box = boxNode.CreateComponent();
box.Color = Color.Red;

//boxnode un position değerini değiştirelim.
boxNode.Position = new Vector3(3,3,3);

Ekranda kırmızı bir box nesnesini görebiliriz. Şimdi biraz animasyon katalım. Animasyonu yaratırken Node nesnesinin FiniteTimeAction objesini kullanacağız. Birden çok action’ı node’a set edebiliriz.

FiniteTimeAction boxAction = 
    new RepeatForever(
        //Rotate by action ı ile rotation animasyonunu ekliyorum.
        new RotateBy(duration: 5, //Animasyonun kaç saniyede tamamlanmasını istediğimi söylüyorum.
                     deltaAngleX: 0,
                     deltaAngleY: 360,//Y ekseni etrafında 360 derece dönecek ve sürekli çalışacak bir action oluşturuyorum.
                     deltaAngleZ: 0
        )
    );

//Önce tüm action ları siliyoruz.
boxNode.RemoveAllActions();

//Sonrada action'ı node a ekliyorum.
boxNode.RunActions(boxAction);

Şimdi de, 100 X 100’lük bir yüzey (düzlem) oluşturalım. Sonra da bu yüzeyin fizik kanunları ile etkilenmesi için rigid body ve collision shape’ini tanımlayıp bu düzlemimiz gibi bir de sphere oluşturup onu da yerçekiminden etkilenip yüzeye düşecek şekilde tasarlayalım.

app.RootNode.RemoveChild(app.RootNode.GetChild("planeNode"));

var planeNode = app.RootNode.CreateChild("planeNode");
var plane = planeNode.CreateComponent();
plane.Color = Color.Green;

//100X100 lük olsun demiştik. Scale i değiştirelim.
planeNode.SetScale(100);

//Bu noktadan itibaren yeşil düzlemimiz canvasımızda belirdi.Şimdi rigidBody ve collision shape componentlerimiz tanımlayalım.
//RigidBody
var planeRigidBody = planeNode.CreateComponent();

//CollisionShape nesnesi, modelimizin diğer modeller ile etkileşim sınırlarını belirler.
var planeCollisionShape = planeNode.CreateComponent();
planeCollisionShape.SetStaticPlane(new Vector3(100,0,100), Quaternion.Identity);

Şimdi yerçekiminden etkilenecek ve yüzeye düşecek küremizi oluşturalım.

app.RootNode.RemoveChild(app.RootNode.GetChild("rigidSphereNode"));
var rigidSphereNode = app.RootNode.CreateChild("rigidSphereNode");
rigidSphereNode.SetScale(2);
rigidSphereNode.Position = new Vector3(-3,5,2);

var rigidSphere = rigidSphereNode.CreateComponent();
rigidSphere.Color = Color.Yellow;

var sphereRigidBody = rigidSphereNode.CreateComponent();
sphereRigidBody.Mass = 1;

var sphereCollisionShape = rigidSphereNode.CreateComponent();
sphereCollisionShape.SetSphere(2, Vector3.Zero, Quaternion.Identity);

Yukarıdaki kod bloğunu da çalıştırdığımızda sarı bir kürenin ekranda belirip plane üzerine düştüğünü ve rootnode’ un rotasyonu olduğu yöne doğru kaydığını görüyoruz.triangle4

Yazıda oluşturduğum workbook’u buradan indirebilirsiniz.

Bir sonraki yazımda görüşmek üzere.

Xamarin.Forms’da Kod Paylaşımı İçin .NET Standard 2.0 Kullanımı

Herkese Merhaba,

Bu yazımda önceden oluşturduğumuz veya yeni oluşturacağımız Xamarin.Forms projemizde, PCL (Portable Class Library) yerine nasıl .Net Standart 2.0 kullanabileceğimizden bahsedeceğim.

Bildiğiniz üzere, Visual Studio ile sıfırdan bir Xamarin.Forms projesi oluşturulduğunda bize iki opsiyon sunar. Bunlardan biri PCL diğeri de Shared Project. Shared Project, aslında File Linking gibi çalışan yazdığınız kodların tüm projelerin içine ayrı ayrı kopyalandığı ve paketlendiği bir kod paylaşım şeklidir yani SP ayrı bir proje olarak derlenip size farklı bir dll sunmamaktadır. Küçük projelerde ve tek kişilik ekiplerle yapılan projelerde mantıklı gibi gözükse de proje ve ekip büyüdükçe sıkıntılar çıkarmaya başlar. Ayrıca aşağıdaki gibi Compiler Directive’ler kullanarak, platform spesifik kodlarınızı yazabilirsiniz. Bu ilk bakışta kolay ve kullanışlı gibi gözükmesine rağmen kodlar çoğaldığında, ortalık biraz karışacaktır ve kodun okunabilirliği düşecektir.

  var path = string.Empty;
  #if WINDOWS_PHONE
  path = "windowsphone";
  #else
  
  #if __SILVERLIGHT__
  path = "silverlight";
  #else
  
  #if __ANDROID__
  path = "android";
  #else
  
  #if __IOS__
  path = "iOS";
  #else
  
  #if __TVOS__
  path = "tv";
  #else
  
  #if __WATCHOS__
  path = "watch";
  #endif
  

Gerek Unit Test yazılabilirliği olsun, gerekse daha temiz bir kod paylaşımı sağlaması vb  gibi farklı sebeplerden PCL birçok Xamarin projesinde kod paylaşımı stratejilerinin en başında gelmektedir.

Fakat bundan sonra, Xamarin.Forms 2.4.xx versiyonları ile beraber .NetStandard 2.0‘a tam destek gelmeye başladı. Microsoft’un da bundan sonra .NetCore‘a ve Standard Library ile yoluna devam edeceğini düşünürsek Xamarin projelerimizde kod paylaşımı için .NetStandard’a geçmenin vakti geldi.

netstandard

NET Standard 2.0‘da şimdiden yazılımcıların hayatını kolaylaştırmak için 20000’den fazla API, en çok kullanılan nuget paketlerinin %70’inden fazlasına uyumluluk mevcut bile. Desteğe dahil olan platformlara UWP desteği ile beraber artık Xamarin de eklendi.

.NET Standard 2.0 kütüphanesini Xamarin.iOS 10.14, Xamarin.Android 7.5, Xamarin.Mac 3.8, and Mono 5.4 versiyonları ve sonrası ile kullanabilirsiniz.

Bilgisayarınızda .Net Core ilgili eksikleriniz varsa şuradan indirebilirsiniz.

Projemde Kullanacağım .NetStandard Versiyonunu Seçerken Neleri Düşünmeliyim?

  • Ne kadar yüksek versiyon seçerseniz, o kadar çok API desteği alırsınız.
  • Ne kadar düşük versiyon seçerseniz, o kadar çok platform tarafından implement edilmiş olan versiyonu kullanıyor olursunuz.

Aslında çok da fazla düşünmenize gerek yok çünkü .Net Standard 2.0 neredeyse tüm platformlar tarafından destekleniyor.

  • NET Core 2.0
  • .NET Framework 4.6.1
  • Mono
  • Xamarin.iOS
  • Xamarin.Android
  • Xamarin.Mac
  • UWP

Tüm bu platformlar hali hazırda Net Standard 2.0′ı implement etmiş durumda.

Peki projemizdeki kod paylaşımını .Net Standard 2.0 olacak şekilde değiştirmekten bahsedeyim. Sıfırdan bir proje oluşturarak işe başlayacağım. Henüz kod paylaşımı için ilk başta Visual Studio bize seçenek olarak .Net Standard 2.0 sunmadığı için PCL seçimi yapacağım ve akabinde bunu .Net Standard 2.0 olarak değiştireceğim.

pclselect

pcl

 

Yukarıdaki seçeneklerle sıfırdan bir Xamarin.Forms projesi oluşturuyorum ve bana yandaki gibi bir Solution veriyor (Windows seçeneği için “İptal” tuşuna bastım. Şu an için onunla ilgilenmiyorum).

Projede hiçbir değişiklik yapmadan önce, solution’ı derliyorum. Tüm solution’ın sorunsuz derlendiğine emin olduktan sonra Solution’a sağ tıklayıp Add New Project diyorum.

 

Aşağıdaki gibi sol taraftaki menüden .Net Standard’ ı seçiyorum ve isimde hiçbir değişiklik yapmadan ClassLibrary1 olarak projemi solution’ a ekliyorum.

netstandartadd

Solution’a eklediğim bu SCL’min versiyonu default olarak (Eğer pc’nizde yüklü ise) 2.0 olarak gelmektedir. ClassLibrary1 projesine sağ tıklandığında en altta Properties’e tıklarsam karşıma gelen pencerenin Target framework kısmında SCL versyionunu görüp bu versiyonda değişiklik yapabilirim.

sclsel

Şimdi ClassLibrary1 projemde Dependencies’e sağ tıklayıp Manage Nuget Packages.. ‘a tıklayıp Xamarin.Forms kütüphanesini ekleyeceğim.

versxam

Yukarıda gördüğünüz gibi, ClassLibrary1 projeme Xamarin.Forms 2.4.0.282 (bu yazıyı yazarken ki son stabil versiyon) kütüphanesini ekleyip derliyorum. Projenin derlendiğine emin olduktan sonra, Pcl projesindeki App.xaml ve MainPage.xaml dosyalarını CTRL tuşuna basarak seçiyorum ve mouse yardımı ile iki dosyayı SCL projeme sürükleyip bırakıyorum (yani kopyalamış oluyorum). Bunu yaptıktan sonra artık PCL projemi solution’dan silebilirim. PCL projesini silmeden önce eğer projenizde daha fazla dosya varsa tüm dosyaları SCL’e kopyaladığınıza emin olun mutlaka.

ClassLibrary1 olarak eklediğim SCL’nin adını, bu proje mouse ile seçili iken F2 tuşuna basarak,  App1 olarak değiştiriyorum (ilk oluşturduğumda projeme verilen default isim bu olduğu için App1 yaptım. Eğer sizin önceden oluşturduğunuz bir projeniz varsa ve PCL in adı örneğin MyApp ise SCL’e de App1 değil bu  MyApp ismini veriniz.).

sclselected

Solution’ımın son hali yandaki gibidir. Gördüğünüz gibi App1 projesi artık bir .NetStandart2.0 projesidir. Dependencies altındaki Xamarin.Forms paketinin yanında sanki sorunluymuş gibi bir ünlem işareti var ama bunu şimdilik dikkate almayın. Projede sorun olmamasına rağmen Visual Studio bunu şimdilik yapıyor ancak Visual Studio’yu açıp kapattığınızda sorun düzeliyor. Fonksiyonel olarak bir sıkıntı olmadığına emin olmak için SCL projemizi derliyoruz. Projenin derlendiğine emin olduktan sonra Android ve iOS projeme bu App1 projemin referansını ekliyorum.

İlk başta gelen App1 ismindeki Portable Class Library projemi Solution’dan sildiğimde, referanslar Android ve iOS projesinde kalkmış oldu. Bu yüzden bu yeni oluşturduğum SCL kütüphanemin referansını, iOS ve Android projeme tekrar ekliyorum. Şimdi yeniden Android ve iOS projelerimi derlediğimde sorunsuz derlendiğini görüyorum. Bu noktadan itibaren Xamarin.Forms projeme .NetStandard 2.0 ile devam edebilirim.

 

Bu yazımda kısaca, var olan veya yeni oluşturduğum bir Xamarin.Forms projemin kod paylaşım stratejisi olarak nasıl PCL’den .NetStandard’a geçebileceğimizi anlatmaya çalıştım.

Özetlemek gerekirse:

  • Solution’a yeni bir .NetStandard 2.0 ClassLibrary’si ekliyorum.
  • Bu yeni eklediğim SCL’e Xamarin.Forms nuget Package’ını ekliyorum.
  • Önceden oluşan PCL’deki dosyaları (xaml, .cs vs) bu yeni oluşturduğum SCL içerisine taşıyorum.
  • PCL projesini solution’dan kaldırıyorum.
  • SCL’in ismini projeden kaldırdığım PCL’in ismi olacak şekilde değiştiriyorum.
  • Son olarak bu yeni oluşturduğum SCL’in referansını Android ve iOS projelerime ekliyorum.

 

Bir sonraki yazımda görüşmek üzere…

NetStandard nedir? .NetCore, .NetFramework ve diğer .Net Platformları ile ilişkisi nasıl? (Bölüm 3)

Selamlar, .NetStandard ile ilgili örnek yapıp bir de developer gözünden bir metafor ile netstandard a bakıp bu seriyi sonlandıracağım yazıma hoşgeldiniz. Önceki yazıları bundan önce okumanızda fayda var. Bölüm1 ve Bölüm2 den sonra buraya devam ederseniz daha tatmin edici olacaktır sizin için 🙂

Önce şu bahsettiğim ve aslında şurada yazılmış olan ve çok hoşuma giden matefordan bahsedelim 🙂 Bir developer için .NetStandard ın, tüm .NetPlatformlarının implemente etmesi gereken API lar bütünü olduğundan bahsetmiştik. Yan, bu durumda her bir .NetStandard versiyonunu bir interface, her bir .Net Platformunu da bir concerete class olarak düşünmek yanlış olmaz 🙂

Bu durumda da aslında şöyle bir .cs dosyası ile tüm NetStandard versiyonlarını ve onu implemente eden platformları yazabiliriz.

Önce .NetStandard ı görelim;

// .NET Standard

interface INetStandard10
{
    void Primitives();
    void Reflection();
    void Tasks();
    void Collections();
    void Linq();
}

interface INetStandard11 : INetStandard10
{
    void ConcurrentCollections();
    void EventSource();
    void InteropServices();
}

interface INetStandard12 : INetStandard11
{
    void ThreadingTimer();
}

interface INetStandard13 : INetStandard12
{
    void AppContext();
    void Console();
    void StringInterpolation();
    void Calendars();
    void FileSystem();
    void Sockets();
    void AsyncLocal();
}

interface INetStandard14 : INetStandard13
{
    void CryptoECDsa();
}

interface INetStandard15 : INetStandard14
{
    void EventCounter();
}

interface INetStandard16 : INetStandard15
{
    void LinqInterpretation();
    void CryptoECCurve();
    void PrecompiledRegex();
}

interface INetStandard20 : INetStandard16
{
    void EverythingThatIsInNetFrameworkAndXamarin();
}

yukarıda gördüğünüz ve daha önce söylediğimiz gibi, .NetStandard versiyonları PCL den farkli olarak lineer bir şekilde gidiyor. Her bir versiyonda da, platformların implemente etmesi gerektiğini düşündükleri (required olarak label ladıkları API ları görüyorsunuz)

Peki birde .NetFramework ve .NetCore implementasyonlarına bakalım;

// .NET Framework

class NetFramework45 : INetStandard11
{
    // ...
}

class NetFramework451 : NetFramework45, INetStandard12
{
    // ...
}

class NetFramework452 : NetFramework451
{
    // ...
}

class NetFramework46 : NetFramework452, INetStandard13
{
    // ...
}

class NetFramework461 : NetFramework46, INetStandard20
{
    // ...
}

class NetFramework462 : NetFramework461
{
    // ...
}

class NetFramework47 : NetFramework462
{
    // ...
}

class NetFramework471 : NetFramework47
{
    // ...
}

// .NET Core

class NetCore10 : INetStandard16
{
    // ...
}

class NetCore11 : NetCore10
{
    // ...
}

class NetCore20 : NetCore11, INetStandard20
{
    // ...
}

Burada da, kolayca .NetStandard 2.0 ın Framework 4.6.1 tarafından tamamen implemente edildiğini, aynı şekilde .NetCore1.0 ın NetStandard 1.6 yı implemente ettiğini,  .NetCore 2.0 ın da .NetStandard 2.0 ı tamamen implemente ettiğini görüyorsunuz:)

Bir yazılımcı için anlaşılması çok daha kolay oldu değil mi 🙂

Bir de .NetCore CLI kullanarak küçük bir örnek yapalım, Visual Studio 2017 den sonra zaten bunu IDE üzerinden yapmayı göstermenin bir lüzumu yok 🙂 . Hem Cross Platform Command Line Interface i biraz kullanmış tanımış oluruz, hemde hakkında bu kadar yazdığımız .NetStandard ı bir de kod tarafından görmüş oluruz.

Öncelikle Windows tarafında Command Prompt u, Mac tarafında da ise Terminal i açıyoruz. Windows tarafı ile Mac tarafında hiçbir kod farklı olmadığı, yazanları iki tarafta da rahatça deneyebilirsiniz.

İlk olarak aşağıdaki kodu çalıştırarak yeni bir class library projesi oluşturuyoruz. bu proje otomatik olarak .NetStandard olarak oluşacaktır.

$ dotnet new classlib -o mystandardlibrary

bu şekilde bir standard class library projesi oluşturmuş olduk. Şimdi Class1 in içeriğini değiştirip basit bir static metod koyalım.

using System;

namespace mystandardlibrary
{
    public class Class1
    {
        public static string GetMessage() => "Hello from .NET Standard!";
    }
}

Şimdi aşağıdaki komut satırını çalıştırarak yeni bir aspnet core projesi oluşturalım. web keyword ü ile default bir aspnet core projesi oluşacak.

$ dotnet new web -o aspnetcoreclient

Oluşturmuş olduğumuz web projesine, class library projesini referans olarak verelim.

$ dotnet add reference ../mystandardlibrary/mystandardlibrary.csproj

Şimdi de son olarak, web projesindeki Startup.cs dosyasında bulunan inline yazılmış ve gelen request e direk cevap veren tek middleware kodunu edit leyip, aşağıdaki gibi, standard class librarydeki metodumuzu kullanacak şekilde düzenleyelim.

app.Run(async (context) =>
{
    var message = mystandardlibrary.Class1.GetMessage();
    await context.Response.WriteAsync(message);
});

Son olarak, web projesi içerisindeyken önce “dotnet build”  projemizi derleyip, sonrada aşağıdaki komut satırını çalıştırarak web projesini ayağa kaldıralım.

$ dotnet run

core

resimde görmüş olduğunuz gibi http ve https portları üzerinde sitemiz 5000 ve 5001 portlarında ayağa kalktı. Browser ımızı açıp http://localhost:5000 adresine gidersek aşağıdaki gibi, web projemizin, NetStandard kütüphanemizdeki kodu çalıştırdığını göreceğiz. 

localhst

Birkaç satır kod ile, tüm .Net Platformlarında kullanabileğimiz .NetStandard2.0 kütüphanemizi oluştumuş ve bir aspnet core projesinde kullanmış olduk. 🙂 Bu 3 yazılık seri de, Genel olarak kod paylaşımını, NetStandard ı ve onun diğer .Net platformlar ile olan ilişkisini anlatmaya çalıştım.Umarım keyif almışsınızdır.

.Net Core ile ilgili detaylı yazı serilerinde görüşmek üzere,