در این قسمت ابتدا نحوهی فعال سازی فریم ورک آزمونهای واحد مایکروسافت و سپس نحوهی فعال سازی این تامین کنندهی بانک اطلاعاتی درون حافظهای را بررسی خواهیم کرد. به علاوه برای سرویس بلاگهای قسمت قبل نیز آزمون واحد خواهیم نوشت.
نحوهی فعالسازی فریم ورک MSTest در یک پروژهی Class library از نوع NET Core.
تنها نکتهی مهم فعالسازی MSTest در یک پروژهی Class library جدید که برای نوشتن آزمونهای واحد مورد استفاده قرار خواهیم داد، تنظیمات فایل project.json آن است که در ذیل آمده است:
{ "version": "1.0.0-*", "testRunner": "mstest", "dependencies": { "Microsoft.NETCore.App": { "type": "platform", "version": "1.0.0" }, "dotnet-test-mstest": "1.1.1-preview", "MSTest.TestFramework": "1.0.1-preview", "NETStandard.Library": "1.6.0", "Microsoft.EntityFrameworkCore": "1.0.0", "Microsoft.EntityFrameworkCore.InMemory": "1.0.0", "Core1RtmEmptyTest.DataLayer": "1.0.0-*", "Core1RtmEmptyTest.Entities": "1.0.0-*", "Core1RtmEmptyTest.Services": "1.0.0-*", "Core1RtmEmptyTest.ViewModels": "1.0.0-*" }, "frameworks": { "netcoreapp1.0": { "imports": [ "dnxcore50", "portable-net45+win8" ] } } }
- به علاوه در اینجا ارجاعاتی را به اسمبلیهای موجودیتها، Services و DataLayer که در قسمت «شروع به کار با EF Core 1.0 - قسمت 14 - لایه بندی و تزریق وابستگیها» بررسی شدند نیز ملاحظه میکنید.
- همچنین وابستگی جدید Microsoft.EntityFrameworkCore.InMemory نیز در اینجا قابل ملاحظه است. این وابستگی را تنها به پروژهی آزمونهای واحد خود اضافه میکنیم. از این جهت که تنظیمات آن صرفا در این قسمت جدید قید میشوند و نه در سایر قسمتهای برنامه.
پس از آن، کار با این فریم ورک، همانند سایر نگارشهای دات نت خواهد بود:
using Microsoft.VisualStudio.TestTools.UnitTesting; namespace EFCore.MsTests { [TestClass] public class CoreTests { [TestMethod] public void Test1() { Assert.IsTrue(true); } } }
پس از نوشتن اولین آزمون واحد، یکبار پروژه را build کرده و سپس از منوی Test، گزینهی Windows را انتخاب کرده و در اینجا گزینهی Test Explorer را انتخاب کنید. اندکی صبر کنید تا آزمونهای واحد شما شناسایی شوند و سپس گزینهی Run All را انتخاب کنید:
تغییرات Context برنامه جهت استفادهی از تامین کنندهی داخل حافظهای
در مورد نحوهی تعریف و افزودن وابستگیهای EF Core در مطلب «شروع به کار با EF Core 1.0 - قسمت 1 - برپایی تنظیمات اولیه» پیشتر بحث شد و همچنین در مطلب «شروع به کار با EF Core 1.0 - قسمت 3 - انتقال مهاجرتها به یک اسمبلی دیگر»، اطلاعات Context برنامه را به اسمبلی دیگری منتقل کردیم.
اگر از روش بازنویسی متد OnConfiguring برای تنظیم تامین کنندهی بانک اطلاعاتی مورد نظر استفاده میکنید، متد OnConfiguring کلاس Context برنامه چنین شکلی را پیدا میکند:
public class ApplicationDbContext : DbContext, IUnitOfWork { private readonly IConfigurationRoot _configuration; public ApplicationDbContext(IConfigurationRoot configuration) { _configuration = configuration; } public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { if (!optionsBuilder.IsConfigured) { optionsBuilder.UseSqlServer( _configuration["ConnectionStrings:ApplicationDbContextConnection"] , serverDbContextOptionsBuilder => { var minutes = (int)TimeSpan.FromMinutes(3).TotalSeconds; serverDbContextOptionsBuilder.CommandTimeout(minutes); }); } }
الف) اضافه شدن سازندهی دومی که <DbContextOptions<ApplicationDbContext را دریافت میکند. از آن در سمت کدهای آزمون واحد برنامه جهت ثبت ()options.UseInMemoryDatabase استفاده میشود.
ب) به متد OnConfiguring، بررسی optionsBuilder.IsConfigured هم اضافه شدهاست. چون در سمت کدهای آزمون واحد، تامین کنندهی بانک اطلاعاتی درون حافظهای اضافه میشود، مقدار optionsBuilder.IsConfigured به true تنظیم خواهد شد و دیگر از تامین کنندهی SQL Server استفاده نمیشود.
اگر از متد OnConfiguring به این شکل استفاده نمیکنید، تنها ذکر سازندهی دوم ضروری است. از این جهت که در آزمونهای واحد، از تنظیمات متد ConfigureServices کلاس آغازین برنامه استفاده نخواهد شد.
نوشتن آزمونهای واحد مخصوص EF Core
پس از برپایی پیشنیازهای نوشتن آزمونها واحد، شامل تنظیمات فریم ورک MSTest و همچنین افزودن وابستگیهای مرتبط با فایل project.json ایی که در ابتدای بحث عنوان شد و اصلاح سازنده و متد OnConfiguring کلاس Context برنامه جهت آماده سازی آنها برای پذیرش تامین کنندههای دیگر، اکنون یک نمونه از آزمونهای واحد درون حافظهای EF Core، چنین شکلی را خواهد داشت:
using System; using System.Linq; using Core1RtmEmptyTest.DataLayer; using Core1RtmEmptyTest.Entities; using Core1RtmEmptyTest.Services; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Core1RtmEmptyTest.MsTests { [TestClass] public class CoreTests { private readonly IServiceProvider _serviceProvider; public CoreTests() { var services = new ServiceCollection(); services.AddEntityFrameworkInMemoryDatabase() .AddDbContext<ApplicationDbContext>(options => options.UseInMemoryDatabase()); services.AddScoped<IUnitOfWork, ApplicationDbContext>(); services.AddScoped<IBlogService, BlogService>(); _serviceProvider = services.BuildServiceProvider(); } [TestMethod] public void Find_searches_url() { // Insert seed data into the database using one instance of the context using (var serviceScope = _serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope()) { using (var context = serviceScope.ServiceProvider.GetRequiredService<IUnitOfWork>()) { context.Set<Blog>().Add(new Blog { Url = "http://sample.com/cats" }); context.Set<Blog>().Add(new Blog { Url = "http://sample.com/catfish" }); context.Set<Blog>().Add(new Blog { Url = "http://sample.com/dogs" }); context.SaveAllChanges(); } } // Use a separate instance of the context to verify correct data was saved to database using (var serviceScope = _serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope()) { using (var context = serviceScope.ServiceProvider.GetRequiredService<IUnitOfWork>()) { Assert.AreEqual(3, context.Set<Blog>().Count()); Assert.AreEqual("http://sample.com/cats", context.Set<Blog>().First().Url); } } // Use a clean instance of the context to run the test using (var serviceScope = _serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope()) { var blogService = serviceScope.ServiceProvider.GetRequiredService<IBlogService>(); var results = blogService.GetPagedBlogsAsNoTracking(pageNumber: 0, recordsPerPage: 10); Assert.AreEqual(3, results.Count); } } } }
همانطور که در قسمت «تغییرات Context برنامه جهت استفادهی از تامین کنندهی داخل حافظهای» فوق عنوان شد، در حین انجام آزمونهای واحد، دیگر به کلاس آغازین برنامه و تنظیمات آن مراجعه نمیشود. بنابراین باید شبیه به عملکرد متد ConfigureServices آنرا در اینجا پیاده سازی کرد. نمونهای از انجام اینکار را در سازندهی کلاس انجام آزمونهای واحد مشاهده میکنید:
private readonly IServiceProvider _serviceProvider; public CoreTests() { var services = new ServiceCollection(); services.AddEntityFrameworkInMemoryDatabase() .AddDbContext<ApplicationDbContext>(options => options.UseInMemoryDatabase()); services.AddScoped<IUnitOfWork, ApplicationDbContext>(); services.AddScoped<IBlogService, BlogService>(); _serviceProvider = services.BuildServiceProvider(); }
سپس همانند قبل، باید تمام سرویسهای مدنظر تنظیم شوند تا بتوان از آنها استفاده کرد.
نکتهی مهم دیگری را که باید به آن دقت داشت، ایجاد scope و سپس دسترسی به سرویسها از طریق این Scope است. از این جهت که چون خارج از طول عمر یک درخواست وب قرار داریم، دیگر Scopeها برای ما به صورت خودکار ایجاد و تخریب نمیشوند و باید همانکاری را که ASP.NET Core در پشت صحنه انجام میدهد، به صورت دستی پیاده سازی کنیم:
using (var serviceScope = _serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope()) { using (var context = serviceScope.ServiceProvider.GetRequiredService<IUnitOfWork>()) {
یک نکتهی تکمیلی
EF Core به همراه تامین کنندهی بانک اطلاعاتی SQLite نیز هست. یکی از نکات ویژهی بانک اطلاعاتی SQLite، امکان تنظیم پارامتری است در رشتهی اتصالی آن، که آنرا نیز تبدیل به یک «بانک اطلاعاتی درون حافظهای» میکند. این روش سالها است که جهت انجام آزمونهای واحد ORMها مورد استفاده قرار میگیرد. بنابراین میتوان آنرا به عنوان جایگزینی برای مطلب جاری نیز درنظر گرفت.
var connectionStringBuilder = new SqliteConnectionStringBuilder { DataSource = ":memory:" }; var connectionString = connectionStringBuilder.ToString(); var connection = new SqliteConnection(connectionString); services.AddEntityFrameworkSqlite().AddDbContext<CmsDbContext>(options => options.UseSqlite(connection));
6.1 PowerShell Core متشر شد.
پروژه مدیریت محتوای Platformus
var scaffolder = new MigrationScaffolder(configuration);
The Entity Framework provider type 'System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' for the 'System.Data.SqlClient' ADO.NET provider could not be loaded. Make sure the provider assembly is available to the running application. See http://go.microsoft.com/fwlink/?LinkId=260882 for more information.
ضمنا آیا اسمبلی مربوط به EF6 را نمیتوان بجز نیوگت از روش دیگری بدست آورد.؟
همچنین EF Power Tools مربوط به EF6 را از کجا میتوان تهیه کرد؟
- Global query filters in Entity Framework Core 2.0
- Implementing tenant providers on ASP.NET Core
- Implementing database per tenant strategy on ASP.NET Core
- Handling missing tenants in ASP.NET Core
- Unit testing multi-tenant database provider
- Defensive database context for multi-tenant ASP.NET Core applications
1.Visual Studio 2017 15.7 منتشر شد
These are the customer-reported issues addressed in 15.7.1:
- This release includes a fix that reduces memory usage and GC pressure during solution load.
Microsoft Security Advisory for .NET Core Denial Of Service Vulnerability
CVE-2018-0765
Microsoft is releasing this security advisory to provide information about a vulnerability in .NET Core and .NET native version 2.0. This advisory also provides guidance on what developers can do to update their applications to remove this vulnerability.
Microsoft is aware of a denial of service vulnerability that exists when .NET Framework and .NET Core improperly process XML documents. An attacker who successfully exploited this vulnerability could cause a denial of service against a .NET Framework, .NET Core, or .NET native application.
The update addresses the vulnerability by correcting how .NET Framework, .NET Core, and .NET native applications handle XML document processing.
If your application is an ASP.NET Core application, developers are also advised to update to ASP.NET Core 2.0.8.