معرفی ASP.NET Core 8، Web API و Minimal APIs

معرفی ASP.NET Core 8، Web API و Minimal APIs

معرفی ASP.NET Core 8، Web API و Minimal APIs

منبع: Coding Clean, Reliable, and Safe REST APIs with ASP.NET Core 8 — Anthony Giretti

اعتبار ترجمه: ترجمه با کمک هوش مصنوعی

فصل ۲: معرفی ASP.NET Core 8

Microsoft نخستین Framework کامل خود برای توسعهٔ برنامه‌های وب را در سال ۲۰۰۲ با ASP.NET Web Forms منتشر کرد. سال‌های بعد با فناوری‌هایی مانند ASP.NET Model-View-Controller (MVC)، ASP.NET Web API و SignalR همراه بود. Framework با سرعت زیادی قابلیت‌های جدید دریافت کرد، درحالی‌که هستهٔ آن—به‌ویژه Assembly معروف System.Web—تغییر بنیادینی نکرد. خیلی زود نیازهای تازه‌ای مطرح شدند: Performance (کارایی) بهتر، امکان اجرای ASP.NET روی سرورهایی غیر از IIS که وب‌سرور Windows-only شرکت Microsoft است، سازگاری بیشتر با Cloud برای Deployment ساده‌تر و Configuration بسیار انعطاف‌پذیرتر. نتیجه، تولد ASP.NET Core بود.

ASP.NET Core بازطراحی کامل ASP.NET است و امکان ساخت انواع برنامه‌ها را فراهم می‌کند:

  • برنامه‌های وب مانند MVC، Razor Pages یا Single-Page Applicationها با Blazor.
  • APIها، شامل REST API، Remote Procedure Call و ارتباط Real-Time.
  • Background Taskهایی که به‌صورت Windows Service، Unix Daemon یا درون برنامهٔ ASP.NET Core اجرا می‌شوند.

doi.org/10.1007/978-1-4842-9979-1_2

در زمان نگارش کتاب، ASP.NET Core 8 که همراه .NET 8 ارائه شده جدیدترین نسخه است و در سراسر کتاب از آن استفاده می‌کنیم. ASP.NET Core 8 دیگر ASP.NET Web Forms و Windows Communication Foundation (WCF)، یعنی Framework سرویس وب مبتنی بر SOAP، را پشتیبانی نمی‌کند؛ بااین‌حال پروژه‌ای به نام CoreWCF در اوایل ۲۰۲۲ منتشر شد.

در این فصل Fundamentals (مبانی) ASP.NET Core و دو نوع برنامه‌ای را که برای ساخت REST API استفاده می‌کنیم بررسی خواهیم کرد:

  • ASP.NET Core Web API
  • ASP.NET Core Minimal APIs

مبانی ASP.NET Core

پیش از ورود به جزئیات، ابتدا Fundamentals را بررسی می‌کنیم. وقتی مبانی ASP.NET Core را بدانیم، می‌توانیم همین دانش را برای ساخت انواع برنامه‌های وب، حتی gRPC، به کار ببریم.

نقطهٔ ورود یک برنامهٔ ASP.NET Core فایل Program.cs است. در این فایل، برنامه با ساخت یک WebApplicationBuilder توسط متد Static یعنی WebApplication.CreateBuilder آغاز می‌شود. WebApplicationBuilder اجازه می‌دهد Componentهای موردنظر را به Configuration اضافه کنیم و سپس آن‌ها را فعال کنیم.

Listing 2-1. نمونهٔ فایل Program.cs

var builder = WebApplication.CreateBuilder(args);
    var app = builder.Build();

    app.MapGet("/", () => "Hello World!");

    app.Run();
تصویر منبع — صفحهٔ 57Visual واقعی استخراج‌شده از PDF، مربوط به صفحهٔ 57.

فایل Program.cs دو بخش مشخص دارد:

  • Services Configuration: نوع برنامه، Libraryهای Third-Party، Authentication، Authorization و ثبت Serviceها در Dependency Injection را شامل می‌شود.
  • Services Activation: Middleware Pipeline در ASP.NET Core را تعریف می‌کند. Middleware یک Component است که پس از قرار گرفتن در Pipeline با ترتیب مشخص، Request و Response را مدیریت می‌کند و می‌تواند قبل و بعد از Component بعدی عملیات انجام دهد؛ شکل ۲-۱ این زنجیره را نمایش می‌دهد.
شکل ۲-۱. Middleware Pipeline در ASP.NET Core

Services Configuration پیش از ساخت برنامه با متد builder.Build() انجام می‌شود و Services Activation پس از آن، ولی پیش از app.Run() قرار می‌گیرد. Listing 2-2 نمونهٔ Configuration یک برنامهٔ Razor Pages است.

Listing 2-2. نمونهٔ Program.cs پیکربندی‌شده

var builder = WebApplication.CreateBuilder(args);

    // Services configuration
    builder.Services.AddRazorPages();

    var app = builder.Build();

    // Services activation
    if (!app.Environment.IsDevelopment())
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.MapRazorPages();

    app.Run();

ممکن است معماری هنوز کمی مبهم باشد؛ شکل ۲-۲ نمای کلی معماری ASP.NET Core را خلاصه می‌کند.

تصویر منبع — صفحهٔ 59Visual واقعی استخراج‌شده از PDF، مربوط به صفحهٔ 59.
شکل ۲-۲. معماری ASP.NET Core

Dependency Injection و Lifetimeها

Dependency Injection در مرکز ASP.NET Core قرار دارد. این تکنیک باعث Loose Coupling میان Objectها، Service Classها و Dependencyهای آن‌ها می‌شود. به‌جای آن‌که Serviceها مستقیماً در Methodها یا Constructorها ساخته شوند، Class اعلام می‌کند به چه Dependencyهایی نیاز دارد. در این کتاب Serviceها معمولاً با Interface پیاده‌سازی‌شدهٔ خود ثبت می‌شوند و Interface در Constructor کلاس مصرف‌کننده Inject خواهد شد. این Decoupling، Code را Abstract‌تر و Testability را بهتر می‌کند.

Lifetime سرویس‌های Inject‌شده بسیار مهم است. بعضی Serviceها باید در هر Request یک Instance تازه داشته باشند، بعضی فقط یک بار در Scope همان Request ساخته شوند و بعضی در کل عمر Application یک Instance مشترک داشته باشند. ASP.NET Core سه Lifetime ارائه می‌کند:

  • Transient: Instance جدید Service برای هر بار Resolution ساخته می‌شود؛ در یک HTTP Request هم ممکن است برای هر مصرف، Instance جدیدی از همان Service ایجاد شود.
  • Scoped: Service در هر HTTP Request فقط یک بار ساخته می‌شود. این Lifetime بسیار رایج است و یک Instance یکتا در Scope همان Request فراهم می‌کند.
  • Singleton: Service فقط یک بار در کل عمر Application ساخته می‌شود و همهٔ کاربران همان Instance را به اشتراک می‌گذارند. ساخت Singleton در Container به‌صورت Thread-safe مدیریت می‌شود، اما اگر Propertyهای Mutable مانند Dictionary دارید، باید از Structureهای Thread-safe مانند ConcurrentDictionary استفاده کنید.

Listing 2-3 ثبت این سه Lifetime را نشان می‌دهد. پارامتر سمت چپ Interface و پارامتر سمت راست Concrete Class پیاده‌ساز آن است. اگر Class آن Interface را پیاده‌سازی نکند، Compilation Error رخ می‌دهد.

Listing 2-3. پیکربندی Lifetimeهای مختلف

var builder = WebApplication.CreateBuilder(args);

    services.AddControllers();
    services.AddSingleton<ISingletonService, SingletonService>();
    services.AddScoped<IScopedService, ScopedService>();
    services.AddTransient<ITransientService, TransientService>();

    var app = builder.Build();

    if (!app.Environment.IsDevelopment())
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }
    
    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.MapRazorPages();

    app.Run();

Listing 2-4 نحوهٔ Inject کردن Serviceها در Constructor یک MVC Controller را پس از ثبت Mapping آن‌ها در Program.cs نشان می‌دهد.

Listing 2-4. MVC Controller با Constructor Injection

public class DemoController : Controller
    {
          private readonly ISingletonService _singletonService;
          private readonly IScopedService _scopedService;
          private readonly ITransientService _transientService;

          public DemoController(ISingletonService singletonService,
                                IScopedService scopedService,
                                ITransientService transientService)
          {
                _singletonService = singletonService;
                _scopedService = scopedService;
                _transientService = transientService;
          }
    }
تصویر منبع — صفحهٔ 62Visual واقعی استخراج‌شده از PDF، مربوط به صفحهٔ 62.

بسته به نیاز ممکن است از Singleton، Scoped یا Transient استفاده کنید، اما باید Hierarchy آن‌ها را بشناسید. یک Transient می‌تواند مستقیماً به Scoped یا Singleton وابسته باشد و یک Scoped می‌تواند به Singleton وابسته باشد. جهت عکس مجاز نیست، زیرا Object با Lifetime طولانی‌تر نباید مستقیماً به Object کوتاه‌عمرتر وابسته شود. شکل ۲-۳ این Hierarchy را خلاصه می‌کند.

شکل ۲-۳. Hierarchy مربوط به Scope و Lifetime

Configuration و Options Pattern

ASP.NET Core امکان افزودن Configuration اضافی را فراهم می‌کند تا از طریق Dependency Injection در هر بخش برنامه مصرف شود. تنظیمات را می‌توان در فایل appsettings.json ذخیره و برای Environmentهای مختلف سفارشی کرد. برای مثال appsettings.development.json می‌تواند Configuration مخصوص Development را داشته باشد. اگر یک Key در هر دو فایل باشد، فایل اختصاصی‌تر مقدار فایل اصلی را Override می‌کند.

می‌توان Objectای از نوع Options ساخت و Configuration را داخل آن Bind کرد؛ این روش Options Pattern نام دارد. Listingهای 2-5 تا 2-8 نمونهٔ Configuration مربوط به SMTP، Mapping آن به SmtpConfiguration، ثبت در Dependency Injection و Inject کردن IOptions<TOptions> در Controller را نشان می‌دهند.

Listing 2-5. SMTP configuration در appsettings.json

{
      "SmtpConfiguration": {
        "Domain": "smtp.gmail.com",
        "Port": 465
      }
    }

Listing 2-6. شیء SmtpConfiguration

public record class SmtpConfiguration
    {
          public string Domain { get; init; }
          public int Port { get; init; }
    }

Listing 2-7. Bind و Register کردن SmtpConfiguration در Dependency Injection

var builder = WebApplication.CreateBuilder(args);    services.
    Configure<SmtpConfiguration>(Configuration.GetSection("SmtpConf
    iguration"));
    ....

Listing 2-8. Inject کردن Options در DemoController

public class DemoController : Controller
    {
          private readonly SmtpConfiguration _smtpConfiguration;

          public DemoController(IOptions<SmtpConfiguration>
           smtpConfigurationOptions)
    
          {
                _smtpConfiguration = smtpConfigurationOptions.Value;
          }
    }

این ساده‌ترین روش استفاده از Options در ASP.NET Core است. بسته به نیاز می‌توان از IOptionsSnapshot<TOptions> و IOptionsMonitor<TOptions> نیز استفاده کرد.

Development Environment

موضوع مهم دیگر امکان فعال‌کردن Development Mode از طریق Configuration است. Development Mode اجازه می‌دهد رفتار برنامه در محیط توسعه با Production فرق کند؛ برای مثال Connection String در Production رمزنگاری شود ولی در Development چنین نباشد. همچنین اطلاعات بسیار جزئی‌تری دربارهٔ Unhandled Error نمایش داده می‌شود. به همین دلیل Development Mode نباید در Production فعال باشد.

برای فعال‌کردن آن، Environment Variable با نام ASPNETCORE_ENVIRONMENT در launchSettings.json یا Project Properties روی Development قرار می‌گیرد. Listing 2-9 نمونه‌ای از تنظیم Development Mode برای IIS و Self-hosting است.

Listing 2-9. Development Mode در launchSettings.json

{
      "iisSettings": {
        "windowsAuthentication": false,
        "anonymousAuthentication": true,
        "iisExpress": {
    
          "applicationUrl": "http://localhost:57090",
          "sslPort": 44366
        }
      },
      "profiles": {
        "IIS Express": {
          "commandName": "IISExpress",
          "launchBrowser": true,
          "environmentVariables": {
            "ASPNETCORE_ENVIRONMENT": "Development"
          }
        },
        "MVCDemo": {
          "commandName": "Project",
          "dotnetRunMessages": "true",
          "launchBrowser": true,
          "applicationUrl": "https://localhost:5001;http://localhost:5000",
          "environmentVariables": {
            "ASPNETCORE_ENVIRONMENT": "Development"
          }
        }
      }
    }

ASP.NET Core Web API

ASP.NET Core Web API همان‌طور که از نامش پیداست برای ساخت Web API به‌کار می‌رود. Web API یک Application Programming Interface است که همراه HTTP استفاده می‌شود. امروزه Web APIها معمولاً از REST و قالب تبادل JSON استفاده می‌کنند؛ XML نیز قابل استفاده است اما کمتر رایج است.

تصویر منبع — صفحهٔ 66Visual واقعی استخراج‌شده از PDF، مربوط به صفحهٔ 66.

APIها از قابلیت‌های HTTP مانند URI بهره می‌برند. با توجه به تنوع زیاد دستگاه‌ها و Terminalهایی که کاربران نهایی استفاده می‌کنند، نیاز داریم داده را سریع و امن به مرورگرها یا Applicationهای جدید ارائه کنیم. ASP.NET Core Web API یک Framework مناسب و Performant برای ساخت سرویس‌هایی است که تعداد زیادی کاربر بتوانند از آن‌ها استفاده کنند.

ASP.NET Core Web API از Pattern معروف Model-View-Controller (MVC) پیروی می‌کند. در برنامهٔ وب سنتی، V یا View همان صفحهٔ وب است؛ در Web API، View عملاً Response در قالب JSON، XML یا قالب دیگر است. شکل ۲-۴ نمای این Architecture را نشان می‌دهد.

شکل ۲-۴. معماری ASP.NET Core Web API
تصویر منبع — صفحهٔ 67Visual واقعی استخراج‌شده از PDF، مربوط به صفحهٔ 67.

ایجاد Web API در Visual Studio 2022

برای ساخت پروژه، در Visual Studio 2022 فیلتر Web را انتخاب کنید تا Project Type با نام ASP.NET Core Web API پیدا شود.

شکل ۲-۵. پیدا کردن Project Type مربوط به ASP.NET Core Web API

پس از انتخاب Template، Project Name، محل ذخیره و Solution Name را مشخص می‌کنید.

تصویر منبع — صفحهٔ 68Visual واقعی استخراج‌شده از PDF، مربوط به صفحهٔ 68.
شکل ۲-۶. ایجاد پروژهٔ جدید ASP.NET Core Web API

در مرحلهٔ بعد گزینه‌های مختلف Application قابل تنظیم‌اند. Runtime را روی جدیدترین گزینه، یعنی .NET 8، قرار دهید؛ ASP.NET Core 8 فقط روی .NET 8 اجرا می‌شود. می‌توان Authentication Type را انتخاب کرد—Windows، Microsoft Identity Platform یا بدون Authentication—و HTTPS، Docker، OpenAPI و استفاده یا عدم استفاده از Controllerها را نیز تنظیم کرد. اگر Controller را غیرفعال کنید، پروژه بر Minimal API استوار خواهد بود.

تصویر منبع — صفحهٔ 69Visual واقعی استخراج‌شده از PDF، مربوط به صفحهٔ 69.
شکل ۲-۷. پیکربندی ASP.NET Core Web API

Docker یک Open Source Containerization Platform است که اجازه می‌دهد Application Source Code به همراه Libraryها و Dependencyهای سیستم‌عامل مورد نیاز برای اجرا، در Container قرار گیرد و در Environmentهای مختلف اجرا شود.

OpenAPI Specification یک Interface استاندارد و مستقل از زبان برای RESTful APIها تعریف می‌کند تا انسان و ماشین بدون خواندن Source Code بتوانند قابلیت‌های سرویس را کشف و درک کنند. Swagger مجموعه ابزارهایی است که روی OpenAPI ساخته شده‌اند.

پس از کلیک روی Create، Visual Studio یک پروژهٔ پیش‌فرض با Model و Controller مربوط به WeatherForecast می‌سازد.

تصویر منبع — صفحهٔ 70Visual واقعی استخراج‌شده از PDF، مربوط به صفحهٔ 70.
تصویر منبع — صفحهٔ 70Visual واقعی استخراج‌شده از PDF، مربوط به صفحهٔ 70.
شکل ۲-۸. Template پیش‌فرض WeatherForecast در ASP.NET Core Web API

شکل ۲-۹ Controller مربوط به WeatherForecastController را نشان می‌دهد.

شکل ۲-۹. کلاس WeatherForecastController
تصویر منبع — صفحهٔ 71Visual واقعی استخراج‌شده از PDF، مربوط به صفحهٔ 71.

در فایل Program.cs، OpenAPI فعال شده است و Swagger UI از همین Configuration استفاده می‌کند.

شکل ۲-۱۰. فایل Program.cs پیکربندی‌شده با OpenAPI (Swagger)

اگر Application را اجرا کنید، Visual Studio مرورگر را با صفحهٔ OpenAPI باز می‌کند و Endpointهای موجود را نمایش می‌دهد. در Template اولیه فقط Endpoint مربوط به GET WeatherForecast وجود دارد. می‌توانید Execute را بزنید و دادهٔ برگشتی را در بخش Response ببینید.

تصویر منبع — صفحهٔ 72Visual واقعی استخراج‌شده از PDF، مربوط به صفحهٔ 72.
شکل ۲-۱۱. صفحهٔ Swagger UI

Swagger UI به‌طور پیش‌فرض باز می‌شود، زیرا هنگام فعال‌کردن OpenAPI، Visual Studio مقدار launchUrl در launchSettings.json را روی swagger تنظیم می‌کند.

تصویر منبع — صفحهٔ 73Visual واقعی استخراج‌شده از PDF، مربوط به صفحهٔ 73.
شکل ۲-۱۲. پارامتر launchUrl با مقدار swagger

HttpRepl

علاوه بر Swagger می‌توان از ابزار Command-line با نام HttpRepl، مخفف HTTP Read-Eval-Print Loop، استفاده کرد. این ابزار سبک و Cross-platform است و با ASP.NET Core API و APIهای دیگر کار می‌کند. HttpRepl درخواست HTTP می‌فرستد و نتیجه را فارغ از محل Hosting نمایش می‌دهد. Verbهای DELETE، GET، HEAD، OPTIONS، PATCH، POST و PUT را پشتیبانی می‌کند.

Listing 2-10. فرمان نصب HttpRepl

dotnet tool install -g Microsoft.dotnet-httprepl

Listing 2-11. فرمان Help

httprepl --help
تصویر منبع — صفحهٔ 74Visual واقعی استخراج‌شده از PDF، مربوط به صفحهٔ 74.
شکل ۲-۱۳. فرمان‌های موجود در HttpRepl

HttpRepl با خواندن فایل swagger.json می‌تواند Endpointها را کشف کند، میان آن‌ها Navigate کند و درخواست اجرا کند. برای اتصال به Base URL محلی از فرمان زیر استفاده می‌شود.

Listing 2-12. اتصال به Base URL محلی API

httprepl https://localhost:5001

نحوهٔ Explore و Navigation آن جالب است، زیرا از فرمان‌هایی شبیه MS-DOS استفاده می‌کند؛ ls برای فهرست Endpointها و cd برای رفتن به Endpoint.

تصویر منبع — صفحهٔ 75Visual واقعی استخراج‌شده از PDF، مربوط به صفحهٔ 75.
شکل ۲-۱۴. Explore، Navigation و اجرای Endpointهای API با HttpRepl
تصویر منبع — صفحهٔ 76Visual واقعی استخراج‌شده از PDF، مربوط به صفحهٔ 76.

Postman

اگر نخواهید از Swagger UI یا HttpRepl استفاده کنید، Postman گزینهٔ دیگری است. Postman یک GUI برای ساخت Requestهای HTTP و آزمودن Endpointهای API است. در آن می‌توان URL، Header، Verb، Query String، Body و سایر پارامترهای Request را تنظیم کرد.

شکل ۲-۱۵. رابط گرافیکی Postman

از میان این سه ابزار، Postman محبوب‌ترین است. بااین‌حال HttpRepl برای علاقه‌مندان ابزارهای Command-line، به‌ویژه کاربران Linux، تجربهٔ جالبی ارائه می‌کند.

تصویر منبع — صفحهٔ 77Visual واقعی استخراج‌شده از PDF، مربوط به صفحهٔ 77.

ASP.NET Core Minimal APIs

ASP.NET Core 8 قابلیت‌های Minimal API را گسترش داده و فاصلهٔ آن‌ها را با Web APIهای مبتنی بر Controller کمتر کرده است. در ادامهٔ کتاب بارها از Minimal API استفاده خواهیم کرد.

دلیل علاقهٔ من به آن‌ها این است که گاهی فقط یک API بسیار کوچک با یک یا دو Endpoint لازم دارم و Data Manipulation ساده است. در این حالت نیازی به Controller نیست و یک فایل Program.cs کافی است. همان‌طور که می‌دانید این فایل می‌تواند Application را با Configuration حداقلی راه‌اندازی کند.

با وجود حداقل بودن Syntax، کل Pipeline اصلی ASP.NET Core همچنان پابرجا است: Dependency Injection و Middlewareها همچنان Request و Responseهای HTTP را مدیریت می‌کنند.

برای شروع می‌توان Project Type با نام ASP.NET Core Empty ایجاد کرد.

شکل ۲-۱۶. ایجاد پروژهٔ ASP.NET Core Empty
تصویر منبع — صفحهٔ 78Visual واقعی استخراج‌شده از PDF، مربوط به صفحهٔ 78.

پس از نام‌گذاری Project، Visual Studio 2022 یک پروژهٔ Minimal با Endpoint پیش‌فرض Hello World! می‌سازد.

شکل ۲-۱۷. پروژهٔ Minimal در ASP.NET Core

شکل ۲-۱۸ Minimal APIای را نشان می‌دهد که Swagger Documentation را برای Endpoint مربوط به Hello ارائه می‌کند. IHelloService در بالای فایل به‌صورت Scoped در Dependency Injection ثبت شده است. C# همچنین اجازه می‌دهد Lambda Expressionها با Attributeهایی مانند FromRoute Decorate شوند تا Route Attribute با نام name به Parameter رشته‌ای name Map شود.

تصویر منبع — صفحهٔ 79Visual واقعی استخراج‌شده از PDF، مربوط به صفحهٔ 79.
شکل ۲-۱۸. Minimal API با Dependency Injection، Attribute روی Lambda و مستندات Swagger
تصویر منبع — صفحهٔ 80Visual واقعی استخراج‌شده از PDF، مربوط به صفحهٔ 80.
شکل ۲-۱۹. Swagger UI برای Minimal API نمونه

من این روش توسعهٔ API را دوست دارم و در عمل تقریباً به‌صورت پیش‌فرض آن را به ASP.NET Core Web API مبتنی بر Controller ترجیح می‌دهم.

جمع‌بندی

در این فصل با ASP.NET Core، مبانی آن و برخی Frameworkهایی که پشتیبانی می‌کند آشنا شدید. ASP.NET Core یک Framework پویا است؛ فناوری‌های متنوع وب را پشتیبانی می‌کند و Microsoft برای آن مستندات مناسبی ارائه کرده است. به همین دلیل Framework محبوب من برای توسعهٔ برنامه‌های وب است و امیدوارم شما نیز از کار با آن لذت ببرید.

در ادامهٔ کتاب با ساخت Minimal APIها خواهیم دید ASP.NET Core 8 تا چه اندازه Framework قدرتمندی است.

منبع: Coding Clean, Reliable, and Safe REST APIs with ASP.NET Core 8 — Anthony Giretti.

فروش یا انتشار این ترجمه منوط به داشتن مجوز لازم از صاحب حقوق اثر است.

امتیاز کاربران به این مقاله

☆☆☆☆☆

0 نفر امتیاز داده اند. میانگین: 0.0 از 5

 

0 نظر

نظر محترم شما در مورد مقاله های وب سایت برنامه نویسی و پایگاه داده

نظرات محترم شما در خدمات رسانی بهتر ما را یاری می نمایند. لطفا اگر مایل بودید یک نظر ما را مهمان فرمائید. آدرس ایمیل و وب سایت شما نمایش داده نخواهد شد.

0 / 500

اطلاعات تماس

  • آدرس:اصفهان-خیابان ام کلثوم غربی - بعد خیابان تخم چی - بیست متر بعد از پیتزا ننه شب - کوچه تعمیر گاه سمار زغالی - پلاک 354 - درب مشکی - طبقه هفتم
  • آدرس ایمیل:najafzade@gmail.com
  • وب سایت:http://www.a00b.com/
  • تلفن ثابت:(+98)9131253620
  • تلفن همراه:09131253620