مطالب
کاهش تعداد بار تعریف using ها در C# 10.0 و NET 6.0.
در مطلب «روش بازگشت به قالب‌های کلاسیک پروژه‌ها در دات نت 6» مشاهده کردیم که قالب پیش‌فرض یک برنامه‌ی کنسول دات نت 6، چنین فایل Program.cs ای را تولید می‌کند:
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");
که در حقیقت همان اجبار به استفاده‌ی از سبک «Top Level Programs» ارائه شده‌ی در C# 9.0 است. اما اگر به همین دو سطر هم دقت کنید، یک تفاوت مهم را با نمونه‌ی C# 9.0 دارد و آن هم عدم ذکر عبارت using System در ابتدای آن است. علت اینجا است که فایل csproj پیش‌فرض پروژه‌های مبتنی بر NET 6.0.، دو تغییر مهم دیگر را هم دارند:
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
</Project>
الف) فعال بودن nullable reference types که در C# 8.0 ارائه شد.
ب) فعال بودن ImplicitUsings که مختص به C# 10.0 است.


بررسی مفهوم  global using directives در C# 10.0

هدف اصلی از وجود Using directives در زبان #C که از نگارش 1 آن در دسترس هستند، خلاصه نویسی نام طولانی اشیاء و متدها است. برای مثال نام اصلی متد Console.WriteLine به صورت System.Console.WriteLine است که با درج فضای نام System در ابتدای فایل، می‌توان از ذکر مجدد آن جلوگیری کرد. از این دست می‌توان به نوع System.Collections.Generic.List نیز اشاره کرد که کمتر کسی علاقمند است تا این نام طولانی را تایپ کند. به همین جهت با استفاده از یک using directive متناظر با فضای نام System.Collections.Generic، ذکر نام این نوع، به List خلاصه می‌شود.
طراحی دات نت 6 مبتنی بر سبک minimalism است! برای نمونه خلاصه کردن نزدیک به 10 سطر فایل Program.cs کلاسیک، به تنها یک سطر که به همراه ذکر using System در ابتدای آن هم نیست. در C# 10.0 دیگر نیازی نیست تا برای مثال ذکر using System را در ده‌ها و یا صدها فایل، بارها و بارها تکرار کرد. برای اینکار تنها کافی است یکبار آن‌را به صورت global تعریف کنیم و پس از آن دیگر نیازی به ذکر آن در کل پروژه نیست:
global using System;
می‌توان این سطر را در ابتدای یک تک فایل cs. قرار داد و ذکر آن به معنای الحاق خودکار آن، در ابتدای تک تک فایل‌های cs. برنامه است.

چند نکته:
- امکان ترکیب global using‌ها و using‌ها معمولی در یک فایل هست.
- امکان تعریف global using‌های استاتیک نیز پیش‌بینی شده‌است:
global using static System.Console;
که برای نمونه در این حالت بجای ذکر Console.WriteLine، تنها ذکر نام متد WriteLine در سراسر برنامه کفایت می‌کند.


مفهوم جدید implicit global using directives در C# 10.0 و به کمک NET SDK 6.0.

تا اینجا دریافتیم که می‌توان دایرکتیوهای سراسری using را در برنامه به صورت دستی تعریف و استفاده کرد. اما ... پروژه‌ی کنسولی که به صورت پیش‌فرض توسط NET SDK 6.0. ایجاد می‌شود، به همراه هیچ global using ای نیست. این مورد توسط تنظیم زیر که جزئی از NET SDK 6.0. است، فعال می‌شود:
<ImplicitUsings>enable</ImplicitUsings>
زمانیکه ImplicitUsings را در فایل csproj برنامه فعال می‌کنیم، یعنی قرار است از یکسری global using‌های از پیش تعریف شده‌ی توسط SDK استفاده کنیم. بنابراین «global using directives» جزئی از ویژگی‌های جدید C# 10.0 است اما « implicit global using directives» تنها یک لطف ارائه شده‌ی توسط NET SDK. است. برای یافتن لیست آن‌ها، پروژه را build کرده و سپس به پوشه‌ی obj\Debug\net6.0 مراجعه کنید. در اینجا به دنبال فایلی مانند MyProjectName. GlobalUsings.g.cs بگردید. محتویات آن به صورت زیر است:
// <auto-generated/>
global using global::System;
global using global::System.Collections.Generic;
global using global::System.IO;
global using global::System.Linq;
global using global::System.Net.Http;
global using global::System.Threading;
global using global::System.Threading.Tasks;
این‌ها همان global using هایی هستند که با فعالسازی تنظیم ImplicitUsings در فایل csproj، به صورت خودکار توسط NET SDK. تولید و به برنامه الحاق می‌شوند.
البته این فایل ویژه به ازای نوع‌های پروژه‌های مختلف، محتوای متفاوتی را دارد. برای مثال در برنامه‌های ASP.NET Core، چنین محتوای پیش‌فرضی را پیدا می‌کند:
// <autogenerated />
global using global::System;
global using global::System.Collections.Generic;
global using global::System.IO;
global using global::System.Linq;
global using global::System.Net.Http;
global using global::System.Threading;
global using global::System.Threading.Tasks;
global using global::System.Net.Http.Json;
global using global::Microsoft.AspNetCore.Builder;
global using global::Microsoft.AspNetCore.Hosting;
global using global::Microsoft.AspNetCore.Http;
global using global::Microsoft.AspNetCore.Routing;
global using global::Microsoft.Extensions.Configuration;
global using global::Microsoft.Extensions.DependencyInjection;
global using global::Microsoft.Extensions.Hosting;
global using global::Microsoft.Extensions.Logging;
این تعاریف در اصل در پوشه‌ی C:\Program Files\dotnet\sdk\6.0.100-rc.2.21505.57\Sdks\Microsoft.NET.Sdk\targets و در فایل Microsoft.NET.GenerateGlobalUsings.targets آن قرار دارند.


روش حذف و یا اضافه‌ی global using‌های پیش‌فرض

اگر به هر دلیلی نمی‌خواهید تعدادی از global usingهای پیش‌فرض به همراه گزینه‌ی ImplicitUsings استفاده کنید، می‌توانید آن‌ها را در فایل csproj به صورت زیر، Remove و یا حتی موارد جدیدی را Include کنید:
<ItemGroup>
   <Import Remove="System.Threading" />
   <Import Include="Microsoft.Extensions.Logging" />
</ItemGroup>
یکی از کاربردهای این قابلیت، تولید کتابخانه‌های multi-target است که می‌توان توسط Conditionها، فضاهای نامی را که نباید برای target خاصی include کرد، مشخص نمود:
<ItemGroup Condition="'$(TargetFramework)' == 'net472'">
</ItemGroup>
مطالب
اشیاء context در ASP.NET
در asp.net  تعدادی اشیاء پایه، حاوی اطلاعات بسیار با ارزشی در خصوص درخواست جاری، application و پاسخی که ارسال می‌شود هستند و به صورت غیر مستقیم جهت دست‌یابی به قسمتهای مرکزی و هسته‌ای چهارچوب asp.net مانند security , stat data می‌توان این اشیاء را بکار گرفت.
بررسی این اشیاء از این جهت حائز اهمیت است که در کنترلر‌ها و ویوها می‌توان پاسخهای ارسالی به کلاینت‌ها را بر حسب شرایط مختلفی مانند درخواست رسیده یا حالت خاص دیگری تغییر داد. ضمن اینکه از این اشیاء در ماژول‌ها و هندلر‌ها نیز استفاده می‌شود. لذا قبل از پرداختن به مفاهیم مرتبط به ماژولها و هندلرها بهتر است این اشیاء بررسی شوند.

کلاس httpcontext هسته‌ی چهارچوب Asp.net است که خواص بسیار مهمی به شرح ذیل را فراهم می‌آورد:
Application : شیء HttpAplicationState را جهت مدیریت Application State Data بر می‌گرداند.
ApplicationInstance  : شیء HttpApplication مرتبط با درخواست جاری را بر می‌گرداند.
Cache : شیء Cache را جهت کش داده‌ها بر می‌گرداند.
Current : خصوصیت استاتیکی که شیء HttpContext درخواست جاری را بر می‌گرداند.
CurrentHandler : وهله‌ای از IHttpHandler را که محتویات درخواست جاری را تولید خواهد کرد،  بر می‌گرداند.
IsDebuggingEnabled : مقدار True یا False را بسته به اینکه Debug فعال باشد یا خیر بر می‌گرداند.
Items : یک Collection را که می‌تواند جهت انتقال State Data بین اجزاء مختلف فریم ورک که در پردازش یک درخواست همکاری می‌کنند، بر گرداند.
GetSection : قسمت خاصی از فایل Web.Config را بر می‌گرداند.
Request : شیء HttpRequest را که حاوی جزئیات درخواست پردازش شده است، بر می‌گرداند.
Response : شیء HttpResponse را بر می‌گرداند که حاوی جزئیات Response ای است که آماده ارسال به مرورگر است.
Session : برگرداننده‌ی شیء HttpSession است. این خاصیت قبل از وقوع رخداد PostAcquireRequestState مربوط به Application، مقدار null را خواهد داشت.
TimeStamp : شیء از نوع Datetime و معرف زمانی است که شیء HttpContext ایجاد شده‌است.
Trace : جهت ثبت اطلاعات تشخیصی به کار می‌رود.

در فایل global از طریق خاصیت Context به وهله‌ای از HttpContext دسترسی داریم. ولی این خاصیت فراگیر نبوده و در ویوها و کنترلر‌ها از طریق خاصیت HttpContext  در دسترس است که در کنترلر خاصیتی از کلاس پایه Controller و در ویو خاصیتی از کلاس پایه WebViewPage می‌باشد و در ماژول‌ها از طریق پارامتر ورودی متد Init در دسترس است‌.
در هندلر‌ها متد ProcessRequest وهله‌ای از شیء HttpContext را دریافت می‌کند.
به طور سراسری در هر نقطه‌ای از برنامه از طریق خاصیت استاتیک HttpContext.Current  به شیء HttpContext مرتبط با درخواست جاری دسترسی خواهیم داشت.
در کلاسهای مدل نیز از طریق خاصیت استاتیک یاد شده می‌توان به این شیء دسترسی داشت؛ ولی بهتر است اگر مدل نیاز به اطلاعاتی در خصوص یک Request داشت این اطلاعات از طریق اشیاء Context در کنترلر دریافت و به عنوان آرگومان به مدل ارسال شوند.
به صورت کلی، خلاصه‌ی مطالب فوق به صورت ذیل می‌باشد:

بخش مورد نظر 
روش دسترسی به اشیاء context
 Controller 
 از طریق خاصیت HttpContext
View 
خاصیت Context
Global Application Class خاصیت Context
Modules 
آرگومان متد Init
Handlers 
 آرگومان متد ProcessRequest
به صورت کلی از طریق خاصیت استاتیک HttpContext.Current


خواص ذکر شده‌ی در جدول فوق، همگی نوع یکسانی ندارند. در فایل  global و هندلر‌ها و ماژولها، دقیقا به همان HtpContext ای دسترسی داریم که قبلا با آن‌ها آشنا شدیم. این نوع از اشیاء (منظور خواص کلاس HttpContext) قبل از اینکه فریم ورک MVC، دست به کار مدیریت یک درخواست شود، کار خود را شروع می‌کنند که این امر کار آزمایش واحد را مشکل می‌کند. برای رفع این مشکل خواص مهیا در کنترلر و ویو وهله‌هایی از کلاسهای متفاوتی را برمی گردانند که از کلاس Context مشتق شده‌اند و ضمنا آزمایش واحد را به سادگی پشتیبانی می‌کنند(+ ) . خاصیت HttpContext کلاس Controller وهله‌ای از کلاس HttpContextBase را بر می‌گردانند. همه‌ی اشیاء context موجود در این کلاس، دارای پسوند Base هستند؛ مانند : HttpRequestBase, HttpResponseBase و...
اگر نیاز داشتید که یک شیء از نوع پسوند دار Base را از یک شیء فاقد این پسوند ایجاد کنید، برای مثال یک شیء HttpRequest دارید، ولی متدی دارید که آرگومان آن وهله‌ای از کلاس HttpRequestBase است، برای این کار کلاسهایی با پسوند Wrapper مانند HttpContextWrapper ,…  وجود دارند که از کلاسهایی با پسوند Base مشتق شده و در متد سازنده خود آرگومانی از کلاسهای اصلی فاقد پسوند Base را می‌گیرند.
ولی عکس آن امکان پذیر نیست و نمی‌توان کلاس با پسوند Base را به نوع اولیه برگرداند. ولی همان طور که گفتیم هر جایی که نیاز داشتیم، می‌توان از طریق خاصیت استاتیک System.Web.HTTPContext.Current به اشیاء Context اصلی دسترسی داشت.
بسیاری از کلاسهای فریم ورک Asp.Net دارای خاصیت‌هایی هستند که به خوااص کلاس HttpContext نگاشت شده‌اند. یکی از این نمونه‌ها کلاس HttpApplication است که کلاس پایه‌ی فایل global نیز هست. همان طور که در ذیل نیز می‌بینید، بسیاری از خواص و متدهای کلاس HttpApplication به نوعی مرتبط با اشیاء context هستند.

Application : به خاصیت HttpContext.Application نگاشت شده‌است که دسترسی به state data application را مهیا می‌سازد.
CompleteRequest : به چرخه حیات جاری خاتمه خاتمه داده و آن را مستقیما به رخداد LogRequest منتقل می‌کند.
Context : شیء HttpContext مرتبط با درخواست جاری را بر می‌گرداند.
Init : هر گاه متد Init یکی از ماژولهای ثبت شده در برنامه فراخوانی شود، این متد صدا زده خواهد شد.
Modules : یک شیء HttpModuleCollection را که حاوی جزئیات ماژولهای برنامه است، بر می‌گرداند.
RegisterModule(type: متد استاتیکی است که یک ماژول جدید را ثبت می‌کند.
Request : مقدار HttpContext.Request را برگشت می‌دهد و در صورتی که این مقدار null باشد، استثنایی رخ خواهد داد.
Response : مقدار HttpContext.Response را برگشت داده و در صورت null بودن این مقدار، استثنایی رخ می‌دهد.
Server : به خاصیت HttpContext.Server نگاشت شده است.
Session : مقدار HttpContext.Session را برگشت می‌دهد که در صورت null بودن این مقدار، استثنایی رخ خواهد داد.

در این مقاله با خواص کلاس HttpContext که اشیائی مهم و پرکاربرد بوده و حاوی اطلاعات بسیار سودمندی هستند، آشنا شدیم. ضمنا همان طور که در ابتدای مقاله گفته شد، از این اشیاء در ماژول‌ها و هندلرها استفاده‌ی زیادی می‌شود.
مطالب
مرور چند تجربه کوتاه با Microsoft virtual pc

از virtual pc که یک ویندوز اکس پی بر روی آن نصب کرده‌ام برای اتصال به VPN‌ استفاده می‌کنم. (متاسفانه آخرین نگارش vmware برای این‌کار جواب نداد)
زمان اتصال به VPN کل سیستم وارد شبکه مورد نظر خواهد شد و این مورد شاید به‌دلایلی برای مثال قطع اینترنت و یا اعمال پالیسی‌های شبکه بر روی کامپیوتر کاری جالب نباشد (استفاده از VPN برای اتصال به یک شبکه دومین ویندوزی). اما با نصب ماشین مجازی و اجرای یک سیستم عامل دیگر به موازات سیستم عامل اصلی، کار اتصال به VPN از داخل ماشین مجازی صورت خواهد گرفت و تمام این اعمال هم از سیستم عامل مادر مجزا و ایزوله خواهند بود.
یک ویندوز اکس پی با اختصاص 200 مگ رم هم کار می‌کند و عملا باری را بر روی سیستم عامل مادر تحمیل نخواهد کرد. همچنین حتما از منوی action گزینه install or update virtual machine additions را انتخاب کنید تا کارآیی سیستم عامل مجازی را بهبود بخشید. حداقل فایده آن این است که اشاره‌گر ماوس را به سادگی می‌توان از ماشین مجازی خارج کرد و هر بار نیازی به فشردن دکمه‌ ALT سمت راست نخواهد بود!
اولین مشکلی که هنگام کار با یک ماشین مجازی خود نمایی می‌کند بحث انتقال فایل بین سیستم عامل مادر (ویندوزی که شما ماشین مجازی را روی آن نصب کرده‌اید) و ماشین مجازی است. عمومی‌ترین راه، ایجاد یک فایل iso از فایل‌های مورد نظر است و سپس انتخاب منوی CD و گزینه capture iso image . این روش بر روی vmware هم جواب می‌دهد (معرفی فایل iso بعنوان CD-ROM آن). خوشبختانه عمل drag & drop (از سیستم عامل مادر به ماشین مجازی) که شاید در وحله اول به ذهن نرسد اینجا بخوبی کار خواهد کرد و مشکل ساخت فایل‌های iso را برطرف می‌کند. (البته vmware کمی پیشرفته‌تر است و حتی copy و Paste را نیز پشتیبانی می‌کند. اما خوب، رایگان نیست!)
مشکل بعدی با ms virtual pc افزایش تدریجی حجم آن است. روز اول 2 گیگ، روز سوم 4 گیگ، هفته بعد می‌شود 6 گیگ! برای فشرده سازی آن می‌توان به روش زیر عمل کرد:
به مسیر زیر مراجعه کنید: (اگر پیش‌فرض‌های نصب را پذیرفته‌اید)
C:\Program Files\Microsoft Virtual PC\Virtual Machine Additions
فایل Virtual Disk Precompactor.iso را از طریق منوی CD و گزینه capture iso image باز کنید. برنامه‌ای به صورت خودکار اجرا خواهد شد که سیستم عامل مجازی را آماده فشرده سازی می‌کند. پس از پایان کار، سیستم عامل مجازی را خاموش کنید. سپس به منوی file گزینه virtual disk wizard مراجعه نمائید. در صفحه بعدی گزینه ویرایش یک ماشین مجازی موجود را انتخاب کرده و فایل ماشین مجازی مورد نظر را که پیشتر برای فشرده سازی آماده کردیم به آن معرفی کنید. در صفحه بعد گزینه compact it را انتخاب کرده و در ادامه می‌توانید مسیر جدیدی را مشخص کنید یا انتخاب کنید که فایل نهایی فشرده شده جایگزین فایل موجود شود.
با اینکار یک ماشین مجازی 6 گیگابایتی به 3 گیگ کاهش حجم یافت که قابل توجه است.
برای استفاده از اینترنت سیستم عامل مادر در ms virtual pc می‌شود از منوی edit ، گزینه setting و انتخاب networking در صفحه ظاهر شده، تنظیم اولین adapter شبکه را بر روی shared networking NAT قرار داد و همه چیز به خوبی کار خواهد کرد. (البته برای استفاده از اینترنت در vmware باید روی کانکشن اینترنت خود در سیستم عامل مادر کلیک راست کرد و سپس انتخاب گزینه advanced و فعال سازی internet connection sharing بر روی کارت شبکه مجازی نصب شده آن ضروری خواهد بود)



مطالب
کارهایی جهت بالابردن کارآیی Entity Framework #3

در قسمت‌های قبلی (^ و ^) راهکارهایی جهت بالا بردن کارآیی، ارائه شد. در ادامه، به آخرین قسمت این سری اشاره خواهم کرد.

فراخوانی متد شناسایی تغییرات

یادآوری: قبل از هر چیز با توجه به این مقاله دانستن این نکته الزامی است که فراخوانی برخی متدها مانند DbSet.Add سبب فراخوانی DataContext.ChangeTracker.DetectChanges خواهند شد.

فرض کنید قصد افزودن 2000 موجودیت دانش آموز را دارید:

for (int i = 0; i < 2000; i++)
{
    Pupil pupil = GetNewPupil();
    db.Pupils.Add(pupil);
}
db.SaveChanges();
در کد بالا بدلیل فراخوانی متد DbSet.Add و به دنبال آن فراخوانی متد DetectChanges در هر بار اجرای حلقه (2000بار) مدت زمان اجرای کد بالا بسیار زیاد است و اگر به پروفایلر نگاهی بیاندازید، اشغال CPU توسط کوئری بالا، بیش از حد متعارف است.

اگر به تصویر بالا دقت کنید بیش از 34 ثانیه (خط 193 قسمت سوم شکل) جهت افزودن 2000 موجودیت به کانتکست سپری شده است. در حالی که درج این 2000 موجودیت کمی بیش از 1 ثانیه (خط 195 قسمت سوم شکل) که 379 میلی ثانیه (قسمت دوم شکل) آن مربوط به اجرای کوئری اختصاص یافته  طول کشیده است.
بیشترین زمان صرف شده‌ی برای درج 2000 موجودیت، در کد برنامه سپری شده است که با بررسی بیشتر در پروفایلر، متوجه زمان بر بودن فراخوانی متد ()DetectChanges که در فضای نام Data.Entity.Core وجود دارد خواهید شد. این متد 2000 بار به تعداد موجودیت هایی که قصد داریم به بانک اطلاعاتی اضافه نماییم، فراخوانی شده است.

همانطور که در شکل بالا مشخص است همان 34 ثانیه جهت ردیابی تغییرات صرف شده است. EF ردیابی تغییرات را بصورت پیش فرض هر زمانی که قصد افزودن یا ویرایش موجودیتی را داشته باشید، انجام خواهد داد و هر چه موجودیت‌های بیشتری را بخواهید ویرایش یا اضافه نمایید، این زمان نیز بیشتر خواهد شد. در حقیقت زمان لازم برای الگوریتم ردیابی تغییرات بصورت نمایی با رشد موجودیت‌ها افزوده می‌شود. به عبارت دیگر اگر این تعداد موجودیت‌ها را به 4000 عدد برسانید، مدت زمان لازم بیش از 2 برابر افزوده خواهد شد.

راه حل اول:
استفاده از متد ()AddRange ارائه شده در EF6 که جهت درج دسته‌ای (Bulk Insert) ارائه شده است:
var list = new List<Pupil>();

for (int i = 0; i < 2000; i++)
{
    Pupil pupil = GetNewPupil();
    list.Add(pupil);
}

db.Pupils.AddRange(list);
db.SaveChanges();

راه حل دوم:

در سناریوهای پیچیده، مانند درج دسته‌ای چندین موجودیت، شاید مجبور به خاموش نمودن این قابلیت شوید:
db.Configuration.AutoDetectChangesEnabled = false;
توجه داشته باشید اگر قصد دارید از امکان ردیابی تغییرات مجددا بهره‌مند شوید، باید این قابلیت را نیز فعال نمایید. با خاموش نمودن ردیابی تغییرات بار دیگر کوئری ابتدایی را اجرا نمایید. مدت زمان لازم جهت افزودن 2000 موجودیت به کانتکست از بیش از 34 ثانیه به 85 میلی ثانیه کاهش یافته است؛ ولی اعمال تغییرات به بانک اطلاعاتی همانند مرتبه اول بیش از 1 ثانیه طول خواهد کشید.


ردیابی تغییرات

هنگامی که موجودیتی را از بانک اطلاعاتی دریافت نمایید، می‌توانید آن را ویرایش نمایید و مجددا به بانک اطلاعاتی اعمال نمایید. چون EF اطلاعی از قصد شما برای موجودیت نمی‌داند، مجبور است تغییرات شما را زیر نظر بگیرد که این زیر نظر گرفتن، هزینه و سربار دارد و این سربار و هزینه برای داده‌های زیاد، بیشتر خواهد شد. بنابراین اگر قصد دارید اطلاعاتی فقط خواندنی را از بانک اطلاعاتی دریافت نمایید، بهتر است صراحتا به EF بگویید این موجودیت را تحت ردیابی قرار ندهد.
string city = "New York";

List<School> schools = db.Schools
    .AsNoTracking()
    .Where(s => s.City == city)
    .Take(100)
    .ToList();

استفاده از متد AsNoTracking  در کد بالا سبب خواهد شد 100 مدرسه که در شهر نیویورک وجود دارد توسط EF، بدون تحت نظر گرفتن آن‌ها از بانک اطلاعاتی دریافت شوند و سرباری نیز تحمیل نشود.

ویوهای از قبل کامپایل شده

معمولا، هنگامی که از EF برای اولین بار استفاده می‌نمایید، ویوهایی ایجاد می‌گردد که برای ایجاد کوئری‌ها مورد استفاده قرار می‌گیرند. این ویوها در طول حیات برنامه فقط یکبار ایجاد می‌شوند. ولی همین یکبار هم زمانبر هستند. خوشبختانه راه‌هایی وجود دارد که ایجاد این ویوها را در زمان runtime انجام نداد و آن راه، استفاده از ویوهای از پیش کامپایل شده است. یکی از راههای ایجاد این ویوها استفاده از Entity Framework Power Tools است. بعد از نصب اکستنشن، بر روی فایل کانتکست راست کلیک کرده و سپس گزینه‌ی Generate Views را از منوی Entity Framework انتخاب کنید.

توجه داشته باشید که هر تغییری را بعد از ایجاد این ویوها بر روی کانتکست اعمال نمایید، باید آن‌ها را مجددا تولید کنید. برای آشنایی بیشتر با این ویوها به این لینک مراجعه کنید. هم چنین پکیج نیوگتی بنام EFInteractiveViews نیز برای این منظور تهیه و توزیع شده است.


حذف کوئری‌های ابتدایی غیر ضروری

در هنگام شروع به کار با EF، چندین کوئری آغازین بر روی دیتابیس اجرا می‌شوند. یکی از کوئری‌های آغازین جهت تشخیص نسخه‌ی دیتابیس است که همانطور در تصویر زیر مشاهده می‌کنید، در حدود چند میلی ثانیه می‌باشد.

با توجه به توضیحات، در صورتیکه اطلاعی از نسخه‌ی دیتابیس دارید، می‌توانید این کوئری ابتدایی را تحریف نمایید. برای اینکار می‌توان توسط متد ()ResolveManifestToken کلاسی که اینترفیس IManifestTokenResolver را پیاده سازی کرده است، نسخه‌ی دیتابیس را برگردانیم و از یک رفت و برگشت به دیتابیس جلوگیری نماییم.

 public class CustomManifestTokenResolver : IManifestTokenResolver
{
    public string ResolveManifestToken(DbConnection connection)
    {
        return "2014";
    }
}
و توسط کلاسی که از کلاس DbConfiguration ارث بری کرده است آن را استفاده نماییم.
 public class CustomDbConfiguration : DbConfiguration
{
    public CustomDbConfiguration()
    {
        SetManifestTokenResolver(new CustomManifestTokenResolver());
    }
}


تخریب کانتکست

تخریب و از بین بردن کانتکست هنگامی که به آن نیاز نداریم بسیار ضروری است. یکی از روشهای اصولی برای Disposing کانتکست، محصور کردن آن بوسیله دستور Using است (البته فرض بر این است که قرار نیست از الگوهای اشاره شده استفاده نماییم). در صورت عدم تخریب صحیح کانتکست باید منتظر آسیب جدی به کارایی Garbage Collector جهت آزاد سازی منابع مورد استفاده کانتکست و هم چنین باز نمودن اتصالات جدید به دیتابیس باشید.


پاسخگویی به چندین درخواست بر روی یک کانکشن

EF از قابلیتی بنام Multiple Result Sets می‌تواند بهره ببرد که این قابلیت باعث می‌شود بر روی یک کانکشن ایجاد شده، یک یا چند درخواست از دیتابیس ارسال و یا دریافت شود که سبب کاهش تعداد رفت و برگشت به دیتابیس می‌شود. کاربرد دیگر این قابلیت، زمانی است که تاخیر زیادی (latency) بین اپلیکیشن و دیتابیس وجود دارد.

برای فعالسازی کافی است مقدار زیر را در کانکشن استرینگ اضافه نمایید:

MultipleActiveResultSets=True;


استفاده از متدهای ناهمگام

در C#5 و EF6 پشتیبانی خوبی از متدهای ناهمگام فراهم شده است و اکثر متدهایی مانند ToListAsync, CountAsync, FirstAsync, SaveChangesAsync و غیره که باعث رفت و برگشت به دیتابیس می‌شوند امکان پشتیبانی ناهمگام را نیز دارند. البته این قابلیت برای برنامه‌های یک درخواست در یک زمان شاید مفید نباشد؛ ولی برای برنامه‌های وبی برعکس. در برنامه وب جهت پشتیبانی از بارگذاری همزمان (concurrent) قابلیت ناهمگام (Async) سبب خواهد شد منابع تا زمان اجرای کوئری به ThreadPool بازگردانده شود و برای سرویس دهی مهیا باشند که باعث افزایش scalability خواهد شد.

بررسی و آزمایش با داده‌های واقعی

در اکثر مواقع کارآیی با حجیم شدن داده‌ها کاهش پیدا می‌کند (البته در صورت عدم رعایت اصول استاندارد). بنابراین بررسی کارآیی در محیط هایی با حجم داده‌های بالا ضروری است. هیچ چیز بدتر از آن نیست که همه چیز در محیط توسعه خوب و بی نقص باشد ولی در محیط عملیاتی به شکست بیانجامد. به همین جهت سعی کنید از ابزارهای تولید داده (^ و ^ و ^) برای ایجاد داده‌های آزمایشی استفاده نمایید. سپس کارآیی کوئری خود را مورد بررسی و آزمایش قرار دهید.

مطالب
آشنایی با Saltarelle کامپایلر قدرتمند #C به جاوااسکریپت

شاید ساده‌ترین تعریف برای  Saltarelle  این باشد که «کامپایلریست که کد‌های C# را به جاوا اسکریپت تبدیل می‌کند». محاسن زیادی را می‌توان برای اینگونه کامپایلر‌ها نام برد؛ مخصوصا در پروژه‌های سازمانی که نگهداری از کد‌های جاوا اسکریپت بسیار سخت و گاهی خارج از توان است و این شاید مهمترین عامل ظهور ابزارهای جدید از قبیل Typescript باشد.

در هر صورت اگر حوصله و وقت کافی برای تجهیز تیم نرم افزاری، به دانش یک زبان جدید مانند Typescript نباشد، استفاده از توان و دانش تیم تولید، از زبان C# ساده‌ترین راه حل است و اگر ابزاری مطمئن برای استفاده از حداکثر قدرت JavaScript همراه با امکانات نگهداری و توسعه کد‌ها وجود داشته باشد، بی شک Saltarelle یکی از بهترین‌های آنهاست.

قبلا کامپایلر هایی از این دست مانند  Script# وجود داشتند، اما فاقد همه امکانات C# بوده وعملا قدرت کامل C# در کد نویسی وجود نداشت. اما با توجه به ادعای توسعه دهندگان این کامپایلر سورس باز در استفاده‌ی حداکثری از کلیه ویژگی‌های C# 5 و با وجود Library ‌های متعدد می‌توان Saltarelle  را عملا یک کامپایلر موفق در این زمینه دانست.

برای استفاده از Saltarelle در یک برنامه وب ساده باید یک پروژه Console Application به Solution اضافه کرد و پکیج Saltarelle.Compiler را از nuget نصب نمایید. بعد از نصب این پکیج، کلیه Reference ‌ها از پروژه حدف می‌شوند و هر بار Build توسط کامپایلر Saltarelle  انجام می‌شود. البته با اولین Build، مقداری Error را خواهید دید که برای از بین بردنشان نیاز است پکیج Saltarelle.Runtime را نیز در این پروژه نصب نمایید:

PM> Install-Package Saltarelle.Compiler
PM> Install-Package Saltarelle.Runtime

در صورتیکه کماکان Build  نهایی با Error همرا بود، یکبار این پروژه را Unload  و سپس مجددا Load نمایید



UI یک پروژه وب MVC است و Client یک Console Application که پکیج‌های مورد نیاز Saltarelle  روی آن نصب شده است.

در صورتیکه پروژه را Build نماییم و نگاهی به پوشه‌ی Debug بیاندازیم، یک فایل JavaScript همنام پروژه وجود دارد:


برای اینکه بعد از هر بار Build ، فایل اسکریپت به پوشه‌ی مربوطه در پروژه UI منتقل شود کافیست کد زیر را در Post Build  پروژه Client بنویسیم: 

copy "$(TargetDir)$(TargetName).js" "$(SolutionDir)SalratelleSample.UI\Scripts"

اکنون پس از هر بار Build ، فایل اسکریپت مورد نظر در پوشه‌ی Scripts پروژه UI  آپدیت می‌شود:


در ادامه کافیست فایل اسکریپت را به layout اضافه کنیم. 

<script src="~/Scripts/SaltarelleSample.Client.js"></script>

در پوشه‌ی Saltarelle.Runtime در پکیج‌های نصب شده، یک فایل اسکریپت به نام mscorlib.min.js نیز وجود دارد که حاوی اسکریپت‌های مورد نیاز Saltarelle در هنگام اجراست. آن را به پوشه اسکریپت‌های پروژه UI کپی نمایید و سپس به Layout  اضافه کنید. 

<script src="~/Scripts/mscorlib.min.js"></script>
<script src="~/Scripts/SaltarelleSample.Client.js"></script>

حال نوبت به اضافه نمودن library‌های مورد نیازمان است. برای دسترسی به آبجکت هایی از قبیل document, window, element و غیره در جاوااسکریپت می‌توان پکیج Saltarelle.Web را در پروژه‌ی Client نصب نمود و برای دسترسی به اشیاء و فرمانهای jQuery، پکیج Salratelle.jQuery را نصب نمایید. 

> Install-Package Saltarelle.Web
> Install-Package Saltarelle.jQuery

به این library‌ها imported library می‌گویند. در واقع، در زمان کامپایل، برای این library‌ها فایل اسکریپتی تولید نمی‌شود و فقط آبجکت‌های #C هستند که که هنگام کامپایل تبدیل به کدهای ساده اسکریپت می‌شوند که اگر اسکریپت مربوط به آنها به صفحه اضافه نشده باشد، اجرای اسکریپت با خطا مواجه می‌شود.

به طور ساده‌تر وقتی از jQuery library استفاده می‌کنید هیچ فایل اسکریپت اضافه‌ای تولید نمی‌شود، اما باید اسکریپت jQuery به صفحه شما اضافه شده باشد.

<script src="~/Scripts/jquery-1.10.2.min.js"></script>

مثال ما یک اپلیکیشن ساده برای خواندن فید‌های همین سایت است. ابتدا کد‌های سمت سرور را در پروژه UI  می نویسیم.

کلاس‌های مورد نیاز ما برای این فید ریدر: 

public class Feed
    {
        public string FeedId { get; set; }
        public string Title { get; set; }
        public string Address { get; set; }

    }
    public class Item
    {
        public string Title { get; set; }
        public string Link { get; set; }
        public string Description { get; set; }
    }

و یک کلاس برای مدیریت منطق برنامه 

 public class SiteManager
    {
        private static List<Feed> _feeds;
        public static List<Feed> Feeds
        {
            get
            {
                if (_feeds == null)
                    _feeds = CreateSites();
                return _feeds;
            }
        }
        private static List<Feed> CreateSites()
        {
            return new List<Feed>() { 
                new Feed(){
                    FeedId = "1",
                    Title = "آخرین تغییرات سایت",
                    Address = "https://www.dntips.ir/rss.xml"
                },
                 new Feed(){
                    FeedId = "2",
                    Title = "مطالب سایت",
                    Address = "https://www.dntips.ir/feeds/posts"
                },
                 new Feed(){
                    FeedId = "3",
                    Title = "نظرات سایت",
                    Address = "https://www.dntips.ir/feeds/comments"
                },
                 new Feed(){
                    FeedId = "4",
                    Title = "خلاصه اشتراک ها",
                    Address = "https://www.dntips.ir/feed/news"
                },
            };
        }

        public static IEnumerable<Item> GetNews(string id)
        {
            XDocument feedXML = XDocument.Load(Feeds.Find(s=> s.FeedId == id).Address);
            var feeds = from feed in feedXML.Descendants("item")
                        select new Item
                        {
                            Title = feed.Element("title").Value,
                            Link = feed.Element("link").Value,
                            Description = feed.Element("description").Value
                        };
            return feeds;
        }

    }

کلاس SiteManager فقط یک لیست از فید‌ها دارد و متدی که با گرفتن شناسه‌ی فید ، یک لیست از آیتم‌های موجود در آن فید ایجاد می‌کند.

حال دو ApiController برای دریافت داده‌ها ایجاد می‌کنیم

public class FeedController : ApiController  
{
        // GET api/<controller>
        public IEnumerable<Feed> Get()
        {
            return SiteManager.Feeds;
        }
    }

public class ItemsController : ApiController
    {
        // GET api/<controller>/5
        public IEnumerable<Item> Get(string id)
        {
            return SiteManager.GetNews(id);
        }
    }

در View پیش‌فرض که Index از کنترلر Home  است،  یک Html ساده برای فرم  صفحه اضافه می‌کنیم 

<div>
    <div>
        <h2>Feeds</h2>
        <ul id="Feeds">
           
        </ul>
    </div>
    <div>
        <h2>Items</h2>
        <p id="FeedItems">
        </p>
    </div>
   
</div>

در المنت Feeds لیست فید‌ها را قرار می‌دهیم و در FeedItems آیتم‌های مربوط به هر فید. حال به سراغ کد‌های سمت کلاینت می‌رویم و به جای جاوا اسکریپت از Saltarelle استفاده می‌کنیم.

کلاس Program را از پروژه Client باز می‌کنیم و متد Main را به شکل زیر تغییر می‌دهیم:

static void Main()
        {
            jQuery.OnDocumentReady(() => {
                FillFeeds();
            });
        }

بعد از کامپایل شدن، کد #C شارپ بالا به صورت زیر در می‌آید: 

$SaltarelleSample_Client_$Program.$main = function() {
$(function() {
$SaltarelleSample_Client_$Program.$fillFeeds();
});
};
$SaltarelleSample_Client_$Program.$main();

و این همان متد معروف jQuery است که Saltarelle.jQuery برایمان ایجاد کرده است.

متد FillFeeds را به شکل زیر پیاده سازی می‌کنیم

private static void FillFeeds()
        {
            jQuery.Ajax(new jQueryAjaxOptions()
            {
                Url = "/api/feed",
                Type = "GET",
                Success = (d,t,r) => {

                    // Fill 
                    var ul = jQuery.Select("#Feeds");
                    jQuery.Each((List<Feed>)d, (idx,i) => {
                        var li = jQuery.Select("<li>").Text(i.Title).CSS("cursor", "pointer");
                        li.Click(eve => {
                            FillData(i.FeedId);
                        });
                        ul.Append(li);
                    });
                }
            });
        }

آبجکت jQuery، متدی به نام Ajax دارد که یک شی از کلاس jQueryAjaxOptions را به عنوان پارامتر می‌پذیرد. این کلاس کلیه خصوصیات متد Ajax در jQuery را پیاده سازی می‌کند. نکته شیرین آن توانایی نوشتن lambda برای Delegate هاست.

خاصیت Success یک Delegate است که 3 پارامتر ورودی را می‌پذیرد.

public delegate void AjaxRequestCallback(object data, string textStatus, jQueryXmlHttpRequest request);

data همان مقداریست که api باز می‌گرداند که یک لیست از Feed هاست. برای زیبایی کار، من یک کلاس Feed در پروژه Client اضافه می‌کنم که خصوصیاتی مشترک با کلاس اصلی سمت سرور دارد و مقدار برگشی Ajax را به آن تبدیل می‌کنم.

کلاس Feed و Item

 [PreserveMemberCase()]
    public class Feed
    {
        //[ScriptName("FeedId")]
        public string FeedId;

        //[ScriptName("Title")]
        public string Title;

        //[ScriptName("Address")]
        public string Address;

    }

    [PreserveMemberCase()]
    public class Item
    {
        // [ScriptName("Title")]
        public string Title;

        // [ScriptName("Link")]
        public string Link;

        // [ScriptName("Description")]
        public string Description;
    }
Attrubute‌های زیادی در Saltarelle وجود دارند و از آنجایی که کامپایلر اسم فیلد‌ها را camelCase کامپایل می‌کند من برای جلوگیری از آن از PreserveMemberCase  بر روی هر کلاس استفاده کردم. می‌توانید اسم هر فیلد را سفارشی کامپایل نمایید. 
jQuery.Each((List<Feed>)d, (idx,i) => {
                        var li = jQuery.Select("<li>").Text(i.Title).CSS("cursor", "pointer");
                        li.Click(eve => {
                            FillData(i.FeedId);
                        });
                        ul.Append(li);
                    });

به ازای هر آیتمی که در شیء بازگشتی وجود دارد، با استفاد از متد each در jQuery یک li ایجاد می‌کنیم. همان طور که می‌بینید کلیه خواص، به شکل Fluent قابل اضافه شدن می‌باشد. سپس برای li یک رویداد کلیک که در صورت وقوع، متد FillData را با شناسه فید کلیک شده فراخوانی می‌کند و در آخر li را به المنت ul اضافه می‌کنیم.

برای هر کلیک هم مانند مثال بالا api را با شناسه‌ی فید مربوطه فراخوانی کرده و به ازای هر آیتم، یک سطر ایجاد می‌کنیم.

private static void FillData(string p)
        {
            jQuery.Ajax(new jQueryAjaxOptions()
            {
                Url = "/api/items/" + p,
                Type = "GET",
                Success = (d, t, r) => {
                    var content = jQuery.Select("#FeedItems");
                    content.Html("");
                    foreach (var item in (List<Item>)d)
                    {
                        var row = jQuery.Select("<div>").AddClass("row").CSS("direction", "rtl");
                        var link = jQuery.Select("<a>").Attribute("href", item.Link).Text(item.Title);
                        row.Append(link);
                        content.Append(row);
                    }
                }
            });
        }
خروجی برنامه به شکل زیر است: 

در این مثال ما از Saltarelle.jQuery برای استفاده از jQuery.js استفاده نمودیم. library‌های متعددی برای Saltarelle  از قبیل  linq,angular,knockout,jQueryUI,nodeJs ایجاد شده و همچنین قابلیت‌های زیادی برای نوشتن imported library‌های سفارشی نیز وجود دارد. 

مطمئنا استفاده از چنین کامپایلرهایی راه حلی سریع برای رهایی از مشکلات متعدد کد نویسی با جاوا اسکریپت در نرم افزارهای بزرگ مقیاس است. اما مقایسه آنها با ابزارهایی از قبیل typescript احتیاج به زمان و تجربه کافی در این زمینه دارد.

مطالب
آموزش LightInject IoC Container - قسمت 1
LightInject در حال حاضر یکی از قدرتمند‌ترین IoC Container‌‌ها است که از لحاظ سرعت و کارآیی در بالاترین جایگاه در میان IoC Container‌‌های موجود قرار دارد. جهت بررسی کارایی IoC Container‌ها می‌توانید به این لینک مراجعه کنید . LightInject یک IoC Container فوق العاده سبک وزن می‌باشد که تمامی قابلیت‌های متداولی که از یک Service Container انتظار می‌رود را شامل می‌شود. تنها شامل یک فایل .cs می‌باشد که تمامی کدهای آن در همین یک فایل نوشته شده‌اند. در پروژه‌های کوچک تا بزرگ بدون از دست دادن کارآیی، با بالاترین سرعت ممکن عمل تزریق وابستگی را انجام می‌دهد. در این مجموعه مقالات به بررسی کامل این IoC Container می‌پردازیم و تمامی قابلیت‌های آن را آموزش می‌دهیم.

نحوه نصب و راه اندازی LightInject
در پنجره Package Manager Console می‌توانید با نوشتن دستور ذیل، نسخه باینری آن را نصب کنید که به فایل .dll آن Reference میدهد.

PM> Install-Package LightInject
 همچنین می‌توانید توسط دستور ذیل فایل .cs آن را به پروژه اضافه نمایید. 

PM> Install-Package LightInject.Source

 آماده سازی پروژه نمونه 
قبل از شروع کار با LightInject، یک پروژه Windows Forms Application را با ساختار کلاس‌های ذیل ایجاد نمایید. (در مقالات بعدی و پس از آموزش کامل LightInject نحوه استفاده از آن را در ASP.NET MVC نیز آموزش می‌دهیم)
    public class PersonModel
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Family { get; set; }
        public DateTime Birth { get; set; }
    }

    public interface IRepository<T> where T:class
    {
        void Insert(T entity);
        IEnumerable<T> FindAll();
    }

    public interface IPersonRepository:IRepository<PersonModel>
    {
    }

    public class PersonRepository:IPersonRepository
    {
        public void Insert(PersonModel entity)
        {
            throw new NotImplementedException();
        }

        public IEnumerable<PersonModel> FindAll()
        {
            throw new NotImplementedException();
        }
    }

    public interface IPersonService
    {
        void Insert(PersonModel entity);
        IEnumerable<PersonModel> FindAll();
    }

    public class PersonService:IPersonService
    {
        private readonly IPersonRepository _personRepository;

        public PersonService(IPersonRepository personRepository)
        {
            _personRepository = personRepository;
        }

        public void Insert(PersonModel entity)
        {
            _personRepository.Insert(entity);
        }

        public IEnumerable<PersonModel> FindAll()
        {
            return _personRepository.FindAll();
        }
    }
توضیحات
PersonModel: ساختار داده ای جدول Person در سمت Application، که در لایه Domain Model ایجاد می‌گردد.
توجه: جهت سهولت تست و تسریع کدنویسی از لایه بندی و از کلاس‌های ViewModel استفاده نکردیم.
IRepository: یک Interface عمومی برای تمامی Interface‌های مربوط به Repository که عملیات مربوط به پایگاه داده مثل بروزرسانی و واکشی اطلاعات را انجام می‌دهند.
IPersonRepository: واسط بین لایه Service و لایه Repository می‌باشد.
PersonRepository: پیاده سازی واقعی عملیات مربوط به پایگاه داده برای PersonModel می‌باشد. به کلاسهایی که حاوی پیاده سازی واقعی کد می‌باشند Concrete Class می‌گویند.
IPersonService: واسط بین رابط کاربری و لایه سرویس می‌باشد. رابط کاربری به جای دسترسی مستقیم به PersonService از IPersonService استفاده می‌کند.
PersonService: دریافت درخواست‌های رابط کاربری و بررسی قوانین تجاری، سپس ارسال درخواست به لایه Repository در صورت صحت درخواست، و در نهایت ارسال پاسخ دریافتی به رابط کاربری. در واقع واسطی بین Repository و UI می‌باشد.
پس از ایجاد ساختار فوق کد مربوط به Form1 را بصورت زیر تغییر دهید.
public partial class Form1 : Form
    {
        private readonly IPersonService _personService;
        public Form1(IPersonService personService)
        {
            _personService = personService;
            InitializeComponent();
        }
    }
توضیحات
در کد فوق به منظور ارتباط با سرویس از IPersonService استفاده نمودیم که به عنوان پارامتر ورودی برای سازنده Form1 تعریف شده است. حتما با Dependency Inversion و انواع Dependency Injection آشنا هستید که به سراغ مطالعه این مقاله آمدید و علت این نوع کدنویسی را هم می‌دانید. بنابراین توضیح بیشتری در این مورد نمی‌دهم.
حال اگر برنامه را اجرا کنید در Program.cs با خطای عدم وجود سازنده بدون پارامتر برای Form1 مواجه می‌شوید که کد آن را باید به صورت زیر تغییر می‌دهیم.
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            var container = new ServiceContainer();
            container.Register<IPersonService, PersonService>();
            container.Register<IPersonRepository, PersonRepository>();
            Application.Run(new Form1(container.GetInstance<IPersonService>()));
        }
توضیحات
کلاس ServiceContainer وظیفه‌ی Register کردن یک کلاس را برای یک Interface دارد. زمانی که می‌خواهیم Form1 را نمونه سازی نماییم و Application را راه اندازی کنیم، باید نمونه ای را از جنس IPersonService ایجاد نموده و به سازنده‌ی Form1 ارسال نماییم. با رعایت اصل DIP، نمونه سازی واقعی یک کلاس لایه دیگر، نباید در داخل کلاس‌های لایه جاری انجام شود. برای این منظور از شیء container استفاده نمودیم و توسط متد GetInstance، نمونه‌ای از جنس IPersonService را ایجاد نموده و به Form1 پاس دادیم. حال container از کجا متوجه می‌شود که چه کلاسی را برای IPersonService نمونه سازی نماید؟
در خطوط قبلی توسط متد Register، کلاس PersonService را برای IPersonService ثبت نمودیم. container نیز برای نمونه سازی به کلاس هایی که برایش Register نمودیم مراجعه می‌نماید و نمونه سازی را انجام می‌دهد. جهت استفاده از PersonService به پارامتر ورودی IPersonRepository برای سازنده‌ی آن نیاز داریم که کلاس PersonRepository را برای IPersonRepository ثبت کردیم.
حال اگر برنامه را اجرا کنید، به درستی اجرا خواهد شد. برنامه را متوقف کنید و به کد موجود در Program.cs مراجعه نموده و دو خط مربوط به Register را Comment نمایید. سپس برنامه را اجرا کنید و خطای تولید شده را ببینید. این خطا بیان می‌کند که امکان نمونه سازی برای IPersonService را ندارد. چون قبلا هیچ کلاسی را برای آن Register نکرده ایم.
Named Services
در برخی مواقع، بیش از یک کلاس وجود دارند که ممکن است از یک Interface ارث بری نمایند. در این حالت و در زمان Register، باید به ServiceContainer بگوییم که کدام کلاس را باید نمونه سازی نماید. برای بررسی این موضوع، کلاسهای زیر را به ساختار پروژه اضافه نمایید.
    public class WorkerModel:PersonModel
    {
        public ManagerModel Manager { get; set; }
    }

    public class ManagerModel:PersonModel
    {
        public IEnumerable<WorkerModel> Workers { get; set; }
    }

    public class WorkerRepository:IPersonRepository
    {
        public void Insert(PersonModel entity)
        {
            throw new NotImplementedException();
        }

        public IEnumerable<PersonModel> FindAll()
        {
            throw new NotImplementedException();
        }
    }

    public class ManagerRepository:IPersonRepository
    {
        public void Insert(PersonModel entity)
        {
            throw new NotImplementedException();
        }

        public IEnumerable<PersonModel> FindAll()
        {
            throw new NotImplementedException();
        }
    }

    public class WorkerService:IPersonService
    {
        private readonly IPersonRepository _personRepository;

        public WorkerService(IPersonRepository personRepository)
        {
            _personRepository = personRepository;
        }

        public void Insert(PersonModel entity)
        {
            var worker = entity as WorkerModel;
            _personRepository.Insert(worker);
        }

        public IEnumerable<PersonModel> FindAll()
        {
            return _personRepository.FindAll();
        }
    }

    public class ManagerService:IPersonService
    {
        private readonly IPersonRepository _personRepository;

        public ManagerService(IPersonRepository personRepository)
        {
            _personRepository = personRepository;
        }

        public void Insert(PersonModel entity)
        {
            var manager = entity as ManagerModel;
            _personRepository.Insert(manager);
        }

        public IEnumerable<PersonModel> FindAll()
        {
            return _personRepository.FindAll();
        }
    }
توضیحات
دو کلاس Manager و Worker به همراه سرویس‌ها و Repository هایشان اضافه شده اند که از IPersonService و IPersonRepository مشتق شده اند.
حال کد کلاس Program را به صورت زیر تغییر می‌دهیم
...
 var container = new ServiceContainer();
            container.Register<IPersonService, PersonService>();
            container.Register<IPersonService, WorkerService>();
            container.Register<IPersonRepository, PersonRepository>();
            container.Register<IPersonRepository, WorkerRepository>();
            Application.Run(new Form1(container.GetInstance<IPersonService>()));
توضیحات
در کد فوق، چون WorkerService بعد از PersonService ثبت یا Register شده است، LightInject در زمان ارسال پارامتر به Form1، نمونه ای از کلاس WorkerService را ایجاد میکند. اما اگر بخواهیم از کلاس PersonService نمونه سازی نماید باید کد را به صورت زیر تغییر دهیم.
...
            container.Register<IPersonService, PersonService>("PersonService");
            container.Register<IPersonService, WorkerService>();
            container.Register<IPersonRepository, PersonRepository>();
            container.Register<IPersonRepository, WorkerRepository>();
            Application.Run(new Form1(container.GetInstance<IPersonService>("PersonService")));
همانطور که مشاهده می‌نمایید، در زمان Register نامی را به آن اختصاص دادیم که در زمان نمونه سازی از این نام استفاده شده است.
اگر در زمان ثبت، نامی را به نمونه‌ی مورد نظر اختصاص داده باشیم، و فقط یک Register برای آن Interface معرفی نموده باشیم، در زمان نمونه سازی، LightInject آن نمونه را به عنوان سرویس پیش فرض در نظر می‌گیرد.
  container.Register<IPersonService, PersonService>("PersonService");
  Application.Run(new Form1(container.GetInstance<IPersonService>()));
در کد فوق، چون برای IPersonService فقط یک کلاس برای نمونه سازی معرفی شده است، با فراخوانی متد GetInstance، حتی بدون ذکر نام، نمونه ای را از کلاس PersonService ایجاد می‌کند.
IEnumerable<T>
زمانی که چند کلاس را که از یک Interface مشتق شده اند، با هم Register می‌نمایید، LightInject این قابلیت را دارد که این کلاس‌های Register شده را در قالب یک لیست شمارشی برگردانید.
            container.Register<IPersonService, PersonService>();
            container.Register<IPersonService, WorkerService>("WorkerService");
            var personList = container.GetInstance<IEnumerable<IPersonService>>();
در کد فوق لیستی با دو آیتم ایجاد می‌شود که یک آیتم از نوع PersonService و دیگری از نوع WorkerService می‌باشد. همچنین از کد زیر نیز می‌توانید استفاده کنید:
            container.Register<IPersonService, PersonService>();
            container.Register<IPersonService, WorkerService>("WorkerService");
            var personList = container.GetAllInstances<IPersonService>();
به جای متد GetInstance از متد GetAllInstances استفاده شده است.
LightInject از Collection‌های زیر نیز پشتیبانی می‌نماید:
  • Array
  • ICollection<T>
  • IList<T>
  • IReadOnlyCollection<T>
  • IReadOnlyList<T>
Values
توسط LightInject می‌توانید مقادیر ثابت را نیز تعریف کنید
            container.RegisterInstance<string>("SomeValue");
            var value = container.GetInstance<string>();
متغیر value با رشته "SomeValue" مقداردهی می‌گردد. اگر چندین ثابت رشته ای داشته باشید می‌توانید نام جداگانه ای را به هر کدام اختصاص دهید و در زمان فراخوانی مقدار به آن نام اشاره کنید.
            container.RegisterInstance<string>("SomeValue","String1");
            container.RegisterInstance<string>("OtherValue","String2");
            var value = container.GetInstance<string>("String2");
متغیر value با رشته "OtherValue" مقداردهی می‌گردد.