C#.NET for non-engineers.
The first course of "A Sr. Developer Course" courses. which contains:
1- C# Fundamentals for non-engineers.
2- DataBase for non-engineers.
3- Asp.NET WebForm for Non-engineers.
4- Application Architecture for no-engineers.
5- ASP.NET MVC for non-engineers.
6- Angular for non-engineers.
This is a course for who knows noting about C# and development if you know nothing about Array, variable, loop, and conditions you are in the right place.
at the end of this course, we will create one small university registration console application together.
You will learn in this course:
C#.NET
.NET Framework
Methods
Recursive methods
C# Primitive Types/Complex Types
conditions
switch case
Arrays
if statement
switch
loops
Creating a method
ref, out
enums
OOP/Object-oriented programing
Generics
Error handling
problem-solving
working with files
level: beginners to upper intermediate
- WMI Provider MSI still failing to install in 16.6
- View History on context menu in Solution Explorer doesn't do anything
- Cannot generate shim for X509Certificate2 with Visual Studio 2019 16.6.0
- Add Controller and Add New Scaffolded Item dialogs are not showing all data contexts after upgrading Visual Studio Enterprise 16.5.6->16.6.0
- Cannot open new json file
- About Microsoft Visual Studio frozen.
- Visual Studio 2019 16.6.0 Microsoft Fakes Issue
- VSSDK IVsHierarchy Regression in VS 16.6.x
- Windows 10 SDK (10.0.19041.1)- ARM64 memcpy crashes when accessing unaligned uncached memory
- Add script to SQL Server Database project does not open User Scripts list
- Fakes generation with ref argument
- Frequent soft hang with Code Analysis callstack in Open Folder project
- Visual Studio Class Designer dark theme support
- Added support for Text Template Transformation Toolkit (T4) in .NET Core projects
- Separate IntelliCode team completions model acquisition from model production.
- Addressed an issue where users may have experienced critical update or installation failures due to the WMIProvider package that would block use of the IDE. Failures in this component no longer block use of the IDE.
- Fixed a problem causing the product to stop responding when working with Xamarin projects on certain scenarios.
- Fixed a bug where VS would crash when attempting to decrypt an invalid UWP code-signing certificate
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 معادل آن ترجمه و اجرا میشوند.