مطالب
توسعه یک Web API با استفاده از ASP.NET Core و MongoDb (قسمت اول)

در این مقاله قصد داریم یک Api تحت وب را با استفاده از فریم‌ورک ASP.NET Core توسعه دهیم تا عملیات CRUD را بر روی دیتابیس MongoDb که یکی از محبوب‌ترین دیتابیس‌های NoSql است، انجام دهد. قبل از شروع کار باید ویژوال استودیو نسخه‌ی 2019 را نصب داشته باشید؛ به‌طوریکه ورک لود ASP.NET and web development را  هم حتما همراه آن نصب کرده باشید. علاوه بر آن باید .Net Core SDK 3.0+ و دیتابیس MongoDb را هم نصب کنید که می‌توانید آنها را از آدرس‌های زیر دانلود کنید. نگران نصب MongoDb هم نباشید چون نکته خاصی ندارد. 

https://docs.mongodb.com/manual/tutorial/install-mongodb-on-windows/

https://dotnet.microsoft.com/download/dotnet-core

نسخه‌ی جاری MongoDb، 4.4 است که پس از نصب، به صورت پیشفرض در آدرس C:\Program Files\MongoDB قرار می‌گیرد. در مسیر C:\Program Files\MongoDB\Server\4.4\bin فایل‌های اصلی MongoDb قرار دارند و برای تعامل با MongoDb، به این فایل‌ها نیاز خواهیم داشت. پس برای اینکه به راحتی بتوان در هر جای سیستم از طریق پاورشل به این فایل‌ها دسترسی داشته باشید، این مسیر را به Path environment variable ویندوز اضافه کنید.

MongoDb دارای یک بخش اصلی یا اصطلاحا یکdaemon  است که وظیفه‌ی آن، پردازش درخواست‌هایی است که برای کار با داده‌ها صادر می‌شود. در حقیقت همه کارهایی که ما با داده‌ها انجام می‌دهیم مثلا دسترسی به داده‌ها و دستکاری آن‌ها، از طریق این daemon انجام می‌گیرد و پشت صحنه‌ی این daemon، با Storage Engine کار خواهد کرد.  برای اجرای daemon، پاور شل را باز کنید و دستور mongod را وارد کنید. اگر با تنظیمات پیشفرض اجرا کنید، بر روی پورت 27017 بالا آمده و فایل‌های دیتابیس را هم در مسیر C:\data\db قرار می‌دهد. اگر این مسیر را نداشته باشید، با خطا مواجه می‌شوید. یا باید این مسیر را تعریف کنید و یا از سوئیچ dbpath -- استفاده کنید تا مسیر فایل دیتابیس را تغییر دهید. پس پاور شل را باز کنید و دستور زیر را وارد کنید.

>> mongod --dbpath C:\BooksData
پس از اجرا شدن daemon ، باید از طریق شل mongo که یک شل جاوااسکریپتی است، به آن متصل شویم. از طریق این شل می‌توان کوئری‌ها و دستورات دستکاری داده‌ها را بر روی دیتابیس MongoDb اجرا کنیم. پس یک کنسول پاورشل جدید را باز کرده و دستور زیر را در آن وارد کنید.
>> mongo
پس از متصل شدن به شل، از طریق دستورuse ، یک دیتابیس را به نام BookstoreDb بسازید. بنابراین دستور زیر را وارد کنید.

>> use BookstoreDb
توجه کنید اگر از قبل این دیتابیس وجود داشته باشد، از آن استفاده می‌کند و گرنه آن را خواهد ساخت. بعد از اینکه پیغام switched to db BookstoreDb را مشاهده کردید، می‌توانید هر جا که به این دیتابیس نیاز داشته باشید، از دستور db استفاده نمایید که اشاره به دیتابیسی دارد که آن را use کرده‌ایم.

بعد از ساختن دیتابیس، باید یک کالکشن بسازید. کالکشن‌ها را می‌توان معادل جداول، در دیتابیس‌های رابطه‌ای تصور کرد. با دستور createCollection می توان اینکار را انجام داد. برای اینکار دستور زیر را وارد کنید.

>> db.createCollection('Books')
با این دستور، یک کالکشن با نام Books ساخته می‌شود. اگر پیغام { ok" : 1" } را دیدید، مطمئن باشید که کالکشن Books به درستی ساخته شده‌است. در واقع بعد از ساختن اولین کالکشن، دیتابیس ساخته می‌شود. با دستور show dbs می‌توانید دیتابیس‌های ساخته شده را ببینید.

بعد از ساختن کالکشن، می‌خواهیم مقداری دیتا را در آن قرار دهیم. معادل رکورد در دیتابیس‌های رابطه‌ای، در دیتابیس مونگو دی‌بی، Document نام دارد که مانند رکوردهای دیتابیس‌های رابطه‌ای نیست و ساختار و اسکیمای خاصی ندارد؛ یعنی می‌توان هر دیتایی را با هر ساختاری در آن ذخیره کرد. می‌خواهیم دو Document را به کالکشن Books اضافه کنیم. پس دستور زیر را وارد می‌کنیم. توجه کنید داده‌ها با ساختار json وارد می‌شوند.

>> db.Books.insertMany([{'Name':'Design Patterns','Price':54.93,'Category':'Computers','Author':'Ralph Johnson'}, {'Name':'Clean Code','Price':43.15,'Category':'Computers','Author':'Robert C. Martin'}])
بعد از اجرای دستور بالا، نتایج زیر را در خروجی می‌بینید که گویای این مطلب است که دو Document جدید اضافه شده‌است و خود سرور، به هر یک از داکیومنت‌ها، یک شناسه یا آی دی اختصاص داده‌است و Ack درست هم برگشت داده شده‌است که به معنای انجام درست کار است. اگر می‌خواهید خودتان به داکیومنت‌هایی که می‌سازید آی دی بدهید، باید از پراپرتی id_ استفاده نمایید.
 {
      "acknowledged" : true,
      "insertedIds" : [
         ObjectId("5bfd996f7b8e48dc15ff215d"),
         ObjectId("5bfd996f7b8e48dc15ff215e")
      ]
}
برای اینکه محتویات کالکشنی را مشاهده کنید، دستور زیر را وارد کنید. همانطور که اشاره شد، db، به دیتابیس ساخته شده اشاره دارد؛ Books همان کالکشن‌مان است و با استفاده از متد find می‌توان داده‌های کالکشن را جستجو کرد که در این مثال ما، هیچ فیلتری به آن نداده‌ایم. پس در نتیجه تمام دیتاها را بر می‌گرداند. متد pretty هم داده‌های برگشتی را در یک ساختار مرتب نمایش می‌دهد.
>> db.Books.find().pretty()
و خروجی زیر را مشاهده خواهید کرد
 {
      "_id" : ObjectId("5bfd996f7b8e48dc15ff215d"),
      "Name" : "Design Patterns",
      "Price" : 54.93,
      "Category" : "Computers",
      "Author" : "Ralph Johnson"
},
{
      "_id" : ObjectId("5bfd996f7b8e48dc15ff215e"),
      "Name" : "Clean Code",
      "Price" : 43.15,
      "Category" : "Computers",
      "Author" : "Robert C. Martin"
}
حالا دیتابیس ما آماده شده‌است. در بخش‌های بعدی با استفاده از فریم ورک   ASP.NET Core Web Api  ، Api هایی خواهیم نوشت که داده‌های این دیتابیس را به بیرون ارائه خواهد داد. 

مطالب
MongoDb در سی شارپ (بخش هشتم)
در الگوهایی که به عنوان واسط بین اپلیکیشن و دیتابیس تعریف میکنیم نام دو الگوی Repository و Unit of work به چشم میخورد. در این سایت بارها این مباحث به صورت گفتمان و مقالات تکرار شده‌اند و میدانیم که این الگوها کمک شایانی برای بالا بردن کارآیی برنامه، عدم تکرار کد، قابلیت استفاده مجدد و راحتی کار برای آزمون‌های واحد و چهارچوب‌های تقلید میکنند.

Unit of Work یا الگوی کار در واقع یک الگو، جهت جمع آوری عملیات کار با دیتابیس است که همه عملیات را تحت یک تراکنش به سمت دیتابیس ارسال میکند تا مبحث Atomic بودن عملیات، به مرحله اجرا گذاشته شود. در صورتیکه یکی از عملیات با نقص یا خطایی روبرو شود، کل عملیات Roll back یا برگشت میخورد. از آنجا که دیتابیس‌های معدودی چون Ravendb این مراحل را تا حدی پیاده سازی میکنند نباید از مونگو هم چنین انتظاری نداشته باشید. مونگو برخورد تراکنشی یا اتمیک ندارد؛ پس پیاده سازی الگوی واحد کاری تاثیری بر روی روند کاری آن ندارد. هر چند تعدادی مثال بدین شکل پیاده شده‌اند، ولی در عمل حقیقی نیستند و تنها یک حرکت مشابه داشته‌اند.

ولی الگوی repository  برای پرهیز از تکرار کد، قابلیت به روزرسانی کد و همچنین عملیاتی چون آزمون‌های واحد و چهارچوب تقلید به کار میرود. وابستگی بین اشیاء را کاهش داده و باعث ایجاد یک کد با دوام‌تر میگردد.

ابتدا قبل از هر چیزی نیاز است تا اتصالات یا ساخت کانکشن به سرور و همچنین دریافت دیتابیس مورد نظر را در قالب یک کلاس تعریف نماییم. نام آن را MongoDbContext میگذارم:
   public class MongoDbContext : IMongoDbContext
    {
        public const string DatabaseName = "MongoDbTest";

        private static readonly IMongoClient _client;
        private static readonly IMongoDatabase Database;

        static MongoDbContext()
        {
            _client = new MongoClient();
            Database = _client.GetDatabase(DatabaseName);
        }

        public IMongoCollection<TEntity> GetCollection<TEntity>()
        {
            return Database.GetCollection<TEntity>(typeof(TEntity).Name.ToLower() + "s");
        }
    }
در حالت بالا شما میتوانید در سازنده کلاس اتصال را برقرار کرده و دیتابیس را دریافت نمایید و از متد GetCollection در سطوح بالاتر، نوع کالکشن درخواستی خود را اعلام کنید. اگر به خط اول کلاس دقت نمایید میبینید که ما از اینترفیسی به نام IMongoDbContext که شامل خطوط زیر میباشد استفاده کردیم و دلیل استفاده این است که اگر قرار باشد از کلاس کانتکست، در کلاس‌های repository استفاده شود، ایجاد وابستگی میکند. چرا که معلوم نیست این کانتکست دقیقا چیست و از کجا آمده است و در آزمون واحد و همچنین تقلید دست ما را می‌بندد و الگوی repository را مردود اعلام میکند. پس از این حیث یک اینترفیس با محتوای زیر تولید کرده‌ایم که از این پس از آن در کدها استفاده میکنیم و پر کردن این اینترفیس‌ها را از طریق تزریق وابستگی‌ها در حالت Constructor Injection که ساده‌ترین نوع آن است انجام میدهیم:
public interface IMongoDbContext
    {    
        IMongoCollection<TEntity> GetCollection<TEntity>();
    }
در صورتیکه دوست دارید محتوای‌های دیگری را چون کانکشن استرینگ و .. نیز در اینجا بگنجانید، به عهده خود شماست. تنها نیاز به تغییراتی کوچک است.
در مرحله بعد یک IMongoDbRepositry ساخته و محتوای آن را به شکل زیر پر میکنیم:
public interface IMongoDbRepository
{
Task<List<TEntity>> GetMany<TEntity>(FilterDefinition<TEntity> filter) where TEntity : class, new();
}
در اینجا کلاس‌ها را از نوع جنریک تعریف میکنیم تا کاربر بتواند هر نوع کلاسی را که نیاز دارد، به سمت این مخزن ارسال کند. در پیاده سازی هم به شکل زیر آن را تعریف میکنیم:
public class MongoRepository : IMongoDbRepository
    {

        private IMongoDbContext _mongoDbContext ;
        public MongoRepository(IMongoDbContext mongoDbContext)
        {
            _mongoDbContext = mongoDbContext;
        }
 public async Task<List<TEntity>> GetMany<TEntity>(FilterDefinition<TEntity> filter) where TEntity : class, new()
        {            
                var collection = GetCollection<TEntity>();
                var entities = await collection.Find(filter).ToListAsync();                
                return entities;
        }

 private IMongoCollection<TEntity> GetCollection<TEntity>()
        {
            return _mongoDbContext.GetCollection<TEntity>();
        } 
 }
همانطور که می‌بینید در ابتدا در سازنده از طریق یک کتابخانه‌ی تزریق وابستگی‌ها (که در اینجا من از Structure map استفاده کرده‌ام) شیء ImongoDbContext را مقدار دهی میکنیم. الان اگر در اینجا بجای تعریف اینترفیس، از همان کلاس مستقیما استفاده میکردیم، بین دو لایه repository و context یک وابستگی ایجاد میشد. ولی در اینجا کانتکست میتواند هر چیزی باشد. بعد از آن به تعریف متد مورد نظر پرداخته‌ایم. البته با توجه به اینکه این تنها یک مثال است، بنده تنها یکی از این متدها را به عنوان نمونه نشان داده‌ام و میتوانید فایل‌های کامل آن را در انتهای مقاله دریافت نمایید. همانطور که مشاهده میکنیم، متدها به صورت غیرهمزمان نوشته شده‌اند که باعث مقیاس پذیری برنامه میشوند و در اینجا از متدهای همزمان استفاده نکرده‌ایم؛ چرا که افرادی که از دیتابیس‌های غیر رابطه‌ای استفاده میکنند، نیاز به مقیاس پذیری بالایی دارند. به همین دلیل نیاز چندانی به استفاده از متدهای همزمان دیده نمیشود. ولی خودتان در صورت تمایل میتوانید آن‌ها را به اینترفیس اضافه کنید. در ضمن در کد بالا متد خصوصی را جهت دریافت کالکشن نوشته‌ایم تا دریافت کالکشن را در کدها، تا حدی خلاصه‌تر و شیواتر کنیم.

الگوی بالا در یک کنترلر به شرح زیر استفاده شده است:
 public class HomeController : Controller
    {
        private IMongoDbRepository _mongoDbRepository;

        public HomeController(IMongoDbRepository mongoDbRepository)
        {
            this._mongoDbRepository = mongoDbRepository;
        }
        // GET: Home
        public async Task<ActionResult> Index()
        {
            var filter = Builders<Resturant>.Filter.Gte("Capacity", 400);
            var c =await _mongoDbRepository.GetMany<Resturant>(filter);       
            return View(c);
        }
    }
در کد بالا رستورانهایی را که 400 نفر یا بیشتر ظرفیت پذیرایی دارند، واکشی کرده و در ویوو نشان میدهد. در اینجا الگوی repo، توسط تزریق وابستگی‌ها ساخته شده و کانتکست آن‌ها به همین شکل ساخته خواهد شد و در کل کنترلر، قابلیت استفاده را دارند.

  MongoRepository.zip
مطالب
OpenCVSharp #15
تشخیص چهره به کمک OpenCV

OpenCV به کمک الگوریتم‌های machine learning (در اینجا Haar feature-based cascade classifiers) و داد‌ه‌های مرتبط با آن‌ها، قادر است اشیاء پیچیده‌ای را در تصاویر پیدا کند. برای پیگیری مثال بحث جاری نیاز است کتابخانه‌ی اصلی OpenCV را دریافت کنید؛ از این جهت که به فایل‌های XML موجود در پوشه‌ی opencv\sources\data\haarcascades آن نیاز داریم. در اینجا از دو فایل haarcascade_eye_tree_eyeglasses.xml و haarcascade_frontalface_alt.xml آن استفاده خواهیم کرد (این دوفایل جهت سهولت کار، به همراه مثال این بحث نیز ارائه شده‌اند).
فایل haarcascade_frontalface_alt.xml اصطلاحا trained data مخصوص یافتن چهره‌ی انسان در تصاویر است و فایل haarcascade_eye_tree_eyeglasses.xml کمک می‌کند تا بتوان در چهره‌ی یافت شده، چشمان شخص را نیز با دقت بالایی تشخیص داد؛ چیزی همانند تصویر ذیل:



مراحل تشخیص چهره توسط OpenCVSharp

ابتدا همانند سایر مثال‌های OpenCV، تصویر مدنظر را به کمک کلاس Mat بارگذاری می‌کنیم:
var srcImage = new Mat(@"..\..\Images\Test.jpg");
Cv2.ImShow("Source", srcImage);
Cv2.WaitKey(1); // do events
 
var grayImage = new Mat();
Cv2.CvtColor(srcImage, grayImage, ColorConversion.BgrToGray);
Cv2.EqualizeHist(grayImage, grayImage);
همچنین در اینجا جهت بالا رفتن سرعت کار و بهبود دقت تشخیص چهره، این تصویر اصلی به یک تصویر سیاه و سفید تبدیل شده‌است و سپس متد Cv2.EqualizeHist بر روی آن فراخوانی گشته‌است. این متد وضوح تصویر را جهت یافتن الگوها بهبود می‌بخشد.
سپس فایل xml یاد شده‌ی در ابتدای بحث را توسط کلاس CascadeClassifier بارگذاری می‌کنیم:
var cascade = new CascadeClassifier(@"..\..\Data\haarcascade_frontalface_alt.xml");
var nestedCascade = new CascadeClassifier(@"..\..\Data\haarcascade_eye_tree_eyeglasses.xml");
 
var faces = cascade.DetectMultiScale(
    image: grayImage,
    scaleFactor: 1.1,
    minNeighbors: 2,
    flags: HaarDetectionType.Zero | HaarDetectionType.ScaleImage,
    minSize: new Size(30, 30)
    );
 
Console.WriteLine("Detected faces: {0}", faces.Length);
پس از بارگذاری فایل‌های XML اطلاعات نحوه‌ی تشخیص چهره و اعضای آن، با فراخوانی متد DetectMultiScale، کار تشخیص چهره و استخراج آن از grayImage انجام خواهد شد. در اینجا minSize، اندازه‌ی حداقل چهره‌ی مدنظر است که قرار هست تشخیص داده شود. نواحی کوچکتر از این اندازه، به عنوان نویز در نظر گرفته خواهند شد و پردازش نمی‌شوند.
خروجی این متد، مستطیل‌ها و نواحی یافت شده‌ی مرتبط با چهره‌های موجود در تصویر هستند. اکنون می‌توان حلقه‌ای را تشکیل داد و این نواحی را برای مثال با مستطیل‌های رنگی، متمایز کرد:
var rnd = new Random();
var count = 1;
foreach (var faceRect in faces)
{
    var detectedFaceImage = new Mat(srcImage, faceRect);
    Cv2.ImShow(string.Format("Face {0}", count), detectedFaceImage);
    Cv2.WaitKey(1); // do events
 
    var color = Scalar.FromRgb(rnd.Next(0, 255), rnd.Next(0, 255), rnd.Next(0, 255));
    Cv2.Rectangle(srcImage, faceRect, color, 3);
  
    count++;
}
 
Cv2.ImShow("Haar Detection", srcImage);
Cv2.WaitKey(1); // do events
در اینجا علاوه بر رسم یک مستطیل، به دور ناحیه‌ی تشخیص داده شده، نحوه‌ی استخراج تصویر آن ناحیه را هم در سطر var detectedFaceImage مشاهده می‌کنید.

همچنین اگر علاقمند باشیم تا در این ناحیه‌ی یافت شده، چشمان شخص را نیز استخراج کنیم، می‌توان به نحو ذیل عمل کرد:
var rnd = new Random();
var count = 1;
foreach (var faceRect in faces)
{
    var detectedFaceImage = new Mat(srcImage, faceRect);
    Cv2.ImShow(string.Format("Face {0}", count), detectedFaceImage);
    Cv2.WaitKey(1); // do events
 
    var color = Scalar.FromRgb(rnd.Next(0, 255), rnd.Next(0, 255), rnd.Next(0, 255));
    Cv2.Rectangle(srcImage, faceRect, color, 3);
 
 
    var detectedFaceGrayImage = new Mat();
    Cv2.CvtColor(detectedFaceImage, detectedFaceGrayImage, ColorConversion.BgrToGray);
    var nestedObjects = nestedCascade.DetectMultiScale(
        image: detectedFaceGrayImage,
        scaleFactor: 1.1,
        minNeighbors: 2,
        flags: HaarDetectionType.Zero | HaarDetectionType.ScaleImage,
        minSize: new Size(30, 30)
        );
 
    Console.WriteLine("Nested Objects[{0}]: {1}", count, nestedObjects.Length);
 
    foreach (var nestedObject in nestedObjects)
    {
        var center = new Point
        {
            X = Cv.Round(nestedObject.X + nestedObject.Width * 0.5) + faceRect.Left,
            Y = Cv.Round(nestedObject.Y + nestedObject.Height * 0.5) + faceRect.Top
        };
        var radius = Cv.Round((nestedObject.Width + nestedObject.Height) * 0.25);
        Cv2.Circle(srcImage, center, radius, color, thickness: 3);
    }
 
    count++;
}
 
Cv2.ImShow("Haar Detection", srcImage);
Cv2.WaitKey(1); // do events
کدهای ابتدایی آن همانند توضیحات قبل است. تنها تفاوت آن، استفاده از nestedCascade بارگذاری شده‌ی در ابتدای بحث می‌باشد. این nestedCascade حاوی trained data استخراج چشمان اشخاص، از تصاویر است. پارامتر ورودی آن‌را نیز تصویر سیاه و سفید ناحیه‌ی چهره‌ی یافت شده‌، قرار داده‌ایم تا سرعت تشخیص چشمان شخص، افزایش یابد.


کدهای کامل این مثال را از اینجا می‌توانید دریافت کنید.
نظرات مطالب
شروع به کار با EF Core 1.0 - قسمت 3 - انتقال مهاجرت‌ها به یک اسمبلی دیگر
روش ارتقاء به EF Core 2.0

حداقل وابستگی‌های مورد نیاز جهت کار با EF Core 2.0 و همچنین اجرای مهاجرت‌های آن به صورت ذیل است:
  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.0" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.0" PrivateAssets="All" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.0" PrivateAssets="All" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="2.0.0" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.0.0" />
  </ItemGroup>
  <ItemGroup>
    <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
  </ItemGroup>

سپس تغییر مهم دیگر، ندید گرفتن پارامتر startup-project به طور کامل است (نکته‌ای که در مطلب فوق در مورد آن بحث شده‌است). اگر Context برنامه‌ی شما دارای پارامتر است، EF Core 2.0 «در حین اجرای مهاجرت‌ها» به صورت صریح نیاز دارد بداند که چطور باید این Context را وهله سازی کرد و دیگر مانند قبل سعی نمی‌کند وابستگی‌های تزریق شده‌ی در آن‌را حدس بزند:
Unable to create an object of type 'ApplicationDbContext'. 
Add an implementation of 'IDesignTimeDbContextFactory<ApplicationDbContext>' to the project, 
or see https://go.microsoft.com/fwlink/?linkid=851728 for additional patterns supported at design time.
به همین جهت در اینجا باید اینترفیس جدید IDesignTimeDbContextFactory را پیاده سازی کرده و سپس مشخص کنید چگونه می‌توان یک ApplicationDbContext را وهله سازی کرد:
    public class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
    {
        public ApplicationDbContext CreateDbContext(string[] args)
        {
            return new ApplicationDbContext(siteSettings, httpContextAccessor, hostingEnvironment, logger);
        }
    }
این کلاس ویژه باید در اسمبلی قرار گیرد که Context برنامه در آن تعریف شده‌است و یافتن آن توسط EF Core 2.0 خودکار است.
یک نمونه پیاده سازی کامل آن را که در پروژه‌ی DNTIdentity بکار رفته‌است، در اینجا می‌توانید مشاهده کنید.

مثالی دیگر برای حالتیکه سازنده‌ی کلاس Context یک <DbContextOptions<T را دریافت می‌کند:
public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<MyDbContext> 
{ 
    public MyDbContext CreateDbContext(string[] args) 
    { 
        IConfigurationRoot configuration = new ConfigurationBuilder() 
            .SetBasePath(Directory.GetCurrentDirectory()) 
            .AddJsonFile("appsettings.json") 
            .Build(); 
        var builder = new DbContextOptionsBuilder<MyDbContext>(); 
        var connectionString = configuration.GetConnectionString("DefaultConnection"); 
        builder.UseSqlServer(connectionString); 
        return new MyDbContext(builder.Options); 
    } 
}
مطالب
لینک‌های هفته اول دی

وبلاگ‌ها و سایت‌های ایرانی

امنیت



ASP. Net


طراحی وب

PHP


اس‌کیوال سرور


سی شارپ


عمومی دات نت


مسایل اجتماعی و انسانی برنامه نویسی


کتاب‌های رایگان جدید


متفرقه
  • آهن بجای کروم! (یک برنامه نویس آلمانی قسمت‌هایی از مرورگر کروم را که در جهت جمع آوری اطلاعات برای گوگل بکار می‌رفته، حذف کرده و مرورگر دیگری به نام آهن را ارائه داده است!)

نظرات اشتراک‌ها
معرفی کتابخانه FastMember برای کار با Reflection
پشنهاد میکنم این مطلب  و مطلب اصلی مطالعه کنید. پایه تمام این کتابخانه‌ها هستند البته کتابخانه‌ی معرفی شده توسط شما امکانات بهتری دارد. این موارد بیشتر برای آشنایی کامل‌تر معرفی کردم.
خودم هم موارد مطلب بالا استفاده کردم و نتیجه‌ی بسیار مناسبی با توجه به سرعت پاسخ‌گویی گرفتم. ممنون
اشتراک‌ها
رزومه چیست؟

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

رزومه چیست؟
نظرات مطالب
معرفی کتابخانه PdfReport
- لطفا برای پرسش و پاسخ در مورد این پروژه، از قسمت مخصوص آن در سایت استفاده کنید.
- یکسری از قلم‌های فارسی ناقص هستند: «iTextSharp و استفاده از قلم‌های محدود فارسی». یا از قلم خوب استفاده کنید و یا جائیکه دو قلم این گزارشگیر را معرفی می‌کنید، دو قلم مکمل را تعریف و معرفی کنید.