مطالب دوره‌ها
استفاده از IL Code Weaving برای تولید ویژگی‌های تکراری مورد نیاز در WCF
با استفاده از IL Code Weaving علاوه بر مدیریت اعمال تکراری پراکنده در سراسر برنامه مانند ثبت وقایع، مدیریت استثناءها، کش کردن داده‌ها و غیره، می‌توان قابلیتی را به کدهای موجود نیز افزود. برای مثال یک برنامه معمول WCF را درنظر بگیرید.
using System.Runtime.Serialization;

namespace AOP03.DataContracts
{
    [DataContract]
    public class User
    {
        [DataMember]
        public int Id { set; get; }

        [DataMember]
        public string Name { set; get; }
    }
}
نیاز است کلاس‌ها و خواص آن توسط ویژگی‌های DataContract و DataMember مزین شوند. در این بین نیز اگر یکی فراموش گردد، کار دیباگ برنامه مشکل خواهد شد و در کل حجم بالایی از کدهای تکراری در اینجا باید در مورد تمام کلاس‌های مورد نیاز انجام شود. در ادامه قصد داریم تولید این ویژگی‌ها را توسط PostSharp انجام دهیم. به عبارتی یک پوشه خاص به نام DataContracts را ایجاد کرده و کلاس‌های خود را به نحوی متداول و بدون اعمال ویژگی خاصی تعریف کنیم. در ادامه پس از کامپایل آن، به صورت خودکار با ویرایش کدهای IL توسط PostSharp، ویژگی‌های لازم را به اسمبلی نهایی اضافه نمائیم.


تهیه DataContractAspect جهت اعمال خودکار ویژگی‌های DataContract و DataMember

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;
using PostSharp.Aspects;
using PostSharp.Extensibility;
using PostSharp.Reflection;

namespace AOP03
{
    [Serializable]
    //این ویژگی تنها نیاز است به کلاس‌ها اعمال شود
    [MulticastAttributeUsage(MulticastTargets.Class)]
    public class DataContractAspect : TypeLevelAspect, IAspectProvider
    {
        public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
        {
            var targetType = (Type)targetElement; //همان نوعی است که ویژگی جاری به آن اعمال خواهد شد

            //این سطر معادل است با درخواست تولید ویژگی دیتاکانترکت
            var introduceDataContractAspect = new CustomAttributeIntroductionAspect(
                new ObjectConstruction(typeof(DataContractAttribute).GetConstructor(Type.EmptyTypes)));

            //این سطر معادل است با درخواست تولید ویژگی دیتاممبر
            var introduceDataMemberAspect = new CustomAttributeIntroductionAspect(
                new ObjectConstruction(typeof(DataMemberAttribute).GetConstructor(Type.EmptyTypes)));

            //در اینجا کار اعمال ویژگی دیتاکانترکت به کلاسی که به عنوان پارامتر متد جاری
            //دریافت شده انجام خواهد شد
            yield return new AspectInstance(targetType, introduceDataContractAspect);

            //مرحله بعد کار اعمال ویژگی دیتاممبر به خواص کلاس است
            foreach (var property in targetType.GetProperties(BindingFlags.Public |
                                                          BindingFlags.DeclaredOnly |
                                                          BindingFlags.Instance))
            {
                if (property.CanWrite)
                    yield return new AspectInstance(property, introduceDataMemberAspect);
            }
        }
    }
}
توضیحات مرتبط با قسمت‌های مختلف این Aspect سفارشی، به صورت کامنت در کدهای فوق ارائه شده‌اند.
برای اعمال آن به سراسر برنامه تنها کافی است به فایل AssemblyInfo.cs پروژه مراجعه و سپس سطر زیر را به آن اضافه کنیم:
 [assembly: DataContractAspect(AttributeTargetTypes = "AOP03.DataContracts.*")]
به این ترتیب در زمان کامپایل پروژه، Aspect تعریف شده به تمام کلاس‌های موجود در فضای نام AOP03.DataContracts اعمال خواهند شد.

در این حالت اگر کلیه ویژگی‌های کلاس User فوق را حذف و برنامه را کامپایل کنیم، با مراجعه به برنامه ILSpy می‌توان صحت اعمال ویژگی‌ها را به کمک PostSharp بررسی کرد:
 

مطالب دوره‌ها
تزریق خودکار وابستگی‌ها در برنامه‌های ASP.NET Web forms
همانطور که در قسمت‌های قبل عنوان شد، دو نوع متداول تزریق وابستگی‌ها وجود دارند:
الف) تزریق وابستگی‌ها در سازنده کلاس
ب) تزریق وابستگی‌ها در خواص عمومی کلاس‌ها یا Setters injection

حالت الف متداول‌ترین است و بیشتر زمانی کاربرد دارد که کار وهله سازی یک کلاس را می‌توان راسا انجام داد. اما در فرم‌ها یا یوزرکنترل‌های ASP.NET Web forms به صورت پیش فرض کار وهله سازی فرم‌ها و یوزرکنترل‌ها توسط موتور ASP.NET انجام می‌شود و در این حالت اگر بخواهیم از تزریق وابستگی‌ها استفاده کنیم، مدام به همان روش معروف Service locator و استفاده از container.Resolve در تمام قسمت‌های برنامه می‌رسیم که آنچنان روش مطلوبی نیست.
اما ... در ASP.NET Web forms می‌توان وهله سازی فرم‌ها را نیز تحت کنترل قرار داد، که برای آن دو روش زیر وجود دارند:
الف) یک کلاس مشتق شده را از کلاس پایه PageHandlerFactory تهیه کنیم. این کلاس را پیاده سازی کرده و نهایتا بجای وهله ساز پیش فرض فرم‌های موتور داخلی ASP.NET، در فایل وب کانفیگ برنامه استفاده کنیم. یک نمونه از پیاده سازی آن‌را در اینجا می‌توانید مشاهده کنید.
مشکلی که این روش دارد سازگاری آن با حالت Full trust است. یعنی برنامه شما در یک هاست Medium trust (اغلب هاست‌های خوب) اجرا نخواهد شد.
ب) روش دوم، استفاده از یک Http Module است برای اعمال Setter injectionها، به صورت خودکار. اکنون که حالت الف را همه جا نمی‌توان بکار برد یا به عبارتی نمی‌توان وهله سازی فرم‌ها را راسا در دست گرفت، حداقل می‌توان خواص عمومی اشیاء صفحه تولید شده را مقدار دهی کرد که در ادامه، این روش را بررسی می‌کنیم.


تهیه ماژول انجام Setters injection به صورت خودکار در برنامه‌های ASP.NET Web forms به کمک StructureMap

پیشنیاز این بحث، مطلب «استفاده از StructureMap به عنوان یک IoC Container» می‌باشد که پیشتر مطالعه کردید (در حد نحوه نصب StructureMap و آشنایی با تنظیمات اولیه آن)
using System.Collections;
using System.Web;
using System.Web.UI;
using StructureMap;

namespace DI05.Core
{
    /// <summary>
    /// تسهیل در کار تزریق خودکار وابستگی‌ها در سطح فرم‌ها و یوزرکنترل‌ها
    /// </summary>
    public class StructureMapModule : IHttpModule
    {
        public void Dispose()
        { }

        public void Init(HttpApplication app)
        {
            app.PreRequestHandlerExecute += (sender, e) =>
            {
                var page = HttpContext.Current.Handler as Page; // The Page handler
                if (page == null)
                    return;

                WireUpThePage(page);
                WireUpAllUserControls(page);
            };
        }

        private static void WireUpAllUserControls(Page page)
        {
            // در اینجا هم کار سیم کشی یوزر کنترل‌ها انجام می‌شود
            page.InitComplete += (initSender, evt) =>
            {
                var thisPage = (Page)initSender;
                foreach (Control ctrl in getControlTree(thisPage))
                {
                    // فقط یوزر کنترل‌ها بررسی شدند
                    // اگر نیاز است سایر کنترل‌های قرار گرفته روی فرم هم بررسی شوند شرط را حذف کنید
                    if (ctrl is UserControl)
                    {
                        ObjectFactory.BuildUp(ctrl);
                    }
                }
            };
        }

        private static void WireUpThePage(Page page)
        {
            ObjectFactory.BuildUp(page); // برقراری خودکار سیم کشی‌ها در سطح صفحات
        }

        private static IEnumerable getControlTree(Control root)
        {
            foreach (Control child in root.Controls)
            {
                yield return child;
                foreach (Control ctrl in getControlTree(child))
                {
                    yield return ctrl;
                }
            }
        }
    }
}
در این ماژول، کار با HttpContext.Current.Handler شروع می‌شود که دقیقا معادل با وهله‌ای از یک صفحه یا فرم می‌باشد. اکنون که این وهله را داریم، فقط کافی است متد ObjectFactory.BuildUp مربوط به StructureMap را روی آن فراخوانی کنیم تا کار Setter injection را انجام دهد. مرحله بعد یافتن یوزر کنترل‌های احتمالی قرار گرفته بر روی صفحه و همچنین فراخوانی متد ObjectFactory.BuildUp، بر روی آن‌ها می‌باشد.
پس از تهیه ماژول فوق، باید آن‌را در فایل وب کانفیگ برنامه معرفی کرد:
<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />

    <httpModules>
      <add name="StructureMapModule" type="DI05.Core.StructureMapModule"/>
    </httpModules>
  </system.web>

  <system.webServer>    
    <modules runAllManagedModulesForAllRequests="true">
      <add name="StructureMapModule" type="DI05.Core.StructureMapModule"/>
    </modules>
    <validation validateIntegratedModeConfiguration="false" />
  </system.webServer>
</configuration>

مثالی از نحوه استفاده از StructureMapModule تهیه شده

فرض کنید لایه سرویس برنامه دارای اینترفیس‌ها و کلاس‌های زیر است:
namespace DI05.Services
{
    public interface IUsersService
    {
        string GetUserEmail(int id);
    }
}


namespace DI05.Services
{
    public class UsersService: IUsersService
    {
        public string GetUserEmail(int id)
        {
            //فقط جهت بررسی تزریق وابستگی‌ها
            return "test@test.com";
        }
    }
}
کار تنظیمات اولیه آن‌ها را در فایل global.asax.cs برنامه انجام خواهیم داد:
using System;
using StructureMap;
using DI05.Services;

namespace DI05
{
    public class Global : System.Web.HttpApplication
    {
        private static void initStructureMap()
        {
            ObjectFactory.Initialize(x =>
            {
                x.For<IUsersService>().Use<UsersService>();

                x.SetAllProperties(y =>
                {
                    y.OfType<IUsersService>();
                });
            });
        }

        protected void Application_Start(object sender, EventArgs e)
        {
            initStructureMap();
        }

        void Application_EndRequest(object sender, EventArgs e)
        {
            ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
        }
    }
}
در اینجا فقط باید دقت داشت که ذکر SetAllProperties الزامی است. از این جهت که از روش Setter injection در حال استفاده هستیم.
مرحله آخر هم استفاده از سرویس‌های برنامه به شکل زیر است:
using System;
using DI05.Services;

namespace DI05
{
    public partial class Default : System.Web.UI.Page
    {
        public IUsersService UsersService { set; get; }

        protected void Page_Load(object sender, EventArgs e)
        {
            lblEmail1.Text = string.Format("From Default Page: {0}", UsersService.GetUserEmail(1));
        }
    }
}
همانطور که ملاحظه می‌کنید در این فرم، هیچ خبری از وجود IoC Container مورد استفاده نیست و کار وهله سازی و مقدار دهی سرویس مورد استفاده به صورت خودکار توسط Http Module تهیه شده انجام می‌شود.


دریافت مثال کامل قسمت جاری
DI05.zip


یک نکته‌ی تکمیلی
برای ارتقاء نکات مطلب جاری به نگارش سوم StructureMap نیاز است موارد ذیل را لحاظ کنید:
الف) نصب بسته‌ی وب آن
PM> Install-Package structuremap.web
ب) ReleaseAndDisposeAllHttpScopedObjects حذف شده را به متد جدید ()HttpContextLifecycle.DisposeAndClearAll تغییر دهید.
ج) x.SetAllProperties را به x.Policies.SetAllProperties ویرایش کنید.
اشتراک‌ها
مقاله ای کامل درباره استفاده از MVC و jQuery و JSON و paging و mapRoute
How to make CRUD with good performance in MVC
How to use jQuery dialog instead of JavaScript confirm or alert
How to make paging in an MVC list
How to make "show more" link using jQuery in MVC
How to use attributes with link
How to make a AJAX call in jQuery
How to use the Form collection in MVC
How to delete multiple records at one shot
How to use partial action in MVC
How to use JSON format in an MVC application
How to fill a master-detail combobox
How to use the jQuery datepicker
How to upload an image in MVC with a jQuery dialog
How to create a table row at client side
How to customize a maproute in Global.asax 
مقاله ای کامل درباره استفاده از MVC و  jQuery و  JSON و  paging و  mapRoute
اشتراک‌ها
دوره 11 ساعته ساخت یک برنامه‌ی مدیریت اموال با Blazor

Full C# Project: Inventory Management System | ASP.NET Core Blazor, EF Core, SQL Server, Identity - YouTube 

00:00:00 Project Demo (ASP.Net Core Blazor Server)
00:05:26 View Inventories
00:14:29 Add Entity Framework Core
00:27:16 View Inventory Use Case
00:36:35 View Inventory Component (Blazor Component)
00:58:04 View Inventory Page
01:08:18 Adding new Inventory
01:34:46 Edit Inventory
02:10:26 View Products Use Case
02:45:52 Search Inventory Component
03:05:50 Add Product
03:52:39 Refactor Product Inventories
04:16:51 Validate Product Price
04:49:14 Edit Product
05:23:34 Delete Product
05:47:48 Purchase Inventory
07:07:40 Produce Products
07:36:29 UI of Producing Products
08:16:05 Sell Product
08:46:36 Inventory Transaction Report
09:43:48 Product Transaction Report
10:10:10 Print Reports
10:19:56 Switch to SQL Server
10:51:30 Add Authentication and Authorization with ASP.NET Core Identity
10:59:57 Look and Feel with Bootstrap 5 

دوره 11 ساعته ساخت یک برنامه‌ی مدیریت اموال با Blazor
مطالب دوره‌ها
استفاده از StructureMap به عنوان یک IoC Container
StructureMap یکی از IoC containerهای بسیار غنی سورس باز نوشته شده برای دات نت فریم ورک است. امکان تنظیمات آن توسط کدنویسی و یا همان Fluent interfaces، به کمک فایل‌های کانفیگ XML و همچنین استفاده از ویژگی‌ها یا Attributes نیز میسر است. امکانات جانبی دیگری را نیز مانند یکی شدن با فریم ورک‌های Dynamic Proxy برای ساده سازی فرآیندهای برنامه نویسی جنبه‌گرا یا AOP، دارا است. در ادامه قصد داریم با نحوه استفاده از این فریم ورک IoC بیشتر آشنا شویم.


دریافت StructureMap

برای دریافت آن نیاز است دستور پاورشل ذیل را در کنسول نیوگت ویژوال استودیو فراخوانی کنید:
 PM> Install-Package structuremap
البته باید دقت داشت که برای استفاده از StructureMap نیاز است به خواص پروژه مراجعه و سپس حالت Client profile را به Full profile تغییر داد تا برنامه قابل کامپایل باشد (در برنامه‌های دسکتاپ البته)؛ از این جهت که StructureMap ارجاعی را به اسمبلی استاندارد System.Web دارد.


آشنایی با ساختار برنامه

ابتدا یک برنامه کنسول را آغاز کرده و سپس یک Class library جدید را به نام Services نیز به آن اضافه کنید. در ادامه کلاس‌ها و اینترفیس‌های زیر را به Class library ایجاد شده، اضافه کنید. سپس از طریق نیوگت به روشی که گفته شد، StructureMap را به پروژه اصلی (ونه پروژه Class library) اضافه نمائید و Target framework آن‌را نیز در حالت Full قرار دهید بجای حالت Client profile.
namespace DI03.Services
{
    public interface IUsersService
    {
        string GetUserEmail(int userId);
    }
}


namespace DI03.Services
{
    public interface IEmailsService
    {
        void SendEmailToUser(int userId, string subject, string body);
    }
}

using System;

namespace DI03.Services
{
    public class UsersService : IUsersService
    {
        public UsersService()
        {
            //هدف صرفا نمایش وهله سازی خودکار این وابستگی است
            Console.WriteLine("UsersService ctor.");
        }

        public string GetUserEmail(int userId)
        {
            //برای مثال دریافت از بانک اطلاعاتی و بازگشت یک نمونه جهت آزمایش برنامه
            return "name@site.com";
        }
    }
}

using System;

namespace DI03.Services
{
    public class EmailsService: IEmailsService
    {
        private readonly IUsersService _usersService;
        public EmailsService(IUsersService usersService)
        {
            Console.WriteLine("EmailsService ctor.");
            _usersService = usersService;
        }

        public void SendEmailToUser(int userId, string subject, string body)
        {
            var email = _usersService.GetUserEmail(userId);
            Console.WriteLine("SendEmailTo({0})", email);
        }
    }
}
در لایه سرویس برنامه، یک سرویس کاربران و یک سرویس ارسال ایمیل تدارک دیده شده‌اند.
سرویس کاربران بر اساس آی دی یک کاربر، برای مثال از بانک اطلاعاتی ایمیل او را بازگشت می‌دهد. سرویس ارسال ایمیل، نیاز به ایمیل کاربری برای ارسال ایمیلی به او دارد. بنابراین وابستگی مورد نیاز خود را از طریق تزریق وابستگی‌ها در سازنده کلاس و وهله سازی شده در خارج از آن (معکوس سازی کنترل)، دریافت می‌کند.
در سازنده‌های هر دو کلاس سرویس نیز از Console.WriteLine استفاده شده‌است تا زمان وهله سازی خودکار آن‌ها را بتوان بهتر مشاهده کرد.
نکته مهمی که در اینجا وجود دارد، بی‌خبری لایه سرویس از وجود IoC Container مورد استفاده است.


استفاده از لایه سرویس و تزریق وابستگی‌ها به کمک  StructureMap

using DI03.Services;
using StructureMap;

namespace DI03
{
    class Program
    {
        static void Main(string[] args)
        {
            // تنظیمات اولیه برنامه که فقط یکبار باید در طول عمر برنامه انجام شود
            ObjectFactory.Initialize(x =>
            {
                x.For<IEmailsService>().Use<EmailsService>();
                x.For<IUsersService>().Use<UsersService>();
            });

            //نمونه‌ای از نحوه استفاده از تزریق وابستگی‌های خودکار
            var emailsService = ObjectFactory.GetInstance<IEmailsService>();
            emailsService.SendEmailToUser(userId: 1, subject: "Test", body: "Hello!");
        }
    }
}
کدهای برنامه را به نحو فوق تغییر دهید. در ابتدا نحوه سیم کشی‌های آغازین برنامه را مشاهده می‌کنید. برای مثال کدهای ObjectFactory.Initialize باید در متدهای آغازین یک پروژه قرار گیرند و تنها یکبار هم نیاز است فراخوانی شوند.
به این ترتیب IoC Container ما زمانیکه قرار است object graph مربوط به IEmailsService درخواستی را تشکیل دهد، خواهد دانست ابتدا به سازنده‌ی کلاس EmailsService می‌رسد. در اینجا برای وهله سازی این کلاس به صورت خودکار، باید وابستگی‌های آن‌را نیز وهله سازی کند. بنابراین بر اساس تنظیمات آغازین برنامه می‌داند که باید از کلاس UsersService برای تزریق خودکار وابستگی‌ها در سازنده کلاس ارسال ایمیل استفاده نماید.
در این حالت اگر برنامه را اجرا کنیم، به خروجی زیر خواهیم رسید:
UsersService ctor.
EmailsService ctor.
SendEmailTo(name@site.com)
بنابراین در اینجا با مفهوم Object graph نیز آشنا شدیم. فقط کافی است وابستگی‌ها را در سازنده‌های کلاس‌ها تعریف کرده و سیم کشی‌های آغازین صحیحی را نیز در ابتدای برنامه معرفی نمائیم. کار وهله سازی چندین سطح با تمام وابستگی‌های متناظر با آن‌ها در اینجا به صورت خودکار انجام خواهد شد و نهایتا یک شیء قابل استفاده بازگشت داده می‌شود.
ابتدایی‌ترین مزیت استفاده از تزریق وابستگی‌ها امکان تعویض آن‌ها است؛ خصوصا در حین Unit testing. اگر کلاسی برای مثال قرار است با شبکه کار کند، می‌توان پیاده سازی آن‌را با یک نمونه اصطلاحا Fake جایگزین کرد و در این نمونه تنها نتیجه‌ی کار را بازگشت داد. کلاس‌های لایه سرویس ما تنها با اینترفیس‌ها کار می‌کنند. این تنظیمات قابل تغییر اولیه IoC container مورد استفاده هستند که مشخص می‌کنند چه کلاس‌هایی باید در سازنده‌های کلاس‌ها تزریق شوند.


تعیین طول عمر اشیاء در StructureMap

برای اینکه بتوان طول عمر اشیاء را بهتر توضیح داد، کلاس سرویس کاربران را به نحو زیر تغییر دهید:
using System;

namespace DI03.Services
{
    public class UsersService : IUsersService
    {
        private int _i;
        public UsersService()
        {
            //هدف صرفا نمایش وهله سازی خودکار این وابستگی است
            Console.WriteLine("UsersService ctor.");
        }

        public string GetUserEmail(int userId)
        {
            _i++;
            Console.WriteLine("i:{0}", _i);
            //برای مثال دریافت از بانک اطلاعاتی و بازگشت یک نمونه جهت آزمایش برنامه
            return "name@site.com";
        }
    }
}
به عبارتی می‌خواهیم بدانیم این کلاس چه زمانی وهله سازی مجدد می‌شود. آیا در حالت فراخوانی ذیل،
 //نمونه‌ای از نحوه استفاده از تزریق وابستگی‌های خودکار
var emailsService1 = ObjectFactory.GetInstance<IEmailsService>();
emailsService1.SendEmailToUser(userId: 1, subject: "Test1", body: "Hello!");

var emailsService2 = ObjectFactory.GetInstance<IEmailsService>();
emailsService2.SendEmailToUser(userId: 1, subject: "Test2", body: "Hello!");
ما شاهد چاپ عدد 2 خواهیم بود یا عدد یک:
 UsersService ctor.
EmailsService ctor.
i:1
SendEmailTo(name@site.com)
UsersService ctor.
EmailsService ctor.
i:1
SendEmailTo(name@site.com)
همانطور که ملاحظه می‌کنید، به ازای هربار فراخوانی ObjectFactory.GetInstance، یک وهله جدید ایجاد شده است. بنابراین مقدار i در هر دو بار مساوی عدد یک است.
اگر به هر دلیلی نیاز بود تا این رویه تغییر کند، می‌توان بر روی طول عمر اشیاء تشکیل شده نیز تاثیر گذار بود. برای مثال تنظیمات آغازین برنامه را به نحو ذیل تغییر دهید:
// تنظیمات اولیه برنامه که فقط یکبار باید در طول عمر برنامه انجام شود
ObjectFactory.Initialize(x =>
{
   x.For<IEmailsService>().Use<EmailsService>();
   x.For<IUsersService>().Singleton().Use<UsersService>();
});
اینبار اگر برنامه را اجرا کنیم، به خروجی ذیل خواهیم رسید:
 UsersService ctor.
EmailsService ctor.
i:1
SendEmailTo(name@site.com)
EmailsService ctor.
i:2
SendEmailTo(name@site.com)
بله. با Singleton معرفی کردن تنظیمات UsersService، تنها یک وهله از این کلاس ایجاد خواهد شد و نهایتا در فراخوانی دوم ObjectFactory.GetInstance، شاهد عدد i مساوی 2 خواهیم بود (چون از یک وهله استفاده شده است).

حالت‌های دیگر تعیین طول عمر مطابق متدهای زیر هستند:
 Singleton()
HttpContextScoped()
HybridHttpOrThreadLocalScoped()
با انتخاب حالت HttpContext، به ازای هر HttpContext ایجاد شده، کلاس معرفی شده یکبار وهله سازی می‌گردد.
در حالت ThreadLocal، به ازای هر Thread، وهله‌ای متفاوت در اختیار مصرف کننده قرار می‌گیرد.
حالت Hybrid ترکیبی است از حالت‌های HttpContext و ThreadLocal. اگر برنامه وب بود، از HttpContext استفاده خواهد کرد در غیراینصورت به ThreadLocal سوئیچ می‌کند.

شاید بپرسید که کاربرد مثلا HttpContextScoped در کجا است؟
در یک برنامه وب نیاز است تا یک وهله از DbContext (مثلا Entity framework) را در اختیار کلاس‌های مختلف لایه سرویس قرار داد. به این ترتیب چون هربار new Context صورت نمی‌گیرد، هربار هم اتصال جداگانه‌ای به بانک اطلاعاتی باز نخواهد شد. نتیجه آن رسیدن به یک برنامه سریع، با سربار کم و همچنین کار کردن در یک تراکنش واحد است. چون هربار فراخوانی new Context به معنای ایجاد یک تراکنش جدید است.
همچنین در این برنامه وب قصد نداریم از حالت طول عمر Singleton استفاده کنیم، چون در این حالت یک وهله از Context در اختیار تمام کاربران سایت قرار خواهد گرفت (و DbContext به صورت Thread safe طراحی نشده است). نیاز است به ازای هر کاربر و به ازای طول عمر هر درخواست، تنها یکبار این وهله سازی صورت گیرد. بنابراین در این حالت استفاده از HttpContextScoped توصیه می‌شود. به این ترتیب در طول عمر کوتاه Object graph‌های تشکیل شده، فقط یک وهله از DbContext ایجاد و استفاده خواهد شد که بسیار مقرون به صرفه است.
مزیت دیگر مشخص سازی طول عمر به نحو HttpContextScoped، امکان Dispose خودکار آن به صورت زیر است:
protected void Application_EndRequest(object sender, EventArgs e)  
{  
  ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();  
}

تنظیمات خودکار اولیه در StructureMap

اگر نام اینترفیس‌های شما فقط یک I در ابتدا بیشتر از نام کلاس‌های متناظر با آن‌ها دارد، مثلا مانند ITest و کلاس Test هستند؛ فقط کافی است از قراردادهای پیش فرض StructureMap برای اسکن یک یا چند اسمبلی استفاده کنیم:
 // تنظیمات اولیه برنامه که فقط یکبار باید در طول عمر برنامه انجام شود
ObjectFactory.Initialize(x =>
{
   //x.For<IEmailsService>().Use<EmailsService>();
   //x.For<IUsersService>().Singleton().Use<UsersService>();  
   x.Scan(scan =>
   {
       scan.AssemblyContainingType<IEmailsService>();
       scan.WithDefaultConventions();
   });  
});
در این حالت دیگر نیازی نیست به ازای اینترفیس‌های مختلف و کلاس‌های مرتبط با آن‌ها، تنظیمات اضافه‌تری را تدارک دید. کار یافتن و برقراری اتصالات لازم در اینجا خودکار خواهد بود.


دریافت مثال قسمت جاری
DI03.zip

به روز شده‌ی این مثال‌ها را بر اساس آخرین تغییرات وابستگی‌های آن‌ها از مخزن کد ذیل می‌توانید دریافت کنید:
Dependency-Injection-Samples
 
نظرات مطالب
ایجاد جداول بهینه سازی شده برای حافظه در SQL Server 2014
ارزش واقعی جداول درون حافظه‌ای را باید با اعمال تراکنش‌های همزمان و بررسی میزان پاسخگویی سیستم بررسی کرد و نه صرفا با یک آزمایش ساده تک ریسمانی. برای این منظور برنامه‌ای به نام ostress.exe توسط مایکروسافت تهیه شده‌است که امکان انجام یک چنین آزمایشاتی را میسر می‌کند. برای دریافت آن به آدرس‌های ذیل مراجعه کنید:
RML Utilities X64
RML Utilities X86

که نهایتا در این مسیر C:\Program Files\Microsoft Corporation\RMLUtils نصب خواهد شد.
سپس در خط فرمان این سه دستور را امتحان کنید:

-- Insert 10000 records using 20 threads, Repeat Execution 3 times

-- disk-based
"C:\Program Files\Microsoft Corporation\RMLUtils\ostress.exe" –n20 –r3 -S. -E -dTestdb2 -q -Q"set statistics time off; SET STATISTICS IO Off; set nocount on; DECLARE @start datetime = getdate(); declare @insertCount int = 10000; declare @startId int = 1; while @startId < @insertCount begin insert into tblNormal values ('Test', '2013-01-01T00:00:00') set @startId +=1 end; Print DATEDIFF(ms,@start,getdate());" –oc:\temp\output

-- memory-optimized, tblMemoryOptimized_Schema_And_Data
"C:\Program Files\Microsoft Corporation\RMLUtils\ostress.exe" –n20 –r3 -S. -E -dTestdb2 -q -Q"set statistics time off; SET STATISTICS IO Off; set nocount on; DECLARE @start datetime = getdate(); declare @insertCount int = 10000; declare @startId int = 1; while @startId < @insertCount begin insert into tblMemoryOptimized_Schema_And_Data values ('Test', '2013-01-01T00:00:00') set @startId +=1 end; Print DATEDIFF(ms,@start,getdate());" –oc:\temp\output

-- memory-optimized, tblMemoryOptimized_Schema_Only
"C:\Program Files\Microsoft Corporation\RMLUtils\ostress.exe" –n20 –r3 -S. -E -dTestdb2 -q -Q"set statistics time off; SET STATISTICS IO Off; set nocount on; DECLARE @start datetime = getdate(); declare @insertCount int = 10000; declare @startId int = 1;  while @startId <  @insertCount begin insert into tblMemoryOptimized_Schema_Only values ('Test', '2013-01-01T00:00:00') set @startId +=1 end; Print DATEDIFF(ms,@start,getdate());" –oc:\temp\output
زمانیکه را که در پایان کار نمایش می‌دهد، مبنای واقعی مقایسه است.

البته برای اجرای این دستورات نیاز است فیلد CustomerID را identity تعریف کنید (در هر سه جدول مطلب جاری).

-- It is not Memory Optimized
CREATE TABLE tblNormal
(
       [CustomerID] int identity NOT NULL PRIMARY KEY NONCLUSTERED, 
       [Name] nvarchar(250) NOT NULL,
   CustomerSince DATETIME not NULL
      INDEX [ICustomerSince] NONCLUSTERED
)

--  DURABILITY = SCHEMA_AND_DATA
CREATE TABLE tblMemoryOptimized_Schema_And_Data
(
    [CustomerID] INT  identity NOT NULL 
PRIMARY KEY NONCLUSTERED HASH WITH (BUCKET_COUNT = 131072),
    [Name] NVARCHAR(250) NOT NULL,
    [CustomerSince] DATETIME NOT NULL
INDEX [ICustomerSince] NONCLUSTERED
) WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_AND_DATA)


-- DURABILITY = SCHEMA_ONLY
CREATE TABLE tblMemoryOptimized_Schema_Only
(
    [CustomerID] INT  identity NOT NULL 
PRIMARY KEY NONCLUSTERED HASH WITH (BUCKET_COUNT = 131072),
    [Name] NVARCHAR(250) NOT NULL,
    [CustomerSince] DATETIME NOT NULL
INDEX [ICustomerSince] NONCLUSTERED
) WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_ONLY)
مطالب
intellisense دار نمودن ViewBag در ASP.NET MVC
در اینجا  و اینجا  با تفاوت‌های ViewData و ViewBag و TempData در ASP.NET MVC آشنا شدید. هدف ما در این مقاله intellisense  دار کردن شیء پویای ViewBag در فایل‌هاب cshtml می‌باشد که گاها در پروژها پیش می‌آید، برنامه نویس، لیستی را به صورت ViewBag به سمت View ارسال نماید.
 ViewBag :
 • یک نوع dynamic است (این نوع در c# 4 معرفی شده است).
• مانند ViewData برای ارسال اطلاعات از کنترلر به view استفاده می‌شود.
• مدت زمان اعتبار مقادیر آن تنها در request جاری است.
• اگر redirect ایی بین صفحات رخ دهد، مقدار آن null خواهد شد.
• به دلایل امنیتی باید قبل از استفاده، null بودن آن تست شود.
• برای استفاده‌ی از آن، cast نیاز نیست. بنابراین سریعتر عمل می‌کند.
در پوشه‌ی Models یک کلاس با نام Persons ایجاد شده که داری پراپرتی‌های زیر می‌باشد:
using System.Web;

namespace Intellisense.Models
{
    public class Persons
    {
        // کلید
        public int Id { get; set; }
        // نام
        public string FirstName { get; set; }
        // نام خانوادگی
        public string LastName { get; set; }
        // نام پدر
        public string FatherName { get; set; }
        // سن
        public int Age { get; set; }
        // شماره تلفن
        public int Mobile { get; set; }
        // آدرس
        public string Address { get; set; }
    }
}
حال نوبت به ایجاد یک اکشن و مقدار دهی ViewBag با لیستی از اشخاص و پاس دادن به سمت View است:
using System.Collections.Generic;
using System.Web.Mvc;
using Intellisense.Models;

namespace Intellisense.Controllers
{
    public class HomeController : Controller
    {
        // GET: Home
        public ActionResult Index()
        {
            // List of person
            var listOfPerson = new List<Persons>
            {
                new Persons() {Id = 1, FirstName = "Jone", LastName = "liy", FatherName = "Sobin", Age = 36, Mobile = +982015222, Address = "..."},
                new Persons() {Id = 2, FirstName = "kety", LastName = "sory", FatherName = "petter", Age = 19, Mobile = +962222155, Address = "..."},
            };
            // Set ViewBag.Persons data from listOfPerson
            ViewBag.Persons = listOfPerson;
            // Show and send ViewBag.Persons to view
            return View();
        }
    }
}
در View می‌توان به دو روش لیست ارسالی موجود در ViewBag.Persons فراخوانی نمود:
  1. استفاده از دات ( . ) 
  2. عمل Cast
در کد زیر نحوه‌ی استفاده از دات را مشاهده خواهید کرد. از معایب استفاده از این روش اشتباهات تایپی است که نام پراپرتی بعد از دات (.) قرار خواهد گرفت و همچنین intellisense برای آن فعال نیست.
@{
    ViewBag.Title = "ViewBag";
}
<table>
    <thead>
        <tr>
            <th>
                Id
            </th>
            <th>
                First Name
            </th>
            <th>
                Last Name
            </th>
            <th>
                Father Name
            </th>
            <th>
                Age
            </th>
            <th>
               Mobile
            </th>
            <th>
                Address
            </th>
        </tr>
    </thead>
    <tbody>
        @{foreach (var item in ViewBag.Persons)
            {
                <tr>
                    <td>
                        @item.Id
                    </td>
                    <td>
                        @item.FirstName
                    </td>
                    <td>
                        @item.LastName
                    </td>
                    <td>
                        @item.FatherName
                    </td>
                    <td>
                        @item.Age
                    </td>
                    <td>
                        @item.Mobile
                    </td>
                    <td>
                        @item.Address
                    </td>
                </tr>
            }
        }
    </tbody>
</table>

Cast:
با استفاده از کلمه کلیدی as عمل casting انجام پذیرفته است که در زیر، دو روش برای casting آورده شده است. در این حالت intellisense نیز فعال می‌گردد:
@using Intellisense.Models
@{
    ViewBag.Title = "ViewBag";
    // روش اول
    // پیشنهاد می‌شود که از روش اول استفاده شود
    // var listOfPerson = ViewBag.Persons as IEnumerable<Persons>;
    // روش دوم
    // var listOfPerson = (IEnumerable<Persons>)ViewBag.Persons;
    var listOfPerson = ViewBag.Persons as IEnumerable<Persons>;
}
<table>
    <thead>
        <tr>
            <th>
                Id
            </th>
            <th>
                First Name
            </th>
            <th>
                Last Name
            </th>
            <th>
                Father Name
            </th>
            <th>
                Age
            </th>
            <th>
               Mobile
            </th>
            <th>
                Address
            </th>
        </tr>
    </thead>
    <tbody>
        @{foreach (var item in listOfPerson)
            {
                <tr>
                    <td>
                        @item.Id
                    </td>
                    <td>
                        @item.FirstName
                    </td>
                    <td>
                        @item.LastName
                    </td>
                    <td>
                        @item.FatherName
                    </td>
                    <td>
                        @item.Age
                    </td>
                    <td>
                        @item.Mobile
                    </td>
                    <td>
                        @item.Address
                    </td>
                </tr>
            }
        }
    </tbody>
</table>
پروژه جاری را می‌توان از اینجا دانلود نمود.
نظرات مطالب
Identity و مباحث مربوطه (قسمت دوم) نحوه بدست آوردن مقادیر Identity
ببین دوست من مطلبتون رو خوندم هم اینو و هم قبلی رو، ازش خوشم اومد اما چیزی راجب درج صریح یا بروز رسانی مقادیر Identity ننوشته بودین. یا اینکه نمیشه در یک جدول دو identity property داشت.
من بلدم با set identity_insert table_name on/off کاری کنم که خودم دستی مقداری را برای خصیصه identity لحاظ کنم. ولی متاسفانه نتونستم مقدار یک ستون با خصیصه Identity رو بروز رسانی (یا همون update) کنم. لطفا بهم بگید که اصلا این کار ممکنه یا من بلد نیستم. البته براساس query زیر بمن SQL Server گفته که نمیشه این ستون را update کرد که ظاهرا هم همین طور(ستون id همانطور که در پیام آمده از نوع identity هست)
update t
set id = new_id
from (select id, row_number() over(order by id) new_id from #temp)t

--Cannot update identity column 'id'.

اصلا اجازه بدین یه جور دیگه سوال رو مطرح کنم من نیاز دارم تمام مقادیر identity رو بروز رسانی کنم تا کاملا پشت سر هم و متوالی بشن این کار را میتونم با یک تابع row_number و یک derived table انجام بدم (اگر بذارن!) همانطور که قبلا نشان دادم، یا با روش زیر این کار را بکنم که البته اجرا نمیشه به این دلیل که در یک جدول نمیشه دو identity property داشت. با فرض اجرا شدن دستور select into باز هم در دستور update با مشکل بر می‌خوردیم (چون نمیشه ستون id را بروز رسانی کرد)
select id, identity(int, 1,1) new_id
into #temptable
from #temp
order by id asc

/*
cannot add identity column, using the SELECT INTO statement, to table '#temptable',
 which already has column 'id' that inherits the identity property.
*/
update t
set id = new_id
from #temp t
join #temptable d
on t.id = d.id;
البته یک راهی برای حل این مساله هست اونم اینه که ابتدا بیاییم تمام داده‌ها جدول را در جدول دیگه ای درج کنیم سپس تمام داده‌های جدول را حذف کنیم سپس داده‌های حذف شده را با id جدید و مرتب شده در جدول اول درج کنیم. به این شکل
declare @t table(id int)

insert into @t
select id from #temp

delete from #temp

set identity_insert #temp on
insert #temp (id)
select row_number() over(order by id) from @t
set identity_insert #temp off
اما مشکلی که وجود داره اینه که اگر جدول ما parent باشه با مشکل واجه میشیم تمام سطرهای جداول child یتیم میشن.

من قصد ندارم صورت مساله نقد و بررسی بشه و اصولی بودن یا صحیح بودنش مورد ارزیابی قرار بگیره فقط برام این یک سوال شده.
مساله عمومی که راجب این ستون وجود داره استفاده کردن از Gap‌های حاصل شده در این ستون برای درج‌های بعدی است. که query آن نیز بسیار ساده و در دسترس است.
آیا شما میدانید که چگونه این مشکل با sequence ای که در نسخه 2012 معرفی شده است حل می‌شود؟