نظرات مطالب
نمایش فرم‌های مودال Ajax ایی در ASP.NET MVC به کمک Twitter Bootstrap
پروژه سورس باز هست. به قسمت  success سورس آن دقت کنید (سطر 74 کد افزونه):
 success: function (result) {
           if (result.success) {
                  $('#dialogDiv').modal('hide');
                  if (options.completeHandler)
                     options.completeHandler();
به completeHandler فراخوانی شده، اطلاعاتی ارسال نمی‌شود.
مطابق نیاز خودتان این قسمت را تغییر داده و استفاده کنید. مثلا result دریافتی را به آن متد ارسال کنید.
نظرات مطالب
ایجاد شناسه ی منحصر به فرد برای هر سیستم
افزونه‌ی مذکور رو میتونید از سایت رسمی خودش   دریافت کنید .
محتوای این پست صرفا مرتبط است با عنوان پست .

تعدادی از اجزای مهم سیستم امنیتی این افزونه شامل :
 1 ) ارتباط با وب سرویس سایت سازنده و دریافت کد فعال سازی موقت مختص به سیستم شما و ثبت اطلاعات سیستم شما در بانک اطلاعاتی سایت است برای جلوگیری استفاده مجدد از نسخه‌ی ازمایشی بعد از 21 روز . ( البته بعد از 21 روز فقط تعدای از قابلیت‌ها غیر فعال میشوند و بقیه رایگان هستند از جمله دیباگینگ php در vs !) . 
2 ) ایجاد کد منحصر به فرد هر سیستم .
3 ) ترکیب کد منحصر به فرد با شماره pakage ای که بعد از نصب افزونه vs به ان اختصاص میدهد و ... 

در کل نکات جالبی رو رعایت کرده بود و تعداد زیادی از کلاس‌ها رو پیاده سازی کرده بود که ارتباطاتی با هم داشتند فقط و فقط جهت سخت کردن debuging که از کارش خوشم اومد ...
نظرات مطالب
معرفی OLTP درون حافظه‌ای در SQL Server 2014

جناب نصیری با تشکر از مقاله مفیدتون لازم می‌دونم در جهت تکمیل مباحث به چند نکته اشاره کنم

1- « اگر حالت SCHEMA_AND_DATA انتخاب شود، اطلاعات شما پس از ری‌استارت سرور نیز در دسترس خواهد بود. این اطلاعات به صورت خودکار از لاگ تراکنش‌ها بازیابی شده و مجددا در حافظه قرار می‌گیرند   «.

بازیابی اطلاعات مربوط به تراکنش‌هایی که به ازای In Memory OLTP است بوسیله Data File + Delta File و Log File می‌باشد. در صورتیکه Schema_AND_Data را به ازای این نوع جداول فعال کنید داده‌های شما در Data File و داده‌های حذف شده در Delta File ثبت می‌گردد. مکانیزم Log File برای In Memory OLTP همچنان مانند جداول Disk base وجود دارد اما با بهینه سازی مناسب مانند ثبت Log Record کمتر به ازای عملیات کاربران و... 

2- در جایی دیگر در متن اشاره شده که In Memory OLTP اجازه استفاده از Identity را به کاربر نمی‌دهد باید اشاره کنم که این موضوع برای نسخه CTP بوده است در نسخه RTM این قابلیت وجود دارد . لازم می‌دانم اشاره کنم که  در Books Online جایی گفته شده که امکان استفاده وجود ندارد و در جایی هم گفته شده وجود دارد .

به مثال زیر دقت کنید

CREATE TABLE test(
[ID] BIGINT IDENTITY(1,1) NOT NULL PRIMARY KEY NONCLUSTERED HASH WITH (BUCKET_COUNT=10000),
N1 NVARCHAR(100),
N2 NVARCHAR(100),
N3 NVARCHAR(100)
) WITH (MEMORY_OPTIMIZED=ON,DURABILITY = SCHEMA_AND_DATA)
GO
این مثال در SQL Server 2014 RTM Edition قابل اجرا است اما یکسری محدودیت داریم . مثلاً مقدار شروع و گام افزایش باید 1 باشد .  

باز هم از مطالب خوب شما متشکرم مقاله مفیدی بود .

مطالب
به روز رسانی View ها و رویه‌های ذخیره شده در SQL server

یکی دیگر از معایب کوئری‌های select * در SQL server این است که تغییرات حاصل در فیلدهای جداول یک بانک اطلاعاتی را در view های ساخته شده از این نوع کوئری‌ها منعکس نمی‌کند.
برای مثال جدول tblTreeItems را با سه فیلد id ، parent و title در نظر بگیرید. فرض کنید بر این اساس view زیر را ساخته‌ایم:

CREATE VIEW GetData
as
SELECT * FROM tblTreeItems

اکنون به جدول فوق ، فیلد جدید isActive را اضافه می‌کنیم. پس از این عملیات اگر کوئری ساده SELECT * FROM GetData را اجرا کنیم، فیلد جدید isActive را در آن نخواهیم دید (برخلاف انتظار که می‌بایست کوئری select * رکوردهای تمام فیلدهای جدول را بر می‌گرداند. در این‌جا ممکن است مدتی وقت صرف دیباگ کردن سیستم شود که چرا تغییرات جدید اعمال نشده و چرا سیستمی که تا چند لحظه پیش داشت کار می‌کرد الان از کار افتاد!).
باید در نظر داشت که هنگام ایجاد یک view ، تصویری از تمامی فیلدهای مورد استفاده در آن زمان، جهت بالابردن کارآیی کوئری و عدم محاسبه مجدد فیلدها در جداول سیستمی ذخیره می‌گردد ( * با نام فیلدهای همان زمان ایجاد (نه زمان فعلی)، جایگزین خواهد شد). این تصویر ایستا است و با تغییر فیلدهای یک جدول به روز نخواهد شد.
برای به روز کردن view ها و stored procedures پس از تغییرات ساختاری در جداول، باید مجددا آنها را کامپایل کرد. برای این منظور راه‌های زیادی وجود دارد، برای مثال drop کردن یک view و ایجاد مجدد آن. یا باز کردن آن view در management studio (حالت alter query) و سپس فشردن دکمه F5 جهت اجرای مجدد کوئری که این‌بار بر اساس اطلاعات جدید به روز خواهد شد. یا استفاده از رویه‌های سیستمی sp_refreshview و sp_recompile که برای کامپایل مجدد view ها و رویه‌های ذخیره شده بکار می‌روند.

برای مدیریت ساده‌تر این موارد ، اسکریپت زیر تمامی view ها و رویه‌های ذخیره شده یک دیتابیس را به صورت خودکار یافته و آنها را مجددا کامپایل می‌کند: (جهت مشاهده آن نیاز به ثبت نام دارد و رایگان است)
Refreshing Views and Recompiling Stored Procs

مطالب
بررسی مدیریت دسترسی در جوملا 1.6-2.5

مطابق با ویکی پدیا، سطوح دسترسی مشخص می‌کند که کدام کاربران یا سیستم پردازش اجازه دسترسی به اشیاء را دارند(Authentication)، همچنین چه عملیات‌هایی بر روی اشیاء مجازند که اجرا شوند(Authorization).

در مورد جوملا، ما دو جنبه جدا برای سطوح دسترسی داریم:

1.       کدام کاربران به چه بخش‌هایی می‌توانند دسترسی داشته باشند؟ برای مثال، انتخاب یک منو برای کدام کاربر فعال خواهد بود؟

2.       چه عملیات (یا اقداماتی) کاربر می‌تواند بر روی اشیاء داشته باشد؟ برای مثال، آیا کاربر می‌تواند یک مطلب را ارسال یا ویرایش کند؟

 

ماهیت‌های موجود در سیستم :

·         کاربران 

کاربر می‌تواند به گروه‌های مختلفی اختصاص یابد.

·         گروه‌ها کاربری

شامل مجوزهایی به صورت پیش فرض می‌باشند که این مجوزها را از سطوح بالایی نیز به ارث می‌برند.

·         سطوح دسترسی

شامل یک یا چند گروه کاربری می‌باشد و سطوح دسترسی به محتواهای سایت نسبت داده می‌شود یعنی اگر یک مطلب دارای سطح دسترسی عمومی باشد آنگاه تمامی گروه‌های کاربری که در عمومی وجود دارند می‌توانند مطلب را مشاهده کنند.

·         عملیات و مجوزها

به صورت پیش فرض یک سری عملیات در سیستم تعریف شده است شامل ویرایش ، حذف و غیره که برای هر گروه کاربری (تعدادی گروه کاربری به صورت پیش فرض در سیستم تعریف شده است) به صورت پیش فرض مجوزهایی در نظر گرفته شده است که این مجوزها قابلیت ارث بری از والد گروه به فرزند رانیز دارا میباشد پس با این حساب همیشه در جوملا والد از سطح دسترسی پایین‌تری نسبت به فرزند برخوردار می‌باشد.

اما باید گفت در جوملا به ازای هر کامپوننت نیز می‌توان این مجوزها را به ازای گروه‌های مختلف تغییر داد در این جا هم هر کامپوننت دارای مجوز‌های پیش فرضی می‌باشد که در هنگام نصب کامپوننت برای آن  در نظر گرفته می‌شود.

 

جداول این سیستم :

: users  جدول کاربران

 usergroups : جدول گروه‌های کاری یا همان نقش‌های کاربری

user_usergroup_map :  جدول واسط بین کاربران و گروه‌های کاری به منظور ایجاد رابطه‌ی چند به چند (n:n)

assets : این جدول که از جوملا 1.6 به بعد به دیتابیس جوملا افزوده شده است مهمترین جدول در این سیستم می‌باشد . که در آن به ازای هر جز که سطح دسترسی باید برای آن لحاظ گردد یک سطر در نظر گرفته می‌شود که این سطر باتوجه به افزایش اجزا سیستم تغییر و به صورت داینامیک به جدول اضافه می‌گردد ضمنا این سطور قابلیت ارث بری از یکدیگر را نیز دارا می‌باشند. در هر بک از سطرها فیلدی به نام rulsوجود دارد محتوای این فیلد از نوع داده ای json می‌باشد با یک مثال شاید بهتر بتوان توضیح داد :

محتوای فیلد کامپوننت بنر :

{"core.admin":{"9":1,"7":1},"core.manage":{"6":1},"core.create":[],"core.delete":[],"core.edit}

در این جا “core.admin”   مجوز دسترسی مدیریتی به این کامپوننت می‌باشد که گروه‌های کاری شماره 7 و 9 دارای چنین دسترسی می‌باشند . ضمنا عملیات‌های "core.create" از سطوح بالاتر یا همان سطر والد خود ارث بری می‌کند.

Viewlevel :  در این جدول سطوح دسترسی تعریف شده اند مهمترین فیلد این جدول نیز rulsنام دارد و حاوی id  گروه هایی است که به این سطح دسترسی ، دسترسی دارند.

به طور مثال سطح دسترسی ثبت نام شده حاوی [6,2,8] می‌باشد یعنی گروه‌های کاری با id‌های مورد نظر می‌توانند به محتواهای با سطح دسترسی ثبت نام شده دسترسی داشته باشند.

 

دیاگرام جداول :

نظرات مطالب
اعمال توابع تجمعی بر روی چند ستون در Entity framework
چگونه توسط EF Core، چندین کوئری را یکجا به بانک اطلاعاتی ارسال کنیم؟

روشی را که در این مطلب مشاهده کردید، در موارد مشابه دیگری هم قابل استفاده‌است. برای مثال فرض کنید اطلاعات یک مشتری را قرار است به صورت زیر ذخیره کنیم:
public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; } = null!;
    public CustomerType Type { get; set; }
}

public enum CustomerType
{
    Individual,
    Institution,
}

حالت عادی کوئری گرفتن از اطلاعات جدول آن که به همراه صفحه بندی، نمایش تعداد رکوردها و یک کوئری دلخواه دیگر باشد، به صورت زیر است:
void ManyQueriesManyCalls()
{
    using var scope = serviceProvider.CreateScope();
    var context = scope.ServiceProvider.GetRequiredService<CustomerContext>();

    var baseQuery = context.Customers.Select(customer => new
                                                         {
                                                             customer.Name,
                                                             customer.Type,
                                                             customer.Id,
                                                         });
    var total = baseQuery.Count();
    var types = baseQuery.GroupBy(x => x.Type)
                         .Select(x => x.Key).ToList();
    var pageSize = 10;
    var pageIndex = 0;
    var results = baseQuery
                  .OrderBy(x => x.Id)
                  .Skip(pageSize * pageIndex)
                  .Take(pageSize)
                  .ToList();
    Console.WriteLine($"Total:{total}, First Type: {types.First()}, First Item: {results.First().Name}");
}
که سبب می‌شود سه کوئری و سه بار رفت و برگشت را به بانک اطلاعاتی داشته باشیم:
      SELECT COUNT(*)
      FROM [Customers] AS [c]

      SELECT [c].[Type]
      FROM [Customers] AS [c]
      GROUP BY [c].[Type]
  
      SELECT [c].[Name], [c].[Type], [c].[Id]
      FROM [Customers] AS [c]
      ORDER BY [c].[Id]
      OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY

اگر بخواهیم این سه کوئری را یکبار به سمت بانک اطلاعاتی ارسال کنیم، می‌توان از همان ترفند گروه بندی مطرح شده‌ی در این مثال برای ترکیب کوئری‌ها استفاده کرد:
void ManyQueriesOnCall()
{
    using var scope = serviceProvider.CreateScope();
    var context = scope.ServiceProvider.GetRequiredService<CustomerContext>();
    var baseQuery = context.Customers.Select(customer => new
                                                         {
                                                             customer.Name,
                                                             customer.Type,
                                                             customer.Id,
                                                         });
    var pageSize = 10;
    var pageIndex = 0;
    var allTogether = baseQuery
                      .GroupBy(x => 1)
                      .Select(bq => new
                                    {
                                        Total = baseQuery.Count(),
                                        Types = baseQuery.GroupBy(x => x.Type)
                                                         .Select(x => x.Key)
                                                         .ToList(),
                                        Results = baseQuery
                                                  .OrderBy(x => x.Id)
                                                  .Skip(pageSize * pageIndex)
                                                  .Take(pageSize)
                                                  .ToList(),
                                    })
                      .FirstOrDefault();

    Console.WriteLine($"Total:{allTogether.Total}, First Type: {allTogether.Types.First()}, First Item: {allTogether.Results.First().Name}");
}
که اینبار فقط یک کوئری outer apply دار را تولید می‌کند و فقط یکبار، رفت و برگشت به بانک اطلاعاتی را شاهد خواهیم بود:
      SELECT [t0].[Key], [t1].[Type], [t2].[Name], [t2].[Type], [t2].[Id]
      FROM (
          SELECT TOP(1) [t].[Key]
          FROM (
              SELECT 1 AS [Key]
              FROM [Customers] AS [c]
          ) AS [t]
          GROUP BY [t].[Key]
      ) AS [t0]
      OUTER APPLY (
          SELECT [c0].[Type]
          FROM [Customers] AS [c0]
          GROUP BY [c0].[Type]
      ) AS [t1]
      OUTER APPLY (
          SELECT [c1].[Name], [c1].[Type], [c1].[Id]
          FROM [Customers] AS [c1]
          ORDER BY [c1].[Id]
          OFFSET @__p_1 ROWS FETCH NEXT @__pageSize_2 ROWS ONLY
      ) AS [t2]
      ORDER BY [t0].[Key], [t1].[Type], [t2].[Id]

کدهای این مثال را از اینجا می‌توانید دریافت کنید: EF7ManyQueriesOneCall.zip
مطالب
روش اجرای پروژه‌های ASP.NET Core توسط Rider و IIS Express
آخرین نگارش Rider، پشتیبانی از اجرای برنامه‌های ASP.NET Core را توسط IIS Express هم اضافه کرده‌است. در این حالت اگر به صورت پیش‌فرض و بدون تنظیم خاصی، سعی در اجرای برنامه‌ی وب خود توسط IIS Express کنید، با خطای زیر مواجه خواهید شد:
HTTP Error 500.21 - Internal Server Error
Handler "aspNetCore" has a bad module "AspNetCoreModule" in its module list
در ادامه قصد داریم روش رفع این مشکل را بررسی کنیم.


پیشنیازهای کار با IIS Express توسط Rider

- نصب IIS Express به صورت جداگانه
- نصب بسته‌ی هاستینگ ASP.NET Core برای IIS
این مورد برای اضافه شدن AspNetCoreModuleV2 به IIS Express خام فوق، الزامی است.

یک نکته: نگارش بسته‌ی هاستینگ، باید با SDK و یا runtime نصب شده، مطابقت داشته باشد (بنابراین نصب SDK و یا Runtime نیز ضروری است).


معرفی بسته‌ی هاستینگ ASP.NET Core به IIS Express

پس از نصب این بسته‌ها، فایل واقع در مسیر زیر را برای یافتن واژه‌ی AspNetCoreModule جستجو کنید (یک چنین فایلی در مسیر 64 بیتی C:\Program Files\IIS Express\config\templates\PersonalWebServer نیز وجود دارد):
%PROGRAMFILES(x86)%\IIS Express\config\templates\PersonalWebServer\applicationhost.config
همچنین مسیر زیر نیز باید موجود باشد:
%PROGRAMFILES(x86)%\IIS Express\Asp.Net Core Module\V2
اما اگر واژه‌ی AspNetCoreModule، در این فایل ذکر نشده بود و یا مسیر پوشه‌ی Asp.Net Core Module فوق وجود نداشت، یعنی بسته‌ی هاستینگ نصب شده، به IIS Express معرفی نشده‌است. برای رفع این مشکلات:
- ابتدا پوشه‌ی C:\Program Files (x86)\IIS\Asp.Net Core Module را به درون پوشه‌ی C:\Program Files (x86)\IIS Express کپی کنید.
- سپس پوشه‌ی C:\Program Files\IIS\Asp.Net Core Module را به درون پوشه‌ی C:\Program Files\IIS Express کپی کنید.

- در آخر نیاز است دو فایل config\templates\PersonalWebServer\applicationhost.config را در پوشه‌های x86 و x64 مربوط به IIS Express به صورت زیر ویرایش کنیم:
- پیش از بسته شدن تگ globalModules در قسمت <system.webServer><globalModules>، دو سطر زیر را اضافه کنید:
در فایل C:\Program Files\IIS Express\config\templates\PersonalWebServer\applicationhost.config
<add name="AspNetCoreModule" image="C:\Program Files\IIS Express\aspnetcore.dll" />
<add name="AspNetCoreModuleV2" image="C:\Program Files\IIS Express\Asp.Net Core Module\V2\aspnetcorev2.dll" />
و همچنین در فایل C:\Program Files (x86)\IIS Express\config\templates\PersonalWebServer\applicationhost.config
<add name="AspNetCoreModule" image="C:\Program Files (x86)\IIS Express\aspnetcore.dll" />
<add name="AspNetCoreModuleV2" image="C:\Program Files (x86)\IIS Express\Asp.Net Core Module\V2\aspnetcorev2.dll" />

- ذیل تگ <sectionGroup name="system.webServer">، سطر زیر را اضافه کنید:
<section name="aspNetCore" overrideModeDefault="Allow" />

- ذیل تگ <system.webServer><modules>، دو سطر زیر را اضافه کنید:
<add name="AspNetCoreModule" lockItem="true" />
<add name="AspNetCoreModuleV2" lockItem="true" />

البته برای ذخیره سازی فایل‌های موجود در Program Files، باید آن‌ها را با دسترسی ادمین باز کنید. برای مثال اگر از ++nodepad استفاده کنید، به صورت خودکار این مساله را تشخیص داده و دسترسی صحیح را درخواست می‌کند.


تنظیم Rider برای یافتن مسیر صحیح AspNetCoreModuleV2 نصب شده

در برنامه‌ی Rider، از منوی File، قسمت settings آن، گزینه‌ی Build, Execution, Deployment | IIS Express را انتخاب و سپس مسیرهای x86 و x64 را به صورت زیر تنظیم کنید:


البته دراپ داون‌های این صفحه، به صورت خودکار این مسیرها را پر می‌کنند. فقط کافی است، مسیر صحیح را از طریق آن‌ها انتخاب کنید.

- اکنون به ریشه‌ی پروژه‌ی خود مراجعه کرده و فایل idea\config\applicationhost.config. را در صورت وجود حذف کنید (البته بهتر است کل پوشه‌ی idea. و همچنین vs. را (در صورت وجود) حذف کنید؛ هر دو را با هم. مهم!). برنامه‌ی Rider، این فایل تنظیمات موقتی IIS Express را بر اساس دو فایل config\templates\PersonalWebServer\applicationhost.config ای که اصلاح کردیم، به صورت خودکار تولید می‌کند و حاوی تمام تغییرات فوق خواهد بود.

- فایل web.config واقع در ریشه‌ی پروژه وب نیز بهتر است یک چنین محتوایی را داشته باشد:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <handlers>
      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified"/>
    </handlers>
    <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%"                
   stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
  </system.webServer>
</configuration>
در اینجا ذکر تنظیم "hostingModel="InProcess سبب بروز خطا می‌شود و به نظر Rider هنوز از آن پشتیبانی نمی‌کند.


تنظیمات IIS Express در Rider

تنظیمات پورت IIS Express، در فایل Properties\launchSettings.json پروژه‌های وب، قابل مشاهده و تغییر است. اگر نیاز به کار با HTTPS باشد، برنامه‌ی Rider، پیام کوچکی را که در آن لینک setup certificate قرار دارد، نمایش می‌دهد و با کلیک بر روی آن، یک مجوز موقتی self-signed certificate تولید و نصب خواهد شد.


و یا در Rider، از منوی بالای صفحه که تنظیمات Build را نمایش می‌دهد، می‌توان IIS Express را به عنوان اجرا کننده‌ی پروژه، انتخاب کرد. پس از انتخاب آن، یکبار دیگر از همان dropdown می‌توان گزینه‌ی edit configuration را انتخاب کرد تا تنظیمات مخصوص IIS Express، ظاهر شود.

مطالب
ارتباط بین کامپوننت‌ها در Vue.js - قسمت سوم استفاده از تزریق وابستگی‌ها
در قسمت‌های قبلی( ^ و ^) نحوه‌ی ارتباط بین کامپوننت‌ها در Vue.js بررسی و مزایا و معایب آنها بیان شد. روش دیگری هم برای ارسال اطلاعات از کامپوننتِ Parent به فرزندانش وجود دارد که با استفاده از Dependency Injection یا به اختصار DI مقدور می‌باشد و در ورژن +2.2 معرفی شد که نحوه‌ی ارتباط بین کامپوننتِ Parent و فرزندانش را آسان نمود. پیش‌تر برای ارتباط از Parent به Child، از Props استفاده میکردیم، ولی اگر قرار بود در چند سطح این ارتباط عمیق باشد، باز هم مدیریت کردن Props مشکل و سخت بود. اکنون با استفاده از provide و inject قادر خواهیم بود تا آبجکت، فانکشن و یا دیتایِ یک کامپوننتِ Parent را در فرزندانش فراخوانی و استفاده کنیم. اگر در حالت عادی نیاز بود تا در دو سطح، یا بیشتر (مانند تصویر زیر) دیتایِ کامپوننت پدر را به فرزند، نوه و ... انتقال دهیم، می‌بایست اطلاعات را بصورت Props به هر Level انتقال دهیم.



روش جاری شباهت زیادی به استفاده از Context در React دارد:

Context provides a way to pass data through the component tree without having to pass props down manually at every level


جهت به اشتراک گذاری دیتا یا تابعی در کامپوننت Parent با Children، به شکل زیر عمل میکنیم. در اینجا با استفاده از provide، دیتای foo به اشتراک گذاشته شده‌است:
// parent component providing 'foo'
var Provider = {
  provide: {
    foo: 'bar'
  },
  // ...
}
و در کامپوننت‌های فرزند به شکل زیر میتوانیم مقدار foo را دریافت کنیم:
// child component injecting 'foo'
var Child = {
  inject: ['foo'],
  created () {
    console.log(this.foo) // => "bar"
  }
  // ...
}

میتوانیم مقدار پیش فرض دیتایِ ارسالی از کامپوننت Parent را در قسمت data و props در کامپوننت Child دریافت نماییم:
Using an injected value as the default for a prop
//دریافت میکنیم props در قسمت  child را در کامپوننت  foo مقدار
const Child = {
  inject: ['foo'],
  props: {
    bar: {
      default () {
        return this.foo
      }
    }
  }
}

Using an injected value as data entry
//دریافت میکنیم data در قسمت  child را در کامپوننت  foo مقدار
const Child = {
  inject: ['foo'],
  data () {
    return {
      bar: this.foo
    }
  }
}

نکته: در این روش در صورتیکه دیتایِ به اشتراک گذاشته شده در کامپوننتِ Parent تغییر کند، مقدار آن در کامپوننت Child تغییری نخواهد کرد و مانند روش‌های قبلی (^ و ^) نیست و نیاز به نوشتن کدی برای تعامل داشتن و به‌روز رسانی مقادیر، در کامپوننت Child می‌باشد.
کد زیر  را در نظر بگیرید؛ با زدن دکمه‌ی Increment counter  مقدار counter در کامپوننتِParent تغییر میکند، ولی در کامپوننت Child، مقدار counter_in_child  تغییری حاصل نمی‌کند.
<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <script src="https://cdn.jsdelivr.net/npm/vue"></script>
  <title>Dependency injection</title>
</head>

<body>
  <div id="app">
    <button @click="counter++">Increment counter</button>
    <h2>Parent</h2>
    <p>{{counter}}</p>
    <div>
      <h3>Child</h3>
      <child></child>
    </div>
  </div>
  
<script>
const Child = {
  inject: ['counter_in_child'],
  template: `<div>Counter Child is:{{ counter_in_child }}</div>`
};

new Vue ({
  el: "#app",
  components: { Child },
  provide() {
    return {
      counter_in_child: this.counter
    };
  },
  data() {
    return {
      counter: 0
    };
  }
});
</script>

</body>
</html>
       
برای اینکه بتوان تغییرات ایجاد شده‌ی بر روی دیتا را در کامپوننتِChild، مشاهده کرد، نیاز داریم کد زیر را در قسمت provide به ازای آن دیتا اضافه کنیم: 
<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <script src="https://cdn.jsdelivr.net/npm/vue"></script>
  <title>Dependency injection</title>
</head>

<body>
  <div id="app">
    <button @click="counter++">Increment counter</button>
    <h2>Parent</h2>
    <p>{{counter}}</p>
    <div>
      <h3>Child</h3>
      <child></child>
    </div>
  </div>
  
<script>
const Child = {
  inject: ['counter_in_child'],
  template: `<div>Counter Child is:{{ counter_in_child.counter }}</div>`
};

new Vue ({
  el: "#app",
  components: { Child },
  provide() {
    const counter_in_child={};
Object.defineProperty(counter_in_child,'counter',{
enumerable:true,
get:()=>this.counter
})
    return {
      counter_in_child
    };
  },
  data() {
    return {
      counter: 0
    };
  }
});
</script>

</body>
</html>

مثالی از نحوه به اشتراک گذاری متد بین Parent و Child.

نتیجه گیری:
A) استفاده از این روش مرسوم نیست و بیشتر برای ساخت پلاگین در Vuejs مورد استفاده قرار میگیرد:
provide  and  inject  are primarily provided for advanced plugin / component library use cases. It is NOT recommended to use them in generic application code
B) برای استفاده از این روش کتابخانه‌هایی جهت ساده‌تر کردن بکارگیری ایجاد شده‌است.
C) این روش برای ارتباط  Sibling Component مناسب نیست.
مطالب
فارسی کردن گرید تلریک در برنامه های ویندوزی

در پروژه‌های ویندوزی یکی از بیشترین ابزار کاربردی گریدویو  تلریک Telerik GridView میباشد و اینکه تمامی امکانات گرید مانند گروه بندی ، فیلترینگ و ... همه فارسی باشند خیلی برای پروژه خوب است.
منم در یکی از پروژه‌ها نیاز به فارسی کردن این ابزار پرکاربرد ویندوزی داشتم و توانستم این مورد را حل کنم . نحوه فارسی کردن این ابزار به شرح ذیل میباشد:

1- یک پروژه جدید ویندوزی در visual studio  ایجاد میکنیم

2- اضافه کردن یک radGridView به فرم و خاصیت Dock آن را به حالت Fill و خاصیت RightToLeft را Yes قرار میدهیم :

3- حال برای اینکه یک سری اطلاعاتی داخل این گرید نمایش بدهیم یک کلاس در همان فرم درست میکنیم مشابه کد ذیل :
   public List<MyCustomData> GetData() {

            List<MyCustomData> myList = new List<MyCustomData>();
            for (int i = 1; i < 11; i++)
            {
                myList.Add(new MyCustomData() {
                     ID = i,
                     Name = "Name Family " + i.ToString(),
                      Age = 29
                });
            }

            return myList;
        }

       public class MyCustomData
        {
            public int ID { get; set; }
            public string Name { get; set; }
            public int Age { get; set; }
            public bool Sex { get; set; }
            
        }

4 - حال برای اینکه این اطلاعات را در گرید نمایش دهیم کد زیر را در بخش Load_Form1 مینویسیم :
 private void Form1_Load(object sender, EventArgs e)
        {
            radGridView1.DataSource = GetData();
        }
5 - در این صورت اگر برنامه را اجرا کنیم بدین صورت در گرید نمایش داده میشود که هیچ کدام از موارد فارسی نیستند:
 
6 - برای اینکه این موارد فارسی شوند نیاز به یک کلاس یا Provider داریم که این عمل ترجمه را انجام دهد که حتی در سایت خود تلریک در بخش مربوطه نیز ارائه شده است. بنده این کلاس را کپی کرده و تمامی ترجمه‌های آنها را نیز نوشتم ( اگر در ترجمه ایرادی بود به بزرگی خودتان بخشیده و تصحیح نمائید . ) که کد آن را در زیر میتوانید در اختیار داشته باشید:
class PersianRadGridLocalizationProvider : RadGridLocalizationProvider
    {
        public override string GetLocalizedString(string id)
        {
            switch (id)
            {
                case RadGridStringId.FilterFunctionBetween: return "بین"; //Between  
                case RadGridStringId.FilterOperatorBetween: return "بین";
                case RadGridStringId.FilterFunctionContains: return "حاوی";
                case RadGridStringId.FilterOperatorContains: return "حاوی";
                case RadGridStringId.FilterFunctionDoesNotContain: return "شامل نشود"; //Does not contain
                case RadGridStringId.FilterOperatorDoesNotContain: return "شامل نشود";
                case RadGridStringId.FilterFunctionEndsWith: return "پایان پذیرد با"; //Ends with 
                case RadGridStringId.FilterOperatorEndsWith: return "پایان پذیرد با";
                case RadGridStringId.FilterFunctionEqualTo: return "برابر با"; //Equals     
                case RadGridStringId.FilterOperatorEqualTo: return "برابر با";
                case RadGridStringId.FilterFunctionGreaterThan: return "بزرگتر از"; //Greater than
                case RadGridStringId.FilterOperatorGreaterThan: return "بزرگتر از";
                case RadGridStringId.FilterFunctionGreaterThanOrEqualTo: return "بزرگتر یا مساوی با"; //Greater than or equal to 
                case RadGridStringId.FilterOperatorGreaterThanOrEqualTo: return "بزرگتر یا مساوی با";
                case RadGridStringId.FilterFunctionIsEmpty: return "خالی باشد"; //Is empty
                case RadGridStringId.FilterOperatorIsEmpty: return "خالی باشد";
                case RadGridStringId.FilterFunctionIsNull: return "تهی باشد"; //Is null
                case RadGridStringId.FilterOperatorIsNull: return "تهی باشد";
                case RadGridStringId.FilterFunctionLessThan: return "کمتر از"; //Less than 
                case RadGridStringId.FilterOperatorLessThan: return "کمتر از";
                case RadGridStringId.FilterFunctionLessThanOrEqualTo: return "کمتر یا مساوی با"; //Less than or equal to
                case RadGridStringId.FilterOperatorLessThanOrEqualTo: return "کمتر یا مساوی با";
                case RadGridStringId.FilterFunctionNoFilter: return "بدون شرط"; //No filter 
                case RadGridStringId.FilterOperatorNoFilter: return "بدون شرط";
                case RadGridStringId.FilterFunctionNotBetween: return "نباشد بین"; //Not between
                case RadGridStringId.FilterOperatorNotBetween: return "نباشد بین"; //Operator
                case RadGridStringId.FilterFunctionNotEqualTo: return "برابر نباشد با"; //Not equal to 
                case RadGridStringId.FilterOperatorNotEqualTo: return "برابر نباشد با";
                case RadGridStringId.FilterFunctionNotIsEmpty: return "خالی نباشد"; //Is not empty          
                case RadGridStringId.FilterFunctionNotIsNull: return "خالی نباشد"; //Is not null         
                case RadGridStringId.FilterFunctionStartsWith: return "شروع شود با"; //Starts with          
                case RadGridStringId.FilterFunctionCustom: return "شرط دلخواه"; //Custom          
                case RadGridStringId.CustomFilterMenuItem: return "شرط دلخواه منو"; //Custom         
                case RadGridStringId.CustomFilterDialogCaption: return "انتخاب شرط دلخواه"; //RadGridView Custom Filter Dialog         
                case RadGridStringId.CustomFilterDialogLabel: return ":نشان دادن سطرهایی که"; //Show rows where:         
                case RadGridStringId.CustomFilterDialogRbAnd: return "و"; //And         
                case RadGridStringId.CustomFilterDialogRbOr: return "یا"; //Or          
                case RadGridStringId.CustomFilterDialogBtnOk: return "تایید"; //OK         
                case RadGridStringId.CustomFilterDialogBtnCancel: return "انصراف"; //Cancel 
                case RadGridStringId.AddNewRowString: return "برای افزودن سطر جدید اینجا کلیک کنید";
                case RadGridStringId.ClearValueMenuItem: return "پاک کردن مقدار سلول";
                case RadGridStringId.DeleteRowMenuItem: return "حذف سطر"; //Delete Row          
                case RadGridStringId.SortAscendingMenuItem: return "مرتب سازی صعودی"; //Sort Ascending         
                case RadGridStringId.SortDescendingMenuItem: return "مرتب سازی نزولی"; //Sort Descending         
                case RadGridStringId.ClearSortingMenuItem: return "حذف مرتب سازی"; //Clear Sorting         
                case RadGridStringId.ConditionalFormattingMenuItem: return "قالب بندی مشروط"; //Conditional Formatting         
                case RadGridStringId.GroupByThisColumnMenuItem: return "گروهبندی بر حسب این ستون"; //Group by this column         
                case RadGridStringId.UngroupThisColumn: return "حذف این ستون از گروهبندی "; //Ungroup this column         
                case RadGridStringId.ColumnChooserMenuItem: return "انتخابگر ستون"; //Column Chooser         
                case RadGridStringId.HideMenuItem: return "مخفی کردن ستون"; //Hide         
                case RadGridStringId.UnpinMenuItem: return "حالت پیش فرض"; //Unpin         
                case RadGridStringId.PinMenuItem: return "حالت ستون"; //Pin       
                case RadGridStringId.PinAtLeftMenuItem: return "چسپیدن به سمت چپ";
                case RadGridStringId.PinAtRightMenuItem: return "چسپیدن به سمت راست";
                case RadGridStringId.PinAtTopMenuItem: return "چسپیدن به بالا";
                case RadGridStringId.PinAtBottomMenuItem: return "چسپیدن به پایین";
                case RadGridStringId.BestFitMenuItem: return "اندازه بهینه ستون"; //Best Fit         
                case RadGridStringId.PasteMenuItem: return "چسپاندن"; //Paste         
                case RadGridStringId.EditMenuItem: return "ویرایش"; //Edit         
                case RadGridStringId.CopyMenuItem: return "کپی"; //Copy         
                case RadGridStringId.ConditionalFormattingCaption: return "قالب بندی مشروط"; //Custom Formatting Condition Editor   
                case RadGridStringId.ConditionalFormattingLblColumn: return "قالب بندی سلولهایی با شرط:"; //Column:         
                case RadGridStringId.ConditionalFormattingLblName: return "نام شرط:"; //Name:          
                case RadGridStringId.ConditionalFormattingLblType: return "مقدار سلول:"; //Type:         
                case RadGridStringId.ConditionalFormattingLblValue1: return "مقدار اول:"; //Value 1:         
                case RadGridStringId.ConditionalFormattingLblValue2: return "مقدار دوم:"; //Value 2:         
                case RadGridStringId.ConditionalFormattingGrpConditions: return "شرایط"; //Conditions         
                case RadGridStringId.ConditionalFormattingGrpProperties: return "مشخصات"; //Properties         
                case RadGridStringId.ConditionalFormattingChkApplyToRow: return "اعمال این شرط به کل سطر"; //Apply to row         
                case RadGridStringId.ConditionalFormattingBtnAdd: return "افزودن شرایط"; //Add         
                case RadGridStringId.ConditionalFormattingBtnRemove: return "حذف شرایط انتخابی"; //Remove         
                case RadGridStringId.ConditionalFormattingBtnOK: return "تایید"; //OK         
                case RadGridStringId.ConditionalFormattingBtnCancel: return "انصراف"; //Cancel         
                case RadGridStringId.ConditionalFormattingBtnApply: return "اعمال قالب بندی"; //Apply         
                case RadGridStringId.ColumnChooserFormCaption: return "انتخاب ستون ها"; //Column Chooser         
                case RadGridStringId.ColumnChooserFormMessage: return "برای حذف یکی از ستونها، آن ستون را به اینجا بکشید";//"Drag a column header from the grid here to remove it from the current view.";
                case RadGridStringId.CompositeFilterFormErrorCaption: return "خطا";
                case RadGridStringId.ConditionalFormattingChooseOne: return "[یکی را انتخاب کنید]";
                case RadGridStringId.ConditionalFormattingContains: return "[حاوی [مقدار اول";
                case RadGridStringId.ConditionalFormattingDoesNotContain: return "حاوی [مقدار اول] نباشد";
                case RadGridStringId.ConditionalFormattingEndsWith: return "با [مقدار اول] پایان یابد";
                case RadGridStringId.ConditionalFormattingEqualsTo: return "[برابر با [مقدار اول";
                case RadGridStringId.ConditionalFormattingIsBetween: return "بین [مقدار اول] و [مقدار دوم] باشد";
                case RadGridStringId.ConditionalFormattingIsGreaterThan: return "[بزرگتر از [مقدار اول";
                case RadGridStringId.ConditionalFormattingIsGreaterThanOrEqual: return "[بزرگتر یا مساوی با [مقدار اول";
                case RadGridStringId.ConditionalFormattingIsLessThan: return "کوچکتر از [مقدار اول]";
                case RadGridStringId.ConditionalFormattingIsLessThanOrEqual: return "کوچکتر یا مساوی با [مقدار اول]";
                case RadGridStringId.ConditionalFormattingIsNotBetween: return "بین [مقدار اول] و [مقدار دوم] نباشد";
                case RadGridStringId.ConditionalFormattingIsNotEqualTo: return "برابر با [مقدار اول] نباشد";
                case RadGridStringId.ConditionalFormattingRuleAppliesOn: return "اعمال شرایط روی:";
                case RadGridStringId.ConditionalFormattingStartsWith: return "با [مقدار اول] شروع می‌شود";
                case RadGridStringId.CustomFilterDialogCheckBoxNot: return "با این شرایط نباشد";
                case RadGridStringId.CustomFilterDialogFalse: return "False";
                case RadGridStringId.CustomFilterDialogTrue: return "True";
                case RadGridStringId.FilterCompositeNotOperator: return "نباشد";
                case RadGridStringId.FilterLogicalOperatorAnd: return "و";
                case RadGridStringId.FilterLogicalOperatorOr: return "یا";
                case RadGridStringId.FilterMenuAvailableFilters: return "فیلتر شده";
                case RadGridStringId.FilterMenuButtonCancel: return "انصراف";
                case RadGridStringId.FilterMenuButtonOK: return "تایید";
                case RadGridStringId.FilterMenuClearFilters: return "پاک کردن فیلتر";
                case RadGridStringId.FilterMenuSearchBoxText: return "جستجو...";
                case RadGridStringId.FilterMenuSelectionAll: return "همه";
                //case RadGridStringId.FilterMenuSelectionAllSearched: return "نتیجه همه جستجو";
                case RadGridStringId.FilterMenuSelectionNotNull: return "خالی نباشد";
                case RadGridStringId.FilterMenuSelectionNull: return "خالی باشد";
                case RadGridStringId.FilterOperatorCustom: return "دلخواه";
                case RadGridStringId.FilterOperatorIsLike: return "مانند";
                case RadGridStringId.FilterOperatorNotIsContainedIn: return "نباشد در";
                case RadGridStringId.FilterOperatorNotIsEmpty: return "خالی نباشد";
                case RadGridStringId.FilterOperatorNotIsLike: return "نباشد شبیه";
                case RadGridStringId.FilterOperatorNotIsNull: return "خالی نباشد";
                case RadGridStringId.FilterOperatorStartsWith: return "شروع شود با";
                case RadGridStringId.GroupingPanelDefaultMessage: return "برای گروهبندی ستونها، ستونی را به اینجا بکشید";
                case RadGridStringId.GroupingPanelHeader: return ":گروهبندی بر حسب";
                case RadGridStringId.NoDataText: return "داده ای برای نمایش وجود ندارد";
                case RadGridStringId.UnpinRowMenuItem: return "حالت پیش فرض";
                default:
                    return base.GetLocalizedString(id);
            }
        }
    }

7 - حال اگر برنامه را اجرا کنید باز موارد انگلیسی گرید تلریک فارسی نمی‌شوند و باید در کلاس Program.cs پروژه این یک خط کد را هم اضافه نمائید.
//using Telerik.WinControls.UI.Localization;

 RadGridLocalizationProvider.CurrentProvider = new PersianRadGridLocalizationProvider();

8 - حال اگر برنامه را اجرا نمایید تمامی موارد را فارسی مشاهده خواهید نمود ( شکل ذیل )

لطفا ما را از نظرات سازنده خود بی نصیب نفرمائید. با تشکر


مطالب
استفاده از خواص راهبری در Entity framework بجای Join نویسی
یکی از مزایای مهم استفاده از Entity framework، خواص راهبری (navigation properties) آن هستند که امکان تهیه کوئری‌های بین جداول را به سادگی و به نحوی منطقی فراهم می‌کنند.
برای مثال دو جدول شهر‌ها و افراد را درنظر بگیرید. مقصود از تعریف جدول شهر‌ها در اینجا، مشخص سازی محل تولد افراد است:
    public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }

        [ForeignKey("BornInCityId")]
        public virtual City BornInCity { get; set; }
        public int BornInCityId { get; set; }
    }

    public class City
    {
        public int Id { get; set; }
        public string Name { get; set; }

        public virtual ICollection<Person> People { get; set; }
    }
در ادامه این کلاس‌ها را در معرض دید EF Code first قرار داده:
    public class MyContext : DbContext
    {
        public DbSet<City> Cities { get; set; }
        public DbSet<Person> People { get; set; }
    }


و همچنین تعدادی رکورد آغازین را نیز به جداول مرتبط اضافه می‌کنیم:
    public class Configuration : DbMigrationsConfiguration<MyContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = true;
            AutomaticMigrationDataLossAllowed = true;
        }

        protected override void Seed(MyContext context)
        {
            var city1 = new City { Name = "city-1" };
            var city2 = new City { Name = "city-2" };
            context.Cities.Add(city1);
            context.Cities.Add(city2);

            var person1 = new Person { Name = "user-1", BornInCity = city1 };
            var person2 = new Person { Name = "user-2", BornInCity = city1 };
            context.People.Add(person1);
            context.People.Add(person2);

            base.Seed(context);
        }
    }
در این حالت برای نمایش لیست نام افراد به همراه محل تولد آن‌ها، بنابر روال سابق SQL نویسی، نوشتن کوئری LINQ زیر بسیار متداول است:
    public static class Test
    {
        public static void RunTests()
        {
            Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, Configuration>());

            using (var context = new MyContext())
            {
                var peopleAndCitiesList = from person in context.People
                           join city in context.Cities
                           on person.BornInCityId equals city.Id
                           select new
                           {
                              PersonName = person.Name,
                              CityName = city.Name
                           };

                foreach (var item in peopleAndCitiesList)
                {
                    Console.WriteLine("{0}:{1}", item.PersonName, item.CityName);
                }
            }
        }
    }
که حاصل آن اجرای کوئری ذیل بر روی بانک اطلاعاتی خواهد بود:
SELECT 
          [Extent1].[BornInCityId] AS [BornInCityId], 
          [Extent1].[Name] AS [Name], 
          [Extent2].[Name] AS [Name1]
FROM  [dbo].[People] AS [Extent1]
INNER JOIN [dbo].[Cities] AS [Extent2] ON [Extent1].[BornInCityId] = [Extent2].[Id]
این نوع کوئری‌های join دار را به نحو ساده‌تری نیز می‌توان در EF با استفاده از خواص راهبری و بدون join نویسی مستقیم تهیه کرد:
var peopleAndCitiesList = context.People
                                  .Select(person => new
                                                         {
                                                             PersonName = person.Name,
                                                             CityName = person.BornInCity.Name
                                                         });
که دقیقا همان خروجی SQL یاد شده را تولید می‌کند.

مثال دوم:
می‌خواهیم لیست شهرها را بر اساس تعداد کاربر متناظر به صورت نزولی مرتب کنیم:
var citiesList = context.Cities.OrderByDescending(x => x.People.Count());
foreach (var item in citiesList)
{
    Console.WriteLine("{0}", item.Name);
}
همانطور که مشاهده می‌کنید از خواص راهبری در قسمت order by هم می‌شود استفاده کرد. خروجی SQL کوئری فوق به صورت زیر است:
SELECT 
[Project1].[Id] AS [Id], 
[Project1].[Name] AS [Name]
FROM ( SELECT 
        [Extent1].[Id] AS [Id], 
        [Extent1].[Name] AS [Name], 
        (SELECT 
                COUNT(1) AS [A1]
                FROM [dbo].[People] AS [Extent2]
                WHERE [Extent1].[Id] = [Extent2].[BornInCityId]) AS [C1]
        FROM [dbo].[Cities] AS [Extent1]
)  AS [Project1]
ORDER BY [Project1].[C1] DESC

مثال سوم:
در ادامه قصد داریم لیست شهرها را به همراه تعداد نفرات متناظر با آن‌ها نمایش دهیم:
 var peopleAndCitiesList = context.Cities
                                     .Select(city => new
                                                 {
                                                     InUseCount = city.People.Count(),
                                                     CityName = city.Name
                                                 });

foreach (var item in peopleAndCitiesList)
{
     Console.WriteLine("{0}:{1}", item.CityName, item.InUseCount);
}
در اینجا از خاصیت راهبری People برای شمارش تعداد اعضای متناظر با هر شهر استفاده شده است.
خروجی SQL کوئری فوق به نحو ذیل است:
SELECT 
[Extent1].[Id] AS [Id], 
(SELECT 
        COUNT(1) AS [A1]
        FROM [dbo].[People] AS [Extent2]
        WHERE [Extent1].[Id] = [Extent2].[BornInCityId]) AS [C1], 
[Extent1].[Name] AS [Name]
FROM [dbo].[Cities] AS [Extent1]