نظرات مطالب
EF Code First #2
با سلام و تشکر بخاطر مقالات مفید EF
بنده طبق مثال مقاله پیش رفتم و متادیتاهای Key و Required را اضافه کردم اما با متادیتای MaxLength به مشکل خوردم .
ویژوال همچین پیغامی میده :
/*
The type 'System.ComponentModel.DataAnnotations.MaxLengthAttribute' exists in both
'c:\Program Files\Microsoft ADO.NET Entity Framework 4.1\Binaries\EntityFramework.dll'
and
'c:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.ComponentModel.DataAnnotations.dll' */

اشتراک‌ها
MagicOnion : یک فریمورک Realtime مبتنی بر gRPC و MessagePack

این فریمورک با استفاده از قابلیت HTTP/2 Streaming مبتنی بر  gRPC  و بهره گیری از  MessagePack  برای Serialization (همراه با LZ4 integration) بستری قدرتمند را برای ارتباطات Realtime فراهم می‌کند.

یکی از مزایای این فریمورک عدم نیاز به فایل‌های .proto مخصوص gRPC است چرا که از interface های سی شارپی برای به اشتراک گذاری امضای Endpoint‌های موجود بین Server و Client استفاده میکند.

یکی از دیگر مزایای آن پشتیبانی از Swagger و داشتن Json Gateway توکار متبنی بر HTTP/1 است که به کمک آن می‌توان به صورت Json/RESTful نیز API‌ها را فراخوانی کرد.

همچنین این فریمورک از OpenTelemetry پشتیبانی کرده و می‌توانید از برنامه‌های مانیتورینگ مانند Prometheus و StackDriver و Zipkin و... بر روی پروژه خود استفاده کنید و یا توسط Grafana یک داشبورد مانیتورینگ ویژوال و Realtime ایجاد کنید.

این فریمورک ابزار مناسبی جهت ارتباطات بین Microservice‌ها می‌باشد.

همچنین جایگزین مناسبی برای سرویس‌های API based مانند ASP.NET Core WebAPI و WCF بوده و نیز جایگزین مناسبی برای SignalR و Socket.io جهت ارتباطات Realtime می‌باشد.

MagicOnion : یک فریمورک Realtime مبتنی بر gRPC و MessagePack
نظرات مطالب
رمزنگاری JWT و افزایش امنیت آن در ASP.NET Core
توسط فیلتر Authorize به صورت خودکار مدیریت میشه. کاربرد JWT در 99 درصد مواقع برای کار با Web API هست (به همین جهت مثال Ajax رو برای کار با Web API مشاهده کردید و یا در برنامه‌های SPA مانند Angular کاربرد داره) و در این زمان فیلتر Authorize، دسترسی غیرمجاز را بسته و status code=401 را بازگشت می‌ده. اینجاست که کلاینت تصمیم می‌گیره بر اساس این status code باید چکار کنه؛ پیامی رو نمایش بده یا کاربر رو به صفحه‌ی لاگین هدایت کنه (گردش کاریش به این صورت هست؛ از فیلتر Authorize شروع میشه و به بستن درخواست و بازگشت status code ویژه‌ای، خاتمه پیدا می‌کنه). این موارد در مطلب و نظرات «اعتبارسنجی مبتنی بر JWT در ASP.NET Core 2.0 بدون استفاده از سیستم Identity» بیشتر بحث شدن. مطلب جاری، یک مطلب تکمیلی هست و نه یک مطلب آغازین.
مطالب
تغییر مهم تعریف رشته‌های اتصالی SQL Server در EF Core 7.0
اگر برنامه‌های مبتنی بر SQL Server خود را به EF 7.0 ارتقاء دهید، در حین اجرای برنامه، به خطای زیر برخواهید خورد:
A connection was successfully established with the server, but then an error occurred during the login process.
(provider: SSL Provider, error: 0 - The certificate chain was issued by an authority that is not trusted.)
علت اینجا است که پروایدر SQL Server مخصوص EF 7.0، از نگارش جدید Microsoft.Data.SqlClient استفاده می‌کند و در این نگارش، تنظیم Encrypt=True، به صورت پیش‌فرض اعمال شده‌است. این تنظیم، پیشتر به صورت Encrypt=False وجود داشت و به همین جهت عموما در حین تعریف رشته‌های اتصالی دیده نمی‌شد.

اگر نیاز به استفاده‌ی از پرچم Encrypt=True وجود داشته باشد:
- باید سرور اس کیوال با یک certificate معتبر تنظیم شود.
- کلاینت باید این certificate را تائید کند. اگر کلاینت چنین قصدی را ندارد، می‌تواند تنظیم TrustServerCertificate=True را به رشته‌ی اتصالی اضافه کند.
در غیراینصورت، خطای ذکر شده را دریافت خواهیم کرد.

برای رفع این مشکل یا باید رمزنگاری اتصالات را در SQL Server پیاده سازی کرد و یا از این پس، ذکر پرچم Encrypt=False در انتهای رشته‌ی اتصالی به آن، ضروری است. برای مثال یک نمونه رشته‌ی اتصالی تغییر یافته‌ی بر اساس این تنظیم، به صورت زیر است:
Data Source=.\\SQLEXPRESS;Initial Catalog=MyTestDb;Integrated Security=true;Encrypt=False;

بدیهی است این تغییر مختص به EF 7.0 نیست و تمام برنامه‌هایی که از ADO.NET و نگارش جدید Microsoft.Data.SqlClient استفاده می‌کنند، باید به آن توجه داشته باشند.
بازخوردهای دوره
انتقال خودکار Data Annotations از مدل‌ها به ViewModelهای ASP.NET MVC به کمک AutoMapper
مدل اصلی عموما همان domain models هستند؛ برای مثال مدل‌های EF و EF از این ویژگی‌ها جهت تنظیم ساختار بانک اطلاعاتی و همچنین اعتبارسنجی خاص خودش استفاده می‌کند. بنابراین قلب طراحی مدل‌های سیستم، مدل‌های domain هستند و view models صرفا کاربرد نمایش سفارشی اطلاعات و همچنین کاهش سطح در معرض دید قرار گرفتن مدل‌های domain را جهت بهبود وضعیت امنیتی سیستم، دارند.
نظرات مطالب
وضعیت فناوری‌های مرتبط با دات نت از دیدگاه مرگ و زندگی!
درود بر شما جناب نصیری به مقوله خوبی پرداختید

امروزه در مورد استفاده از تکنولوژی های جدید در سیستم های جدید نظرات زیاد و متناقصی هست مثلا به نظر شما تو یه سیستم که تراکنش اون بسیار بالا در حدود مثلا 1 میلیون تراکنش در روز آیا استفاده از EF عاقلانه است یا نه؟

تکنولوژی های جدید به سمت راحتی برنامه نویسان و خوانایی کد سوق داده شده اند ولی در عوض به اتلاف Performance می انجامند!
مطالب
پشتیبانی توکار از انجام کارهای پس‌زمینه در ASP.NET Core 2x
از زمان ASP.NET Core 2.1، قابلیت جدیدی به نام Generic Host، به آن اضافه شده‌است که از آن می‌توان برای انجام کارهای متداول پس زمینه، مانند ارسال ایمیل‌های خبرنامه‌ی یک برنامه، تهیه فایل‌های پشتیبان و غیره استفاده کرد.


Generic Host چیست؟

Generic Host یکی از ویژگی‌های جدید ASP.NET Core 2.1 است. هدف آن جداسازی HTTP pipeline برنامه، از Web Host API آن است. یکی از مزایای این‌کار، امکان استفاده‌ی از آن نه فقط در پروژه‌های وب، بلکه در پروژه‌های کنسول نیز می‌باشد. به این ترتیب می‌توان کارهای غیر HTTP را از برنامه‌ی وب مجزا کرد تا به کارآیی بیشتری رسید و برای این منظور اینترفیس IHostedService را که در فضای نام Microsoft.Extensions.Hosting قرار دارد، برای ثبت کارهای پس‌زمینه‌ی خارج از اعمال web host جاری، ارائه داده‌اند:
namespace Microsoft.Extensions.Hosting
{
    public interface IHostedService
    {
        Task StartAsync(CancellationToken cancellationToken);
        Task StopAsync(CancellationToken cancellationToken);
    }
}
بنابراین برای ایجاد یک HostedService، نیاز است سرویس کارهای پس‌زمینه‌ی ما، اینترفیس IHostedService را پیاده سازی کند. متد StartAsync آن جائی‌است که تنها یکبار پس از آغاز برنامه اجرا می‌شود و هدف آن اجرای کار پس‌زمینه‌ی مدنظر است. متد StopAsync نیز دقیقا پیش از خاتمه‌ی برنامه فراخوانی خواهد شد تا اگر نیاز به پاکسازی منابعی وجود داشته باشد، بتوان از این فرصت استفاده کرد. به این ترتیب اگر نیاز به اجرای متناوب کار پس‌زمینه‌ای وجود دارد، پیاده سازی آن به خود ما واگذار شده‌است.


یک مثال: معرفی کار پس‌زمینه‌ای که هر دو ثانیه یکبار انجام می‌شود

در SampleHostedService زیر، عبارت Hosted service executing به همراه زمان جاری، هر دو ثانیه یکبار لاگ می‌شود و اگر برنامه را توسط دستور dotnet run اجرا کنید، می‌توانید خروجی آن‌را در کنسول، مشاهده کنید:
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace MvcTest
{
    public class SampleHostedService : IHostedService
    {
        private readonly ILogger<SampleHostedService> _logger;

        public SampleHostedService(ILogger<SampleHostedService> logger)
        {
            _logger = logger;
        }

        public async Task StartAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("Starting Hosted service");

            while (!cancellationToken.IsCancellationRequested)
            {
                _logger.LogInformation("Hosted service executing - {0}", DateTime.Now);
                await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken);
            }
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("Stopping Hosted service");
            return Task.CompletedTask;
        }
    }
}
در ادامه برای معرفی این کار پس‌زمینه به سیستم به صورت یک سرویس با طول عمر Singleton خواهیم داشت:
namespace MvcTest
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<IHostedService, SampleHostedService>();
روش دیگر انجام اینکار استفاده از متد الحاقی AddHostedService است:
services.AddHostedService<SampleHostedService>();
مزیت اینکار این است که متد Configure واقع در کلاس Startup یک چنین امضایی را دارد:
 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
و IHostingEnvironment هم در فضای نام Microsoft.AspNetCore.Hosting واقع شده‌است و هم در فضای نام Microsoft.Extensions.Hosting که IHostedService در آن قرار دارد. به همین جهت چون متد AddHostedService، تعریف IHostedService را مخفی می‌کند، خطای زمان کامپایلی را جهت مشخص سازی صریح فضای نام  IHostingEnvironment دریافت نخواهید کرد:
Startup.cs(82,56): error CS0104: 'IHostingEnvironment' is an ambiguous reference between
'Microsoft.AspNetCore.Hosting.IHostingEnvironment' and 'Microsoft.Extensions.Hosting.IHostingEnvironment'


مشکلات پیاده سازی کار پس‌زمینه‌ی SampleHostedService فوق

هر چند اگر مثال فوق را اجرا کنید، خروجی مناسبی را دریافت خواهید کرد، اما دارای این اشکال مهم نیز هست:
D:\MvcTest>dotnet run
info: MvcTest.SampleHostedService[0]
      Starting Hosted service
info: MvcTest.SampleHostedService[0]
      Hosted service executing - 02/19/2019 14:45:10
info: MvcTest.SampleHostedService[0]
      Hosted service executing - 02/19/2019 14:45:12
info: MvcTest.SampleHostedService[0]
      Hosted service executing - 02/19/2019 14:45:14
Ctrl+C
Application is shutting down...
Hosting environment: Development
Content root path: D:\MvcTest
Now listening on: https://localhost:5001
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.
پس از اجرای دستور dotnet run، سرویس پس زمینه شروع به کار کرده‌است. پس از مدتی کلیدهای Ctrl+C را فشرده‌ایم تا این حلقه‌ی بی‌نهایت و برنامه خاتمه یابد. اینجا است که مشاهده می‌کنید تازه قسمت هاست برنامه‌ی وب ما شروع به کار کرده‌است؛ یعنی دقیقا زمانیکه پروسه‌ی برنامه در حال خاتمه یافتن است. چرا اینگونه رفتار کرده‌است؟
از دیدگاه ASP.NET Core، یک کار پس زمینه زمانی خاتمه یافته محسوب می‌شود که متد StartAsync، مقدار Task.CompletedTask را بازگرداند؛ در غیراینصورت، در حال اجرا درنظر گرفته می‌شود و چون در پیاده سازی فوق این نکته رعایت نشده‌است، این Task همواره در حال اجرا و خاتمه نیافته محسوب می‌شود و نوبت به مابقی کارها نخواهد رسید. همچنین در قسمت StopAsync نیز بهتر است یک فیلد CancellationTokenSource تعریف شده‌ی در سطح کلاس را مورد استفاده قرار داد و متد Cancel آن‌را فراخوانی کرد تا اطلاع رسانی صحیحی را به متد StartAsync در مورد خاتمه‌ی برنامه، انجام دهد.
برای این منظور و جهت ساده سازی و پیاده سازی تمام این نکات، از اینترفیس خام IHostedService، یک کلاس abstract به نام BackgroundService نیز در فضای نام Microsoft.Extensions.Hosting پیش بینی شده‌است:
namespace Microsoft.Extensions.Hosting
{
    public abstract class BackgroundService : IHostedService, IDisposable
    {
        protected BackgroundService();
        public virtual void Dispose();
        public virtual Task StartAsync(CancellationToken cancellationToken);
        public virtual Task StopAsync(CancellationToken cancellationToken);
        protected abstract Task ExecuteAsync(CancellationToken stoppingToken);
    }
}
برای استفاده‌ی از آن تنها کافی است متد ExecuteAsync آن‌را پیاده سازی کنیم. به این ترتیب اینبار پیاده سازی SampleHostedService به صورت زیر تغییر می‌کند:
namespace MvcTest
{
    public class PrinterHostedService : BackgroundService
    {
        private readonly ILogger<SampleHostedService> _logger;

        public PrinterHostedService(ILogger<SampleHostedService> logger)
        {
            _logger = logger;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            _logger.LogInformation("Starting Hosted service");

            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation("Hosted service executing - {0}", DateTime.Now);
                await Task.Delay(TimeSpan.FromSeconds(2), stoppingToken);
            }
        }
    }
}
اینبار اگر این کار پس‌زمینه را به سیستم معرفی:
namespace MvcTest
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddHostedService<PrinterHostedService>();
و سپس برنامه را اجرا کنیم:
D:\MvcTest>dotnet run
Hosting environment: Development
infoContent root path: D:\MvcTest
Now listening on: https://localhost:5001
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.
: MvcTest.SampleHostedService[0]
      Starting Hosted service
info: MvcTest.SampleHostedService[0]
      Hosted service executing - 02/19/2019 15:00:23
info: MvcTest.SampleHostedService[0]
      Hosted service executing - 02/19/2019 15:00:25
info: MvcTest.SampleHostedService[0]
      Hosted service executing - 02/19/2019 15:00:27
Application is shutting down...
^C
مشاهده می‌کنیم که ابتدا هاست وب برنامه شروع به کار کرده‌است و سپس سرویس انجام کارهای پس‌زمینه در حال اجرا است و به این ترتیب اجرای این سرویس پس‌زمینه، تداخلی را در کار برنامه‌ی وب ایجاد نکرده‌است. بنابراین از این پس بجای استفاده‌ی از IHostedService خام، از نمونه‌ی بهبود یافته‌ی BackgroundService آن استفاده کنید.


یک نکته: تزریق وابستگی DbContext برنامه در یک سرویس کار پس‌زمینه

IHostedServiceها با طول عمر singleton به سیستم تزریق وابستگی‌ها معرفی می‌شوند. در این حالت اگر سرویس‌هایی با طول عمر transient و یا scoped را به آن‌ها تزریق کنید، دیگر طول عمر مدنظر شما را نداشته و آن‌ها هم به صورت singleton عمل خواهند کرد. هر چند خود سیستم تزریق وابستگی‌های NET Core. با صدور استثنائی، از این مساله جلوگیری می‌کند (در این مورد در مطالب «مهارت‌های تزریق وابستگی‌ها در برنامه‌های NET Core. - قسمت چهارم - پرهیز از الگوی Service Locator در برنامه‌های وب» و همچنین «قسمت سوم - رهاسازی منابع سرویس‌های IDisposable» بیشتر بحث شده‌است). یک چنین مواردی را به صورت زیر با تزریق IServiceScopeFactory و ساخت صریح یک Scope می‌توان مدیریت کرد:
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

public abstract class ScopedBackgroundService : BackgroundService
{
    private readonly IServiceScopeFactory _serviceScopeFactory;

    public ScopedBackgroundService(IServiceScopeFactory serviceScopeFactory)
    {
        _serviceScopeFactory = serviceScopeFactory;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        using (var scope = _serviceScopeFactory.CreateScope())
        {
            await ExecuteInScope(scope.ServiceProvider, stoppingToken);
        }
    }

    public abstract Task ExecuteInScope(IServiceProvider serviceProvider, CancellationToken stoppingToken);
}
از این پس برای تعریف کارهای پس‌زمینه‌ای که نیاز به تزریق سرویس‌هایی با طول عمر Scoped یا Transient دارند، می‌توان کلاس سرویس وظیفه را از ScopedBackgroundService مشتق کرد و سپس متد ExecuteInScope آن‌را پیاده سازی نمود. serviceProvider ای که در اینجا در اختیار مصرف کننده قرار می‌گیرد، داخل Scope قرار دارد و توسط آن می‌توان سرویس‌های مدنظر را توسط متدهایی مانند serviceProvider.GetRequiredService، دریافت کرد.


طراحی سرویس کارهای پس‌زمینه‌ی زمان‌بندی شده

ASP.NET Core، متد ExecuteAsync را یکبار بیشتر اجرا نمی‌کند. بنابراین پیاده سازی تایمری که بخواهد برای مثال ارسال ایمیل‌های خبرنامه‌ی سایت را هر روز ساعت 11 شب انجام دهد، به خود ما واگذار شده‌است. برای پیاده سازی بهتر این تایمر می‌توان از کتابخانه‌ی NCrontab که توسط نویسنده‌ی کتابخانه‌ی معروف ELMAH تهیه شده‌است، استفاده کرد که با برنامه‌های NET Core. نیز سازگاری دارد:
 dotnet add package ncrontab
عبارات Cron، روش بسیار متداولی برای تعریف و انجام کارهای زمانبندی شده در سیستم‌های لینوکسی هستند. برای مثال عبارت * * * 0 1 سبب اجرای یک وظیفه، هر روز یک دقیقه پس از نیمه‌شب، می‌شود و فرمت کلی 5 قسمتی آن، به صورت زیر است:
┌───────────── minute (0 - 59) 
│ ┌───────────── hour (0 - 23) 
│ │ ┌───────────── day of month (1 - 31) 
│ │ │ ┌───────────── month (1 - 12) 
│ │ │ │ ┌───────────── day of week (0 - 6) (Sunday to Saturday; 
│ │ │ │ │                                       7 is also Sunday on some systems) 
│ │ │ │ │ 
│ │ │ │ │ 
* * * * *
و یا عبارت 6 قسمتی آن چنین مفهومی را دارد:
* * * * * *
- - - - - -
| | | | | |
| | | | | +--- day of week (0 - 6) (Sunday=0)
| | | | +----- month (1 - 12)
| | | +------- day of month (1 - 31)
| | +--------- hour (0 - 23)
| +----------- min (0 - 59)
+------------- sec (0 - 59)
اگر ScopedBackgroundService فوق را با CrontabSchedule یاد شده ترکیب کنیم، می‌توانیم به یک کلاس abstract دیگر برسیم که طراحی کلاس پایه‌ی اجرای کارهای زمانبندی شده را ارائه می‌دهد:
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using NCrontab;
using static NCrontab.CrontabSchedule;

public abstract class ScheduledScopedBackgroundService : ScopedBackgroundService
{
    private CrontabSchedule _schedule;
    private DateTime _nextRun;

    protected abstract string Schedule { get; }

    public ScheduledScopedBackgroundService(IServiceScopeFactory serviceScopeFactory)
     : base(serviceScopeFactory)
    {
        _schedule = CrontabSchedule.Parse(Schedule, new ParseOptions { IncludingSeconds = true });
        _nextRun = _schedule.GetNextOccurrence(DateTime.Now);
    }

    public override async Task ExecuteInScope(IServiceProvider serviceProvider, CancellationToken stoppingToken)
    {
        do
        {
            var now = DateTime.Now;
            if (now > _nextRun)
            {
                await ScheduledExecuteInScope(serviceProvider, stoppingToken);
                _nextRun = _schedule.GetNextOccurrence(DateTime.Now);
            }
            await Task.Delay(1000, stoppingToken); //1 second delay
        }
        while (!stoppingToken.IsCancellationRequested);
    }

    public abstract Task ScheduledExecuteInScope(IServiceProvider serviceProvider, CancellationToken stoppingToken);
}
این کلاس پایه، توسط متد CrontabSchedule.Parse، مقدار رشته‌ای Schedule را با فرمت Cron (فرمت 6 قسمتی که دارای ثانیه هم هست) دریافت و پردازش می‌کند. سپس متد GetNextOccurrence، زمان بعدی اجرای این وظیفه را مشخص می‌کند.
روش استفاده‌ی از آن برای تعریف یک وظیفه‌ی جدید نیز به صورت زیر است:
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

public class MyScheduledTask : ScheduledScopedBackgroundService
{
    private readonly ILogger<MyScheduledTask> _logger;

    public MyScheduledTask(
        IServiceScopeFactory serviceScopeFactory,
        ILogger<MyScheduledTask> logger) : base(serviceScopeFactory)
    {
        _logger = logger;
    }

    protected override string Schedule => "*/10 * * * * *"; //Runs every 10 seconds

    public override Task ScheduledExecuteInScope(IServiceProvider serviceProvider, CancellationToken stoppingToken)
    {
        _logger.LogInformation("MyScheduledTask executing - {0}", DateTime.Now);
        return Task.CompletedTask;
    }
}
در اینجا ابتدا کار با پیاده سازی کلاس پایه ScheduledScopedBackgroundService شروع می‌شود. سپس باید مقدار Schedule را با فرمت 6 قسمتی مشخص کرد. برای مثال در سرویس فوق، این تنظیم سبب اجرای هر 10 ثانیه یکبار این وظیفه می‌گردد. در آخر، خود وظیفه داخل متد ScheduledExecuteInScope تعریف خواهد شد که serviceProvider دریافتی آن، داخل یک Scope قرار دارد.
روش معرفی آن به سیستم نیز مانند قبل است:
namespace MvcTest
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddHostedService<MyScheduledTask>();
در این حالت اگر برنامه را اجرا کنید، یک چنین خروجی را که بیانگر اجرای هر 10 ثانیه یکبار وظیفه‌ی تعریف شده‌است، مشاهده می‌کنید:
D:\MvcTest>dotnet run
Hosting environment: Development
Content root path: D:\MvcTest
Now listening on: https://localhost:5001
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.
info: MyScheduledTask[0]
      MyScheduledTask executing - 02/19/2019 19:18:50
info: MyScheduledTask[0]
      MyScheduledTask executing - 02/19/2019 19:19:00
info: MyScheduledTask[0]
      MyScheduledTask executing - 02/19/2019 19:19:10
Application is shutting down...
^C
نظرات مطالب
شروع به کار با EF Core 1.0 - قسمت 2 - به روز رسانی ساختار بانک اطلاعاتی
یک نکته‌ی تکمیلی
اگر خواستید استراتژی آغازین DropCreateDatabaseAlways مربوط به EF 6.x را با EF Core شبیه سازی کنید، می‌توان یک چنین کدی را در سازنده‌ی کلاس Context نوشت (مفید برای انجام Integration Tests):
public class SampleDBContext : DbContext
{
    private static bool _created = false; 
    public SampleDBContext() 
    { 
        if (!_created) // DropCreateDatabaseAlways
        { 
            _created = true; 
            Database.EnsureDeleted(); 
            Database.EnsureCreated(); 
        } 
    }