اشتراک‌ها
اعمال فیلترهای اینستاگرام بر روی تصاویر تحت وب
 Many love using Instagram and the filters that come with the app, to make their photos more interesting and beautiful. So far though, the use of these filters are restricted to use inside the app. What if you want to use Instagram filters on web images, outside of the app, like photos you want to put up in your personal blog or website ?
اعمال فیلترهای اینستاگرام بر روی تصاویر تحت وب
اشتراک‌ها
پیاده سازی یک Filter سفارشی برای نگاشت استثنای همزمانی به خطاهای MadelState
 public class HandleConcurrencyExceptionAttribute : FilterAttribute, IExceptionFilter
    {
        private PropertyMatchingMode _propertyMatchingMode;
        /// <summary>
        /// This defines when the concurrencyexception happens, 
        /// </summary>
        public enum PropertyMatchingMode
        {
            /// <summary>
            /// Uses only the field names in the model to check against the entity. This option is best when you are using 
            /// View Models with limited fields as opposed to an entity that has many fields. The ViewModel (or model) field names will
            /// be used to check current posted values vs. db values on the entity itself.
            /// </summary>
            UseViewModelNamesToCheckEntity = 0,
            /// <summary>
            /// Use any non-matching value fields on the entity (except timestamp fields) to add errors to the ModelState.
            /// </summary>
            UseEntityFieldsOnly = 1,
            /// <summary>
            /// Tells the filter to not attempt to add field differences to the model state.
            /// This means the end user will not see the specifics of which fields caused issues
            /// </summary>
            DontDisplayFieldClashes = 2
        }


        public HandleConcurrencyExceptionAttribute()
        {
            _propertyMatchingMode = PropertyMatchingMode.UseViewModelNamesToCheckEntity;
        }

        public HandleConcurrencyExceptionAttribute(PropertyMatchingMode propertyMatchingMode)
        {
            _propertyMatchingMode = propertyMatchingMode;
        }


        /// <summary>
        /// The main method, called by the mvc runtime when an exception has occured.
        /// This must be added as a global filter, or as an attribute on a class or action method.
        /// </summary>
        /// <param name="filterContext"></param>
        public void OnException(ExceptionContext filterContext)
        {
            if (!filterContext.ExceptionHandled && filterContext.Exception is DbUpdateConcurrencyException)
            {
                //Get original and current entity values
                DbUpdateConcurrencyException ex = (DbUpdateConcurrencyException)filterContext.Exception;
                var entry = ex.Entries.Single();
                //problems with ef4.1/4.2 here because of context/model in different projects.
                //var databaseValues = entry.CurrentValues.Clone().ToObject();
                //var clientValues = entry.Entity;
                //So - if using EF 4.1/4.2 you may use this workaround
                var clientValues = entry.CurrentValues.Clone().ToObject();
                entry.Reload();
                var databaseValues = entry.CurrentValues.ToObject();

                List<string> propertyNames;

                filterContext.Controller.ViewData.ModelState.AddModelError(string.Empty, "The record you attempted to edit "
                        + "was modified by another user after you got the original value. The "
                        + "edit operation was canceled and the current values in the database "
                        + "have been displayed. If you still want to edit this record, click "
                        + "the Save button again to cause your changes to be the current saved values.");
                PropertyInfo[] entityFromDbProperties = databaseValues.GetType().GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance);

                if (_propertyMatchingMode == PropertyMatchingMode.UseViewModelNamesToCheckEntity)
                {
                    //We dont have access to the model here on an exception. Get the field names from modelstate:
                    propertyNames = filterContext.Controller.ViewData.ModelState.Keys.ToList();
                }
                else if (_propertyMatchingMode == PropertyMatchingMode.UseEntityFieldsOnly)
                {
                    propertyNames = databaseValues.GetType().GetProperties(BindingFlags.Public).Select(o => o.Name).ToList();
                }
                else
                {
                    filterContext.ExceptionHandled = true;
                    UpdateTimestampField(filterContext, entityFromDbProperties, databaseValues);
                    filterContext.Result = new ViewResult() { ViewData = filterContext.Controller.ViewData };
                    return;
                }



                UpdateTimestampField(filterContext, entityFromDbProperties, databaseValues);

                //Get all public properties of the entity that have names matching those in our modelstate.
                foreach (var propertyInfo in entityFromDbProperties)
                {

                    //If this value is not in the ModelState values, don't compare it as we don't want
                    //to attempt to emit model errors for fields that don't exist.

                    //Compare db value to the current value from the entity we posted.

                    if (propertyNames.Contains(propertyInfo.Name))
                    {
                        if (propertyInfo.GetValue(databaseValues, null) != propertyInfo.GetValue(clientValues, null))
                        {
                            var currentValue = propertyInfo.GetValue(databaseValues, null);
                            if (currentValue == null || string.IsNullOrEmpty(currentValue.ToString()))
                            {
                                currentValue = "Empty";
                            }

                            filterContext.Controller.ViewData.ModelState.AddModelError(propertyInfo.Name, "Current value: "
                                 + currentValue);
                        }
                    }

                    //TODO: hmm.... how can we only check values applicable to the model/modelstate rather than the entity we saved?
                    //The problem here is we may only have a few fields used in the viewmodel, but many in the entity
                    //so we could have a problem here with that.
                    //object o = propertyInfo.GetValue(myObject, null);
                }

                filterContext.ExceptionHandled = true;

                filterContext.Result = new ViewResult() { ViewData = filterContext.Controller.ViewData };
            }
        }
پیاده سازی یک Filter سفارشی برای نگاشت استثنای همزمانی به خطاهای MadelState
اشتراک‌ها
اعتبارسنجی IOptions توسط کتابخانه MiniValidation

In this post I described the problem that by default, DataAnnotation validation doesn't recursively inspect all properties in an object for DataAnnotation attributes. There are several solutions to this problem, but in this post I used the MiniValidation library from Damian Edwards. This simple library provides a convenience wrapper around DataAnnotation validation, as well as providing features like recursive validation. Finally I showed how you can replace the built-in DataAnnotation validation with a MiniValidation-based validator

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOptions<MySettings>()
    .BindConfiguration("MySettings")
    .ValidateMiniValidation() // 👈 Replace with mini validation
    .ValidateOnStart();

var app = builder.Build();
OptionsValidationException: 
  DataAnnotation validation failed for 'MySettings' member: 'Nested.Value' with errors: 'The Value field is required.'.; 
  DataAnnotation validation failed for 'MySettings' member: 'Nested.Count' with errors: 'The field Count must be between 1 and 100.'.
Microsoft.Extensions.Options.OptionsFactory<TOptions>.Create(string name)
Microsoft.Extensions.Options.OptionsMonitor<TOptions>+<>c__DisplayClass10_0.<Get>b__0()


اعتبارسنجی IOptions  توسط کتابخانه MiniValidation
اشتراک‌ها
سری چالش یادگیری NET.

Over 40 hours of FREE Learning inside of this awesome collection of 8 Paths and 5 additional bonus modules.

Topics include Basic C# skills, Web API development, Blazor Apps, Static Web Apps, Xamarin and Visual Studio or VS Code 

سری چالش یادگیری NET.
مطالب
سری بررسی SQL Smell در EF Core - استفاده از مدل Entity Attribute Value - بخش دوم
در مطلب قبلی، مدل EAV را معرفی کردیم و گفتیم که این نوع پیاده‌سازی در واقع یک SQL Smell است؛ زیرا کوئری نویسی را سخت میکند و همچنین به دلیل عدم امکان تعریف constraints، کنترلی بر روی صحت دیتاهای وارده شد نخواهیم داشت. در نهایت با برنامه‌ای روبرو خواهیم شد که درک صحیحی از ماهیت دیتا ندارد. اما اگر در شرایطی مجبور به استفاده‌ی از این مدل هستید، بهتر است از فرمت JSON برای ذخیره‌سازی دیتای داینامیک استفاده کنید. بیشتر دیتابیس‌های رابطه‌ایی به صورت native از نوع داده‌ایی JSON پشتیبانی میکنند:  
CREATE TABLE EmployeeJsonAttributes (
  Id int NOT NULL AUTO_INCREMENT,
  EmployeeId int NOT NULL,
  Attributes json DEFAULT NULL,
  PRIMARY KEY (Id),
  FOREIGN KEY (EmployeeId) REFERENCES EmployeeEav (Id) ON DELETE CASCADE
)
همانطور که مشاهده می‌کنید در اینجا تایپ ستون Attributes، به JSON تنظیم شده است. بنابراین می‌توانیم از قابلیت‌های توکار دیتابیس (MySQL در مطلب جاری) برای ذخیره و بازیابی داده‌های JSON استفاده کنیم. در ادامه دو روش ذخیره JSON  را مشاهده میکنید: 
INSERT INTO EmployeeJsonAttributes VALUES (
101, 
  '{
  "name": "Jon",
    "lastName": "Doe",
    "dateOfBirth": "1989-01-01 10:10:10+05:30",
    "skills": [ "C#", "JS" ],
    "address":  {
  "country": "UK",
      "city": "London",
      "email": "jon.doe@example.com"
    }
  }'
)

INSERT INTO efcoresample.EmployeeJsonAttributes VALUES (
101, 
  JSON_OBJECT(
"name", "Jon", 
"lastName", "Doe",
"dateOfBirth", "1989-01-01 10:10:10+05:30",
"skills", JSON_ARRAY("C#", "JS"),
    "address", JSON_OBJECT(
  "country", "UK",
      "city", "London",
  "email", "jon.doe@example.com"
    )
  )
)

به عنوان مثال در ادامه میخواهیم کشور محل تولد یک کاربر خاص را نمایش دهیم. برای اینکار می‌توانیم از JSON_EXTRACT استفاده کنیم:
SELECT JSON_EXTRACT(Attributes, '$.address.country') as Country 
FROM EmployeeJsonAttributes
WHERE EmployeeId = 101;

-- Conutry
-- "UK"

همچنین می‌توانیم از عملگر column-path نیز به جای JSON_EXTRACT استفاده کنیم:
SELECT Attributes -> '$.address.country' as Country 
FROM EmployeeJsonAttributes
WHERE EmployeeId = 101;

-- Conutry
-- "UK"

بنابراین به راحتی می‌توانیم کوئری مطلب قبل را اینگونه بازنویسی کنیم:
SELECT EmployeeId, Attributes ->> '$.DateOfBirth' AS BirthDate FROM EmployeeJsonAttributes
WHERE Attributes ->> '$.DateOfBirth' > DATE_SUB(CURRENT_DATE(), INTERVAL 25 YEAR)
همانطور که مشاهده می‌کنید در کوئری فوق یک عملگر < دیگر نیز اضافه کرده‌ایم. هدف از آن حذف “” از خروجی نهایی می‌باشد. 

استفاده از JSON در EF Core 
متاسفانه در EF Core به صورت مستقیم نمی‌توانیم از JSON درون کلاس‌های سی‌شارپ استفاده کنیم (+ )، در نتیجه در سمت کلاس‌های سی‌شارپ باید از string استفاده کنیم و به نوعی به EF Core اطلاع دهیم که تایپ ستون موردنظرمان JSON است. در نتیجه خروجی نهایی درون دیتابیس، یک فیلد با تایپ JSON خواهد بود. برای اینکار به دو شیوه می‌توانیم تایپ ستون موردنظر را تعیین کنیم: 
// Fluent API
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Employee>(entity =>
    {
        entity.Property(e => e.Attributes).HasColumnType("json");
    });
}

// Data Annotations
[Column(TypeName = "json")]
public string Attributes { get; set; }

در نهایت برای تشکیل بانک اطلاعاتی، به مدلی با ساختار زیر نیاز خواهیم داشت:
public class EmployeeJsonAttribute
{
    public int Id { get; set; }
    public virtual EmployeeEav Employee { get; set; }
    public int EmployeeId { get; set; }
    [Column(TypeName = "json")]
    public string Attributes { get; set; }
}
در اینجا به جای تعریف ستون‌ها و مقادیر داینامیک‌شان از یک فیلد از نوع رشته‌ایی با نام Attributes استفاده شده است. از آنجائیکه نوع ستون در سمت دیتابیس به JSON تنظیم خواهد شد، در نتیجه هر نوع ساختار JSON معتبری را می‌توانیم درون آن ذخیره کنیم:
dbContext.EmployeeJsonAttributes.Add(new EmployeeJsonAttribute
{
    EmployeeId =  101,
    Attributes = JsonSerializer.Serialize(new
    {
        FirstName = "Sirwan",
        LastName = "Afifi",
        DateOfBirth = DateTime.Now.AddYears(-31)
    })
});

dbContext.SaveChanges();
همانطور که اشاره شده به دلیل عدم پشتیبانی از JSON در حال حاضر در EF Core امکان کوئری نویسی بر روی ستون JSON را نداریم. در همین حد که براساس فیلدهای دیگر جستجو را انجام داده و خروجی را Deserialize کنیم:
var employee = dbContext.EmployeeJsonAttributes.Find(201);
Console.WriteLine(JsonSerializer.Deserialize<Employee>(employee.Attributes).DateOfBirth);

برای نوشتن کوئری روی ستون JSON می‌توانید از Query Types  نیز استفاده کنید. 
اشتراک‌ها
پیش نمایش MAUI و اجرای یک مثال

At Microsoft Build 2021 .NET MAUI Preview 4 was launched. This version is already pretty complete and starts to reflect what the end result is going to look like. In this video I will show you the new .NET MAUI template in Visual Studio 2019 and walk you through the Weather 21 demo app.  

پیش نمایش MAUI و اجرای یک مثال
اشتراک‌ها
افزونه‌ای برای پیش‌نمایش خروجی مرورگر داخل VSCode به همراه قابلیت دیباگ

Browser Preview for VS Code enables you to open a real browser preview inside your editor that you can debug. Browser Preview is powered by Chrome Headless, and works by starting a headless Chrome instance in a new process. This enables a secure way to render web content inside VS Code, and enables interesting features such as in-editor debugging and more! 

افزونه‌ای برای پیش‌نمایش خروجی مرورگر داخل VSCode به همراه قابلیت دیباگ
اشتراک‌ها
تولید محتوای پویا در Angular

محتوای پویا Angular  : 

Multiple ways to create Angular components dynamically at runtime 

In this article, I am going to show you several ways of creating dynamic content in Angular. You will get examples of custom list templates, dynamic component creation, runtime component and module compilation. Full source code will be available at the end of the article.

 
تولید محتوای پویا در Angular
اشتراک‌ها
مقدمه ای بر Web Sql

In this post we will see some informations about Web SQL. I know you all are familiar with SQL, If not I strongly recommend you to read some basic informations here . As the name implies, Web SQL has so many similarities with SQL. So if you are good in SQL, you will love Web SQL too. Web SQL is an API which helps the developers to do some database operations in client side, like creating database, open the transaction, creating tables, inserting values to tables, deleting values, reading the data. 

مقدمه ای بر Web Sql
اشتراک‌ها
به کار بردن متدهای GET و POST چندگانه در ASP.NET Core Web API

In ASP.NET Core MVC and Web API are parts of the same unified framework. That is why an MVC controller and a Web API controller both inherit from Controller base class. Usually a Web API controller has maximum of five actions - Get(), Get(id), Post(), Put(), and Delete(). However, if required you can have additional actions in the Web API controller. This article shows how.

Let's say you have a Web API controller named CustomerController with the following skeleton code. 

به کار بردن متدهای GET و POST چندگانه در ASP.NET Core Web API