مطالب
Blazor 5x - قسمت 26 - برنامه‌ی Blazor WASM - ایجاد و تنظیمات اولیه
در قسمت قبل، پایه‌ی Web API و سرویس‌های سمت سرور برنامه‌ی کلاینت Blazor WASM این سری را آماده کردیم. این برنامه‌ی سمت کلاینت، قرار است توسط عموم کاربران آن جهت رزرو کردن اتاق‌های هتل فرضی مثال این سری، مورد استفاده قرار گیرد. پیش از این نیز یک برنامه‌ی Blazor Server را تهیه کردیم که کار آن صرفا محدود است به مسائل مدیریتی هتل؛ مانند تعریف اتاق‌ها و امکانات رفاهی آن.


ایجاد یک پروژه‌ی جدید Blazor WASM

برای تکمیل پیاده سازی قسمت سمت کلاینت پروژه‌ی این سری، نیاز به یک پروژه‌ی جدید Blazor WASM را داریم که می‌توان آن‌را با اجرای دستور dotnet new blazorwasm  در یک پوشه‌ی خالی، ایجاد کرد. کدهای این پروژه را می‌توانید در پوشه‌ی HotelManagement\BlazorWasm\BlazorWasm.Client فایل پیوستی انتهای بحث مشاهده کنید.


افزودن فایل‌های جاوااسکریپتی مورد نیاز

شبیه به کاری که در مطلب «Blazor 5x - قسمت یازدهم - مبانی Blazor - بخش 8 - کار با جاوا اسکریپت» انجام دادیم، در اینجا هم قصد افزودن یکسری کتابخانه‌ی جاوااسکریپتی و CSS ای را داریم که توسط LibMan آن‌ها را مدیریت خواهیم کرد.
- بنابراین در ابتدا به پوشه‌ی BlazorWasm.Client\wwwroot\css وارد شده و پوشه‌های پیش‌فرض bootstrap و open-iconic آن‌را حذف می‌کنیم؛ چون تحت مدیریت هیچ package manager ای نیستند و در این حالت، مدیریت به روز رسانی و یا بازیابی آن‌ها به صورت خودکار میسر نیست.
- سپس فایل wwwroot\css\app.css را هم ویرایش کرده و سطر زیر را از ابتدای آن حذف می‌کنیم:
@import url('open-iconic/font/css/open-iconic-bootstrap.min.css');
- اکنون دستورات زیر را در ریشه‌ی پروژه‌ی WASM، اجرا می‌کنیم تا کتابخانه‌های مدنظر ما، تحت مدیریت libman، در پوشه‌ی wwwroot/lib نصب شوند:
dotnet tool update -g Microsoft.Web.LibraryManager.Cli
libman init
libman install bootstrap --provider unpkg --destination wwwroot/lib/bootstrap
libman install open-iconic --provider unpkg --destination wwwroot/lib/open-iconic
libman install jquery --provider unpkg --destination wwwroot/lib/jquery
libman install toastr --provider unpkg --destination wwwroot/lib/toastr
این دستورات همچنین فایل libman.json متناظری را نیز جهت اجرای دستور libman restore برای دفعات آتی، تولید می‌کند.

- بعد از نصب بسته‌های ذکر شده، فایل wwwroot\index.html را به صورت زیر به روز رسانی می‌کنیم تا به مسیرهای جدید بسته‌های CSS و JS نصب شده، اشاره کند:
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
    />
    <title>BlazorWasm.Client</title>
    <base href="/" />

    <link href="lib/toastr/build/toastr.min.css" rel="stylesheet" />
    <link
      href="lib/open-iconic/font/css/open-iconic-bootstrap.min.css"
      rel="stylesheet"
    />
    <link href="lib/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" />
    <link href="css/app.css" rel="stylesheet" />
    <link href="BlazorWasm.Client.styles.css" rel="stylesheet" />
  </head>

  <body>
    <div id="app">Loading...</div>

    <div id="blazor-error-ui">
      An unhandled error has occurred.
      <a href="" class="reload">Reload</a>
      <a class="dismiss">🗙</a>
    </div>

    <script src="lib/jquery/dist/jquery.min.js"></script>
    <script src="lib/toastr/build/toastr.min.js"></script>
    <script src="js/common.js"></script>
    <script src="_framework/blazor.webassembly.js"></script>
  </body>
</html>
مداخل فایل‌های css را در قسمت head و فایل‌های js را پیش از بسته شدن تگ body تعریف می‌کنیم. در اینجا نیازی به ذکر پوشه‌ی آغازین wwwroot نیست؛ چون base href تعریف شده، به این پوشه اشاره می‌کند.

- محتویات فایل wwwroot\css\app.css را هم به صورت زیر تغییر می‌دهیم تا یک spinner و شیوه نامه‌های نمایش تصاویر، به آن اضافه شوند:
.valid.modified:not([type="checkbox"]) {
  outline: 1px solid #26b050;
}

.invalid {
  outline: 1px solid red;
}

.validation-message {
  color: red;
}

#blazor-error-ui {
  background: lightyellow;
  bottom: 0;
  box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
  display: none;
  left: 0;
  padding: 0.6rem 1.25rem 0.7rem 1.25rem;
  position: fixed;
  width: 100%;
  z-index: 1000;
}

#blazor-error-ui .dismiss {
  cursor: pointer;
  position: absolute;
  right: 0.75rem;
  top: 0.5rem;
}

.spinner {
  border: 16px solid silver !important;
  border-top: 16px solid #337ab7 !important;
  border-radius: 50% !important;
  width: 80px !important;
  height: 80px !important;
  animation: spin 700ms linear infinite !important;
  top: 50% !important;
  left: 50% !important;
  transform: translate(-50%, -50%);
  position: absolute !important;
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }

  100% {
    transform: rotate(360deg);
  }
}

.room-image {
  display: block;
  width: 100%;
  height: 150px;
  background-size: cover !important;
  border: 3px solid green;
  position: relative;
}

.room-image-title {
  position: absolute;
  top: 0;
  right: 0;
  background-color: green;
  color: white;
  padding: 0px 6px;
  display: inline-block;
}
- همچنین فایل جدید wwwroot\js\common.js را که در قسمت 11 این سری ایجاد کردیم، به پروژه‌ی جاری نیز با محتوای زیر اضافه می‌کنیم تا سبب سهولت دسترسی به toastr شود:
window.ShowToastr = (type, message) => {
  if (type === "success") {
    toastr.success(message, "Operation Successful", { timeOut: 10000 });
  }
  if (type === "error") {
    toastr.error(message, "Operation Failed", { timeOut: 10000 });
  }
};

- در قسمت 11، در بخش «کاهش کدهای تکراری فراخوانی متدهای جاوا اسکریپتی با تعریف متدهای الحاقی» آن، کلاس JSRuntimeExtensions را تعریف کردیم که سبب کاهش تکرار کدهای استفاده از تابع ShowToastr می‌شود. این فایل‌را در پروژه‌ی BlazorServer.App\Utils\JSRuntimeExtensions.cs این سری نیز استفاده کردیم. یا می‌توان مجددا آن‌را به پروژه‌ی جاری کپی کرد؛ یا آن‌را در یک پروژه‌ی اشتراکی قرار داد. برای مثال اگر آن‌را به پوشه‌ی BlazorWasm.Client\Utils کپی کردیم، نیاز است فضای نام آن‌را اصلاح کرده و سپس آن‌را به انتهای فایل BlazorWasm.Client\_Imports.razor نیز اضافه کنیم تا در تمام کامپوننت‌های برنامه قابل استفاده شود:
@using BlazorWasm.Client.Utils


تغییر و ساده سازی منوی برنامه‌ی کلاینت

در برنامه‌ی کلاینت جاری دیگر نمی‌خواهیم منوی پیش‌فرض سمت چپ صفحه را شاهد باشیم. به همین جهت ابتدا فایل Shared\MainLayout.razor را به صورت زیر ساده می‌کنیم:
@inherits LayoutComponentBase

<NavMenu />
<div>
  @Body
</div>
سپس محتوای فایل Shared\NavMenu.razor را نیز حذف کرده و با تعاریف زیر جایگزین می‌کنیم:
<nav class="navbar navbar-expand-sm navbar-dark bg-dark p-0">
    <a class="navbar-brand mx-4" href="#">Navbar</a>
    <button class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent"
            aria-expanded="false"
            aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse pr-2" id="navbarSupportedContent">
        <ul class="navbar-nav mr-auto"></ul>
        <ul class="my-0 navbar-nav">
            <li class="nav-item p-0">
                <NavLink class="nav-link" href="registration">
                    <span class="p-2">
                        Register
                    </span>
                </NavLink>
            </li>
            <li class="nav-item p-0">
                <NavLink class="nav-link" href="login">
                    <span class="p-2">
                        Login
                    </span>
                </NavLink>
            </li>
        </ul>
    </div>
</nav>
تا اینجا اگر برنامه‌ی سمت کلاینت را اجرا کنیم، شکل زیر را پیدا کرده که به همراه یک navbar افقی قرار گرفته‌ی در بالای صفحه است؛ به همراه دو لینک به قسمت‌های ثبت‌نام و لاگین:



تغییر محتوای صفحه‌ی آغازین برنامه


صفحه‌ی ابتدایی برنامه، یعنی کامپوننت Pages\Index.razor را نیز به صورت زیر تغییر می‌دهیم:
@page "/"

<form>
    <div class="row p-0 mx-0 mt-4">
        <div class="col-12 col-md-5  offset-md-1 pl-2  pr-2 pr-md-0">
            <div class="form-group">
                <label>Check In Date</label>
                <input type="text" class="form-control" />
            </div>
        </div>
        <div class="col-8 col-md-3 pl-2 pr-2">
            <div class="form-group">
                <label>No. of nights</label>
                <select class="form-control">
                    @for (var i = 1; i <= 10; i++)
                    {
                        <option value="@i">@i</option>
                    }
                </select>
            </div>
        </div>
        <div class="col-4 col-md-2 p-0 pr-2">
            <div class="form-group">
                <label>&nbsp;</label>
                <input type="submit" value="Go" class="btn btn-success btn-block" />
            </div>
        </div>
    </div>
</form>
در اینجا فرمی تعریف شده که تاریخ ورود و رزرو اتاقی را مشخص می‌کند؛ به همراه دراپ‌داونی برای انتخاب تعداد شب‌های اقامت مدنظر.


تعریف View Model رابط کاربری Pages\Index.razor

پس از تعریف محتوای ثابت برنامه، اکنون نوبت به پویا سازی آن است. به همین جهت نیاز است مدلی را برای صفحه‌ی آغازین برنامه تعریف کرد تا بتوان فرم آن‌را به این مدل متصل کرد. این مدل چون مختص به برنامه‌ی کلاینت است، آن‌را در پوشه‌ی جدید Models\ViewModels ایجاد می‌کنیم:
using System;

namespace BlazorWasm.Client.Models.ViewModels
{
    public class HomeVM
    {
        public DateTime StartDate { get; set; } = DateTime.Now;

        public DateTime EndDate { get; set; }

        public int NoOfNights { get; set; } = 1;
    }
}
در اینجا EndDate، یک خاصیت محاسباتی است که بر اساس تاریخ شروع و تعداد شب‌های انتخابی، قابل محاسبه‌است.
پس از این تعریف، بهتر است فضای نام آن‌را نیز به فایل BlazorWasm.Client\_Imports.razor افزود، تا کار با آن در کامپوننت‌های برنامه، ساده‌تر شود:
using BlazorWasm.Client.Models.ViewModels
اکنون می‌توان فرم Pages\Index.razor را به مدل فوق متصل کرد که شامل این تغییرات است:
- ابتدا فیلدی که ارائه کننده‌ی شیء ViewModel فرم است را تعریف می‌کنیم:
@code{
    HomeVM HomeModel = new HomeVM();
}
- سپس بجای یک form ساده، از EditForm اشاره کننده‌ی به این فیلد، استفاده خواهیم کرد:
<EditForm Model="HomeModel">
 // ...
</EditForm>
- در آخر بجای input معمولی، از کامپوننت InputDate متصل به HomeModel.StartDate :
<InputDate min="@DateTime.Now.ToString("yyyy-MM-dd")"
           @bind-Value="HomeModel.StartDate"
           type="text"
           class="form-control" />
و بجای select معمولی، از نمونه‌ی متصل شده‌ی به HomeModel.NoOfNights استفاده می‌کنیم:
<select @bind="HomeModel.NoOfNights">


تعریف Local Storage سمت کلاینت

در ادامه می‌خواهیم اگر کاربری زمان شروع رزرو اتاقی را به همراه تعداد شب مدنظر، انتخاب کرد، با کلیک بر روی دکمه‌ی Go، به یک صفحه‌ی مشاهده‌ی جزئیات منتقل شود. بنابراین نیاز داریم تا اطلاعات انتخابی کاربر را به نحوی ذخیره سازی کنیم. برای یک چنین سناریوی سمت کلاینتی، می‌توان از local storage استاندارد مرورگرها استفاده کرد که امکان کار آفلاین با برنامه را نیز فراهم می‌کند.
برای این منظور کتابخانه‌ای به نام Blazored.LocalStorage طراحی شده‌است که پس از نصب آن توسط دستور زیر:
dotnet add package Blazored.LocalStorage
نیاز است سرویس‌های آن‌را به سیستم تزریق وابستگی‌های برنامه اضافه کرد. در برنامه‌های Blazor Server، اینکار را در فایل Startup برنامه انجام می‌دادیم؛ اما در اینجا، سرویس‌ها در فایل Program.cs تعریف می‌شوند:
namespace BlazorWasm.Client
{
    public class Program
    {
        public static async Task Main(string[] args)
        {
            var builder = WebAssemblyHostBuilder.CreateDefault(args);
            // ...
            builder.Services.AddBlazoredLocalStorage();
            // ...
        }
    }
}
پس از این تعاریف می‌توان از سرویس ILocalStorageService آن در کامپوننت‌های برنامه استفاده کرد. البته جهت سهولت استفاده‌ی از این سرویس بهتر است فضای نام آن‌را به فایل BlazorWasm.Client\_Imports.razor افزود:
@using Blazored.LocalStorage
اکنون برای استفاده از آن به کامپوننت Pages\Index.razor مراجعه کرده و سرویس‌های ILocalStorageService و IJSRuntime را به کامپوننت تزریق می‌کنیم:
@page "/"

@inject ILocalStorageService LocalStorage
@inject IJSRuntime JsRuntime

<EditForm Model="HomeModel" OnValidSubmit="SaveInitialData">
همچنین متدی را هم برای مدیریت رویداد OnValidSubmit تعریف خواهیم کرد:
@code{
    HomeVM HomeModel = new HomeVM();

    private async Task SaveInitialData()
    {
        try
        {
            HomeModel.EndDate = HomeModel.StartDate.AddDays(HomeModel.NoOfNights);
            await LocalStorage.SetItemAsync("InitialRoomBookingInfo", HomeModel);
        }
        catch (Exception e)
        {
            await JsRuntime.ToastrError(e.Message);
        }
    }
}
در اینجا با استفاده از متد SetItemAsync و ذکر یک کلید دلخواه، اطلاعات مدل فرم را در local storage مرورگر ذخیره کرده‌ایم. همچنین اگر خطایی هم رخ دهد توسط ToastrError نمایش داده خواهد شد.
برای مثال اگر تاریخ و عددی را انتخاب کنیم، نتیجه‌ی حاصل از کلیک بر روی دکمه‌ی Go را می‌توان در قسمت Local storage مرورگر جاری مشاهده کرد:


البته با توجه به اینکه می‌خواهیم از کلید InitialRoomBookingInfo در سایر کامپوننت‌های برنامه نیز استفاده کنیم، بهتر است آن‌را به یک پروژه‌ی مشترک مانند BlazorServer.Common که پیشتر نام نقش‌هایی مانند Admin را در آن تعریف کردیم، منتقل کنیم:
namespace BlazorServer.Common
{
    public static class ConstantKeys
    {
        public const string LocalInitialBooking = "InitialRoomBookingInfo";
    }
}
سپس باید ارجاعی به آن پروژه را افزوده:
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
  <ItemGroup>
    <ProjectReference Include="..\..\BlazorServer\BlazorServer.Common\BlazorServer.Common.csproj" />
  </ItemGroup>
</Project>
همچنین فضای نام آن‌را نیز به فایل BlazorWasm.Client\_Imports.razor اضافه می‌کنیم:
@using BlazorServer.Common
اکنون می‌توان از کلید ثابت تعریف شده‌ی مشترک، استفاده کرد:
await LocalStorage.SetItemAsync(ConstantKeys.LocalInitialBooking, HomeModel);

در آخر قصد داریم با کلیک بر روی Go، به یک صفحه‌ی جدید مانند نمایش لیست اتاق‌ها هدایت شویم. به همین جهت کامپوننت جدید Pages\HotelRooms\HotelRooms.razor را ایجاد می‌کنیم:
@page "/hotel/rooms"

<h3>HotelRooms</h3>

@code {

}
سپس در کامپوننت Pages\Index.razor با استفاده از سرویس NavigationManager، کار هدایت خودکار کاربر را به این کامپوننت جدید انجام خواهیم داد:
@page "/"

@inject ILocalStorageService LocalStorage
@inject IJSRuntime JsRuntime
@inject NavigationManager NavigationManager


@code{
    HomeVM HomeModel = new HomeVM();

    private async Task SaveInitialData()
    {
        try
        {
            HomeModel.EndDate = HomeModel.StartDate.AddDays(HomeModel.NoOfNights);
            await LocalStorage.SetItemAsync(ConstantKeys.LocalInitialBooking, HomeModel);
            NavigationManager.NavigateTo("hotel/rooms");
        }
        catch (Exception e)
        {
            await JsRuntime.ToastrError(e.Message);
        }
    }
}


کدهای کامل این مطلب را از اینجا می‌توانید دریافت کنید: Blazor-5x-Part-26.zip
نظرات مطالب
ASP.NET MVC #18
البته به طور دستی تونستم این مورد رو موقتا برطرف کنم
 FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
                      1,                                     // ticket version
                      admin.UserName,                              // authenticated username
                      DateTime.Now,                          // issueDate
                      DateTime.Now.AddMinutes(30),           // expiryDate
                      true,                          // true to persist across browser sessions
                      "",                              // can be used to store additional user data
                      FormsAuthentication.FormsCookiePath);  // the path for the cookie

                    // Encrypt the ticket using the machine key
                    var encryptedTicket = FormsAuthentication.Encrypt(ticket);

                    // Add the cookie to the request to save it
                    var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket) {HttpOnly = true};
                    Response.Cookies.Add(cookie);
اشتراک‌ها
دوره بررسی تازه‌های ASP.NET 5 از Tuts plus
ASP.NET is almost 15 years old and it has evolved to become a flexible and extremely powerful platform. But 15 years is a long time, especially in the world of web technology, and the folks at Microsoft knew it was time to change ASP.NET. In this course, Envato Tuts+ instructor Jeremy McPeak will walk you through the major changes to ASP.NET in version 5. Along the way, you'll see how these changes will affect your project and how the new features can make your life as a developer easier. You'll also get a first look at the new Tag Helpers, inversion of control and dependency injection features, with practical examples.
دوره بررسی تازه‌های ASP.NET 5 از Tuts plus
مطالب
بدست آوردن نام کشور و مشخصات کامل آن از روی آدرس IP

سایت‌های بسیاری هستند که سرویس‌هایی را برای بدست آوردن مشخصات کشور، از روی IP ارائه می‌دهند؛ ولی اکثر آنها برای این سرویسی که ارائه میدهند هزینه دریافت می‌کنند. سایتی که من در این مقاله معرفی خواهم کرد این سرویس را به رایگان ارائه می‌هد، به شرط اینکه درخواست‌های شما در هر ساعت بیشتر از 10000 نباشد. اگر این اتفاق روی دهد، یعنی درخواست‌های شما به بیش از 10000 در ساعت برسد، درخواست‌های شما با خطای HTTP 403, forbidden مواجه خواهد شد و تا زمانیکه محدودیت شما به پایان برسد، باید منتظر بمانید.

سرویسی که این سایت ارائه می‌دهد، سورس باز و رایگان میباشد. اگر شما با این محدودیت 10000 درخواست در ساعت مشکلی داشتید، می‌توانید این سرویس را از اینجا دریافت و آن‌را در سرور خودتان اجرا کنید. سورس سرویس هم بر روی github موجود هست.

API ارائه شده توسط این سایت، درخواست‌ها را بصورت زیر دریافت میکند:
freegeoip.net/{format}/{IP_or_hostname}
منظور از فرمت، قالبی است که پس از درخواست برای شما ارسال خواهد شد که به صورت‌های زیر خواهد بود:
freegeoip.net/xml/4.2.2.2 : XML
freegeoip.net/csv/8.8.8.8 :CSV
freegeoip.net/json/github.com :JSON
برای مثال اگر چنین درخواستی را ارسال کنیم:
http://freegeoip.net/xml/162.158.88.214
پاسخی که دریافت میکنیم بدین صورت خواهد بود:
<Response>
<IP>162.158.88.214</IP>
<CountryCode>DE</CountryCode>
<CountryName>Germany</CountryName>
<RegionCode>HE</RegionCode>
<RegionName>Hesse</RegionName>
<City>Frankfurt am Main</City>
<ZipCode>60438</ZipCode>
<TimeZone>Europe/Berlin</TimeZone>
<Latitude>50.1167</Latitude>
<Longitude>8.6833</Longitude>
<MetroCode>0</MetroCode>
</Response>
که در آن تمامی مشخصات مربوط به آن کشور، برای ما ارسال خواهد شد.

اگر آدرس IP را مشخص نکنید مشخصات مربوط به IP آدرس خودتان را دریافت خواهید کرد.


در ادامه از یک برنامه   console application برای دریافت این پاسخ  ارسال شده از سرویس و استخراج داده‌ها از آن استفاده خواهیم کرد.

البته این روش برای برنامه‌های تحت وب هم به همین صورت خواهد بود و تفاوتی نمی‌کند.

از این روش می‌توانید برای بلاک کردن کشورهایی که نمیخواهید به برنامه‌ی شما دسترسی پیدا کنند استفاده کنید و یا اینکه بدانید ip هایی که از سایت شما بازدید میکنند از کدام کشورهای جهان هستند و یا کار خلاقانه‌ای که می‌توانید انجام دهید، نمایش مکان‌های بازدید کننده‌ها بر روی نقشه گوگل، با استفاده از طول و عرض جغرافیایی که این سرویس در اختیارتان می‌گذارد‌، می‌باشد
 public static void ReadXmlElements(string ipAddress)
        {           
            XDocument xdoc=XDocument.Load("http://www.freegeoip.net/xml/" + ipAddress);
            var country = xdoc.Descendants("Response").Select(c => new
            {
                IpAddress = c.Element("IP")?.Value,
                CountryCode = c.Element("CountryCode")?.Value,
                CountryName = c.Element("CountryName")?.Value,
                RegionCode = c.Element("RegionCode")?.Value,
                RegionName = c.Element("RegionName")?.Value,
                City = c.Element("City")?.Value,
                ZipCode = c.Element("ZipCode")?.Value,
                TimeZone = c.Element("TimeZone")?.Value,
                Latitude = c.Element("Latitude")?.Value,
                Longitude = c.Element("Longitude")?.Value,
                MetroCode = c.Element("MetroCode")?.Value,
            });

             var countryData = country.First();
            Console.WriteLine("CountryName :" + countryData.CountryName 
                +Environment.NewLine + "CountryCode :"+countryData.CountryCode
                + Environment.NewLine + "RegionCode :"+countryData.RegionCode
                + Environment.NewLine + "RegionName :" + countryData.RegionName
                + Environment.NewLine + "City :" + countryData.City
                + Environment.NewLine + "ZipCode :" + countryData.ZipCode
                + Environment.NewLine + "TimeZone :" + countryData.TimeZone
                + Environment.NewLine + "Latitude :" + countryData.Latitude
                + Environment.NewLine + "Longitude :" + countryData.Longitude
                + Environment.NewLine + "MetroCode :" + countryData.MetroCode
                ); 
            
            Console.ReadKey();
        }

در متد main برنامه، متد ReadXmlElements را فراخوانی کرده و آدرس آی پی مورد نظر را پاس میدهیم:  

static void Main(string[] args)
        {
            ReadXmlElements("162.158.88.214");
        }
که نتیجه‌ی نمونه‌ای از آن‌را در تصویر ذیل می‌توانید مشاهده کنید


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

public class WorldCountries
    {
        public string CountryCode { get; set; }
        public string CountryName { get; set; }

    }

 public static class GenerateCountries
    {
        public static IList<WorldCountries> CreateCountries()
        {
            return new[]
                {
new WorldCountries { CountryCode = "AF", CountryName = "Afghanistan"},
new WorldCountries { CountryCode = "AX", CountryName = "Åland Islands"},
new WorldCountries { CountryCode = "AL", CountryName = "Albania"},
new WorldCountries { CountryCode = "DZ", CountryName = "Algeria"},
new WorldCountries { CountryCode = "AS", CountryName = "American Samoa"},
new WorldCountries { CountryCode = "AD", CountryName = "Andorra"},
new WorldCountries { CountryCode = "AO", CountryName = "Angola"},
new WorldCountries { CountryCode = "AI", CountryName = "Anguilla"},
new WorldCountries { CountryCode = "AQ", CountryName = "Antarctica"},
new WorldCountries { CountryCode = "AG", CountryName = "Antigua and Barbuda"},
new WorldCountries { CountryCode = "AR", CountryName = "Argentina"},
new WorldCountries { CountryCode = "AM", CountryName = "Armenia"},
new WorldCountries { CountryCode = "AW", CountryName = "Aruba"},
new WorldCountries { CountryCode = "AU", CountryName = "Australia"},
new WorldCountries { CountryCode = "AT", CountryName = "Austria"},
new WorldCountries { CountryCode = "AZ", CountryName = "Azerbaijan"},
new WorldCountries { CountryCode = "BS", CountryName = "Bahamas"},
new WorldCountries { CountryCode = "BH", CountryName = "Bahrain"},
new WorldCountries { CountryCode = "BD", CountryName = "Bangladesh"},
new WorldCountries { CountryCode = "BB", CountryName = "Barbados"},
new WorldCountries { CountryCode = "BY", CountryName = "Belarus"},
new WorldCountries { CountryCode = "BE", CountryName = "Belgium"},
new WorldCountries { CountryCode = "BZ", CountryName = "Belize"},
new WorldCountries { CountryCode = "BJ", CountryName = "Benin"},
new WorldCountries { CountryCode = "BM", CountryName = "Bermuda"},
new WorldCountries { CountryCode = "BT", CountryName = "Bhutan"},
new WorldCountries { CountryCode = "BA", CountryName = "Bosnia and Herzegovina"},
new WorldCountries { CountryCode = "BW", CountryName = "Botswana"},
new WorldCountries { CountryCode = "BV", CountryName = "Bouvet Island"},
new WorldCountries { CountryCode = "BR", CountryName = "Brazil"},
new WorldCountries { CountryCode = "IO", CountryName = "British Indian Ocean Territory"},
new WorldCountries { CountryCode = "BN", CountryName = "Brunei Darussalam"},
new WorldCountries { CountryCode = "BG", CountryName = "Bulgaria"},
new WorldCountries { CountryCode = "BF", CountryName = "Burkina Faso"},
new WorldCountries { CountryCode = "BI", CountryName = "Burundi"},
new WorldCountries { CountryCode = "KH", CountryName = "Cambodia"},
new WorldCountries { CountryCode = "CM", CountryName = "Cameroon"},
new WorldCountries { CountryCode = "CA", CountryName = "Canada"},
new WorldCountries { CountryCode = "CV", CountryName = "Cape Verde"},
new WorldCountries { CountryCode = "KY", CountryName = "Cayman Islands"},
new WorldCountries { CountryCode = "CF", CountryName = "Central African Republic"},
new WorldCountries { CountryCode = "TD", CountryName = "Chad"},
new WorldCountries { CountryCode = "CL", CountryName = "Chile"},
new WorldCountries { CountryCode = "CN", CountryName = "China"},
new WorldCountries { CountryCode = "CX", CountryName = "Christmas Island"},
new WorldCountries { CountryCode = "CC", CountryName = "Cocos (Keeling) Islands"},
new WorldCountries { CountryCode = "CO", CountryName = "Colombia"},
new WorldCountries { CountryCode = "KM", CountryName = "Comoros"},
new WorldCountries { CountryCode = "CG", CountryName = "Congo"},
new WorldCountries { CountryCode = "CK", CountryName = "Cook Islands"},
new WorldCountries { CountryCode = "CR", CountryName = "Costa Rica"},
new WorldCountries { CountryCode = "HR", CountryName = "Croatia"},
new WorldCountries { CountryCode = "CU", CountryName = "Cuba"},
new WorldCountries { CountryCode = "CW", CountryName = "Curaçao"},
new WorldCountries { CountryCode = "CY", CountryName = "Cyprus"},
new WorldCountries { CountryCode = "CZ", CountryName = "Czech Republic"},
new WorldCountries { CountryCode = "DK", CountryName = "Denmark"},
new WorldCountries { CountryCode = "DJ", CountryName = "Djibouti"},
new WorldCountries { CountryCode = "DM", CountryName = "Dominica"},
new WorldCountries { CountryCode = "DO", CountryName = "Dominican Republic"},
new WorldCountries { CountryCode = "EC", CountryName = "Ecuador"},
new WorldCountries { CountryCode = "EG", CountryName = "Egypt"},
new WorldCountries { CountryCode = "SV", CountryName = "El Salvador"},
new WorldCountries { CountryCode = "GQ", CountryName = "Equatorial Guinea"},
new WorldCountries { CountryCode = "ER", CountryName = "Eritrea"},
new WorldCountries { CountryCode = "EE", CountryName = "Estonia"},
new WorldCountries { CountryCode = "ET", CountryName = "Ethiopia"},
new WorldCountries { CountryCode = "FK", CountryName = "Falkland Islands (Malvinas)"},
new WorldCountries { CountryCode = "FO", CountryName = "Faroe Islands"},
new WorldCountries { CountryCode = "FJ", CountryName = "Fiji"},
new WorldCountries { CountryCode = "FI", CountryName = "Finland"},
new WorldCountries { CountryCode = "FR", CountryName = "France"},
new WorldCountries { CountryCode = "GF", CountryName = "French Guiana"},
new WorldCountries { CountryCode = "PF", CountryName = "French Polynesia"},
new WorldCountries { CountryCode = "TF", CountryName = "French Southern Territories"},
new WorldCountries { CountryCode = "GA", CountryName = "Gabon"},
new WorldCountries { CountryCode = "GM", CountryName = "Gambia"},
new WorldCountries { CountryCode = "GE", CountryName = "Georgia"},
new WorldCountries { CountryCode = "DE", CountryName = "Germany"},
new WorldCountries { CountryCode = "GH", CountryName = "Ghana"},
new WorldCountries { CountryCode = "GI", CountryName = "Gibraltar"},
new WorldCountries { CountryCode = "GR", CountryName = "Greece"},
new WorldCountries { CountryCode = "GL", CountryName = "Greenland"},
new WorldCountries { CountryCode = "GD", CountryName = "Grenada"},
new WorldCountries { CountryCode = "GP", CountryName = "Guadeloupe"},
new WorldCountries { CountryCode = "GU", CountryName = "Guam"},
new WorldCountries { CountryCode = "GT", CountryName = "Guatemala"},
new WorldCountries { CountryCode = "GG", CountryName = "Guernsey"},
new WorldCountries { CountryCode = "GN", CountryName = "Guinea"},
new WorldCountries { CountryCode = "GW", CountryName = "Guinea-Bissau"},
new WorldCountries { CountryCode = "GY", CountryName = "Guyana"},
new WorldCountries { CountryCode = "HT", CountryName = "Haiti"},
new WorldCountries { CountryCode = "HM", CountryName = "Heard Island and McDonald Islands"},
new WorldCountries { CountryCode = "VA", CountryName = "Holy See (Vatican City State)"},
new WorldCountries { CountryCode = "HN", CountryName = "Honduras"},
new WorldCountries { CountryCode = "HK", CountryName = "Hong Kong"},
new WorldCountries { CountryCode = "HU", CountryName = "Hungary"},
new WorldCountries { CountryCode = "IS", CountryName = "Iceland"},
new WorldCountries { CountryCode = "IN", CountryName = "India"},
new WorldCountries { CountryCode = "ID", CountryName = "Indonesia"},
new WorldCountries { CountryCode = "IR", CountryName = "Iran"},
new WorldCountries { CountryCode = "IQ", CountryName = "Iraq"},
new WorldCountries { CountryCode = "IE", CountryName = "Ireland"},
new WorldCountries { CountryCode = "IM", CountryName = "Isle of Man"},
new WorldCountries { CountryCode = "IL", CountryName = "Israel"},
new WorldCountries { CountryCode = "IT", CountryName = "Italy"},
new WorldCountries { CountryCode = "JM", CountryName = "Jamaica"},
new WorldCountries { CountryCode = "JP", CountryName = "Japan"},
new WorldCountries { CountryCode = "JE", CountryName = "Jersey"},
new WorldCountries { CountryCode = "JO", CountryName = "Jordan"},
new WorldCountries { CountryCode = "KZ", CountryName = "Kazakhstan"},
new WorldCountries { CountryCode = "KE", CountryName = "Kenya"},
new WorldCountries { CountryCode = "KI", CountryName = "Kiribati"},
new WorldCountries { CountryCode = "KP", CountryName = "Korea"},
new WorldCountries { CountryCode = "KW", CountryName = "Kuwait"},
new WorldCountries { CountryCode = "KG", CountryName = "Kyrgyzstan"},
new WorldCountries { CountryCode = "LV", CountryName = "Latvia"},
new WorldCountries { CountryCode = "LB", CountryName = "Lebanon"},
new WorldCountries { CountryCode = "LS", CountryName = "Lesotho"},
new WorldCountries { CountryCode = "LR", CountryName = "Liberia"},
new WorldCountries { CountryCode = "LY", CountryName = "Libya"},
new WorldCountries { CountryCode = "LI", CountryName = "Liechtenstein"},
new WorldCountries { CountryCode = "LT", CountryName = "Lithuania"},
new WorldCountries { CountryCode = "LU", CountryName = "Luxembourg"},
new WorldCountries { CountryCode = "MO", CountryName = "Macao"},
new WorldCountries { CountryCode = "MK", CountryName = "Macedonia"},
new WorldCountries { CountryCode = "MG", CountryName = "Madagascar"},
new WorldCountries { CountryCode = "MW", CountryName = "Malawi"},
new WorldCountries { CountryCode = "MY", CountryName = "Malaysia"},
new WorldCountries { CountryCode = "MV", CountryName = "Maldives"},
new WorldCountries { CountryCode = "ML", CountryName = "Mali"},
new WorldCountries { CountryCode = "MT", CountryName = "Malta"},
new WorldCountries { CountryCode = "MH", CountryName = "Marshall Islands"},
new WorldCountries { CountryCode = "MQ", CountryName = "Martinique"},
new WorldCountries { CountryCode = "MR", CountryName = "Mauritania"},
new WorldCountries { CountryCode = "MU", CountryName = "Mauritius"},
new WorldCountries { CountryCode = "YT", CountryName = "Mayotte"},
new WorldCountries { CountryCode = "MX", CountryName = "Mexico"},
new WorldCountries { CountryCode = "FM", CountryName = "Micronesia"},
new WorldCountries { CountryCode = "MD", CountryName = "Moldova"},
new WorldCountries { CountryCode = "MC", CountryName = "Monaco"},
new WorldCountries { CountryCode = "MN", CountryName = "Mongolia"},
new WorldCountries { CountryCode = "ME", CountryName = "Montenegro"},
new WorldCountries { CountryCode = "MS", CountryName = "Montserrat"},
new WorldCountries { CountryCode = "MA", CountryName = "Morocco"},
new WorldCountries { CountryCode = "MZ", CountryName = "Mozambique"},
new WorldCountries { CountryCode = "MM", CountryName = "Myanmar"},
new WorldCountries { CountryCode = "NA", CountryName = "Namibia"},
new WorldCountries { CountryCode = "NR", CountryName = "Nauru"},
new WorldCountries { CountryCode = "NP", CountryName = "Nepal"},
new WorldCountries { CountryCode = "NL", CountryName = "Netherlands"},
new WorldCountries { CountryCode = "NC", CountryName = "New Caledonia"},
new WorldCountries { CountryCode = "NZ", CountryName = "New Zealand"},
new WorldCountries { CountryCode = "NI", CountryName = "Nicaragua"},
new WorldCountries { CountryCode = "NE", CountryName = "Niger"},
new WorldCountries { CountryCode = "NG", CountryName = "Nigeria"},
new WorldCountries { CountryCode = "NU", CountryName = "Niue"},
new WorldCountries { CountryCode = "NF", CountryName = "Norfolk Island"},
new WorldCountries { CountryCode = "MP", CountryName = "Northern Mariana Islands"},
new WorldCountries { CountryCode = "NO", CountryName = "Norway"},
new WorldCountries { CountryCode = "OM", CountryName = "Oman"},
new WorldCountries { CountryCode = "PK", CountryName = "Pakistan"},
new WorldCountries { CountryCode = "PW", CountryName = "Palau"},
new WorldCountries { CountryCode = "PS", CountryName = "Palestine"},
new WorldCountries { CountryCode = "PA", CountryName = "Panama"},
new WorldCountries { CountryCode = "PG", CountryName = "Papua New Guinea"},
new WorldCountries { CountryCode = "PY", CountryName = "Paraguay"},
new WorldCountries { CountryCode = "PE", CountryName = "Peru"},
new WorldCountries { CountryCode = "PH", CountryName = "Philippines"},
new WorldCountries { CountryCode = "PN", CountryName = "Pitcairn"},
new WorldCountries { CountryCode = "PL", CountryName = "Poland"},
new WorldCountries { CountryCode = "PT", CountryName = "Portugal"},
new WorldCountries { CountryCode = "PR", CountryName = "Puerto Rico"},
new WorldCountries { CountryCode = "QA", CountryName = "Qatar"},
new WorldCountries { CountryCode = "RE", CountryName = "Réunion"},
new WorldCountries { CountryCode = "RO", CountryName = "Romania"},
new WorldCountries { CountryCode = "RU", CountryName = "Russian Federation"},
new WorldCountries { CountryCode = "RW", CountryName = "Rwanda"},
new WorldCountries { CountryCode = "BL", CountryName = "Saint Barthélemy"},
new WorldCountries { CountryCode = "KN", CountryName = "Saint Kitts and Nevis"},
new WorldCountries { CountryCode = "LC", CountryName = "Saint Lucia"},
new WorldCountries { CountryCode = "MF", CountryName = "Saint Martin (French part)"},
new WorldCountries { CountryCode = "PM", CountryName = "Saint Pierre and Miquelon"},
new WorldCountries { CountryCode = "VC", CountryName = "Saint Vincent and the Grenadines"},
new WorldCountries { CountryCode = "WS", CountryName = "Samoa"},
new WorldCountries { CountryCode = "SM", CountryName = "San Marino"},
new WorldCountries { CountryCode = "ST", CountryName = "Sao Tome and Principe"},
new WorldCountries { CountryCode = "SA", CountryName = "Saudi Arabia"},
new WorldCountries { CountryCode = "SN", CountryName = "Senegal"},
new WorldCountries { CountryCode = "RS", CountryName = "Serbia"},
new WorldCountries { CountryCode = "SC", CountryName = "Seychelles"},
new WorldCountries { CountryCode = "SL", CountryName = "Sierra Leone"},
new WorldCountries { CountryCode = "SG", CountryName = "Singapore"},
new WorldCountries { CountryCode = "SX", CountryName = "Sint Maarten (Dutch part)"},
new WorldCountries { CountryCode = "SK", CountryName = "Slovakia"},
new WorldCountries { CountryCode = "SI", CountryName = "Slovenia"},
new WorldCountries { CountryCode = "SB", CountryName = "Solomon Islands"},
new WorldCountries { CountryCode = "SO", CountryName = "Somalia"},
new WorldCountries { CountryCode = "ZA", CountryName = "South Africa"},
new WorldCountries { CountryCode = "GS", CountryName = "South Georgia and the South Sandwich Islands"},
new WorldCountries { CountryCode = "SS", CountryName = "South Sudan"},
new WorldCountries { CountryCode = "ES", CountryName = "Spain"},
new WorldCountries { CountryCode = "LK", CountryName = "Sri Lanka"},
new WorldCountries { CountryCode = "SD", CountryName = "Sudan"},
new WorldCountries { CountryCode = "SR", CountryName = "Suriname"},
new WorldCountries { CountryCode = "SJ", CountryName = "Svalbard and Jan Mayen"},
new WorldCountries { CountryCode = "SZ", CountryName = "Swaziland"},
new WorldCountries { CountryCode = "SE", CountryName = "Sweden"},
new WorldCountries { CountryCode = "CH", CountryName = "Switzerland"},
new WorldCountries { CountryCode = "SY", CountryName = "Syrian Arab Republic"},
new WorldCountries { CountryCode = "TW", CountryName = "Taiwan"},
new WorldCountries { CountryCode = "TJ", CountryName = "Tajikistan"},
new WorldCountries { CountryCode = "TZ", CountryName = "Tanzania"},
new WorldCountries { CountryCode = "TH", CountryName = "Thailand"},
new WorldCountries { CountryCode = "TL", CountryName = "Timor-Leste"},
new WorldCountries { CountryCode = "TG", CountryName = "Togo"},
new WorldCountries { CountryCode = "TK", CountryName = "Tokelau"},
new WorldCountries { CountryCode = "TO", CountryName = "Tonga"},
new WorldCountries { CountryCode = "TT", CountryName = "Trinidad and Tobago"},
new WorldCountries { CountryCode = "TN", CountryName = "Tunisia"},
new WorldCountries { CountryCode = "TR", CountryName = "Turkey"},
new WorldCountries { CountryCode = "TM", CountryName = "Turkmenistan"},
new WorldCountries { CountryCode = "TC", CountryName = "Turks and Caicos Islands"},
new WorldCountries { CountryCode = "TV", CountryName = "Tuvalu"},
new WorldCountries { CountryCode = "UG", CountryName = "Uganda"},
new WorldCountries { CountryCode = "UA", CountryName = "Ukraine"},
new WorldCountries { CountryCode = "AE", CountryName = "United Arab Emirates"},
new WorldCountries { CountryCode = "GB", CountryName = "United Kingdom"},
new WorldCountries { CountryCode = "US", CountryName = "United States"},
new WorldCountries { CountryCode = "UM", CountryName = "United States Minor Outlying Islands"},
new WorldCountries { CountryCode = "UY", CountryName = "Uruguay"},
new WorldCountries { CountryCode = "UZ", CountryName = "Uzbekistan"},
new WorldCountries { CountryCode = "VU", CountryName = "Vanuatu"},
new WorldCountries { CountryCode = "VE", CountryName = "Venezuela"},
new WorldCountries { CountryCode = "VN", CountryName = "Viet Nam"},
new WorldCountries { CountryCode = "VG", CountryName = "British Virgin Islands"},
new WorldCountries { CountryCode = "VI", CountryName = "US Virgin Islands"},
new WorldCountries { CountryCode = "WF", CountryName = "Wallis and Futuna"},
new WorldCountries { CountryCode = "EH", CountryName = "Western Sahara"},
new WorldCountries { CountryCode = "YE", CountryName = "Yemen"},
new WorldCountries { CountryCode = "ZM", CountryName = "Zambia"},
new WorldCountries { CountryCode = "ZW", CountryName = "Zimbabwe"},
                };
        }
    }

دریافت کد کامل این پروژه