نظرات مطالب
EF Code First #12
من از EF 4.3.1 استفاده می‌کنم ولی متد AddOrUpdate ندارد
مطالب
دریافت خروجی سایت
یکی از مشکلاتی که من هر روز در لاگ‌های سایت مشاهده می‌کنم، علاقه وافر بسیاری برای دریافت محتوای کل سایت با استفاده از برنامه‌های مخصوص آن است. البته این افراد هیچ وقت به طور کامل موفق نخواهند شد چون سایت پس از مدتی IP آن‌ها را خواهد بست. اما ... این بازی از روز اول تمامی نداشته ....



بنابراین ضمن اعلام آتش بس (!) اعلام می‌دارد کل محتوای سایت به صورت یک فایل PDF در قسمت ویژه کاربران سایت، قابل دریافت است و یا «دریافت خروجی کامل NET Tips. با فرمت EPub»
این محتوا به صورت خودکار هر روز صبح ساعت 5، بر اساس آخرین تغییرات سایت، به روز خواهد شد.
 

یک نکته: فایل‌های CHM دریافتی از طریق مرورگرها، به صورت پیش‌فرض قابل نمایش نیستند. باید بر روی آن‌ها کلیک راست کنید و سپس در برگه‌ی خواص فایل، بر روی دکمه‌ی unblock آن فایل کلیک کنید تا قابل استفاده شود. 

نظرات مطالب
پیاده سازی یک سیستم دسترسی Role Based در Web API و AngularJs - بخش سوم (پایانی)
در پاسخ به سوال شما باید عرض کنم که حرف شما کاملا درست است. به این دلیل که با هر فراخوانی از سمت کلاینت لیست permissionهای کاربر واکشی میشود. برای کم کردن این فراخوانی‌ها و واکشی‌ها ما چند راه در پیش رو خواهیم داشت.
1. استفاده از  caching اولین راه حل و ساده‌ترین راه حل هست. به این صورت که در هنگامی که کاربر وارد برنامه میشود تمامی دسترسی‌های او در cache ذخیره شود. برای این کار نیاز به نوشتن سرویسی برای مدیریت این حافظه است. فرض کنید در این حین دسترسی نقشی که کاربر در آن نقش است تغییر کند. بنابراین باید تمامی cache از نو ایجاد شود. توجه کنید که ما نمیتوانیم در معماری REST و Web API از Session استفاده کنیم. به این دلیل که فرایندها در این معماری Stateless هستند، به این معنی که چیزی را در خود نگه نمیدارند.
2. روش دیگر استفاده از Claim در Asp.Net Identity 2 است. در سیستم Identity جدید Asp شما قادر هستید چندین Claim برای کاربر تنظیم (set) کنید. برای این کار میتوانید مقاله ای در این زمینه را از سایت bitOfTech مطالعه کنید. در این مجموعه  مقالات تشریح شده است که چگونه میتوان Claim‌های شخصی سازی شده در سیستم تعریف کرد. در نهایت این Claimها hash شده و در Token کاربر ذخیره میشوند. توصیه میکنم اگر تعداد دسترسی‌های شما در هر نقش زیاد نیست میتوانید از این روش استفاده کنید. البته این را مد نظر داشته باشید در این مقالات نحوه Authorize کردن کاربر با آنچه ما در این مجموعه مقالات تشریح کردیم کمی متفاوت است. 
مسیرراه‌ها
SQL Server
آخرین تاریخ بروزرسانی 93/10/21


SQL Server 2005

SQL Server 2008

SQL Server 2012

SQL Serve 2014


نظرات مطالب
غیرمعتبر شدن کوکی‌های برنامه‌های ASP.NET Core هاست شده‌ی در IIS پس از ری‌استارت آن
یک نکته‌ی تکمیلی: روش ذخیره سازی کلید موقتی تولید شده در بانک اطلاعاتی بجای حافظه‌ی سرور

سیستم data protection به همراه اینترفیسی است به نام IXmlRepository که از آن می‌توان برای مشخص سازی محل ذخیره سازی XML ایی اطلاعات کلید تولید شده استفاده کرد. این امکان هم وجود دارد که این اینترفیس را طوری پیاده سازی کرد تا اطلاعات را درون بانک اطلاعاتی ذخیره کند. به صورت ذیل:
ابتدا کلاس AppDataProtectionKey را به عنوان یک موجودیت جدید به سیستم EF معرفی می‌کنیم:
public class AppDataProtectionKey
{
    public int Id { get; set; }
    public string FriendlyName { get; set; }
    public string XmlData { get; set; }
}
کار این جدول، ذخیره سازی اطلاعات کلید موقتی است تا پس از ری استارت سرور، این اطلاعات از دست نروند و قابلیت بازیابی خودکار را داشته باشند.


سپس آن‌را به Context برنامه به صورت ذیل اضافه می‌کنیم:
 public virtual DbSet<AppDataProtectionKey> AppDataProtectionKeys { get; set; }
با این تنظیمات:
modelBuilder.Entity<AppDataProtectionKey>(builder =>
{
   builder.ToTable("AppDataProtectionKeys");
   builder.HasIndex(e => e.FriendlyName).IsUnique();
});

در ادامه پیاده سازی ویژه‌ی ذیل را از IXmlRepository، که از اطلاعات فوق استفاده می‌کند، تهیه خواهیم کرد:
    public class DataProtectionKeyService : IXmlRepository
    {
        private readonly IServiceProvider _serviceProvider;

        public DataProtectionKeyService(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
            _serviceProvider.CheckArgumentIsNull(nameof(_serviceProvider));
        }

        public IReadOnlyCollection<XElement> GetAllElements()
        {
            return _serviceProvider.RunScopedContext<ReadOnlyCollection<XElement>>(context =>
            {
                var dataProtectionKeys = context.Set<AppDataProtectionKey>();
                return new ReadOnlyCollection<XElement>(dataProtectionKeys.Select(k => XElement.Parse(k.XmlData)).ToList());
            });
        }

        public void StoreElement(XElement element, string friendlyName)
        {
            // We need a separate context to call its SaveChanges several times,
            // without using the current request's context and changing its internal state.
            _serviceProvider.RunScopedContext(context =>
            {
                var dataProtectionKeys = context.Set<AppDataProtectionKey>();
                var entity = dataProtectionKeys.SingleOrDefault(k => k.FriendlyName == friendlyName);
                if (null != entity)
                {
                    entity.XmlData = element.ToString();
                    dataProtectionKeys.Update(entity);
                }
                else
                {
                    dataProtectionKeys.Add(new AppDataProtectionKey
                    {
                        FriendlyName = friendlyName,
                        XmlData = element.ToString()
                    });
                }
                context.SaveChanges();
            });
        }
    }
در این اینترفیس نحوه‌ی دسترسی به یک context جدید، اندکی متفاوت است از حالت‌های متداول. در اینجا چون می‌خواهیم این کلاس تاثیری را بر روی واحد کار درخواست جاری نگذارد، یک context جدید را برای آن وهله سازی می‌کنیم و از context موجود در طی طول عمر درخواست جاری استفاده نخواهیم کرد.
اطلاعات متدهای سرویس فوق به صورت خودکار توسط سیستم data-protection تامین می‌شوند. تنها کاری را که در اینجا انجام داده‌ایم، گوش فرادادن به این تغییرات و ذخیره سازی آن‌ها در بانک اطلاعاتی است.

مرحله‌ی آخر کار، معرفی این تغییرات به سیستم است که نحوه‌ی انجام آن‌را در ذیل مشاهده می‌کنید:
        private static void addCustomDataProtection(this IServiceCollection services, SiteSettings siteSettings)
        {
            services.AddScoped<IXmlRepository, DataProtectionKeyService>();
            services.AddSingleton<IConfigureOptions<KeyManagementOptions>>(serviceProvider =>
            {
                return new ConfigureOptions<KeyManagementOptions>(options =>
                {
                    var scopeFactory = serviceProvider.GetRequiredService<IServiceScopeFactory>();
                    using (var scope = scopeFactory.CreateScope())
                    {
                        options.XmlRepository = scope.ServiceProvider.GetService<IXmlRepository>();
                    }
                });
            });
            services
                .AddDataProtection()
                .SetDefaultKeyLifetime(siteSettings.CookieOptions.ExpireTimeSpan)
                .SetApplicationName(siteSettings.CookieOptions.CookieName)
                .UseCryptographicAlgorithms(new AuthenticatedEncryptorConfiguration
                {
                    EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
                    ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
                });
        }
ابتدا محل تامین سرویس IXmlRepository مشخص شده‌است. سپس روش مقدار دهی XmlRepository  را ملاحظه می‌کنید که باید به این صورت باشد. مقدار آن نیز از سرویس DataProtectionKeyService سفارشی ما تامین می‌شود. در انتها طول عمر کلید تولید شده، نام برنامه و الگوریتم‌های مدنظر تنظیم شده‌اند.

همین مقدار تنظیم سبب خواهد شد تا به صورت خودکار اطلاعات موقتی کلیدهای رمزنگاری سیستم data-protection در بانک اطلاعاتی ذخیره شده و یا بازیابی شوند.

این تغییرات به پروژه‌ی DNTIdentity اعمال شده‌اند.