مطالب
شروع کار با GraphQL در ASP.NET Core
در این مقاله هدف این است که GraphQL را در ASP.NET Core راه اندازی کنیم. از یک کتابخانه ثالث برای آسان‌تر کردن یکپارچگی استفاده می‌کنیم و همچنین با جزئیات، توضیح خواهیم داد که چگونه می‌توان از element‌های مربوط به GraphQL مثل (Type ،Query و Schema) برای کامل کردن فرآیند یکپارچگی در ASP.NET Core استفاده کنیم.

GraphQL  و تفاوت‌های آن با REST
GraphQl یک query language می‌باشد که query‌ها را با استفاده از type system‌‌‌هایی که ما برای داده‌ها تعریف می‌کنیم، اجرا می‌کند. GraphQL  به هیچ زبان یا پایگاه داده مشخصی گره نخورده است. 

  •  GraphQL نیازمند رفت و برگشت‌های کمتری به server، به منظور بازیابی داده‌ها برای template یا view است. همراه با REST ما مجبور هستیم که چندیدن endpoint مثلا  (... api/students, api/courses, api/instructors ) را برای گرفتن همه داده‌های که برای template یا view نیاز داریم ملاقات کنیم؛ ولی این شرایط در GraphQL برقرار نیست. با GraphQL ما تنها یک query را ایجاد می‌کنیم که چندین تابع (resolver) را در سمت سرور فراخوانی می‌کند و همه داده‌ها را از منابع مختلفی، در یک درخواست برگشت می‌دهد. 

  • همراه با REST، همانطور که Application ما رشد می‌کند، تعداد endpoint‌ها هم زیاد می‌شوند که این نیازمند زمان بیشتری برای نگهداری می‌باشد. اما با GraphQL ما تنها یک endpoint  داریم؛ همین! 
  • با استفاده از GraphQL، ما هرگز به مشکل گرفتن داده‌هایی کم یا زیاد از منبع روبرو نخواهیم شد. به این خاطر است که ما query‌ها را با فیلد‌هایی که چیز‌هایی را که نیاز داریم، نشان می‌دهند، تعریف می‌کنیم. در این صورت ما همیشه چیز‌هایی را که درخواست داده‌ایم، دریافت می‌کنیم.

بنابراین اگر یک query شبیه زیر را ارسال کنیم :
query OwnersQuery {
  owners {
    name
    account {
      type
    }
  } 
}
صد درصد مطمئن هستیم که خروجی زیر برگشت داده می‌شود:
{
  "data": {
    "owners": [
     {
      "name": "John Doe",
      "accounts": [
        {
          "type": "Cash"
        },
        {
          "type": "Savings"
        }
      ]
     }
    ]
  }
}

همراه با REST  این شرایط برقرار نمی‌باشد. بعضی از مواقع ما چیزی بیشتر یا کمتر از آنچه که نیاز داریم دریافت می‌کنیم؛ که این بستگی به اینکه چگونه action‌ها در یک endpoint مشخص، پیاده سازی شده‌اند، دارد.  

شروع کار 
یک پروژه جدید را با استفاده از دستور زیر ایجاد می‌کنیم: 
dotnet new api -n ASPCoreGraphQL
سپس ساختار زیر را ایجاد می‌کنیم :


پوشه Contracts شامل واسط‌های مورد نیاز برای repository logic می‌باشد:

namespace ASPCoreGraphQL.Contracts
{
    public interface IOwnerRepository
    {
    }
}
namespace ASPCoreGraphQL.Contracts
{
    public interface IAccountRepository
    {
    }
}


در پوشه Models، کلاس‌های مدل را نگه داری می‌کنیم؛ به همراه یک کلاس context و کلاس‌های configuration:
public class Owner
{
    [Key]
    public Guid Id { get; set; }
    [Required(ErrorMessage = "Name is required")]
    public string Name { get; set; }
    public string Address { get; set; }
 
    public ICollection<Account> Accounts { get; set; }
}

public class Account
{
    [Key]
    public Guid Id { get; set; }
    [Required(ErrorMessage = "Type is required")]
    public TypeOfAccount Type { get; set; }
    public string Description { get; set; }
 
    [ForeignKey("OwnerId")]
    public Guid OwnerId { get; set; }
    public Owner Owner { get; set; }
}

public enum TypeOfAccount
{
    Cash,
    Savings,
    Expense,
    Income
}
    public class ApplicationContext : DbContext
    {
        public ApplicationContext(DbContextOptions options)
            : base(options)
        {
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {

        }

        public DbSet<Owner> Owners { get; set; }
        public DbSet<Account> Accounts { get; set; }
    }

در پوشه Repository، کلاس‌های مرتبط با منطق بازیابی داده‌ها را داریم:
public class OwnerRepository : IOwnerRepository
{
    private readonly ApplicationContext _context;
 
    public OwnerRepository(ApplicationContext context)
    {
        _context = context;
    }
}
public class AccountRepository : IAccountRepository
{
    private readonly ApplicationContext _context;
 
    public AccountRepository(ApplicationContext context)
    {
        _context = context;
    }
}
repository logic، یک راه اندازی ابتدایی بدون هیچ لایه اضافه‌تری است.

کلاس context و کلاس‌های repository، در فایل Startup.cs ثبت می‌شوند:
public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationContext>(opt =>
         opt.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); 
 
    services.AddScoped<IOwnerRepository, OwnerRepository>();
    services.AddScoped<IAccountRepository, AccountRepository>();
 
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
        .AddJsonOptions(options => options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore);
}


Integration of GraphQL in ASP.NET Core 
برای کار کردن با GraphQL در ابتدا نیاز است که کتابخانه GraphQL را نصب کنیم. به همین منظور در ترمینال مربوط به VS Code، دستور زیر را وارد می‌کنیم: 
dotnet add package GraphQL
و همچنین کتابخانه‌ی زیر که به ما کمک می‌کند تا GraphQL.NET را به عنوان یک وابستگی دریافت کنیم:
dotnet add package GraphQL.Server.Transports.AspNetCore
و در نهایت نصب کتابخانه زیر که کمک می‌کند query‌های GraphQL را به سرور ارسال کنیم:
dotnet add package GraphQL.Server.Ui.Playground

(Creating GraphQL Specific Objects (Type, Query, Schema

کار را با ایجاد کردن یک پوشه جدید به نام GraphQL و سپس در آن ایجاد یک پوشه دیگر به نام GraphQLSchema، شروع می‌کنیم. در پوشه GraphQLSchema، یک کلاس را به نام AppSchema، ایجاد می‌کنیم.
کلاس AppSchema باید از کلاس Schema ارث بری کند تا در فضای نام GraphQL.Types قرار گیرد. در سازنده این کلاس، IDependencyResolver را تزریق می‌کنیم که قرار است به ما کمک کند تا اشیاء Query ،Mutation یا Subscription را resolve کنیم:
public class AppSchema : Schema
{
    public AppSchema(IDependencyResolver resolver)
        :base(resolver)
    {
 
    }
}
چیزی که مهم است بدانیم این است که خصوصیات schema، مثل Query ،Mutation و Subscription، واسط IObjectGraphType را پیاده سازی می‌کنند تا اشیائی را که قرار است resolve کنیم، همین type را پیاده سازی کرده باشند. در ضمن GraphQL API نمی‌تواند مدل را به عنوان نتیجه به صورت مستقیم بازگشت دهد.
فعلا این کلاس را در همین حالت می‌گذاریم و سپس یک پوشه را به نام GraphQLTypes در پوشه GraphQL ایجاد می‌کنیم. در پوشه GraphQLTypes یک کلاس را به نام OwnerType ایجاد می‌کنیم:
public class OwnerType : ObjectGraphType<Owner>
{
    public OwnerType()
    {
        Field(x => x.Id, type: typeof(IdGraphType)).Description("Id property from the owner object.");
        Field(x => x.Name).Description("Name property from the owner object.");
        Field(x => x.Address).Description("Address property from the owner object.");
    }
}
از کلاس OwnerType به عنوان یک جایگزین برای مدل Owner درون یک GraphQL API استفاده می‌کنیم. این کلاس از نوع جنریک ObjectGraphType ارث بری می‌کند. با متد Field، فیلد‌هایی را که بیانگر خصوصیات مدل Owner می‌باشند، مشخص می‌کنیم.
در ابتدا واسط IOwnerRepository و کلاس  OwnerRepository را به حالت زیر ویرایش می‌کنیم:
public interface IOwnerRepository
{
    IEnumerable<Owner> GetAll();
}


public class OwnerRepository : IOwnerRepository
{
    private readonly ApplicationContext _context;
 
    public OwnerRepository(ApplicationContext context)
    {
        _context = context;
    }
 
    public IEnumerable<Owner> GetAll() => _context.Owners.ToList();
}

در ادامه یک پوشه دیگر را به نام GraphQLQueries در پوشه‌ی GraphQL ایجاد و سپس در آن یک کلاس را به نام AppQuery ایجاد و آن را به حالت زیر ویرایش می‌کنیم:
public class AppQuery : ObjectGraphType
{
    public AppQuery(IOwnerRepository repository)
    {
        Field<ListGraphType<OwnerType>>(
           "owners",
           resolve: context => repository.GetAll()
       );
    }
}

توضیحات AppQuery
همانطور که می‌بینیم این کلاس از ObjectGraphType ارث بری می‌کند. در سازنده کلاس، IOwnerRepository را تزریق می‌کنیم و یک فیلد را به منظور برگشت دادن نتیجه برای یک Query مشخص، ایجاد می‌کنیم. در این کلاس، از نوع جنریک متد Field، استفاده کرده‌ایم که تعدادی type را به عنوان یک پارامتر جنریک پذیرش می‌کند که این بیانگر GraphQL.NET برای type ‌های معمول در NET. می‌باشد. علاوه بر ListGraphType،  نوع‌هایی مثل IntGraphType  و StringGraphType و ... وجود دارند (لیست کامل).
پارامتر owners نام فیلد می‌باشد (query مربوط به کلاینت باید با این نام مطابقت داشته باشد) و پارامتر دوم نتیجه می‌باشد.
بعد از انجام این مقدمات، اکنون کلاس AppSchema  را باز می‌کنیم و به حالت زیر آن را ویرایش می‌کنیم:
public class AppSchema : Schema
{
    public AppSchema(IDependencyResolver resolver)
        :base(resolver)
    {
        Query = resolver.Resolve<AppQuery>();
    }
}

Libraries and Schema Registration 
 در کلاس Startup نیاز است کتابخانه‌های نصب شده و هم چنین  کلاس schema ایجاد شده را ثبت کنیم. این کار را با ویرایش کردن متد ConfigureServices  و Configure  انجام میدهیم:
public void ConfigureServices(IServiceCollection services)
{
    ...
 
    services.AddScoped<IDependencyResolver>(s => new FuncDependencyResolver(s.GetRequiredService));
    services.AddScoped<AppSchema>();
 
    services.AddGraphQL(o => { o.ExposeExceptions = false; })
        .AddGraphTypes(ServiceLifetime.Scoped);

   ...
}
در متد ConfigureServices، در ابتدا DependencyResolver و سپس کلاس schema را ثبت می‌کنیم. علاوه بر آن، GraphQL را با متد AddGraphQL ثبت می‌کنیم. سپس همه تایپ‌های GraphQL را با متد AddGraphTypes ثبت می‌کنیم. بدون این متد (AddGraphTypes)، ما مجبور بودیم که همه type ‌ها و query ‌ها را به صورت دستی در APIامان ثبت کنیم.
در نهایت در متد schema  Configure را به خط لوله درخواست‌ها (request’s pipeline) اضافه می‌کنیم و هم چنین ابزار Playground UI:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
   ...
    app.UseGraphQL<AppSchema>();
    app.UseGraphQLPlayground(options: new GraphQLPlaygroundOptions());
    app.UseMvc();
}

برای آزمایش GraphQL API امان، از ابزار GraphQL.UI.Playground استفاده می‌کنیم. در ابتدا پروژه را با دستور زیر اجرا می‌کنیم:
dotnet run
و سپس در مرورگر به این آدرس می‌رویم: 
https://localhost:5001/ui/playground
اکنون یک query را با نام owners ارسال می‌کنیم (این نام باید با نام query که در AppQuery در نظر گرفتیم، مطابقت داشته باشد). سپس نتیجه لازم را دریافت می‌کنیم. همانطور که مشاهده می‌کنیم، همه چیز بر اساس انتظاری که می‌رفت کار می‌کند. 



در قسمت بعد درابطه با  کوئری‌های پیشرفته، Error Handling و Data Loader در GraphQL  صحبت خواهیم کرد. 

کد‌های مربوط به این قسمت را از اینجا دریافت کنید .ASPCoreGraphQL.zip
مطالب
آموزش Xamarin Forms - قسمت اول - نصب و راه اندازی اولین پروژه زمارین

در  مقاله قبلی ، درباره دلایل استفاده از Xamarin ، کمی صحبت کردیم. حال وقت آن رسیده که به سراغ نصب و راه اندازی اولین پروژه زمارین برویم.

اگر شما از Visual Studio 2015  به بعد استفاده کنید، موقع نصب قادر خواهید بود که با انتخاب گزینه Mobile Development و انتخاب Xamarin ، آن را نصب و همچنین تمامی فایل‌های مربوط به آن را دریافت کنید. در نظر داشته باشید که در طول این پروسه شما باید از ف.یل.تر شکن استفاده کنید، چرا که بعضی از فایل‌ها مانند Android Sdk بر روی سرور گوگل قرار دارد و گوگل آپی‌های ایران را برای برنامه نویسان فیلتر کرده است (البته اگر بسته‌ی کامل VS 2017 را دریافت کرده باشید، تمام این پیش نیازها، به همراه این بسته‌ی 21~ گیگابایتی موجود است و این مشکلات را نخواهید داشت). 

حال اگر در حال حاضر Visual Studio را بر روی سیستم خود نصب دارید و زمارین را نصب نکرده اید میتوانید از طریق خود سایت زمارین اقدام به دانلود آن بکنید. در نظر داشته باشید، وقتیکه فایل نصبی را از سایت دریافت میکنید، برنامه شروع به نصب خودکار زمارین و تمامی موارد مورد نیاز خود میکند که در این مورد هم به ف.یل.تر شکن نیاز دارید (منهای بسته‌ی کامل VS 2017 که پیشتر عنوان شد). همانطور که بالا گفته شد فایل هایی مانند Android Sdk را نمیتوان از آی پی ایران دانلود کرد (مگر اینکه از سایت‌های واسط استفاده کنید).

پس از موافقت با حقوق کپی رایت زمارین، سیستم شما را جستجو کرده و تمامی موارد مورد نیاز را که نیاز به نصب دارند، به شما نشان داده و نصب خواهد کرد.



اگر همه مراحل با موفقیت به پایان برسد، پیغامی مبنی بر موفقیت آمیز بودن عملیات را دریافت خواهید کرد. اما اگر به هر دلیلی فایل نصبی نتواند فایل‌های مورد نیاز را دانلود کند، پیغامی مبنی بر شکست عملیات دانلود فایل مورد نظر را دریافت می‌کنید. در این صورت میتوانید صفحه‌ای را مشاهده کنید که درون آن تمامی فایل‌های دانلود نشده و لینک دانلود مستقیم آنها قرار دارند و شما میتوانید فایل‌های offline آنها را دانلود کرده و به صورت دستی بر روی سیستم نصب نمایید. 


اگر تمامی فایل‌های مورد نظر را دانلود کرده باشید، قادر خواهید بود اولین پروژه‌ی خود را شروع کنید. قبل از اینکه کار با زمارین را شروع کنیم، اجازه دهید از اینکه ویژوال استودیو تمامی فایل‌های نصب شده را تشخیص داده یا خیر، مطمئن شویم. ویژوال استودیوی خود را باز کرده و از منوی Tools، گزینه‌ی Options را انتخاب و بعد از باز شدن صفحه مورد نظر، در انتهای لیست، گزینه Xamarin را انتخاب کنید.

 


اگر تمامی مراحل با موفقیت انجام شده باشند، ویژوال استودیو تمامی فایل‌ها را به صورت خودکار تشخیص خواهد داد. اما اگر ویژوال استودیو به هر دلیلی هر کدام از این‌ها را تشخیص نداد، ابتدا از نصب بودن آنها اطمینان حاصل نمایید و سپس به صورت دستی مسیر آنها را مشخص کنید.

نکته : در نظر داشته باشید فایل‌های زیر برای اجرای برنامه بر روی اندروید میباشند و اگر شما تمایلی به اجرای نرم افزار خود را بر روی اندروید ندارید، میتوانید از آنها صرف نظر کنید.


در این مرحله میخواهیم اولین برنامه زمارین خود را شروع کنیم. همانطور که در مقاله قبلی  توضیح داده شد، شما میتوانید از xamarin forms و یا xamarin native استفاده کنید. Xamarin forms ساختاری برای code sharing میباشد که توسط شرکت زمارین توسعه داده شده‌است. به این ترتیب شما قادر خواهید بود که با استفاده از Xamarin Forms با نوشتن کمترین کد، نرم افزار خود را بر روی پلتفرم‌های پشتیبانی شده‌ی توسط زمارین اجرا کنید. استفاده از Xamarin Forms برای یک پروژه‌ی تجاری بسیار مناسب میباشد؛ اما در برخی موارد شما باید از Xamarin Native هم استفاده نمایید که در این صورت هم زمارین دست شما را نخواهد بست و قادر خواهید بود که به صورت ترکیبی از Xamarin Forms و Xamarin Native از آن استفاده نمایید.


حال به سراغ ساخت اولین پروژه زمارین برویم. در ابتدا برای ایجاد یک پروژه، از منوی File گزینه New و سپس گزینه Project را انتخاب کنید. در پنجره باز شده از سمت چپ گزینه C# را انتخاب و از زیر منوی Cross Platform گزینه Cross Platform App را انتخاب کنید.


پس از تایید با صفحه زیر مواجه خواهید شد.



در این قسمت همانطورکه مشاهده میکنید میتوانید از دو نوع  قالب استفاده کنید و همانطور که از نام آنها مشخص است، Master Detail دو پروژه خواهد ساخت که میتوانید از آن برای سناریو‌های خاص استفاده کنید. در قسمت پایین، UI Technology مشخص کننده‌ی شیوه پیاده سازی ظاهر برنامه است. زمارین فرم برای پیاده سازی ظاهر برنامه از Xaml استفاده میکند و شما میتوانید از طریق آن ظاهر تمامی پلت فرم‌ها را پیاده کنید. همچنین قادر خواهید بود بجای استفاده از Xaml، از زبان‌های مخصوص هر پلتفرم مانند Xml برای اندروید استفاده کرده و ظاهر نرم افزار خود را با استفاده از آن پیاده کنید.


زمارین فرم برای Code Sharing از دو روش استفاده میکند.

Shared Project

مزایا:

· شما به تمامی قسمت‌های یک پلتفرم دسترسی دارید.

· قادر خواهید بود کدهایی مخصوص به هر پلتفرم را بنویسید.

· میتوانید با استفاده از Conditional Compilation، بر اساس نوع پلتفرم، شروطی را اعمال نمایید.

معایب:

· شما با این روش نمیتوانید DLL ایی را تولید کنید و از آن در پروژه‌های دیگر استفاده نمایید.

· نوشتن Unit Testing نسبت به روش Portable پیچیده‌تر است.


Portable Class Library

مزایا:

· شما قادر خواهید بود از پروژه خود DLL تهیه کرده و در مابقی پروژه‌ها از آن استفاده کنید.

· نوشتن Unit Test به سادگی امکان پذیر است.

معایب:

· در این روش شما نمیتوانید از کد‌های مخصوص به هر پلتفرم ( Platform-Specific ) استفاده کنید (البته با استفاده از Dependency Injection امکان پذیر است). 

· فقط قادر خواهید بود که از زیر مجموعه .Net استفاده نمایید.


در ادامه پس از انتخاب Xamarin Forms و Shared Project، بر روی Ok کلیک کنید. همانطور که میبینید ویژوال استودیو شروع به ساخت پروژه‌های برنامه میکند. اگر تمامی Sdk ‌های مورد نیاز را نصب کرده باشید، ویژوال استدیو 5 پروژه را برای شما میسازد (در نظر داشته باشید که اگر SDK مربوط به Universal Windows Platform را هم نصب کرده باشید، پروژه‌ی مربوط به آن را نیز خواهید دید).



اولین پروژه، پروژه Shared است که کد‌های برنامه در این پروژه نوشته خواهد شد.

دومین پروژه همانطور که از پسوند آن مشخص است، پروژه مربوط به اندروید است. در نظر داشته باشید که پروژه‌هایی که مربوط به پلتفرم‌ها میباشند، برای نوشتن کدهای مخصوص به هر پلتفرم در دسترس میباشند و کدهای نوشته شده در این پروژه‌ها و پروژه Shared ترکیب شده و بعد کامپایل میشوند.

در زمارین برنامه‌ها از فایلی به نام App اجرا میشوند. این فایل علاوه بر دسترسی به Life Cycle اپلیکیشن، وظیفه‌ی دیگر آن مشخص کردن اولین صفحه‌ی برنامه نیز میباشد. این فایل درون پروژه Shared  قرار دارد.



همانطور که مشاهده میکنید پس از باز کردن فایل App، در متد سازنده آن صفحه اصلی، به صفحه‌ای به نام MainPage که یک فایل Xaml میباشد، تنظیم شده‌است. پس از باز کردن فایل MainPage با کدهای زیر مواجه میشویم. 

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:PreviewerTest"
             x:Class="PreviewerTest.MainPage">

<Label Text="Welcome to Xamarin Forms!" 
           VerticalOptions="Center" 
           HorizontalOptions="Center" />
</ContentPage>


که مشخص کننده یک لیبل با متن Welcome to Xamarin Forms! میباشد. پس از اجرای برنامه میتوانیم کد اجرا شده را مشاهده کنیم. 

اشتراک‌ها
قسمت 4 از آموزش سی شارپ

در این ویدیو در مورد ساختار دات نت، معماری runtime، CLR و هر چیزی که مربوط به فضای دات نت است صحبت کردیم.

 
قسمت 4 از آموزش سی شارپ
اشتراک‌ها
مجله InfoQ درباره .NET Core

در این مجله، تجربه و دیدگاه هفت نویسنده پیرامون دات نت فریم ورک و مهاجرت پیش رو به دات نت کور گردآوری شده است.

مجله InfoQ درباره .NET Core
نظرات مطالب
استفاده از GitHub Actions برای Build و توزیع خودکار پروژه‌های NET Core.
یک نکته تکمیلی:
برای Build پروژه‌های NET Framework Full. (مانند پروژه‌های ASP.NET MVC قدیم) باید به شکل زیر عمل کنید.
jobs:
  build:

    runs-on: windows-latest
    
    steps:
    - name: Checkout
      uses: actions/checkout@v2
        
    - name: Setup MSBuild
      uses: microsoft/setup-msbuild@v1.0.0  
       
    - name: Setup NuGet
      uses: nuget/setup-nuget@v1.0.2
     
    - name: Restore NuGet Packages
      run: nuget restore src/WebApplication1.sln
 
    - name: Build (Release)
      run: msbuild src/WebApplication1.sln /p:Configuration=Release
  • دستور runs-on: windows-latest این workflow را بر روی ویندوز اجرا میکنه (بدیهیه که پروژه‌های دات نت Full بر روی غیر از ویندوز قابل build شدن نیست)
  • در step دوم MSBuild رو توسط اکشن microsoft/setup-msbuild نصب میکنیم.
  • در step سوم Nuget رو توسطاکشن nuget/setup-nuget نصب میکنیم.
  • در step چهارم وابستگی (پکیج)‌های پروژه رو restore میکنیم. 
  • در step چهارم پروژه رو توسط msbuild و در مود Release بیلد میکنیم.
  • عبارت src/WebApplication1.sln به پوشه و نام فایل سلوشن شما اشاره میکنه.

و برای Test پروژه‌های خود میتونین از اکشن  Malcolmnixon/Setup-VSTest به نحو زیر استفاده کنین
    - name: Setup VSTest
      uses: Malcolmnixon/Setup-VSTest@v2

    - name: VSTest
      run: vstest.console ClassLibrary.Test\bin\Debug\ClassLibrary.Test.dll
عبارت ClassLibrary.Test\bin\Debug\ClassLibrary.Test.dll   به مسیر و نام dll تست شما اشاره میکنه.
نظرات اشتراک‌ها
سری 11 قسمتی معماری تمیز با Angular 10 و Web API
این پروژه از آخرین نسخه LTS دات نت یعنی .net core 3.1 استفاده می‌کنه
ولی یک پروژه خوب راجع به همین موضوع هست که انگیولار ۱۰ به همراه دات نت نسخه ۵ و معماری تمیز (Clean Architecture) استفاده می‌کنه و به صورت بسته نیوگت هم عرضه می‌شه که آدرس گیت هاب:
هست.