namespace electron_factorial { public class MyMath { public int Factorial(int number) { if (number < 2) return number; return Factorial(number - 1)*number; } public Task<object> CalcFactorial(object obj) { return Task.Factory.StartNew(() => Factorial((int) obj) as object); } } }
سپس کتابخانه تولید شده را به داخل دایرکتوری پروژه انتقال میدهیم. پروژه electron-edge را در پروژه صدا میزنیم؛ این پروژه که برای الکترون بهینه شده است از روی پروژه Edge فورک شده است که برای خروجی دات نت در node.js تولید شده بود.
npm install electron-edge
حالا کد زیر را مینویسیم:
<script> function myFunction() { var edge = require('electron-edge'); var CalcFactorial = edge.func({ assemblyFile: 'electron-factorial.dll', typeName: 'electron_factorial.MyMath', methodName: "CalcFactorial" }); document.getElementById("calc").addEventListener("click", function (e) { var inputText = document.getElementById("txtnumber").value; CalcFactorial(Number(inputText), function (error, result) { document.getElementById("factorial").value=result; }); }); } </script>
ابتدا بسته زیر را از طریق nuget نصب نمایید:
dotnet add package MongoDB.Driver
سپس مدلهای زیر را ایجاد نمایید:
public class BaseModel { public BaseModel() { CreationDate=DateTime.Now; } public string Id { get; set; } public DateTime CreationDate { get; set; } public bool IsRemoved { get; set; } public DateTime? ModificationDate { get; set; } }
این مدل شامل یک کلاس پایه برای id,CreationDate,ModificationDate,IsRemoved میباشد که بسیار شبیه مدلهایی است که عموما در EntityFramework تعریف میکنیم.
برای اینکه فیلد Id به صورت objectId ایجاد شود ولی به صورت رشتهای استفاده شود ابتدا ویژگی BsonId را در بالای آن تعریف کرده تا به عنوان شناسه یکتا سند شناخته شود و سپس با استفاده از ویژگی BsonRepresentation اعلام میکنیم که کار تبدیل به رشته و بلعکس آن به صورت خودکار در پشت صحنه صورت بگیرد:
public class BaseModel { [BsonId] [BsonRepresentation((BsonType.ObjectId))] public string Id { get; set; } }
البته این حالت برای زمانی مناسب است که ما
در استفاده از ویژگیها محدودیتی نداشته باشیم؛ ولی در بسیاری از نرم افزارها که از
معماریهای چند لایه مانند لایه پیازی استفاده میشود استفاده از این خصوصیتها یعنی اعمال کارکرد کتابخانه بالاتر بر روی لایههای زیرین که هسته نرم افزار
شناخته میشوند که صحیح نبوده و باید توسط لایههای بالاتر این تغییرات اعمال شوند که
میتواند از طریق کلاس این کار را انجام دهید. به ازای هر مدل که نیاز به تغییرات
دارد، یک حالت جدید تعریف شده و در ابتدای برنامه در فایل Program.cs یا قبل از دات نت 6 در Startup.cs صدا زده میشوند.
BsonClassMap.RegisterClassMap<BaseModel>(map => { map.SetIdMember(map.GetMemberMap(x=>x.Id)); map.GetMemberMap(x => x.Id) .SetSerializer(new StringSerializer(BsonType.ObjectId)); });
یک نکته بسیار مهم: کلاس و متد BsonClassMap . RegisterClassMap قادر به اعمال تغییرات بر روی خصوصیتهای کلاس والد نیستند و آن خصوصیات حتما باید در آن کلاسی که آن را کانفیگ میکنید، تعریف شده باشند؛ یعنی چنین چیزی که در کد زیر میبینید در زمان اجرا با یک خطا مواجه خواهد شد:
public class Employee : BaseModel { public string FirstName { get; set; } public string LastName { get; set; } } //================= BsonClassMap.RegisterClassMap<Employee >(map => { map.SetIdMember(map.GetMemberMap(x=>x.Id)); map.GetMemberMap(x => x.Id) .SetSerializer(new StringSerializer(BsonType.ObjectId)); });
روش استفاده از مونگو در asp.net core به صورت زیر بسیار متداول میباشد که در قسمتهای پیشین هم در این مورد نوشته بودیم:
MongoDbContext
public interface IMongoDbContext { IMongoCollection<TEntity> GetCollection<TEntity>(); } public class MongoDbContext : IMongoDbContext { private readonly IMongoClient _client; private readonly IMongoDatabase _database; public MongoDbContext(string databaseName,string connectionString) { var settings = MongoClientSettings.FromUrl(new MongoUrl(connectionString)); _client = new MongoClient(settings); _database = _client.GetDatabase(databaseName); } public IMongoCollection<TEntity> GetCollection<TEntity>() { return _database.GetCollection<TEntity>(typeof(TEntity).Name.ToLower() + "s"); } }
سپس از طریق کد زیر IMongoDbContext را به سیستم تزریق وابستگیها معرفی میکنیم. الگوی استفاده شدهی در اینجا بر خلاف نسخههای sql که عموما به صورت AddScoped تعریف میشدند، در اینجا به صورت AddSingleton تعریف کردیم و نحوه پیاده سازی آن را نیز در طرف سمت راست به صورت صریح اعلام کردیم:
public static class MongoDbContextService { public static void AddMongoDbContext(this IServiceCollection services,string databaseName,string connectionString) { services.AddSingleton<IMongoDbContext>(serviceProvider => new MongoDbContext(databaseName, connectionString)); } } //=============== Program.cs builder.Services.AddMongoDbContext("bookstore", "mongodb://localhost:27017");
پیاده سازی SoftDelete در مونگو
در مونگو چیزی تحت عنوان Global Query Filter نداریم که تمام کوئری هایی که به سمت دیتابیس ارسال میشوند، توسط کانتکس اطلاح شوند؛ بدین جهت برای پیاده سازی این خصوصیت میتوان اینترفیسی با نام <IRepository<T را به شکل زیر طراحی نماییم:
public interface IRepository<T> where T : BaseModel { IMongoCollection<T> GetCollection(); IMongoQueryable<T> GetFilteredCollection(); } public class Repository<T> : IRepository<T> where T:BaseModel { private IMongoDbContext _mongoDbContext; public Repository(IMongoDbContext mongoDbContext) { _mongoDbContext = mongoDbContext; } public IMongoCollection<T> GetCollection() { return _mongoDbContext.GetCollection<T>(); } public IMongoQueryable<T> GetFilteredCollection() { var query= _mongoDbContext.GetCollection<T>().AsQueryable(); //================= Global Query Filters ==================== //Filter 1 query=query.Where(x => x.RemovedAt.HasValue == false); //============================================================== return query; } }
این کلاس یا اینترفیس شامل دو متد هستند که کلاس جنریک آنها باید از BaseModel ارث بری کرده باشد و اولین متد، تنها یک کالکشن بدون هیچگونه فیلتری است که میتواند نقش متد IgnoreQueryFilters را بازی کند و دیگری GetFilteredCollection است که در این متد ابتدا کالکشنی دریافت شده و سپس آن را به حالت کوئری تغییر داده و فیلترهای مورد نظر، مانند حذف منطقی را پیاده سازی میکنیم:
public interface IRepository<T> where T : BaseModel { IMongoCollection<T> GetCollection(); IMongoQueryable<T> GetFilteredCollection(); } public class Repository<T> : IRepository<T> where T:BaseModel { private IMongoDbContext _mongoDbContext; public Repository(IMongoDbContext mongoDbContext) { _mongoDbContext = mongoDbContext; } public IMongoCollection<T> GetCollection() { return _mongoDbContext.GetCollection<T>(); } public IMongoQueryable<T> GetFilteredCollection() { var query= _mongoDbContext.GetCollection<T>().AsQueryable(); //================= Global Query Filters ==================== //Filter 1 query=query.Where(x => x.RemovedAt.HasValue == false); //============================================================== return query; } }
اصلاح تاریخ ویرایش در مدل
در EF به لطف dbset و همچنین ChangeTracking امکان شناسایی حالتها وجود دارد و میتوانید در متدی مانند saveChanges مقدار تاریخ ویرایش را تنظیم نمود. برای مدلهای منگو چنین چیزی وجود ندارد و به همین دلیل چند روش زیر پیشنهاد میگردد:
یک. استفاده از اینترفیس INotifyPropertyChanged یا جهت حذف کدهای تکراری نیز از الگوی AOP بهره بگیرید.
دو. استفاده از یک <Repository<T همانند بالا که شامل متدهای داخلی Update و Delete هستند که در آنجا میتوانید این مقادیر را به صورت مستقیم تغییر دهید.
// See https://aka.ms/new-console-template for more information Console.WriteLine("Hello, World!");
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net6.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> </Project>
ب) فعال بودن ImplicitUsings که مختص به C# 10.0 است.
بررسی مفهوم global using directives در C# 10.0
هدف اصلی از وجود Using directives در زبان #C که از نگارش 1 آن در دسترس هستند، خلاصه نویسی نام طولانی اشیاء و متدها است. برای مثال نام اصلی متد Console.WriteLine به صورت System.Console.WriteLine است که با درج فضای نام System در ابتدای فایل، میتوان از ذکر مجدد آن جلوگیری کرد. از این دست میتوان به نوع System.Collections.Generic.List نیز اشاره کرد که کمتر کسی علاقمند است تا این نام طولانی را تایپ کند. به همین جهت با استفاده از یک using directive متناظر با فضای نام System.Collections.Generic، ذکر نام این نوع، به List خلاصه میشود.
طراحی دات نت 6 مبتنی بر سبک minimalism است! برای نمونه خلاصه کردن نزدیک به 10 سطر فایل Program.cs کلاسیک، به تنها یک سطر که به همراه ذکر using System در ابتدای آن هم نیست. در C# 10.0 دیگر نیازی نیست تا برای مثال ذکر using System را در دهها و یا صدها فایل، بارها و بارها تکرار کرد. برای اینکار تنها کافی است یکبار آنرا به صورت global تعریف کنیم و پس از آن دیگر نیازی به ذکر آن در کل پروژه نیست:
global using System;
چند نکته:
- امکان ترکیب global usingها و usingها معمولی در یک فایل هست.
- امکان تعریف global usingهای استاتیک نیز پیشبینی شدهاست:
global using static System.Console;
مفهوم جدید implicit global using directives در C# 10.0 و به کمک NET SDK 6.0.
تا اینجا دریافتیم که میتوان دایرکتیوهای سراسری using را در برنامه به صورت دستی تعریف و استفاده کرد. اما ... پروژهی کنسولی که به صورت پیشفرض توسط NET SDK 6.0. ایجاد میشود، به همراه هیچ global using ای نیست. این مورد توسط تنظیم زیر که جزئی از NET SDK 6.0. است، فعال میشود:
<ImplicitUsings>enable</ImplicitUsings>
// <auto-generated/> global using global::System; global using global::System.Collections.Generic; global using global::System.IO; global using global::System.Linq; global using global::System.Net.Http; global using global::System.Threading; global using global::System.Threading.Tasks;
البته این فایل ویژه به ازای نوعهای پروژههای مختلف، محتوای متفاوتی را دارد. برای مثال در برنامههای ASP.NET Core، چنین محتوای پیشفرضی را پیدا میکند:
// <autogenerated /> global using global::System; global using global::System.Collections.Generic; global using global::System.IO; global using global::System.Linq; global using global::System.Net.Http; global using global::System.Threading; global using global::System.Threading.Tasks; global using global::System.Net.Http.Json; global using global::Microsoft.AspNetCore.Builder; global using global::Microsoft.AspNetCore.Hosting; global using global::Microsoft.AspNetCore.Http; global using global::Microsoft.AspNetCore.Routing; global using global::Microsoft.Extensions.Configuration; global using global::Microsoft.Extensions.DependencyInjection; global using global::Microsoft.Extensions.Hosting; global using global::Microsoft.Extensions.Logging;
روش حذف و یا اضافهی global usingهای پیشفرض
اگر به هر دلیلی نمیخواهید تعدادی از global usingهای پیشفرض به همراه گزینهی ImplicitUsings استفاده کنید، میتوانید آنها را در فایل csproj به صورت زیر، Remove و یا حتی موارد جدیدی را Include کنید:
<ItemGroup> <Import Remove="System.Threading" /> <Import Include="Microsoft.Extensions.Logging" /> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net472'"> </ItemGroup>
بررسی وضعیت فعلی پروژه Roslyn
انشاا... در هر دو مورد کد مدیریت شده و native کد صحبت خواهیم نمود . کد مدیریت شده همانطور که شما فرمودین تحت common language runtime اجرا میشود و برای اجرای برنامه نیاز به نصب دات نت فریمورک روی ماشین مقصد هست ، ولی native کد فقط از توابع کتابخانه ای استفاده میکند و نیازی به نصب .net framework جهت اجرای برنامه بر روی ماشین مقصد ندارد . آموزشهایی که تا کنون داده ام (2 مورد ) با توجه به گفته شما مربوط به قسمت native آن میباشد .
در ادامه حتما در مورد تفاوتهای کد مدیریت شده و کد محلی صحبت خواهیم نمود .
تغییر اعمال شد .
- LightSwitch و دیگر هیچ ! | vcsharp.ir
- پوسترهای NET Framework 3.5 , 4.0 | pspcommunity.org
- بررسی ترافیک بین کلاینت و سرویس توسط ابزار Fiddler | www.30sharp.com
- چگونه از کتابخانههای برنامه «ویراستیار» در دات نت استفاده کنیم؟ | www.virastyar.ir
- روند نگارش Request For Proposal :: RFP | hrnews.blogfa.com
- ReSharper و ASP.NET MVC | hadihariri.com
- VisualSVN Server 2.5.2 منتشر شد | www.visualsvn.com
- دلایل سوئیچ از فلش به سیلورلایت و عدم استفاده از HTML5 | blog.lovefilm.com
- مشکلات توسعه نرم افزار در آمریکا! | www.muktware.com
LLBLGEN یکی از ORM های تجاری بسیار با کیفیت دات نت است و علاوه بر اینکه هویت مستقلی دارد، امکان تولید کدهای مخصوص Entity framework و NHibernate را هم دارا است.
اخیرا این شرکت تصمیم گرفته است که سیستم پشتیبانی مشتریان خودش را که نمونهای از آنرا در اینجا میتوانید ملاحظه کنید، سورس باز کند.
حداقل پیشنیازهای نصب این انجمن به شرح زیر است:
- ASP.NET 2.0+
- SQL Server 2000 or higher / CE Desktop 3.5
- NET 3.5+