InMemory Caching در ASP.NET MVC
شناسه پست: 1496
بازدید: 1414

چکیده: کش درون حافظه ای (InMemory Cache) در ASP.NET MVC 6 و ASP.NET Core، یکی از راه های قابل اطمینان برای جلوگیری از رفت و برگشت های اضافی به منبع داده ها برای داده هایی که به صورت مکرر تغییر نمیکنند میباشد. در این مقاله ما به این موضوع میپردازیم.

کش کردن باعث میشود شما داده ها را در حافظه برای دسترسی سریعتر ذخیره نمایید. زمانیکه که شما به داده ها مجددا دسترسی پیدا میکنید، این شیوه باعث میشه اپلیکیشن شما داده ها را به جای اینکه از منبع داده ها دریافت کند، ان را از کش واکشی کند. این باعث بهبود عملکرد و مقیاس پذیری میشود. کش کردن بنابرین زمانیکه منبع داده ها به طور موقت در دسترس نباشد به کار می آید.

ASP.NET Caching به ساده ترین شیوه

پیاده سازی عملیات کش کردن در اپلیکیشنهای ASP.NET، کمک میکند تا درخواست های غیرضروری به یک سرور منبع داده خارجی برای داده هایی که به صورت مکرر تغییر نمیکنند حذف گردد. کش کردن جهت بهینه سازی عملکرد، از داده ها یک کپی میگیرد. این کپی برای یک مدت زمانی کمی یا مدت زمانی که در اپلیکیشن شما تنظیم میشود در حافظه باقی میماند. در نسخه های اولیه ASP.NET، ما تکنیکهای مختلفی از کش کردن را در اختیار داشتیم. برای مثال: Data Caching، OutputCaching، InMemory Caching و غیره.

InMemory caching در ASP.NET MVC 6 و ASP.NET Core 1.0 ساده ترین راه کش کردن میباشد، که در این تکنیک، داده های کش شده در حافظه وب سرور لوکال ذخیره میشود. وقتی وب اپلیکیشن روی یک وب سرور قرار میگیرد، سپس کش درون حافظه ای پیاده سازی شده برای آن وب اپلیکیشن، حافظه همان وب سرور را استفاده میکند. با این حال، اگر وب اپلیکیشن ASP.NET در Cloud بر روی چند وب سرور قرار بگیرد ، سپس کش درون حافظه در سرورهای مختلف، متفاوت خواهد بود.

توجه: ASP.NET Core 1.0 (قبلاً با نام ASP.NET 5 شناخته می شد) طراحی مجدد از ASP.NET است که در تمام این سالها استفاده میکردیم. در ورژنهای اولیه Web API ،ASP.NET به عنوان یک فریم ورک جداگانه ارائه شده بود; اما با پیش رفتن به سمت ورژن Web API ،ASP.NET Core 1.0 با ASP.NET MVC ادغام شد که در نتیجه MVC 6 نامیده شد. این باعث بوجود آمدن این مزیت شد که بتوان اپلیکیشنها را با استفاده از HTML و API service ها فقط با یک فریم ورک ایجاد کرد.

پیاده سازی کش درون حافظه ای در ASP.NET MVC 6

ما این اپلیکیشن را با استفاده از Visual Studio 2015 و  ASP.NET MVC 6 و Core 1.0 ایجاد میکنیم.

مرحله 1: Visual Studio 2015 را باز کنید و یک ASP.NET Web Application جدید از پنجره New Project ایجاد نمایید و نام آن را InMemoryCaching بگذارید و سپس OK را کلیک کنید. سپس پنجره New ASP.NET Project نمایش داده خواهد شد. Empty را از ASP.NET Template برای ایجاد پروژه جدید انتخاب نمایید.

مرحله 2: در پروژه، فایل project.json را باز نمایید و از آنجایی که ما قصد داریم یک اپلیکیشن MVC  ایجاد نماییم، dependency reference های زیر را در قسمت dependencie وارد نمایید:

"Microsoft.AspNet.Authentication.Cookies": "1.0.0-rc1-final",
"Microsoft.AspNet.IISPlatformHandler": "1.0.0-rc1-final",
"Microsoft.AspNet.Mvc": "6.0.0-rc1-final",
"Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-rc1-final",
"Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final",
"Microsoft.AspNet.StaticFiles": "1.0.0-rc1-final",
"Microsoft.AspNet.Tooling.Razor": "1.0.0-rc1-final",
"Microsoft.Extensions.CodeGenerators.Mvc": "1.0.0-rc1-final",
"Microsoft.Extensions.Configuration.FileProviderExtensions": "1.0.0-rc1-final",
"Microsoft.Extensions.Configuration.Json": "1.0.0-rc1-final",
"Microsoft.Extensions.Configuration.UserSecrets": "1.0.0-rc1-final",
"Microsoft.Extensions.Caching.Abstractions": "1.0.0-rc1-final",
"Microsoft.Extensions.Caching.Memory": "1.0.0-rc1-final"


در کد بالا، رفرنسهای مربوط به caching قرار گرفته اند. در Caching ،ASP.NET Core 1.0 یک سرویس است. این سرویس باید در اپلیکیشن ما با استفاده از تزریق وابستگی اضافه شود.

مرحله 3: در پروژه یک پوشه جدید به نام Models ایجاد نمایید و یک فابل کلاس درون آن ایجاد کرده و کدهای زیر را درون آن قرار دهید:

using System.Collections.Generic;
 
namespace InMemoryCaching.Models
{
    public class Employee
    {
        public int EmpNo { get; set; }
        public string EmpName { get; set; }
    }
    public class EmployeesDatabase : List<Employee>
    {
        public EmployeesDatabase()
        {
            Add(new Employee() { EmpNo = 1, EmpName = "A" });
            Add(new Employee() { EmpNo = 2, EmpName = "B" });
            Add(new Employee() { EmpNo = 3, EmpName = "C" });
            Add(new Employee() { EmpNo = 4, EmpName = "D" });
            Add(new Employee() { EmpNo = 5, EmpName = "E" });
            Add(new Employee() { EmpNo = 6, EmpName = "F" });
        }
    }
 
    public class DataAccess
    {
        public List<Employee> Get()
        {
            return new EmployeesDatabase();
        }
    }
}


در کد بالا، یک کلاس موجودیت به نام Employee و یک کلاس EmployeeDatabase با داده های تستی مربوط به چند کارمند درون آن تعریف شده است. کلاس DataAccess برای دسترسی به داده ها مورد استفاده قرار میگیرد.

مرحله 4: در پروژه، یک پوشه جدید به نام Services با یک فایل کلاس درون آن ایجاد نمایید. کدهای زیر را درون این کلاس قرار دهید:

using InMemoryCaching.Models;
using System.Collections.Generic;
 
namespace InMemoryCaching.Services
{
    public interface IService<T> where T :class
    {
        IEnumerable<T> Get();
    }
 
    public class EmployeeService : IService<Employee>
    {
        DataAccess ds;
        public EmployeeService(DataAccess d)
        {
            ds = d;
        }
        public IEnumerable<Employee> Get()
        {
            return ds.Get();
        }
    }
}


کد بالا شامل کلاس EmployeeService  میباشد که رابط IService<T> را پیاده سازی میکند. در این مورد، T نوع داده ای Employee میباشد. آبجکت DataAccess با استفاده از اینجکشن در سازنده به EmployeeService پاس داده شده است.

مرحله 5: در پروژه، ما فایل Startup.cs را داریم که شامل کلاس Startup میباشد. در متد ()ConfigureServices، کد زیر را جهت استفاده از MVC اضافه کنید و کلاسهای  DataAccess و EmployeeService را با استفاده از تزریق وابستگی ثبت نمایید:

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped(typeof(DataAccess));
    services.AddSingleton<IService<Employee>, EmployeeService>();
    services.AddCaching();
    services.AddMvc();
}


()AddCaching یک اکستنشن متد است که مسئول اضافه کردن Memory Caching است.

مرحله 6: در کلاس Startup، کد زیر را درون متد ()Configure جهت استفاده از MVC routing و صفحه Diagnostic ها اضافه کنید:

public void Configure(IApplicationBuilder app)
{
    app.UseIISPlatformHandler();
 
    app.UseDeveloperExceptionPage();
 
    app.UseStaticFiles();
 
    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Employee}/{action=Index}/{id?}");
    });
}


مرحله 7: در پروژه، یک پوشه جدید به نام Controllers اضافه نمایید. در این پوشه، یک کنترلر جدید به نام EmployeeController اضافه کنید و کدهای زیر را درون آن قرار دهید:

using InMemoryCaching.Models;
using InMemoryCaching.Services;
using Microsoft.AspNet.Mvc;
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Generic;
using System.Linq;
 
 
namespace InMemoryCaching.Controllers
{
    public class EmployeeController : Controller
    {
        private readonly IMemoryCache _MemoryCache;
 
        private readonly IService<Employee> _service;
        //1
        public EmployeeController(IMemoryCache memCache,
            IService<Employee> serv)
        {
            _MemoryCache = memCache;
            _service = serv;
        }
 
        // GET: /<controller>/
        public IActionResult Index()
        {
            var Emps = SetGetMemoryCache();
            return View(Emps);
        }
 
        private List<Employee> SetGetMemoryCache()
        {
            //2
            string key = "MyMemoryKey-Cache";
            List<Employee> Employees;
     
            //3: We will try to get the Cache data
            //If the data is present in cache the
            //Condition will be true else it is false
            if (!_MemoryCache.TryGetValue(key, out Employees))
            {
                //4.fetch the data from the object
                Employees = _service.Get().ToList();
                //5.Save the received data in cache
                _MemoryCache.Set(key, Employees,
                    new MemoryCacheEntryOptions()
                    .SetAbsoluteExpiration(TimeSpan.FromMinutes(1)));
 
               ViewBag.Status = "Data is added in Cache";
 
            }
            else
            {
                Employees = _MemoryCache.Get(key) as List<Employee>;
                ViewBag.Status = "Data is Retrieved from in Cache";
            }
            return Employees;
        }
    }
}


در کنترلر بالا، متد خصوصی ()SetGetMemoryCache برای ذخیره داده ها در Memory Cache استفاده میشود. این متد شامل موارد زیر میباشد:

(توجه: شماره خطهای موارد زیر اشاره به شماره هایی دارد که در کامنتها در کد بالا آورده شده اند.)

  1. سازنده کنترلر با اینترفیس IMemoryCache  و IService، اینجکت شده است.
  2. با استفاده از متغیر key، داده های مربوط به کش خوانده یا نوشته میشود.
  3. ما سعی میکنیم که با استفاده از متد ()TryGetValue، داده های مربوط به کش را از کش درون حافظه دریافت کنیم که این متد شامل دو پارامتر میباشد. اولین پارامتر به عنوان کلید Cache و دومین پارامتر به عنوان پارامتر خروجی به اسم Employees میباشد که به عنوان List<Employee> تعریف شده است. اگر داده در کش موجود نباشد در نتیجه این متد false در غیر اینصورت true برمیگرداند.
  4. این مرحله، داده ها را با استفاده از متد ()Get که از Service فراخوانی میشود واکشی میکند.
  5. این مرحله مسئول ذخیره داده ها در کش با استفاده از متد ()Set از کلاس MemoryCacheEntryOptions  میباشد. ما باید یک زمان انقضای قطعی (absolute expiration) برای کش تعریف کنیم. هم اکنون ما آن را بر روی 1 دقیقه تنظیم کرده ایم.

اگر داده ها از قبل در کش موجود باشند سپس قسمت else در کد به اجرا درخواهد آمد که داده ها بر اساس Key از کش خوانده خواهند شد و در آبجکت Employees ذخیره میگردد. ما از ViewBag.Status برای نمایش پیام مربوط به وضعیت Cache در view استفاده میکنیم.

همچنین ما میتوانیم زمان انقضا بر حسب شرایط (Sliding Expiration) را با استفاده از متد ()SetSlidingExpiration از کلاس MemoryCacheEntryOptions را تنظیم کنیم تا داده ها را تا زمانی که حداقل یکبار در آن مدت زمان تعیین شده مورد درخواست قرار میگیرد در کش نگه داریم. یعنی در صورتی داده های درون کش منقضی میشود که داده ها در آن مدت زمان تعیین شده مورد درخواست قرار نگیرد. ما میتوانیم این کار را با استفاده از کد زیر انجام دهیم:

new MemoryCacheEntryOptions()
        .SetSlidingExpiration(TimeSpan.FromMinutes(2))


در این مورد، ما آن را بر روی 2 دقیقه تنظیم کرده ایم.

مرحله 8: در پوشه Views، یک زیرپوشه به نام Employee اضافه کنید و درون آن یک MVC View به نام Index.cshtml اضافه کنید. کد markup زیر را درون آن قرار دهید:

@model IEnumerable<InMemoryCaching.Models.Employee>
 
@{
      
    ViewData["Title"] = "Index";
}
 
<h2>Index</h2>
<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.EmpNo)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.EmpName)
        </th>
        <th></th>
    </tr>
 
    @foreach (var item in Model)
    {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.EmpNo)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.EmpName)
            </td>
        </tr>
    }
</table>
 
<div>@{            }</div>


کد بالا داده های مربوط به کارمندان را نمایش خواهد داد.

اپلیکیشن را اجرا نمایید. از آنجایی که اپلیکیشن اولین بار اجرا میشود، نتیجه به صورت زیر نمایش داده خواهد شد:

داده های ست شده در کش

داده ها در کش اضافه شده است. حال F5 را بزنید، نتیجه به صورت زیر خواهد بود:

کش در asp.net

داده ها از کش دریافت شده است.

نتیجه گیری

کش درون حافظه ای (InMemory Cache) در ASP.NET Core، یکی از راه های قابل اطمینان برای جلوگیری از رفت و برگشت های اضافی به منبع داده ها برای داده هایی که به صورت مکرر تغییر نمیکنند میباشد. این همچنین عملکرد اپلیکیشن را بهبود میدهد.

برای دانلود سورس برنامه اینجا کلیک کنید.

نویسنده

امید عباسی
من امید عباسی هستم. سالهاست که در زمینه برنامه نویسی با تکنولوژی دات نت فعالیت میکنم و عاشق این هستم که تجربیات و دانش خودم را در این زمینه با دیگران به اشتراک بزارم. خیلی دوست دارم که نظر و انتقاد خودتون رو در مورد این نوشته برای من بنویسید تا بتونم در آینده، مطالب بهتر و ارزشمندتری را برای شما فراهم کنم. در صورت داشتن هرگونه سوال هم در قسمت دیدگاه ها میتونید با بنده در ارتباط باشید