If you stumble into this with no idea who I am or why I’m arrogant enough to think I’m qualified to potentially criticize the ASP.Net Core internals, I’m the primary author of both StructureMap (the IoC container) and an alternative “previous generation” OSS web development framework called FubuMVC that tackled a lot of the same problems that ASP.Net Core addresses now that were not part of older ASP.Net MVC or Web API.
ml5.js is a high level JavaScript library for machine learning. The main idea of this project is to further reduce the barriers between lower level machine learning and creative outputs using JavaScript
public interface IHaveCustomMapping { void CreateMappings(AutoMapper.Profile profile); }
public class PostDtoMapping : IHaveCustomMapping { public void CreateMappings(Profile profile) { profile.CreateMap<PostDto, Post>().ReverseMap(); } }
public class CustomMappingProfile : Profile { public CustomMappingProfile(IEnumerable<IHaveCustomMapping> haveCustomMappings) { foreach (var item in haveCustomMappings) item.CreateMappings(this); } }
- این کلاس از AutoMapper.Profile ارث بری کردهاست.
- درون سازندهی خود لیستی از اشیاء اینترفیس IHaveCustomMapping را دریافت کرده و بر روی آنها گردش میکند.
- و متد CreateMappings هرکدام را فراخوانی کرده و خودش (this : شی جاری) را (که از نوع Profile شده) به عنوان پارامتر ورودی پاس میدهد.
public static class AutoMapperConfiguration { public static void InitializeAutoMapper() { Mapper.Initialize(config => { config.AddCustomMappingProfile(); }); //Compile mapping after configuration to boost map speed Mapper.Configuration.CompileMappings(); } public static void AddCustomMappingProfile(this IMapperConfigurationExpression config) { config.AddCustomMappingProfile(Assembly.GetEntryAssembly()); } public static void AddCustomMappingProfile(this IMapperConfigurationExpression config, params Assembly[] assemblies) { var allTypes = assemblies.SelectMany(a => a.ExportedTypes); //Find all classes that implement IHaveCustomMapping inteface and create new instance of each var list = allTypes.Where(type => type.IsClass && !type.IsAbstract && type.GetInterfaces().Contains(typeof(IHaveCustomMapping))) .Select(type => (IHaveCustomMapping)Activator.CreateInstance(type)); //Create a new automapper Profile for this list to create mapping then add to the config var profile = new CustomMappingProfile(list); config.AddProfile(profile); } }
- توضیحات متد های InitializeAutoMapper و AddCustomMappingProfile، مشابه مطلب قبل است و لازم به ذکر مجدد نیست.
- متد AddCustomMappingProfile آرایهای از اسمبلیها را دریافت و سپس تمامی نوعهای قابل دسترس آنها را (ExportedTypes) واکشی میکند.
- سپس توسط شرط Where، نوعهایی که کلاس بوده، abstract نیستند و از اینترفیس IHaveCustomMapping مشتق شدهاند فیلتر میشوند.
- سپس توسط متد Activator.CreateInstance، وهلهای از آنها ایجاد و به نوع IHaveCustomMapping تبدیل میشوند و نهایتا لیستی از اشیاء وهله سازی شده را باز میگرداند.
- سپس وهلهای از نوع CustomMappingProfile (که مسئول اعمال Mappingهای اشیاء دریافتی است و قبلا بررسی کردیم) ایجاد میکنیم و لیست مذکور را به سازنده آن پاس میدهیم.
- نهایتا profile ساخته شده (حاوی تمامی Mappingهای اعمال شده) را توسط متد config.AddProfile به AutoMapper معرفی میکنیم (در این لحظه تمامی Mappingهای تعریف شده داخل profile، به AutoMapper اعمال میشوند).
public abstract class BaseDto<TDto, TEntity, TKey> : IHaveCustomMapping where TEntity : BaseEntity<TKey> { [Display(Name = "ردیف")] public TKey Id { get; set; } /// <summary> /// Maps this dto to a new entity object. /// </summary> public TEntity ToEntity() { return Mapper.Map<TEntity>(CastToDerivedClass(this)); } /// <summary> /// Maps this dto to an exist entity object. /// </summary> public TEntity ToEntity(TEntity entity) { return Mapper.Map(CastToDerivedClass(this), entity); } /// <summary> /// Maps the specified entity to a new dto object. /// </summary> public static TDto FromEntity(TEntity model) { return Mapper.Map<TDto>(model); } protected TDto CastToDerivedClass(BaseDto<TDto, TEntity, TKey> baseInstance) { return Mapper.Map<TDto>(baseInstance); } //Get automapper Profile then create mapping and ignore unmapped properties public void CreateMappings(Profile profile) { var mappingExpression = profile.CreateMap<TDto, TEntity>(); var dtoType = typeof(TDto); var entityType = typeof(TEntity); //Ignore mapping to any property of source (like Post.Categroy) that dose not contains in destination (like PostDto) //To prevent from wrong mapping. for example in mapping of "PostDto -> Post", automapper create a new instance for Category (with null catgeoryName) because we have CategoryName property that has null value foreach (var property in entityType.GetProperties()) { if (dtoType.GetProperty(property.Name) == null) mappingExpression.ForMember(property.Name, opt => opt.Ignore()); } //Pass mapping expressin to customize mapping in concrete class CustomMappings(mappingExpression.ReverseMap()); } //Concrete class can override this method to customize mapping public virtual void CustomMappings(IMappingExpression<TEntity, TDto> mapping) { } }
- کلاس جنریک BaseDto، متدCreateMappings اینترفیس IHaveCustomMapping را پیاده سازی میکند.
- درون این متد، Mapping بین دو نوع TDto و TEntity، توسط ()<profile.CreateMap<TDto, TEntity کانفیگ میشود.
- مانند مطلب قبل، خواصی را که نباید نگاشت شوند، توسط Reflection یافته و Ignore میکنیم.
- سپس Mapping برعکس را توسط ReverseMap اعمال کرده و به متد زیرین آن که virtual نیز است، پاس میدهیم.
public class PostDto : BaseDto<PostDto, Post, long> { public string Title { get; set; } public string Text { get; set; } public int CategoryId { get; set; } public string CategoryName { get; set; } //=> Category.Name public string FullTitle { get; set; } //=> custom mapping for "Title (Category.Name)" public override void CustomMappings(IMappingExpression<Post, PostDto> mapping) { mapping.ForMember( dest => dest.FullTitle, config => config.MapFrom(src => $"{src.Title} ({src.Category.Name})")); } }
- این کلاس، خاصیتی به نام FullTitle دارد که معادلی (خاصیت همنامی) در کلاس Post برای آن وجود ندارد و قرار است مقدار ترکیبی حاصل از Title و Category.Name را نمایش دهد.
- به همین جهت متد CustomMappings را باز نویسی کرده، شیء mapping را دریافت و سفارشی سازی لازم را روی آن انجام دادهایم.
- توسط متد ForMember مشخص کردهایم که مقدار خاصیت FullTitle باید حاصلی از ترکیب Title و Category.Name به نحو مشخص شده باشد ( توسط متد MapFrom).
List<PostDto> list = //ProjectTo method select only needed properties (of PostDto) not all properties //Also select only needed property of navigations (like Post.Category.Name) not all unlike Include //This ability called "Projection" await _applicationDbContext.Posts.ProjectTo<PostDto>() //We can also use Where on IQuerable<PostDto> .Where(p => p.Title.Contains("test") || p.CategoryName.Contains("test")) .ToListAsync();
- متد ProjectTo کوئری post را به IQueryable ای از postDto تبدیل میکند (این قابلیت Projection نامیده میشود).
- نگاشت خودکار خواص موجود در postDto توسط AutoMapper به صورت خودکار انجام میشود و فقط خواص لازم برای postDto واکشی میشوند (نه همه خواص در جدول post، که این به لحاظ کارآیی بهتر است).
- همچنین اگر خواصی را داخل Navigation Propertyها مانند CategoryName داشته باشیم، موقع کوئری گرفتن از دیتابیس، آنها نیز اعمال شده و فقط خواص لازم از Category واکشی میشوند (فقط خاصیت Name، بر خلاف Include که همه ستونها را واکشی میکند).
- همچنین میتوان بر روی خواص Dto شرط Where را قرار داد مانند p.CategoryName.Contains("test") و تماما به کوئری SQL معادل آن ترجمه و اجرا میشوند.
Here are some of the reasons why nullable reference types are less than ideal:
- Invoking a member on a null value will issue a System.NullReferenceException exception, and every invocation that results in a System.NullReferenceException in production code is a bug. Unfortunately, however, with nullable reference types we “fall in” to doing the wrong thing rather than the right thing. The “fall in” action is to invoke a reference type without checking for null.
- There’s an inconsistency between reference types and value types (following the introduction of Nullable<T>) in that value types are nullable when decorated with “?” (for example, int? number); otherwise, they default to non-nullable. In contrast, reference types are nullable by default. This is “normal” to those of us who have been programming in C# for a long time, but if we could do it all over, we’d want the default for reference types to be non-nullable and the addition of a “?” to be an explicit way to allow nulls.
- It’s not possible to run static flow analysis to check all paths regarding whether a value will be null before dereferencing it, or not. Consider, for example, if there were unmanaged code invocations, multi-threading, or null assignment/replacement based on runtime conditions. (Not to mention whether analysis would include checking of all library APIs that are invoked.)
- There’s no reasonable syntax to indicate that a reference type value of null is invalid for a particular declaration.
- There’s no way to decorate parameters to not allow null.
In this post I'll show how to create a logging provider that writes logs to the file system. In production, I'd recommended using a more fully-featured system like Serilog instead of this library, but I wanted to see what was involved to get a better idea of the process myself.
The code for the file logging provider is available on GitHub, or as the NetEscapades.Extensions.Logging.RollingFile package on NuGet.
Bridge Network Driver
The bridge
networking driver is the first driver on our list. It’s simple to understand, simple to use, and simple to troubleshoot, which makes it a good networking choice for developers and those new to Docker. The bridge
driver creates a private network internal to the host so containers on this network can communicate. External access is granted by exposing ports to containers. Docker secures the network by managing rules that block connectivity between different Docker networks.
Overlay Network Driver
The built-in Docker overlay
network driver radically simplifies many of the complexities in multi-host networking. It is a swarm scope driver, which means that it operates across an entire Swarm or UCP cluster rather than individual hosts. With the overlay
driver, multi-host networks are first-class citizens inside Docker without external provisioning or components. IPAM, service discovery, multi-host connectivity, encryption, and load balancing are built right in. For control, the overlay
driver uses the encrypted Swarm control plane to manage large scale clusters at low convergence times.
MACVLAN Driver
The macvlan
driver is the newest built-in network driver and offers several unique characteristics. It’s a very lightweight driver, because rather than using any Linux bridging or port mapping, it connects container interfaces directly to host interfaces. Containers are addressed with routable IP addresses that are on the subnet of the external network.
As a result of routable IP addresses, containers communicate directly with resources that exist outside a Swarm cluster without the use of NAT and port mapping. This can aid in network visibility and troubleshooting. Additionally, the direct traffic path between containers and the host interface helps reduce latency. macvlan
is a local scope network driver which is configured per-host. As a result, there are stricter dependencies between MACVLAN and external networks, which is both a constraint and an advantage that is different from overlay
or bridge
.
There are two MySQL providers for Entity Framework Core:
- The official one from MySQL: MySql.Data.EntityFrameworkCore. As of now, the latest version is 8.0.19, and works with Entity Framework Core 2.1 (and probably also 2.2). Since EF Core 3.0 is a major version with breaking changes, you cannot use it with this provider.
- The Pomelo provider: Pomelo.EntityFrameworkCore.MySql. There is a 3.1 version of this provider.
In other words, if you want to use EF Core 3.0/3.1 with MySQL, at this point you need to use the Pomelo provider (or wait for the official MySQL one to get released).
This is an initial release of a partial implementation of the .NET platform on top of the Java Virtual Machine, and compatible with Android runtime. The Bluebonnet bytecode compiler translates .NET CIL into Java bytecode in Java classes, and additional run-time support is provided by the Baselib library.
معرفی C# Source Generators
مخلص کلام اینکه : اگه با Fody یا PostSharp و همچنین Code Analyzerها آشنایی دارین. این قابلیت یه چیزی تو مایههای ترکیب ایناس و بهتون اجازه میده موقع Compile شدن کد پروژه رو Analyze کنین و یه کد جدیدی بهش اضافه کنین. (مثلا پیاده سازی اینترفیس INotifyPropertyChanged به صورت خودکار به هنگام کامپایل)
We’re pleased to introduce the first preview of Source Generators, a new C# compiler feature that lets C# developers inspect user code and generate new C# source files that can be added to a compilation. This is done via a new kind of component that we’re calling a Source Generator.
To get started with Source Generators, you’ll need to install the latest .NET 5 preview and the latest Visual Studio preview.
نمونه ای از پیاده سازی INotifyPropertyChanged with C# 9.0 Source Generators