Yazılım Mimarileri ve Tasarım Desenleri Üzerine

Asp.NET Core’da Route Handler Oluşturma

Merhaba,

Asp.NET Core uygulamalarında kendi route handler yapılanmamızı oluşturarak belli başlı isteklere özel cevaplar verebiliriz. Aslında bizler bu konuya dair önceden Asp.NET MVC’de HttpHandler Oluşturma başlığı altında bir değerlendirmeyi standart Asp.NET MVC için kaleme almış bulunmaktayız. Bu içeriğimizde ise benzer yapılanmayı Asp.NET Core uygulaması için nasıl gerçekleştireceğimizi; konuyu daha geniş değerlendirerek, Core çekirdeği çerçevesinde daha fazla muhakeme ederek inceleyeceğiz.

İlk olarak Asp.NET Core mimarisinde bir request sürecinde hangi adımların gerçekleştiğini hatırlayarak, ilgili konumuzun kuramsal temelini oluşturalım. Ardından route handler yapılanmasının hangi kurallar çerçevesinde, nasıl sağlanacağını inceleyerek bir image boyutlandırma kurgusu üzerinden örneklendirme yapıp makalemizi noktalayalım.

Request sürecinde neler oluyor?

süreçteki genel olaylar bu çerçevede ceyran etmektedir.

İşte bu işleyişin son basamağında, süreçte en son route handler dediğimiz noktaya temas edilecektir. Burada eşleşen şemalara karşı route mekanizmaları handler edilerek gerekli yönlendirmeler response edilecektir.

Bizler klasik route şemaları oluşturmak yerine custom route handler yapıları inşa ederek bu son noktada devreye sokabiliriz. Dolayısıyla kendimize özel istekler tanımlayabilir ve farklı işlemlere tabi tutulan yönlendirmelerde bulunabiliriz. Tüm bu yapılanmayı custom route handler oluşturarak gerçekleştirebiliriz ve bunu yaparken Asp.NET Core mimarisinde, standart Asp.NET MVC mimarisindeki yaptığımız çalışmadan oldukça farklı ve sade bir şekilde çaba göstererek sağlayabiliriz.

Peki custom route handler nasıl oluşturulur?
Bunun için tek yapılması gereken “RequestDelegate” isimli delegate’i geriye dönen metot tasarlamaktadır.

    public class ExampleHandler
    {
        public RequestDelegate Handler()
        {
            return async c => await Task.Run(async () =>
            {
                await c.Response.WriteAsync("hello world");
            });
        }
    }

İşte bu kadar… Ne kadar basit değil mi? Ekrana “hello world” yazacak custom route handler’ımızı oluşturmuş olduk. Şimdi bu oluşturmuş olduğumuz route handler’ı kullanabilmek için route şemalarında aşağıdaki gibi belirtmemiz yeterli olacaktır.

    public class Startup
    {
        IHostingEnvironment _hostingEnvironment;
        public Startup(IHostingEnvironment hostingEnvironment) => _hostingEnvironment = hostingEnvironment;

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
                app.UseDeveloperExceptionPage();

            app.UseStaticFiles();
            app.UseMvcWithDefaultRoute();
            app.UseMvc(routes =>
            {
                routes.MapRoute("customroute", new ExampleHandler().Handler());
                routes.MapRoute(
                    name: "Default",
                    template: "{controller=Home}/{action=Index}/{id?}"
                    );
            });

        }
    }

Yukarıdaki kod bloğunu incelerseniz eğer oluşturduğumuz custom route handler’ı nerede kullandığımızı belki direkt olarak yakalayamayabilirsiniz. O yüzden daha net odaklanabilmek için ilgili satırları sade bir şekilde aşağıya alıyorum…

.
.
.
            app.UseMvc(routes =>
            {
                routes.MapRoute("customroute", new ExampleHandler().Handler());
                routes.MapRoute(
                    name: "Default",
                    template: "{controller=Home}/{action=Index}/{id?}"
                    );
            });
.
.
.

Evet… Görüldüğü üzere tanımladığımız route handler’ımız, “customroute” şeklinde tanımlanmış bir route üzerinde handler edilmektedir.

İşte bu kadar basit…

Şimdi bu temelde image boyutlandırma üzerine örneklendirme ile konumuzu zenginleştirip, makalemizi noktalayabiliriz.

Custom Route Handler İle Image Boyutlandırma

    public class ImageHandler
    {
        IHostingEnvironment _hostingEnvironment;
        public ImageHandler(IHostingEnvironment hostingEnvironment) => _hostingEnvironment = hostingEnvironment;
        public RequestDelegate Handler()
        {
            return async c => await Task.Run(async () =>
            {
                string fileName = c.GetRouteValue("fileName").ToString();

                FileInfo imageFile = new FileInfo($"{_hostingEnvironment.WebRootPath}\\{fileName}");

                using (MagickImage magicImage = new MagickImage(imageFile))
                {
                    int width = magicImage.Width, height = magicImage.Height;

                    if (!string.IsNullOrEmpty(c.Request.Query["w"].ToString()))
                        width = int.Parse(c.Request.Query["w"].ToString());
                    if (!string.IsNullOrEmpty(c.Request.Query["h"].ToString()))
                        height = int.Parse(c.Request.Query["h"]);


                    magicImage.Resize(width, height);
                    var buffer = magicImage.ToByteArray();
                    c.Response.Clear();
                    c.Response.ContentType = string.Concat("image/", imageFile.Extension.Replace(".", ""));
                    await c.Response.Body.WriteAsync(buffer, 0, buffer.Length);
                }

                await c.Response.WriteAsync($"{_hostingEnvironment.WebRootPath}\\{fileName}");
            });
        }
    }

Yukarıdaki “ImageHandler” isimli custom route handler’ı incelerseniz eğer tetiklendiği özel yönlendirici üzerinde gelen bazı route ve querystring parametreleri eşliğinde görseli boyutlandırmakta ve ContentType değerini gelen görselin extensionına uygun bir şekilde ayarlayarak response etmektedir. Ayrıca resim dosyaları üzerinde işlem yapabilmek içinde MagicImage kütüphanesi kullanılmaktadır.

İlgili custom route handler’a özel olarak aşağıdaki gibi bir route tanımlayalım.

    public class Startup
    {
        IHostingEnvironment _hostingEnvironment;
        public Startup(IHostingEnvironment hostingEnvironment) => _hostingEnvironment = hostingEnvironment;

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
                app.UseDeveloperExceptionPage();

            app.UseStaticFiles();
            app.UseMvcWithDefaultRoute();
            app.UseMvc(routes =>
            {
                routes.MapRoute("image/{fileName}", new ImageHandler(_hostingEnvironment).Handler());
                routes.MapRoute(
                    name: "Default",
                    template: "{controller=Home}/{action=Index}/{id?}"
                    );
            });
        }
    }

Bu işlemden sonra aşağıdaki ekran görüntüsünde görüldüğü üzere ilgili route image ContentType’ında response edilmektedir.

Ayrıca bu şekilde handler edilen image nesneleri <img src=”…”  /> html nesnesinde direkt olarak kaynak olarak belirtilebilir ve dolayısıyla dinamik bir şekilde resim yapılanmasıda kullanılabilir şekilde ayarlanmış olur.

<img src="https://localhost:5001/image/image-1.jpg?w=200&h=250" />
<img src="https://localhost:5001/image/image-2.jpg?w=300&h=350" />
<img src="https://localhost:5001/image/image-3.jpg?w=400&h=450" />


Görüldüğü üzere…

İlgilenenlerin faydalanması dileğiyle…

Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar dilerim.

Mobil sürümden çık