مطالب
ارتقاء به Entity framework 6 و استفاده از بانک‌های اطلاعاتی غیر از SQL Server
برای ارتقاء برنامه‌های قدیمی به EF 6 (که با دات نت 4 به بعد سازگار است) دو حالت استفاده از نیوگت را در حین افزودن ارجاعات لازم به کتابخانه‌های مرتبط با EF باید مدنظر داشت:
الف) از نیوگت استفاده کرده‌اید
در این حالت فقط کافی است کنسول پاورشل نیوگت را در VS.NET گشوده و دستور update-package را صادر کنید. (1) به صورت خودکار آخرین نگارش EF دریافت شده و (2) همچنین فایل کانفیگ برنامه برای افزودن و به روز رسانی تعاریف مرتبط با نگارش 6 به روز گردیده و (3) همچنین اسمبلی اضافی و قدیمی System.Data.Entity.dll نیز حذف خواهد شد.

ب) اگر از نیوگت استفاده نکرده‌اید
ابتدا یک فایل متنی ساده را به نام packages.config با محتوای ذیل به پروژه خود اضافه کنید.
 <?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="EntityFramework" version="5.0.0" targetFramework="net40" />
</packages>
سپس بر روی نام Solution در VS.NET کلیک راست کرده و گزینه فعال سازی Restore بسته‌های نیوگت را فعال کنید (انتخاب گزینه Enable NuGet Package Restore). در ادامه یکبار برنامه را Build کنید تا پوشه packages به صورت خودکار از اینترنت دریافت و بازسازی شود. اکنون دستور update-package را در کنسول پاورشل نیوگت صادر کنید. همان مراحل قسمت الف تکرار خواهند شد.

لازم به ذکر است، اگر پروژه شما از چندین زیر پروژه تشکیل شده است که هر کدام نیز ارجاعی را به اسمبلی EF دارند، باید فایل packages.config فوق را به این زیر پروژه‌ها نیز اضافه کنید. دستور update-package، زیر پروژه‌ها را نیز اسکن کرده و تمام ارجاعات لازم را به صورت خودکار به روز می‌کند. همچنین اسمبلی‌های قدیمی اضافی را نیز حذف خواهد کرد. به این ترتیب با تداخل نگارش‌های قدیمی و جدید EF مواجه نخواهید شد.


مشکلاتی که ممکن است با آن‌ها مواجه شوید:

الف) برنامه کامپایل نمی‌شود
تنها تغییری که جهت کامپایل برنامه باید انجام دهید، استفاده از فضاهای نام جدید بجای فضاهای قدیمی موجود در اسمبلی منسوخ و حذف شده System.Data.Entity.dll است. خود VS.NET قابلیت یافتن فضاهای نام مرتبط را دارد و یا اگر از Resharper نیز استفاده می‌کنید، این قابلیت بهبود یافته است. در کل مثلا System.Data.EntityState شده است System.Data.Entity.EntityState و امثال آن که به روز رسانی آن‌ها نکته خاصی ندارد .


ب) پروایدر بانک اطلاعاتی مورد استفاده یافت نمی‌شود
به صورت پیش فرض فقط پروایدر SQL Server به همراه بسته EF 6 است. حتی پروایدر SQL Server CE نیز با آن ارائه نمی‌شود. اگر از SQL Server CE استفاده کرده‌اید، باید دستور ذیل را نیز پس از نصب EF 6 صادر کنید:
 PM> Install-Package EntityFramework.SqlServerCompact
تا با خطای ذیل مواجه نشوید:
 No Entity Framework provider found for the ADO.NET provider with invariant name 'System.Data.SqlServerCe.4.0'.
Make sure the provider is registered in the 'entityFramework' section of the application config file.
See http://go.microsoft.com/fwlink/?LinkId=260882 for more information.
استفاده از نیوگت به روشی که عنوان شد، فایل کانفیگ برنامه شما را جهت افزودن تعاریف پروایدرهای لازم، به روز می‌کند و این مورد در EF 6 الزامی است (حتما باید تعریف پروایدر در فایل کانفیگ موجود باشد).


ج) خطای عدم وجود کلید خارجی جدول Migration را دریافت می‌کنید
 The foreign key constraint does not exist. [ PK_dbo.__MigrationHistory ]
تا EF 5 نام کلید اصلی جدول MigrationHistory به صورت PK___MigrationHistory می‌باشد.
 ALTER TABLE [__MigrationHistory] ADD CONSTRAINT [PK___MigrationHistory] PRIMARY KEY ([MigrationId]);
در EF 6 این نام شده است PK_dbo.__MigrationHistory
برای حل این مشکل تنها کافی است دستورات ذیل را یکبار بر روی بانک اطلاعاتی خود صادر کنید تا نام مورد نظر به عنوان کلید اصلی جدول migration اضافه شود؛ در غیراینصورت اصلا برنامه اجرا نخواهد شد:
 ALTER TABLE [__MigrationHistory] drop CONSTRAINT [PK___MigrationHistory];
ALTER TABLE [__MigrationHistory] ADD CONSTRAINT [PK_dbo.__MigrationHistory] PRIMARY KEY (MigrationId);
البته یکبار برنامه را اجرا کنید. اگر خطای نبود کلید اصلی یاد شده صادر شد، آنگاه دو دستور فوق را اجرا نمائید.
نظرات مطالب
آشنایی با NHibernate - قسمت هشتم
برای اینکه از بحث دور نشیم، در NHibernate این الگوها قابل مشاهده است:
الگوی Facade که همان session و ISession معروف آن است و کار آن فراخوانی تعداد قابل ملاحظه‌ای زیر سیستم و مخفی کردن آن‌ها از دید کاربر نهایی است. به این صورت شما توانایی کار کردن با انواع بانک‌های اطلاعاتی را بدون درگیر شدن با جزئیات آن‌ها از طریق یک اینترفیس عمومی پیدا می‌کنید.
الگوی proxy که پایه و اساس lazy loading آن است.
الگوی object pool جهت مدیریت اتصالات آن به بانک اطلاعاتی
الگوی Interpreter جهت مدیریت کوئری‌های ویژه آن
و ...

الگوی Repository هم یک نوع نگارش سفارشی الگوی Facade است. در اینجا یک سیستم پیچیده (یک سطح بالاتر است از ISession که کارش مخفی کردن ساختار داخلی NHibernate است) یا همان ORM مورد نظر را دریافت کرده و یک اینترفیس ساده، قابل درک و عمومی را از آن را ارائه می‌دهد. هدف آن مخفی کردن ریز جزئیات روش کار با یک ORM خاص است. به همین جهت به آن Persistence Ignorance هم گفته می‌شود.
الگوی Repository یکی از الگوهای اصلی DDD یا Domain driven design است.
نظرات مطالب
EF Code First #12
اگر از VS 2013 و EF 6 استفاده می‌کنید، حالت DB First آن در حقیقت مهندسی معکوس دیتابیس موجود به حالت Code first است. برای مثال اگر این فایل DbModel.edmx را تولید کند، ذیل آن فایل DbModel.Context.tt مشخص است که حاصل آن تولید خودکار یک چنین کلاسی است:
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated from a template.
//
//     Manual changes to this file may cause unexpected behavior in your application.
//     Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace EFDbFirstDependencyInjection.DataLayer
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;
    
    public partial class TestDbIdentityEntities : DbContext
    {
        public TestDbIdentityEntities()
            : base("name=TestDbIdentityEntities")
        {
        }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            throw new UnintentionalCodeFirstException();
        }
    
        public virtual DbSet<Category> Categories { get; set; }
        public virtual DbSet<Product> Products { get; set; }
    }
}
این کلاس دقیقا از DbContext حالت Code first استفاده می‌کند و کلا ObjectContext قدیمی را کنار گذاشته‌اند (حتی برای حالت DB First).


بنابراین تمام نکات مطلب جاری در مورد حالت DB First موجود در VS 2013 صادق است. فقط باید فایل DbModel.Context.tt آن‌را اصلاح کنید تا IUnitOfWork را به صورت خودکار به انتهای تعریف کلاس Context اضافه کند. مابقی مسایل آن یکی است.
مطالب
روش از کار انداختن صفحه‌ی Add service reference در VS.NET

در جهت تکمیل بحث "بررسی امنیتی، حین استفاده از jQuery Ajax"، یک مورد دیگر را هم می‌توان اضافه کرد: چگونه صفحه‌ی معروف Add service reference را در VS.NET جهت سرویس WCF خود از کار بیندازیم؟
راه حل آن هم بسیار ساده است اما چون عموما در منابع مرتبط با جملات و کلمات بیش از حد فنی بیان می‌شود، شاید از دید دور مانده باشد:
اگر WCF Service تولیدی شما تنها قرار است توسط برنامه‌ی Silverlight یا جاوا اسکریپتی موجود در پروژه‌ی جاری مورد استفاده قرار گیرد، باید Meta Data مرتبط با آن سرویس را جهت بالابردن امنیت سیستم، حذف نمود. توسط این Meta Data می‌توان ServiceContract ، OperationContract و سایر اطلاعات یک WCF Service را استخراج نمود.

الف) روش غیر فعال کردن متادیتا در یک Ajax enabled WCF Service

به فایل وب کانفیگ برنامه مراجعه کرده و تغییر زیر را اعمال کنید:
...
<behavior name="">
<serviceMetadata httpGetEnabled="false" httpsGetUrl="false" />
...
</behavior>
...

ب) روش غیرفعال کردن متادیتا در یک Silverlight enabled WCF Service

ابتدا قسمت الف را اعمال نموده سپس تغییر زیر را نیز لحاظ نمائید (IMetadataExchange به صورت کامنت درآمده):
<!-- <endpoint address="mex" binding="mexHttpBinding"
contract="IMetadataExchange" /> -->

با این تغییرات ساده، گزینه‌ی Add service reference دیگر قابلیت تشخیص خودکار اطلاعات سرویس شما را نداشته و با یک خطا متوقف خواهد شد:
The HTML document does not contain Web service discovery information.
Metadata contains a reference that cannot be resolved.

سؤال:
1- آیا با این تغییر در عملکرد WCF سرویس ما اخلال ایجاد خواهد شد؟
پاسخ: خیر. تنها Web service discovery information را از کار انداخته‌ایم.
2- در صورت تغییر کدهای WCF Service چه باید کرد؟
پاسخ: اگر امضای متدها و اینترفیس‌های تعریف شده تغییری نداشته‌اند، لزومی به هیچ نوع تغییری نیست. در غیراینصورت، سریع موارد الف و ب فوق را به حالت اول برگردانده، کلاینت مورد استفاده را به روز کنید، مجددا متادیتا را حذف نمائید.

بازخوردهای پروژه‌ها
چند پیشنهاد
با تشکر از ایده و نرم افزار جالب شما، چند ایده به نظر بنده می‌تواند کمک کننده باشد:
1. دانلود خودکار یا غیر خودکار آخرین دیتابیس توسط برنامه
2. تبدیل لینک‌های داخلی از لینک به سایت به لینک در سطح داخلی برنامه
3. دانلود عکس‌ها و فایل‌های مرتبط جهت ایجاد نسخه 100% آفلاین
4. ایجاد امکان full screen برای html viewer برای خواندن ساده‌تر متون
اشتراک‌ها
ده‌هزار بار سریع‌تر! شدن تشخیص جفت‌های آکولاد در VSCode، یک درس آموزنده برای برنامه‌نویس‌ها

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

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

ده‌هزار بار سریع‌تر! شدن تشخیص جفت‌های آکولاد در VSCode، یک درس آموزنده برای برنامه‌نویس‌ها
اشتراک‌ها
انتشار ReSharper Ultimate 2018.3.2

ReSharper 2018.3.2 bug-fix update fixes:

- Many issues in C#, VB.NET, and TypeScript Code Analysis.
- More than a dozen issues related to parameter name hints.
- Missing “Find Code Dependent on Module” item in a context menu for a project node in the Solution Explorer tab.
- Several issues in Unit Testing.
- Some issues related to auto-detect naming style.
 

انتشار ReSharper Ultimate 2018.3.2
مطالب
روش دیگر نوشتن Model binderهای سفارشی در ASP.NET Core 7x با معرفی IParseable
ASP.NET MVC از روش بکارگیری binding providerها برای تدارک زیرساخت model binding استفاده می‌کند که در این روش، داده‌های پارامترهای یک action method از طریق هدرها، کوئری استرینگ‌ها، بدنه‌ی درخواست و غیره تهیه می‌شوند. در حالت پیش‌فرض اگر این پارامترها از نوع‌های ساده‌ای مانند اعداد و یا DateTime تشکیل شده باشند و یا به همراه یک TypeConverter باشند که امکان تبدیل این رشته را به آن نوع خاص بدهد، به صورت خودکار bind خواهند شد و هر نوع دیگری، به صورت یک نوع پیچیده درنظر گرفته می‌شود. نوع پیچیده یعنی bind برای مثال اطلاعات بدنه‌ی درخواست به تک تک خواص آن نوع. برای نمونه در کنترلر زیر:
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private static readonly string[] Summaries =
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy",
        "Hot", "Sweltering", "Scorching",
    };

    // /WeatherForecast/GetForecast2?from=1&to=3
    [HttpGet("[action]")]
    public IEnumerable<WeatherForecast> GetForecast2(Duration days)
    {
        return Enumerable.Range(days.From, days.To)
                         .Select(index => new WeatherForecast
                                          {
                                              Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
                                              TemperatureC = Random.Shared.Next(-20, 55),
                                              Summary = Summaries[Random.Shared.Next(Summaries.Length)],
                                          })
                         .ToArray();
    }
}
که از دو مدل زیر استفاده می‌کند:
public class Duration
{
    public int From { get; set; }
    public int To { get; set; }
}

public class WeatherForecast
{
    public DateOnly Date { get; set; }

    public int TemperatureC { get; set; }

    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);

    public string? Summary { get; set; }
}
می‌توان خواص پارامتر days را از طریق کوئری استرینگ‌های HttpGet، برای مثال با ارائه‌ی آدرس WeatherForecast/GetForecast2?from=1&to=3 به صورت خودکار تامین کرد. زمانیکه اطلاعات رسیده چنین شکلی را داشته باشند، کار پردازش و bind آن‌ها در حالت HttpGet، خودکار است.


روش دیگر پردازش اطلاعات رشته‌ای رسیده و تشکیل یک Model Binder سفارشی در ASP.NET Core 7x

اکنون فرض کنید بجای آدرس WeatherForecast/GetForecast2?from=1&to=3 که اطلاعات را از طریق کوئری استرینگ مشخص و استانداردی دریافت می‌کند، می‌خواهیم اطلاعات آن‌را از طریق یک قالب سفارشی و غیراستاندارد مانند WeatherForecast/GetForecast3/1-3 دریافت کنیم:
// /WeatherForecast/GetForecast3/1-3
[HttpGet("[action]/{days}")]
public IEnumerable<WeatherForecast> GetForecast3(Days days)
    {
        return Enumerable.Range(days.From, days.To)
                         .Select(index => new WeatherForecast
                                          {
                                              Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
                                              TemperatureC = Random.Shared.Next(-20, 55),
                                              Summary = Summaries[Random.Shared.Next(Summaries.Length)],
                                          })
                         .ToArray();
    }
یکی از راه‌های انجام اینکار، نوشتن model binderهای سفارشی مخصوص است و یا اکنون در ASP.NET Core 7x می‌توان با پیاده سازی اینترفیس IParsable به صورت خودکار و با روشی دیگر به این مقصود رسید:
using System.Diagnostics.CodeAnalysis;
using System.Globalization;

namespace NET7Mvc.Models;

public class Days : IParsable<Days>
{
    public Days(int from, int to)
    {
        From = from;
        To = to;
    }

    public int From { get; }
    public int To { get; }

    public static bool TryParse([NotNullWhen(true)] string? value,
                                IFormatProvider? provider,
                                [MaybeNullWhen(false)] out Days result)
    {
        var items = value?.Split('-', StringSplitOptions.RemoveEmptyEntries);
        if (items is { Length: 2 })
        {
            if (int.TryParse(items[0], NumberStyles.None, provider, out var from)
                && int.TryParse(items[1], NumberStyles.None, provider, out var to))
            {
                result = new Days(from, to);
                return true;
            }
        }

        result = default;
        return false;
    }

    public static Days Parse(string value, IFormatProvider? provider)
    {
        if (!TryParse(value, provider, out var result))
        {
            throw new ArgumentException("Could not parse the given value.", nameof(value));
        }

        return result;
    }
}
- برای پیاده سازی این اینترفیس باید دو متد TryParse و Parse آن‌را به صورت فوق پیاده سازی کرد و توسط آن، روش تبدیل رشته‌ی دریافتی از کاربر را به شیء مدنظر، مشخص کرد.
- همینقدر که مدلی IParsable را پیاده سازی کرده باشد، از امکانات آن به صورت خودکار استفاده خواهد شد و نیازی به معرفی و یا تنظیمات خاص دیگری ندارد.
- البته این قابلیت جدید نیست و پشتیبانی از IParsable، پیشتر در Minimal API دات نت 6 ارائه شده بود؛ اما در دات نت 7 توسط ASP.NET Core MVC نیز قابل استفاده شده‌است.