نظرات مطالب
مقایسه مجوزهای سورس باز
سلام،
شما لطفا دارید.
طبق مقاله زیر MPL محبوب‌ترین است:
The Mozilla Public License (MPL) is the most popular open source license that contains a weak copyleft provision

http://www.onlamp.com/pub/a/onlamp/2004/11/18/licenses.html
مطالب
مثالی از الگوی Delegate Dictionary
این الگو چیز جدیدی نیست و قبلا تو سری مطالب «مروری بر کاربردهای Action و Func» دربارش مطلب نوشته شده و...
البته با توجه به جدید بودن این الگو اسم واحدی براش مشخص نشده ولی تو این مطلب «الگوی Delegate Dictionary» معرفی شده که بنظرم از بقیه بهتره.
به طور خلاصه این الگو میگه اگه قراره براساس شرایط (ورودی) خاصی کار خاصی انجام بشه بجای استفاده از IF و Switch از DictionaryوFunc یا Action استفاده کنیم.

برای مثال فرض کنید مدلی به شکل زیر داریم
public class Person
{
    public int Id { get; set; }
    public Gender Gender { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}
قراره براساس جنسیت(شرایط) شخص اعتبارسنجی متفاوتی(کار خاص) رو انجام بدیدم.مثلا در اینجا قراره چک کنیم اگه شخص مرد بود اسم زنونه انتخاب نکرده باشه و...
خب روش معمول به این شکل میتونه باشه
switch (person.Gender)
{
    case Gender.Male:
        if (IsMale(person.FirstName))
        {
            //Isvalid
        }
        break;
    case Gender.Female:
        if (IsFemale(person.FirstName))
        {
            //Isvalid
        }
        break;
}
خب این روش خوب جواب میده ولی باید در حد توان استفاده از IF و Switch رو کم کرد.مثلا تو همین مثال ما اصل Open/Closed رو نقض کردیم فکر کنید قرار باشه اعتبارسنجی دیگه ای از همین دست به این کد(کلاس) اضافه بشه باید تغیرش بدیم پس این کد(کلاس) برای تغییر بسته نیست.در اینجور موارد «الگوی Delegate Dictionary» به کار ما میاد.
ما میایم توابع مورد نظرمون رو داخل یک Dictionary ذخیره میکنیم.
var genderFuncs = new Dictionary<Gender, Func<string, bool>>
                {
                    {Gender.Male , (x) => IsMale(x)},
                    {Gender.Female , (x) => IsFemale(x)}
                };
فرض کنید پیاده سازی توابع به شکل زیر باشه
public static bool IsMale(string name)
{
    //check...
    return true;
}
public static bool IsFemale(string name)
{
    //check...
    if (name == "Farzad")
    {
        return false;    
    }
    return true;
}
نحوه استفاده
var dummyPerson = new List<Person>
                {
                    new Person
                        {Id = 1, Gender = Gender.Male, FirstName = "Mohammad", LastName = "Saheb"},
                    new Person
                        {Id = 2, Gender = Gender.Female, FirstName = "Farzad", LastName = "Mojidi"}
                };

foreach (var person in dummyPerson)
{
    bool isValid = genderFuncs[person.Gender].Invoke(person.FirstName);          
}
با همین روش میشه قسمت آخر مقاله ی خوب آقای کیاست رو هم Refactor کرد.
var query = context.Students.AsQueryable();
  if (searchByName)
  {
      query= query.FindStudentsByName(name);
  }
  if (orderByAge)
  {
      query = query.OrderByAge();
  }
  if (paging)
  {
     query =  query.SkipAndTake(skip, take);
  }
  return query.ToList();
توابع رو داخل یک دیکشنری ذخیره میکنیم
var searchTypeFuncs = new Dictionary<SearchType, Func<IQueryable<Student>, string, IQueryable<Student>>>
                    {
                        {SearchType.FirstName, (x, y) => x.FindStudentsByName(y)},
                        {SearchType.LastName, (x, y) => x.FindStudentsByLastName(y)}
                    };
نحوه استفاده
public static IList<Student> SearchStudents(IQueryable<Student> students, SearchType type, string keyword)
{
    var result = searchTypeFuncs[type].Invoke(students, keyword);
    return result.ToList();
}
اشتراک‌ها
انتشار Samsung Releases 4th Preview of Visual Studio Tools for Tizen including support for .NET Core 2.0 Preview

Samsung has released the fourth preview of Visual Studio Tools for Tizen. Tizen is a Linux-based open source OS running on over 50 million Samsung devices including TVs, wearables, and mobile phones. Since announcing its collaboration with Microsoft on .NET Core and Xamarin.Forms projects last November, Samsung has steadily released preview versions of.NET support for Tizen with enriched features, such as supporting TV application development and various Visual Studio tools for Tizen.

انتشار Samsung Releases 4th Preview of Visual Studio Tools for Tizen including support for .NET Core 2.0 Preview
مطالب
بررسی Source Generators در #C - قسمت اول - معرفی
Source Generators که به همراه C# 9.0 ارائه شدند، یک فناوری نوین meta-programming است و به عنوان جزئی از پروسه‌ی استاندارد کامپایل برنامه، ظاهر می‌شود. هدف اصلی از ارائه‌ی Source Generators، تولید کدهای تکراری مورد استفاده‌ی در برنامه‌ها است. برای مثال بجای انجام کارهای تکراری مانند پیاده سازی متدهای GetHashCode، ToString و یا حتی یک AutoMapper و یا Serializer، برای تمام کلاس‌های برنامه، Source Generators می‌توانند آن‌ها را به صورت خودکار پیاده سازی کنند و همچنین با هر تغییری در کدهای کلاس‌ها، این پیاده سازی‌ها به صورت خودکار به روز خواهند شد. مزیت این روش نه فقط تولید پویای کدها است، بلکه سبب بهبود کارآیی برنامه هم خواهند شد؛ از این جهت که برای مثال می‌توان اعمالی مانند Serialization را بدون انجام Reflection در زمان اجرا، توسط آن‌ها پیاده سازی کرد.


زمانیکه پروسه‌ی کامپایل برنامه شروع می‌شود، در این بین، به مرحله‌ی جدیدی به نام «تولید کدها» می‌رسد. در این حالت، کامپایلر تمام اطلاعاتی را که در مورد پروژه‌ی جاری در اختیار دارد، به تولید کننده‌ی کد معرفی شده‌ی به آن ارائه می‌دهد. بر اساس این اطلاعات غنی ارائه شده‌ی توسط کامپایلر، تولید کننده‌ی کد، شروع به تولید کدهای جدیدی کرده و آن‌ها را در اختیار ادامه‌ی پروسه‌ی کامپایل، قرار می‌دهد. پس از آن، کامپایلر با این کدهای جدید، همانند سایر کدهای موجود در پروژه رفتار کرده و عملکرد عادی خودش را ادامه می‌دهد.

یک برنامه می‌تواند از چندین Source Generators نیز استفاده کند که روش قرار گرفتن آن‌‌ها را در پروسه‌ی کامپایل، در شکل زیر مشاهده می‌کنید:



Source Generators از یکدیگر کاملا مستقل هستند و اطلاعات آن‌ها Immutable است. یعنی نمی‌توان اطلاعات تولیدی توسط یک Source Generator را در دیگری تغییر داد و تمام فایل‌های تولیدی توسط انواع Source Generators موجود، به پروسه‌ی کامپایل نهایی اضافه می‌شوند. هرچند زمانیکه فایلی توسط یک تولید کننده‌ی کد، به کامپایلر اضافه می‌شود، بلافاصله اطلاعات آن در کل برنامه و IDE و تمام Source Generators موجود دیگر، قابل مشاهده و استفاده است.


مقایسه‌ای بین تولید کننده‌های کد و فناوری IL Weaving

Source Generators، تنها راه و روش تولید کد، نیستند و پیش از آن روش‌هایی مانند استفاده از T4 templates ، Fody ، PostSharp و امثال آن نیز ارائه شده‌است. در ادامه مقایسه‌ای را بین تولید کننده‌های کد و فناوری IL Weaving را که پیشتر در سری AOP در این سایت مطالعه کرده‌اید، مشاهده می‌کنید:
تولید کننده‌های کد:
- تنها می‌توانند فایل‌های جدید را اضافه کنند. یعنی «در حین» پروسه‌ی کامپایل ظاهر می‌شوند و به عنوان یک مکمل، تاثیر گذارند. برای مثال نمی‌توانند محتوای یک خاصیت یا متد از پیش موجود را تغییر دهند. اما می‌توانند هر نوع کد partial ای را «تکمیل» کنند.
- محتوای اضافه شده‌ی توسط یک تولید کننده‌ی کد، بلافاصله توسط Compiler شناسایی شده و بررسی می‌شود و همچنین در Intellisense ظاهر شده و به سادگی قابل دسترسی است. همچنین، قابلیت دیباگ نیز دارد.

IL Weaving:
- می‌توانند bytecode برنامه را تغییر دهند. یعنی «پس از» پروسه‌ی کامپایل ظاهر شده و کدهایی را به اسمبلی نهایی تولید شده اضافه می‌کنند. در این حالت محدودیتی از لحاظ محل تغییر کدها وجود ندارد. برای مثال می‌توان بدنه‌ی یک متد یا خاصیت را بطور کامل بازنویسی کرد و کارکردهایی مانند تزریق کدهای caching و logging را دارند.
- کدهایی که توسط این پروسه اضافه می‌شوند، در حین کدنویسی متداول، قابلیت دسترسی ندارند؛ چون پس از پروسه‌ی کامپایل، به فایل باینری نهایی تولیدی، اضافه می‌شوند. بنابراین قابلیت دیباگ به همراه سایر کدهای برنامه را نیز ندارند. به علاوه چون توسط کامپایلر در حین پروسه‌ی کامپایل، بررسی نمی‌شوند، ممکن است به همراه قطعه کدهای غیرقابل اجرایی نیز باشند و دیباگ آن‌ها بسیار مشکل است.



آینده‌ی Reflection به چه صورتی خواهد شد؟

هرچند Reflection کار تولید کدی را انجام نمی‌دهد، اما یکی از کارهای متداول با آن، یافتن و محاسبه‌ی اطلاعات خواص و فیلدهای اشیاء، در زمان اجرا است و مزیت کار کردن با آن نیز این است که اگر خاصیتی یا فیلدی تغییر کند، نیازی به بازنویسی قسمت‌های پیاده سازی شده‌ی با Reflection نیست. به همین جهت برای مثال تقریبا تمام کتابخانه‌های Serialization، از Reflection برای پیاده سازی اعمال خود استفاده می‌کنند.
امروز، تمام اینگونه عملیات را توسط Source Generators نیز می‌توان انجام داد و این فناوری جدید، قابلیت به روز رسانی خودکار کدهای تولیدی را با کم و زیاد شدن خواص و فیلدهای کلاس‌ها دارد و نمونه‌ای از آن، Source Generator توکار مرتبط با کار با JSON در دات نت 6 است که به شدت سبب بهبود کارآیی برنامه، در مقایسه با استفاده‌ی از Reflection می‌شود؛ چون اینبار تمام محاسبات دقیق مرتبط با Serialization به صورت خودکار در زمان کامپایل برنامه انجام می‌شود و جزئی از خروجی برنامه‌ی نهایی خواهد شد و دیگر نیازی به محاسبه‌ی هرباره‌ی اطلاعات مورد نیاز، در زمان اجرای برنامه نیست.
نمونه‌ای از روش دسترسی به اطلاعات کلاس‌ها و خواص و فیلدهای آن‌ها را در زمان کامپایل برنامه توسط Source Generators، در مثال قسمت بعد، مشاهده خواهید کرد.


وضعیت T4 templates چگونه خواهد شد؟

در سال‌های آغازین ارائه‌ی دات نت، استفاده از T4 templates جهت تولید کدها بسیار مرسوم بود؛ اما با ارائه‌ی Source Generators، این ابزار نیز منسوخ شده در نظر گرفته می‌‌شود.
T4 Templates همانند Source Generators تنها کدها و فایل‌های جدیدی را تولید می‌کنند و توانایی تغییر کدهای موجود را ندارند. اما مشکل مهم آن، داشتن Syntax ای خاص است که توسط اکثر IDEها پشتیبانی نمی‌شود. همچنین عموما اجرای آن‌ها نیز دستی است و برخلاف Source Generators، با تغییرات کدها، به صورت خودکار به روز نمی‌شوند.


تغییرات زبان #C در جهت پشتیبانی از تولید کننده‌های کد

از سال‌های اول ارائه‌ی زبان #C، واژه‌ی کلیدی partial، جهت فراهم آوردن امکان تقسیم کدهای یک کلاس، به چندین فایل، میسر شد که از این قابلیت در فناوری T4 Templates زیاد استفاده می‌شد. اکنون با ارائه‌ی تولید کننده‌های کد، واژه‌ی کلیدی partial را می‌توان به متدها نیز افزود تا پیاده سازی اصلی آن‌ها، در فایلی دیگر، توسط تولید کننده‌های کد انجام شود. تا C# 8.0 امکان افزودن واژه‌ی کلیدی partial به متدهای خصوصی یک کلاس و آن هم از نوع void وجود داشت و در C# 9.0 به متدهای عمومی کلاس‌ها نیز اضافه شده‌است و اکنون این متدها می‌توانند void هم نباشند:
partial class MyType
{
   partial void OnModelCreating(string input); // C# 8.0

   public partial bool IsPet(string input);  // C# 9.0
}

partial class MyType
{
   public partial bool IsPet(string input) =>
     input is "dog" or "cat" or "fish";
}
نظرات مطالب
ساخت یک Form Generator ساده در MVC
View Source صفحه را در زمان اجرا مشاهده کنید، مقادیر Name را در المان‌های HTML صفحه بررسی کنید.
اطلاعات بیشتر در این خصوص (+)
مطالب
استفاده از EF در اپلیکیشن های N-Tier : قسمت دوم
در قسمت قبل معماری اپلیکیشن‌های N-Tier و بروز رسانی موجودیت‌های منفصل توسط Web API را بررسی کردیم. در این قسمت بروز رسانی موجودیت‌های منفصل توسط WCF را بررسی می‌کنیم.

بروز رسانی موجودیت‌های منفصل توسط WCF

سناریویی را در نظر بگیرید که در آن عملیات CRUD توسط WCF پیاده سازی شده اند و دسترسی داده‌ها با مدل Code-First انجام می‌شود. فرض کنید مدل اپلیکیشن مانند تصویر زیر است.

همانطور که می‌بینید مدل ما متشکل از پست‌ها و نظرات کاربران است. برای ساده نگاه داشتن مثال جاری، اکثر فیلدها حذف شده اند. مثلا متن پست ها، نویسنده، تاریخ و زمان انتشار و غیره. می‌خواهیم تمام کد دسترسی داده‌ها را در یک سرویس WCF پیاده سازی کنیم تا کلاینت‌ها بتوانند عملیات CRUD را توسط آن انجام دهند. برای ساختن این سرویس مراحل زیر را دنبال کنید.

  • در ویژوال استودیو پروژه جدیدی از نوع Class Library بسازید و نام آن را به Recipe2 تغییر دهید.
  • با استفاده از NuGet Package Manager کتابخانه Entity Framework 6 را به پروژه اضافه کنید.
  • سه کلاس با نام‌های Post, Comment و Recipe2Context به پروژه اضافه کنید. کلاس‌های Post و Comment موجودیت‌های مدل ما هستند که به جداول متناظرشان نگاشت می‌شوند. کلاس Recipe2Context آبجکت DbContext ما خواهد بود که بعنوان درگاه عملیاتی EF عمل می‌کند. دقت کنید که خاصیت‌های لازم WCF یعنی DataContract و DataMember در کلاس‌های موجودیت‌ها بدرستی استفاده می‌شوند. لیست زیر کد این کلاس‌ها را نشان می‌دهد.
[DataContract(IsReference = true)]
public class Post
{
    public Post()
    {
        comments = new HashSet<Comments>();
    }
    
    [DataMember]
    public int PostId { get; set; }
    [DataMember]
    public string Title { get; set; }
    [DataMember]
    public virtual ICollection<Comment> Comments { get; set; }
}

[DataContract(IsReference=true)]
public class Comment
{
    [DataMember]
    public int CommentId { get; set; }
    [DataMember]
    public int PostId { get; set; }
    [DataMember]
    public string CommentText { get; set; }
    [DataMember]
    public virtual Post Post { get; set; }
}

public class EFRecipesEntities : DbContext
{
    public EFRecipesEntities() : base("name=EFRecipesEntities") {}

    public DbSet<Post> posts;
    public DbSet<Comment> comments;
}
  • یک فایل App.config به پروژه اضافه کنید و رشته اتصال زیر را به آن اضافه نمایید.
<connectionStrings>
  <add name="Recipe2ConnectionString"
    connectionString="Data Source=.;
    Initial Catalog=EFRecipes;
    Integrated Security=True;
    MultipleActiveResultSets=True"
    providerName="System.Data.SqlClient" />
</connectionStrings>
  • حال یک پروژه WCF به Solution جاری اضافه کنید. برای ساده نگاه داشتن مثال جاری، نام پیش فرض Service1 را بپذیرید. فایل IService1.cs را باز کنید و کد زیر را با محتوای آن جایگزین نمایید.
[ServiceContract]
public interface IService1
{
    [OperationContract]
    void Cleanup();
    [OperationContract]
    Post GetPostByTitle(string title);
    [OperationContract]
    Post SubmitPost(Post post);
    [OperationContract]
    Comment SubmitComment(Comment comment);
    [OperationContract]
    void DeleteComment(Comment comment);
}
  • فایل Service1.svc.cs را باز کنید و کد زیر را با محتوای آن جایگزین نمایید. بیاد داشته باشید که پروژه Recipe2 را ارجاع کنید و فضای نام آن را وارد نمایید. همچنین کتابخانه EF 6 را باید به پروژه اضافه کنید.
public class Service1 : IService
{
    public void Cleanup()
    {
        using (var context = new EFRecipesEntities())
        {
            context.Database.ExecuteSqlCommand("delete from [comments]");
            context. Database.ExecuteSqlCommand ("delete from [posts]");
        }
    }

    public Post GetPostByTitle(string title)
    {
        using (var context = new EFRecipesEntities())
        {
            context.Configuration.ProxyCreationEnabled = false;
            var post = context.Posts.Include(p => p.Comments).Single(p => p.Title == title);
            return post;
        }
    }

    public Post SubmitPost(Post post)
    {
        context.Entry(post).State =
            // if Id equal to 0, must be insert; otherwise, it's an update
            post.PostId == 0 ? EntityState.Added : EntityState.Modified;
        context.SaveChanges();
        return post;
    }

    public Comment SubmitComment(Comment comment)
    {
        using (var context = new EFRecipesEntities())
        {
            context.Comments.Attach(comment);
            if (comment.CommentId == 0)
            {
                // this is an insert
                context.Entry(comment).State = EntityState.Added);
            }
            else
            {
                // set single property to modified, which sets state of entity to modified, but
                // only updates the single property – not the entire entity
                context.entry(comment).Property(x => x.CommentText).IsModified = true;
            }
            context.SaveChanges();
            return comment;
        }
    }

    public void DeleteComment(Comment comment)
    {
        using (var context = new EFRecipesEntities())
        {
            context.Entry(comment).State = EntityState.Deleted;
            context.SaveChanges();
        }
    }
}


  • در آخر پروژه جدیدی از نوع Windows Console Application به Solution جاری اضافه کنید. از این اپلیکیشن بعنوان کلاینتی برای تست سرویس WCF استفاده خواهیم کرد. فایل program.cs را باز کنید و کد زیر را با محتوای آن جایگزین نمایید. روی نام پروژه کلیک راست کرده و گزینه Add Service Reference را انتخاب کنید، سپس ارجاعی به سرویس Service1 اضافه کنید. رفرنسی هم به کتابخانه کلاس‌ها که در ابتدای مراحل ساختید باید اضافه کنید.
class Program
{
    static void Main(string[] args)
    {
        using (var client = new ServiceReference2.Service1Client())
        {
            // cleanup previous data
            client.Cleanup();
            // insert a post
            var post = new Post { Title = "POCO Proxies" };
            post = client.SubmitPost(post);
            // update the post
            post.Title = "Change Tracking Proxies";
            client.SubmitPost(post);
            // add a comment
            var comment1 = new Comment { CommentText = "Virtual Properties are cool!", PostId = post.PostId };
            var comment2 = new Comment { CommentText = "I use ICollection<T> all the time", PostId = post.PostId };
            comment1 = client.SubmitComment(comment1);
            comment2 = client.SubmitComment(comment2);
            // update a comment
            comment1.CommentText = "How do I use ICollection<T>?";
            client.SubmitComment(comment1);
            // delete comment 1
            client.DeleteComment(comment1);
            // get posts with comments
            var p = client.GetPostByTitle("Change Tracking Proxies");
            Console.WriteLine("Comments for post: {0}", p.Title);
            foreach (var comment in p.Comments)
            {
                Console.WriteLine("\tComment: {0}", comment.CommentText);
            }
        }
    }
}
اگر اپلیکیشن کلاینت (برنامه کنسول) را اجرا کنید با خروجی زیر مواجه می‌شوید.

Comments for post: Change Tracking Proxies
Comment: I use ICollection<T> all the time


شرح مثال جاری

ابتدا با اپلیکیشن کنسول شروع می‌کنیم، که کلاینت سرویس ما است. نخست در یک بلاک {} using وهله ای از کلاینت سرویس مان ایجاد می‌کنیم. درست همانطور که وهله ای از یک EF Context می‌سازیم. استفاده از بلوک‌های using توصیه می‌شود چرا که متد Dispose بصورت خودکار فراخوانی خواهد شد، چه بصورت عادی چه هنگام بروز خطا. پس از آنکه وهله ای از کلاینت سرویس را در اختیار داشتیم، متد Cleanup را صدا می‌زنیم. با فراخوانی این متد تمام داده‌های تست پیشین را حذف می‌کنیم. در چند خط بعدی، متد SubmitPost را روی سرویس فراخوانی می‌کنیم. در پیاده سازی فعلی شناسه پست را بررسی می‌کنیم. اگر مقدار شناسه صفر باشد، خاصیت State موجودیت را به Added تغییر می‌دهید تا رکورد جدیدی ثبت کنیم. در غیر اینصورت فرض بر این است که چنین موجودیتی وجود دارد و قصد ویرایش آن را داریم، بنابراین خاصیت State را به Modified تغییر می‌دهیم. از آنجا که مقدار متغیرهای int بصورت پیش فرض صفر است، با این روش می‌توانیم وضعیت پست‌ها را مشخص کنیم. یعنی تعیین کنیم رکورد جدیدی باید ثبت شود یا رکوردی موجود بروز رسانی گردد. رویکردی بهتر آن است که پارامتری اضافی به متد پاس دهیم، یا متدی مجزا برای ثبت رکوردهای جدید تعریف کنیم. مثلا رکوردی با نام InsertPost. در هر حال، بهترین روش بستگی به ساختار اپلیکیشن شما دارد.

اگر پست جدیدی ثبت شود، خاصیت PostId با مقدار مناسب جدید بروز رسانی می‌شود و وهله پست را باز می‌گردانیم. ایجاد و بروز رسانی نظرات کاربران مشابه ایجاد و بروز رسانی پست‌ها است، اما با یک تفاوت اساسی: بعنوان یک قانون، هنگام بروز رسانی نظرات کاربران تنها فیلد متن نظر باید بروز رسانی شود. بنابراین با فیلدهای دیگری مانند تاریخ انتشار و غیره اصلا کاری نخواهیم داشت. بدین منظور تنها خاصیت CommentText را بعنوان Modified علامت گذاری می‌کنیم. این امر منجر می‌شود که Entity Framework عبارتی برای بروز رسانی تولید کند که تنها این فیلد را در بر می‌گیرد. توجه داشته باشید که این روش تنها در صورتی کار می‌کند که بخواهید یک فیلد واحد را بروز رسانی کنید. اگر می‌خواستیم فیلدهای بیشتری را در موجودیت Comment بروز رسانی کنیم، باید مکانیزمی برای ردیابی تغییرات در سمت کلاینت در نظر می‌گرفتیم. در مواقعی که خاصیت‌های متعددی می‌توانند تغییر کنند، معمولا بهتر است کل موجودیت بروز رسانی شود تا اینکه مکانیزمی پیچیده برای ردیابی تغییرات در سمت کلاینت پیاده گردد. بروز رسانی کل موجودیت بهینه‌تر خواهد بود.

برای حذف یک دیدگاه، متد Entry را روی آبجکت DbContext فراخوانی می‌کنیم و موجودیت مورد نظر را بعنوان آرگومان پاس می‌دهیم. این امر سبب می‌شود که موجودیت مورد نظر بعنوان Deleted علامت گذاری شود، که هنگام فراخوانی متد SaveChanges اسکریپت لازم برای حذف رکورد را تولید خواهد کرد.

در آخر متد GetPostByTitle یک پست را بر اساس عنوان پیدا کرده و تمام نظرات کاربران مربوط به آن را هم بارگذاری می‌کند. از آنجا که ما کلاس‌های POCO را پیاده سازی کرده ایم، Entity Framework آبجکتی را بر می‌گرداند که Dynamic Proxy نامیده می‌شود. این آبجکت پست و نظرات مربوط به آن را در بر خواهد گرفت. متاسفانه WCF نمی‌تواند آبجکت‌های پروکسی را مرتب سازی (serialize) کند. اما با غیرفعال کردن قابلیت ایجاد پروکسی‌ها (ProxyCreationEnabled=false) ما به Entity Framework می‌گوییم که خود آبجکت‌های اصلی را بازگرداند. اگر سعی کنید آبجکت پروکسی را سریال کنید با پیغام خطای زیر مواجه خواهید شد:

The underlying connection was closed: The connection was closed unexpectedly 

می توانیم غیرفعال کردن تولید پروکسی را به متد سازنده کلاس سرویس منتقل کنیم تا روی تمام متدهای سرویس اعمال شود.

در این قسمت دیدیم چگونه می‌توانیم از آبجکت‌های POCO برای مدیریت عملیات CRUD توسط WCF استفاده کنیم. از آنجا که هیچ اطلاعاتی درباره وضعیت موجودیت‌ها روی کلاینت ذخیره نمی‌شود، متدهایی مجزا برای عملیات CRUD ساختیم. در قسمت‌های بعدی خواهیم دید چگونه می‌توان تعداد متدهایی که سرویس مان باید پیاده سازی کند را کاهش داد و چگونه ارتباطات بین کلاینت و سرور را ساده‌تر کنیم.

اشتراک‌ها
Tools for Apache Cordova - مثال ها و مستندات
Open source code is the norm for so many developers these days, and unsurprisingly, so is open documentation. From Azure to TypeScript, public repositories have become a go-to place for sharing samples, tutorials, and “tips and tricks” so that everyone can learn and contribute together as a community.
Tools for Apache Cordova - مثال ها و مستندات
اشتراک‌ها
Ventoy؛ ابزاری سورس باز برای ساخت bootable USB drive از فایل‌های ISO سیستم عامل‌های مختلف

Ventoy is an open source tool to create bootable USB drive for ISO files. With ventoy, you don't need to format the disk again and again, you just need to copy the iso file to the USB drive and boot it. You can copy many iso files at a time and ventoy will give you a boot menu to select them (screenshot). Both Legacy BIOS and UEFI are supported in the same way. 260+ ISO files are tested (list).
 

Ventoy؛ ابزاری سورس باز برای ساخت bootable USB drive از فایل‌های ISO سیستم عامل‌های مختلف