مطالب
پیدا کردن MAC Address از روی IP

دستگاه کارتخوان تحت شبکه‌ای را تصور کنید که تا دیروز در شبکه دیده می‌شد اما امروز ناپدید شده! دیگر نمی‌شود با آن ارتباط برقرار کرد و توسط برنامه نوشته شده آن‌را تخلیه کرد. به صورت پیش فرض یک IP ثابت به این دستگاه‌ها انتساب داده می‌شود مثلا 192.168.1.100 . حال اگر در شبکه این IP رزرو نشود ممکن است DHCP این IP را به کامپیوتر دیگری بدهد یا روتری به اشتباه از آن استفاده کند. الان چطور باید تشخیص داد که این IP توسط چه وسیله‌ای در حال استفاده است؟
برای بدست آوردن MAC Address یک دیوایس در شبکه از دستور خط فرمان ARP می‌توان استفاده کرد. برای مثال:

arp -a

و یا :
arp -a findstr 192.168.1.100


اگر در این لیست‌ها MAC Address آی پی مورد نظر شما یافت نشد، ابتدا آن IP را ping کنید و بعد دستورات فوق را استفاده نمائید. علت هم این است که دستورات فوق تنها ARP table ایی را بر اساس ارتباطات ایستگاه کاری فعلی با شبکه نمایش می‌دهند و اگر کامپیوتر فعلی هیچ ارتباطی با IP مورد نظر نداشته باشد، خروجی خاصی را نمایش نخواهد داد.

حال اگر با برنامه نویسی بخواهیم این‌کار را انجام دهیم با استفاده از تابع API زیر نیز می‌توان به همین نتیجه رسید:

[System.Runtime.InteropServices.DllImport("Iphlpapi.dll", EntryPoint = "SendARP")]
internal extern static Int32 SendArp(Int32 destIpAddress, Int32 srcIpAddress, byte[] macAddress, ref Int32 macAddressLength);

public static System.Net.NetworkInformation.PhysicalAddress GetMacFromIP(System.Net.IPAddress IP)
{
if (IP.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork)
throw new ArgumentException("supports just IPv4 addresses");

Int32 addrInt = IpToInt(IP);
Int32 srcAddrInt = 0;
byte[] mac = new byte[6]; // 48 bit

int length = mac.Length;
int reply = SendArp(addrInt, srcAddrInt, mac, ref length);

byte[] emptyMac = new byte[12];

if (reply != 0)
{
//No MAC Address found for the IP Address
return new System.Net.NetworkInformation.PhysicalAddress(emptyMac);
}
return new System.Net.NetworkInformation.PhysicalAddress(mac);
}

private static Int32 IpToInt(System.Net.IPAddress IP)
{
byte[] bytes = IP.GetAddressBytes();
return BitConverter.ToInt32(bytes, 0);
}
مک آدرسی که در حال استفاده از IP ما بود:
00:0F:8F:F1:EE:40

مک آدرس واقعی دستگاه کارتخوان:
00.64.00.00.5E.7A

این تداخل رخ داده، باعث شده بود که ارتباط با دستگاه کارتخوان قطع شود. همانطور که می‌دانید سه بایت اول هر مک آدرس می‌تواند بیانگر شرکت سازنده‌ای باشد. 00:0F:8F مربوط به روترهای سیسکو است.
مطالب
آشنایی با الگوی طراحی Bridge
سناریو زیر را در نظر بگیرید:
قصد دارید تا در برنامه‌ی خود ارسال پیام از طریق پیامک و ایمیل را راه اندازی کنید. هر کدام از این روش‌ها نیز برای خود راه‌های متفاوتی دارند. برای مثال ارسال پیامک از طریق وب سرویس یا یک API خارجی و غیره.
کاری را که می‌توان انجام داد، بشرح زیر نیز می‌توان بیان نمود:
ابتدا یک Interface ایجاد می‌کنیم (IBridge) و در آن متد Send را قرار می‌دهیم. این متد یک پارامتر ورودی از نوع رشته می‌گیرد و به کمک آن میتوان اقدام به ارسال پیامک یا ایمیل یا هر چیز دیگری نمود. کلاس‌هایی این واسط را پیاده سازی می‌کنند که یکی از روش‌های اجرای کار باشند (برای مثال کلاس WebService که یک روش ارسال پیامک یا ایمیل است).
    public interface IBridge
    {
        string Send(string parameter);
    } 
    public class WebService: IBridge
    {
        public string Send(string parameter)
        {
            return parameter + " sent by WebService";
        }
    }
    public class API: IBridge
    {
        public string Send(string parameter)
        {
            return parameter + " sent by API";
        }
    }
سپس در ادامه به مکانیزمی نیاز داریم تا بتوانیم از طریق آن پیامک یا ایمیل را ارسال کنیم. خوب می‌خواهیم ایمیل ارسال کنیم؛ اولین سوالی که مطرح می‌شود این است که چگونه ارسال کنیم؟ پس باید در مکانیزم خود زیرساختی برای پاسخ به این سوال آماده باشد.
public abstract class Abstraction
    {
        public IBridge Bridge;
        public abstract string SendData();
    }
    public class SendEmail : Abstraction
    {
        public override string SendData ()
        {
            return Bridge.Send("Email");
        }
    }
    public class SendSMS: Abstraction
    {
        public override string SendData ()
        {
            return Bridge.Send("SMS");
        }
    }
در کد فوق یک کلاس انتزاعی ایجاد کردیم و در آن یک object از نوع واسط خود قرار دادیم. این object به ما کمک می‌کند تا به طریق آن شیوه‌ی ارسال ایمیل یا پیامک را مشخص سازیم و به سوال خود پاسخ دهیم. سپس در ادامه متد SendData  آورده شده است که به کمک آن اعلام می‌کنیم که قصد ارسال ایمیل یا پیامک را داریم و نهایتا هر یک از کلاس‌های ایمیل یا پیامک، این متد را برای خود پیاده سازی کرده‌اند. 
قبل از ادامه اجازه دهید کمی در مورد بدنه‌ی یکی از متدهای SendData صحبت کنیم. در این متد با کمک Bridge متد Send موجود در واسط صدا زده شده است. از آنجا که این object از نظر سطح دسترسی عمومی می‌باشد، لذا از بیرون از کلاس قابل دسترسی است. این باعث می‌شود تا قبل از فراخوانی متد SendData  موجود در کلاس ایمیل یا پیامک اعلام کنیم که Bridge از چه نوعی است (به چه روشی می‌خواهیم ارسال رخ دهد).
  Abstraction ab1 = new Email();
  ab1.Bridge = new WebService();
  Console.WriteLine(ab1.SendData ());
  ab1.Bridge = new API();
  Console.WriteLine(ab1.SendData ());
   Abstraction ab2 = new SMS();
   ab2.Bridge = new WebService();
   Console.WriteLine(ab2.SendData ());
    ab2.Bridge = new API();
    Console.WriteLine(ab2.SendData ());
نهایتا در کد فوق ابتدا بیان می‌کنیم که قصد ارسال ایمیل را داریم. سپس اعلام می‌داریم که این ارسال را به کمک WebService می‌خواهیم انجام دهی. و نهایتا ارسال را انجام می‌دهیم.
به کل این الگویی که ایجاد کردیم، الگوی Bridge گفته می‌شود.
حال فکر کنید قصد ارسال MMS دارید. در اینصورت فقط کافیست یک کلاس MMS ایجاد کنید و تمام؛ بدون اینکه کدی اضافی را بنویسید یا برنامه را تغییر دهید. یا فرض کنید روش ارسال جدیدی را می‌خواهید اضافه کنید. برای مثال ارسال به روش XYZ. در اینصورت فقط کافیست یک کلاس XYZ را ایجاد کنید که IBridge را پیاده سازی می‌کند.
مطالب
رمزنگاری Connection String از طریق خط فرمان

برای رمز نگاری Connection String ابتدا Command Prompt  را از مسیر زیر باز کنید 


Start Menu\Programs\Microsoft Visual Studio 2010\Visual Studio Tools\Visual Studio Command Prompt
و سپس دستور زیر را برای رمزنگاری Connection String وارد کنید :
aspnet_regiis.exe -pef "connectionStrings" "sulotion path"
در اینجا پارامتر اول (pef) مشخص می‌کند که Application ما از نوع File System Website است،پارامتر دوم(connectionStrings) نام کلید موردنظری است که می‌خواهیم Encrypt شود،در اینجا می‌توانیم هر کلیدی را Encrypt  کنیم به عنوان مثال فرض کنید تنظیمات SMTP را در Web.Config بدین صورت داریم : 
<system.net> 
    <mailSettings> 
      <smtp deliveryMethod="Network"> 
        <network host="smtp.gmail.com" port="587" userName="username@gmail.com" password="password" /> 
      </smtp> 
    </mailSettings> 
  </system.net> 
برای رمزنگاری بدین صورت عمل می‌کنیم :
aspnet_regiis.exe -pef "system.net/mailSettings/smtp" "sulotion path"
و بعد از Encrypt کردن توسط دستور فوق بدین صورت در Web.Config نمایش داده می‌شود :
  <system.net>
    <mailSettings>
      <smtp configProtectionProvider="RsaProtectedConfigurationProvider">
        <EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element"
          xmlns="http://www.w3.org/2001/04/xmlenc#">
          <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" />
          <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
            <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
              <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
              <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
                <KeyName>Rsa Key</KeyName>
              </KeyInfo>
              <CipherData>
                <CipherValue>QuOFQrT6XwxDhQjFnM3EByleyWqYY6lA1cGK1Dzli/hrDOYSj35ADk4MB3PeLOMVYh76kB8vch0/iZKAZaJlNUPKi/iZjEzE755B3sILKGLxfkH3j3qKHB0x1WN65L6zBXgzufphCVaNRobQXOl5J3E0Df8VCf/bERZu741HLPs=</CipherValue>
              </CipherData>
            </EncryptedKey>
          </KeyInfo>
          <CipherData>
            <CipherValue>NdwBe0mWZ+Yg/DEzNuiDfXlGpicoH1ZMn54FTrLuVsY3rawS/k6KPID3bZvOWB/XYseTYFGhqs7FUEqIYMvWjJYYmDAzk6dd4iv9y6ch3ZcXWQ/R5TkQLWoLQPYgdwGI3uJNs22t28xUISm1wS0uDbizCM2Io+DzSQe8N4Ih2MP9mb2NCbZ4BZEBCPvCevpSpdEjGN9v7hk=</CipherValue>
          </CipherData>
        </EncryptedData>
      </smtp>
    </mailSettings>
  </system.net>
در اینجا Encryption از نوع RSAProtectedConfigurationProvider انتخاب شده است که می‌توانیم آنرا به DataProtectionConfgurationProvider تغییر دهیم که مورد اول از روش رمز نگاری کلید عمومی RSA استفاده می‌کند.
برای Decrypt کردن هم فقط کافی است پارامتر اول دستور aspnet_regiis را به pdf تغییر دهیم :
aspnet_regiis.exe -pdf "system.net/mailSettings/smtp" "sulotion path"


مطالب دوره‌ها
اعمال غیر همزمان و چند ریسمانی
تصور عموم بر آن است که اعمال غیر همزمان با چند ریسمانی به یک معنا هستند. این مورد الزاما صحیح نیست. برای مثال دریافت غیرهمزمان یک فایل را از اینترنت درنظر بگیرید. شاید اینطور به نظر برسد که در اینجا یک ترد جدید ایجاد شده و در آن کل کار دریافت فایل آغاز می‌گردد؛ اما خیر. ایجاد یک ترد جدید تنها در قسمت‌های خاصی از یک پروسه انجام می‌شود. همچنین از لحاظ فنی امکان انجام کل کار در یک ترد، بدون بلاک کردن آن وجود دارد. از این جهت که بیشتر زمان، جهت صبر کردن دریافت پاسخی از سرور صرف می‌شود. زمانیکه کلاینت درخواستی را ارسال می‌کند، دیگر کار خاصی را نمی‌تواند انجام دهد تا اینکه پاسخی را دریافت کند.
زمانیکه از یک API غیرهمزمان برای مدیریت چنین عملیاتی استفاده می‌شود، ترد جاری را در این حالت در خواب فرو می‌برد. برای اینکه کار بیشتری برای انجام وجود ندارد. همچنین با اینکه کلاینت درخواستی را ارسال می‌کند یا پاسخی را دریافت، برای مدیریت کل عملیات در اکثر اوقات نیازی به تردها ندارد. این سخت افزار شبکه‌ی نصب شده در سیستم است که عمده‌ی کار را انجام می‌دهد و نه برنامه. زمانیکه برنامه درخواست ارسال اطلاعاتی را بر روی شبکه ارائه می‌دهد، درایور سخت افزار شبکه است که به سخت افزار مرتبط فرمان می‌دهد چه اطلاعاتی را باید ارسال کند. اکثر اینگونه سخت افزارها قادرند اطلاعات را خارج از حافظه‌ی اصلی سیستم دریافت کنند. در اینجا درایور تنها باید به سخت افزار عنوان کند، چه اطلاعاتی را و به کجا باید ارسال کند. بنابراین CPU تنها در طی ارسال این فرمان است که مشغول می‌باشد و نه خارج از آن و این زمان اصلا در مقایسه با زمان ارسال اطلاعات توسط سخت افزار مرتبط، طولانی نیست. CPU  مجددا زمانی درگیر خواهد شد که سخت افزار شبکه، اطلاعاتی را دریافت کرده است و باز هم این زمان در مقایسه با زمان دریافت اطلاعات توسط سخت افزار شبکه بسیار کوتاه است.
اغلب کارهای IO به همین شکل هستند. شبیه به همین روند در حالت دسترسی به سخت دیسک وجود دارد. مدت زمانیکه CPU به دیسک کنترلر اعلام می‌کند چه اطلاعاتی را نیاز دارد در مقایسه با مدت زمانیکه دیسک کنترلر این اطلاعات را واقعا بارگذاری می‌کند، بسیار ناچیز است.
نمونه‌ی دیگر آن کار با بانک‌های اطلاعاتی است. در اغلب اوقات برنامه‌ی ما صرفا یک درخواست را به بانک اطلاعاتی ارائه می‌دهد و اصل عملیات در جایی دیگر و توسط موتور بانک اطلاعاتی، خارج از برنامه پردازش می‌گردد.
بنابراین جهت پردازش یک پروسه‌ی خاص، در بسیاری از مراحل آن تنها یک ترد کافی است و هدف اصلی اعمال غیرهمزمان، کاهش تعداد تردهایی است که برنامه جهت پردازش عملیاتی خاص، نیاز دارد. این نوع الگوریتم‌ها طوری طراحی شده‌اند تا تردها تنها زمانی بکار گرفته شود که واقعا CPU قرار است کار خاصی را انجام دهد و نه برای مثال زمانیکه دیسک کنترلر یا سخت افزار شبکه مشغول به کار هستند (و ویندوز به صورت توکار دارای یک چنین API ایی هست). این مساله در سمت کلاینت، سبب خواهد شد تا ترد UI آزاد شود و بتواند به درخواست‌های رسیده کاربر بهتر پاسخ دهد. همچنین این مساله در سمت سرور نیز بسیار مفید است، زیرا برنامه قادر خواهد شد تا به تعداد بیشتری از درخواست‌ها به صورت همزمان پاسخ دهد. زیرا با کاهش تعداد تردهای درگیر، مقیاس پذیری سیستم افزایش می‌یابد.
مطالب
توسعه برنامه های Cross Platform با Xamarin Forms & Bit Framework - قسمت ششم
در پنج قسمت گذشته به نحوه نصب و راه اندازی Xamarin برای توسعه هر سه پلتفرم Android / iOS / Windows پرداختیم. حال با داشتن محیطی آماده برای کد زدن و تست، می‌توانیم به آموزش کد نویسی بپردازیم.
ابتدا بد نیست نگاهی به ساختار XamApp بیاندازیم. این پروژه‌ی مثال، خود از چهار قسمت تشکیل شده‌است:
XamApp | XamApp.Android | XamApp.UWP | XamApp.iOS
در خود XamApp درصد زیادی (گاهی تا 95%) از کد پروژه پیاده سازی می‌شود که بین سه پلتفرم مشترک است و شامل ظاهر فرم‌ها و منطق برنامه می‌شود. در پاره‌ای از مواقع، لازم می‌شود که از امکانات هر پلتفرم استفاده کنیم و در این صورت به سراغ پروژه‌های Android - iOS - Windows می‌رویم. نه تنها امکانات هر پلتفرم را در همان زبان CSharp و Visual Studio می‌توانید استفاده کنید، بلکه Documentation مربوطه به زبان CSharp برای تک تک امکانات سیستم عامل‌ها وجود دارد و اصلا لازم نیست برای فراگیری نحوه کار AR Kit در iOS به سراغ مستندات Apple بروید و یا برای کار با Intent در Android سری به سایت گوگل بزنید!
برای پیاده سازی UI از XAML استفاده می‌کنیم. XAML خود XML است، به همراه کلی امکانات هیجان انگیز که سعی می‌کنیم بجای ارائه یک توضیح کلی، به مرور و با معرفی امکاناتش، شما را با ماهیت خود XAML آشنا کنیم.
در XAML، همه چیز Tag هست (<>). برای مثال برای ایجاد یک دکمه داریم:
<Button Text="This is a test button" />
در XAML هر تگ، معادل یک کلاس CSharp ای است. در نتیجه ما کلاس Button هم داریم. همچنین Text در مثال بالا به این معنا است که کلاس Button دارای یک Property با نام Text است.

عناصر UI خود به سه دسته تقسیم می‌شوند. Page - Layout - Control
Page‌ها که شامل Content Page - MasterDetail Page - Tabbed Page و ... می‌شوند، صفحات برنامه را تشکیل می‌دهند. Content Page، ساده‌ترین نوع صفحه‌است که کل صفحه نمایش را پر می‌کند و همان طور که از اسمش بر می‌آید، Content ای برای نمایش دارد.

Tabbed Page نیز چندین Tab را نمایش می‌دهد که هر ‌Tab خود یک Content Page است. Carousel Page نیز همانند Tabbed Page است، ولی با Swipe کردن به چپ و راست می‌شود بین صفحات چرخید. هر دوی اینها Multi Page محسوب می‌شوند. MasterDetail نیز این امکان را می‌دهد که از بغل منویی برای Swipe کردن وجود داشته باشد. در نهایت Navigation Page محتوای یک Content Page را نمایش می‌دهد، ولی در بالای آن Navigation Bar دارد؛ شامل دکمه بازگشت به صفحه قبل و Title صفحه جاری و ...


علاوه بر Page ها، Layout‌ها نیز وجود دارند. برای مثال، Stack Layout برای چینش خطی (افقی یا عمودی) استفاده می‌شود. Grid برای ساختار شبکه‌ای استفاده می‌شود و Flex Layout عملکردی مشابه با Flex در وب دارد.

برای مثال، در صورتی که بخواهید چهار دکمه را هم اندازه با هم نمایش دهید، دارید:

    <Grid>
        <Button Text="1" Grid.Row="0" Grid.Column="0" />
        <Button Text="2" Grid.Row="0" Grid.Column="1" />
        <Button Text="3" Grid.Row="1" Grid.Column="0" />
        <Button Text="4" Grid.Row="1" Grid.Column="1" />
    </Grid>


در نهایت کنترل‌ها را داریم. برای مثال Label، Button و ... هر کدام از اینها نقشی را ایفا می‌کنند و امکاناتی دارند.

پس Page داریم، داخل Page از Layout استفاده می‌کنیم برای چینش کلی صفحه و در نهایت از کنترل‌های Image، ListView، Button و ... استفاده می‌کنیم تا ظاهر فرم تکمیل شود.


هر Page علاوه بر ظاهر خود، دارای یک منطق نیز هست. منطق، کاری است که آن فرم انجام می‌دهد. برای مثال فرم لاگین می‌تواند یک Stack Layout عمودی باشد، شامل یک Entry برای گرفتن نام کاربری، یک Entry برای گرفتن رمز عبور، که IsPassword آن True است و در نهایت یک دکمه که برای انجام عمل لاگین است.

در قسمت منطق که با CSharp نوشته می‌شود، ما یک Property از جنس string برای نگه داشتن نام کاربری داریم. یک Property از جنس string برای نگه داشتن رمز عبور و یک Command که عمل لاگین را انجام دهد. Property اول با نام UserName به Text آن Entry اول وصل می‌شود (به اصطلاح Bind می‌شود) و همین طور Property دوم با نام Password نیز به Text آن Entry دوم که IsPassword اش True بود وصل می‌شود و در نهایت Command لاگین به دکمه لاگین وصل می‌شود.


برای زدن ظاهر فرم لاگین، در پروژه XamApp روی فولدر Views راست کلیک نموده و از منوی Add به New Item رفته و Content Page را می‌زنیم. نام آن را LoginView.xaml می‌گذاریم که داخل تگ Content Page خواهیم داشت:

    <StackLayout Orientation="Vertical">
        <Entry Placeholder="User name" Text="{Binding UserName}" />
        <Entry IsPassword="True" Placeholder="Password" Text="{Binding Password}" />
        <Button Command="{Binding LoginCommand}" Text="Login" />
    </StackLayout>

برای زدن منطق، در پروژه XamApp روی فولدر ViewModels راست کلیک نموده و از منوی Add گزینه Class را انتخاب کرده و نام آن را LoginViewModel.cs می‌گذاریم که در داخل آن خواهیم داشت:

public class LoginViewModel : BitViewModelBase
{
        public string UserName { get; set; }

        public string Password { get; set; }

        public BitDelegateCommand LoginCommand { get; set; }

        public LoginViewModel()
        {
            LoginCommand = new BitDelegateCommand(Login);
        }

        public async Task Login()
        {
            // Login implementation ...
        }
}

BitDelegateCommand در این مثال، وظیفه اجرای متد Login را به عهده دارد و آن را اجرا می‌کند؛ زمانیکه کاربر روی دکمه لاگین Click یا Tap کند.


برای این که Content Page جدید، یعنی LoginView به همراه منطق آن، یعنی LoginViewModel در برنامه نشان داده شوند، لازم است با Navigation به آن صفحه برویم. برای این کار، ابتدا باید این زوج را رجیستر کنیم. برای این کار به متد RegisterTypes در کلاس App رفته (زیر فایل App.xaml یک فایل App.xaml.cs است) و خط زیر را به آن اضافه می‌کنیم:

containerRegistry.RegisterForNav<LoginView, LoginViewModel>("Login");

حال در متد OnInitializedAsync در چند خط بالاتر داریم:

await NavigationService.NavigateAsync("/Login", animated: false);

این سطر باعث می‌شود که Navigation Service که همان طور که از اسمش بر می‌آید، کارش Navigation بین صفحات است، صفحه لاگین را باز کند.

هم اکنون پروژه XamApp بروز شده و دارای این مثال است. در صورتی که آن را الآن Clone کنید و یا در صورتی که از قبل گرفته بودید، دستور git pull را برای گرفتن آخرین تغییرات بزنید، می‌توانید این کدها رو داخل پروژه داشته باشید.

برنامه را اجرا کنید و در متد Login، یک Break point بگذارید. سپس برنامه را اجرا کنید. User Name و Password را پر کنید و بر روی دکمه لاگین بزنید. خواهید دید که متد لاگین اجرا می‌شود و User Name و Password با مقادیری که نوشته بودید، پر شده‌اند.

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

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


روش ایجاد یک پروژه‌ی کتابخانه‌ای، از کامپوننت‌های Blazor

اگر از ویژوال استودیو استفاده می‌کنید، نوع «Razor Class Library»، پروژه‌های مخصوص کتابخانه‌های کامپوننت‌های Blazor را آغاز می‌کند و اگر می‌خواهید از CLI استفاده کنید، باید از دستور «dotnet new razorclasslib» استفاده کرد؛ که قابلیت تبدیل به بسته‌های نیوگت را با دستور dotnet pack داشته و به این ترتیب می‌توان آن‌ها را به اشتراک گذاشت و یا حتی می‌توان ارجاعی از این پروژه را در سایر پروژه‌های شخصی، مورد استفاده قرار داد.
ساختار پیش‌فرض فایل csproj اینگونه پروژه‌ها به صورت زیر است:
<Project Sdk="Microsoft.NET.Sdk.Razor">
  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
  </PropertyGroup>
  
  <ItemGroup>
    <SupportedPlatform Include="browser" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="5.0.6" />
  </ItemGroup>
</Project>

روش افزودن فایل‌های ثابت مورد استفاده‌ی در کتابخانه

پروژه‌ی پیش‌فرضی که در اینجا ایجاد می‌شود، به همراه یک پوشه‌ی wwwroot نیز هست. این پوشه محلی است که باید فایل‌های ثابت اشتراکی پروژه را مانند فایل‌های CSS و JS مورد استفاده، قرار داد.
این نوع پروژه‌ها از ویژگی Isolated CSS و یا Isolated JS ارائه شد‌ه‌ی در Blazor 5x نیز پشتیبانی می‌کنند.


روش استفاده‌ی از فایل‌های ثابت موجود در یک کتابخانه

این فایل‌های ثابت به همراه بسته‌ی نهایی پروژه، به صورت خودکار توزیع می‌شوند (و نیازی به ارائه‌ی مجزای آن‌ها نیست) و برای استفاده‌ی از آن‌ها در پروژه‌های دیگر، باید از روش مسیردهی زیر استفاده کرد:
/_content/PackageId/MyImage.png
- content_ مسیر آغاز کننده‌ی دسترسی به منابع یک کتابخانه‌ی کامپوننت‌های Blazor است.
- PackageId عموما همان نام پروژه‌ی مورد استفاده‌است (نام فایل csproj مانند MyBlazorComponentLibrary). هرچند می‌توان آن‌را به صورت مجزایی در فایل csproj نیز مقدار دهی کرد.
- در این مثال MyImage.png، نام منبعی است که قرار است از آن استفاده کنیم و پیشتر در پوشه‌ی wwwroot کتابخانه، کپی شده‌است و یا حتی می‌توان زیر پوشه‌هایی را نیز در اینجا ایجاد و از آن‌ها استفاده کرد؛ مانند:
/_content/MyBlazorComponentLibrary/scripts/HelloWorld.js
همچنین باید دقت داشت که مداخل فایل‌های اسکریپتی کتابخانه را مانند:
<script src="_content/MyBlazorComponentLibrary/exampleJsInterop.js"></script>
در برنامه‌های Blazor WASM باید به فایل wwwroot/index.html و در برنامه‌های Blazor Server به فایل Pages/_Host.cshtml افزود و این مداخل باید پیش از یکی از فایل‌های framework/blazor.server.js_ و یا framework/blazor.webassembly.js_ تعریف شوند.


روش استفاده‌ی از کتابخانه‌ی نهایی تولید شده

برای استفاده‌ی از کتابخانه‌ی نهایی تولید شده یا می‌توان ارجاعی را به فایل csproj آن، به پروژه‌ی خود افزود:
<ItemGroup>
   <ProjectReference Include="..\MyBlazorComponentLibrary\MyBlazorComponentLibrary.csproj" />
</ItemGroup>
و یا می‌توان بسته‌ی نیوگت آن‌را (در صورت وجود) نصب کرد.

پس از آن، جهت سهولت استفاده‌ی از این کامپوننت‌های اشتراکی، بهتر است فضای نام آن‌ها را به فایل Imports.razor_ پروژه‌ی خود افزود؛ تا نیازی به تعریف آن‌ها در تمام کامپوننت‌های مورد استفاده نباشد.
اشتراک‌ها
Visual Studio Code 1.34 منتشر شد

Welcome to the April 2019 release of Visual Studio Code. During April, we were busy with the Preview release of the Remote Development extensions. These extensions let you work with VS Code over SSH on a remote machine or VM, in Windows Subsystem for Linux (WSL), or inside a Docker container. 

Visual Studio Code 1.34 منتشر شد
اشتراک‌ها
آشنایی با IBM Swift Sandbox

The IBM Swift Sandbox is an interactive website that lets you write Swift code and execute it in a server environment – on top of Linux! Each sandbox runs on IBM Cloud in a Docker container. In addition, both the latest versions of Swift and its standard library are available for you to use. 

آشنایی با IBM Swift Sandbox
مطالب
React 16x - قسمت 17 - مسیریابی - بخش 3 - یک تمرین
به عنوان تمرین، همان برنامه‌ی طراحی گریدی را که تا قسمت 14 تکمیل کردیم، با معرفی مسیریابی بهبود خواهیم بخشید. برای این منظور یک NavBar بوت استرپی را به بالای صفحه اضافه می‌کنیم که دارای سه لینک movies ،customers و rentals است. به همین جهت نیاز به دو کامپوننت مقدماتی customers و rentals نیز وجود دارد که تنها یک h1 را نمایش می‌دهند. به علاوه منوی راهبری برنامه نیز باید بر اساس مسیر فعال جاری، با رنگ مشخصی، فعال بودن مسیریابی گزینه‌ی انتخابی را مشخص کند. در این برنامه اگر کاربر، آدرس نامعتبری را وارد کرد، باید به صفحه‌ی not-found هدایت شود. همچنین می‌خواهیم تمام عناوین فیلم‌های نمایش داده شده‌ی در جدول، تبدیل به لینک‌هایی به صفحه‌ی جدید جزئیات آن‌ها شوند. در این صفحه باید یک دکمه‌ی Save هم وجود داشته باشد تا با کلیک بر روی آن، به صورت خودکار به صفحه‌ی movies هدایت شویم.


برپایی پیش‌نیازها

ابتدا کتابخانه‌ی react-router-dom را نصب می‌کنیم:
 npm i react-router-dom --save
سپس کامپوننت App را با BrowserRouter آن در فایل index.js محصور می‌کنیم؛ تا کار انتقال مدیریت تاریخچه‌ی مرور صفحات در مرورگر، به درخت کامپوننت‌های React انجام شود:
import { BrowserRouter } from "react-router-dom";

//...

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById("root")
);


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

برای تکمیل نیازمندی‌هایی که در مقدمه عنوان شد، این کامپوننت‌های جدید را ایجاد می‌کنیم:
کامپوننت بدون حالت تابعی src\components\customers.jsx با این محتوا:
import React from "react";

const Customers = () => {
  return <h1>Customers</h1>;
};

export default Customers;

کامپوننت بدون حالت تابعی src\components\rentals.jsx با این محتوا:
import React from "react";

const Rentals = () => {
  return <h1>Rentals</h1>;
};

export default Rentals;

کامپوننت بدون حالت تابعی src\components\notFound.jsx با این محتوا:
import React from "react";

const NotFound = () => {
  return <h1>Not Found</h1>;
};

export default NotFound;

کامپوننت بدون حالت تابعی src\components\movieForm.jsx با این محتوا:
import React from "react";

const MovieForm = () => {
  return (
    <div>
      <h1>Movie Form</h1>
      <button className="btn btn-primary">Save</button>
    </div>
  );
};

export default MovieForm;


ثبت مسیریابی‌های مورد نیاز برنامه

پس از نصب کتابخانه‌ی مسیریابی و راه اندازی آن، اکنون نوبت به تعریف مسیریابی‌های مورد نیاز برنامه در فایل app.js است:
import "./App.css";

import React from "react";
import { Redirect, Route, Switch } from "react-router-dom";

import Customers from "./components/customers";
import Movies from "./components/movies";
import NotFound from "./components/notFound";
import Rentals from "./components/rentals";

function App() {
  return (
    <main className="container">
      <Switch>
        <Route path="/movies" component={Movies} />
        <Route path="/customers" component={Customers} />
        <Route path="/rentals" component={Rentals} />
        <Route path="/not-found" component={NotFound} />
        <Redirect to="/not-found" />
      </Switch>
    </main>
  );
}

export default App;
- در اینجا ابتدا چهار مسیریابی جدید را جهت نمایش صفحات کامپوننت‌هایی که ایجاد کردیم، تعریف و سپس نکته‌ی «مدیریت مسیرهای نامعتبر درخواستی» قسمت قبل را نیز با افزودن کامپوننت Redirect، پیاده سازی کرده‌ایم. به علاوه پیشتر نمایش کامپوننت Movies را داخل container تعریف شده داشتیم که اکنون با وجود این مسیریابی‌ها، نیازی به تعریف المان آن نیست و از return تعریف شده، حذف شده‌است.
تا اینجا اگر برنامه را اجرا کنیم، بلافاصله به http://localhost:3000/not-found هدایت می‌شویم. از این جهت که هنوز مسیریابی را برای / یا ریشه‌ی سایت که در ابتدا نمایش داده می‌شود، تنظیم نکرده‌ایم. به همین جهت Redirect زیر را پیش از آخرین Redirect تعریف شده اضافه می‌کنیم تا با درخواست ریشه‌ی سایت، به آدرس /movies هدایت شویم:
<Redirect from="/" to="/movies" />
و هانطور که در بخش 1 این قسمت بررسی کردیم، چون این مسیریابی با تمام آدرس‌های شروع شده‌ی با / تطابق پیدا می‌کند، وجود Switch در اینجا ضروری است؛ تا پس از انطباق با اولین مسیر ممکن، کار مسیریابی به پایان برسد. به علاوه با تعریف این Redirect، اگر مثلا آدرس نامعتبر http://localhost:3000/xyz را درخواست کنیم، به آدرس movies/ هدایت می‌شویم؛ چون / با xyz/ تطابق پیدا کرده و کار در همینجا به پایان می‌رسد. به همین جهت ذکر ویژگی exact در تعریف این Redirect ویژه ضروری است؛ تا صرفا به ریشه‌ی سایت پاسخ دهد:
<Redirect from="/" exact to="/movies" />


افزودن منوی راهبری به برنامه

ابتدا فایل جدید src\components\navBar.jsx را ایجاد می‌کنیم؛ با این محتوا:
import React from "react";
import { Link, NavLink } from "react-router-dom";

const NavBar = () => {
  return (
    <nav className="navbar navbar-expand-lg navbar-light bg-light">
      <Link className="navbar-brand" to="/">
        Home
      </Link>
      <button
        className="navbar-toggler"
        type="button"
        data-toggle="collapse"
        data-target="#navbarNavAltMarkup"
        aria-controls="navbarNavAltMarkup"
        aria-expanded="false"
        aria-label="Toggle navigation"
      >
        <span className="navbar-toggler-icon" />
      </button>
      <div className="collapse navbar-collapse" id="navbarNavAltMarkup">
        <div className="navbar-nav">
          <NavLink className="nav-item nav-link" to="/movies">
            Movies
          </NavLink>
          <NavLink className="nav-item nav-link" to="/customers">
            Customers
          </NavLink>
          <NavLink className="nav-item nav-link" to="/rentals">
            Rentals
          </NavLink>
        </div>
      </div>
    </nav>
  );
};

export default NavBar;
توضیحات:
- ساختار کلی NavBar ای را که ملاحظه می‌کنید، دقیقا از مثال‌های رسمی مستندات بوت استرپ 4 گرفته شده‌است و تمام classهای آن با className جایگزین شده‌اند.
- سپس تمام anchor‌های موجود در یک منوی راهبری بوت استرپ را به Link و یا NavLink تبدیل کرده‌ایم تا برنامه به صورت SPA عمل کند؛ یعنی با کلیک بر روی هر لینک، بارگذاری کامل صفحه در مرورگر صورت نگیرد و تنها محل و قسمتی که توسط کامپوننت‌های Route مشخص شده، به روز رسانی شوند. تفاوت NavLink با Link در کتابخانه‌ی react-router-dom، افزودن خودکار کلاس active به المانی است که بر روی آن کلیک شده‌است. به این ترتیب بهتر می‌توان تشخیص داد که هم اکنون در کجای منوی راهبری قرار داریم.
- پس از تبدیل anchor‌ها به Link و یا NavLink، مرحله‌ی بعد، تبدیل href‌های لینک‌های قبلی به ویژگی to است که هر کدام باید به یکی از مسیریابی‌های تنظیم شده، مقدار دهی گردد.

پس از تعریف کامپوننت منوی راهبری سایت، به app.js بازگشته و این کامپوننت را پیش از مسیریابی‌های تعریف شده اضافه می‌کنیم:
import NavBar from "./components/navBar";
// ...

function App() {
  return (
    <React.Fragment>
      <NavBar />
      <main className="container">
        // ...
      </main>
    </React.Fragment>
  );
}

export default App;
در اینجا چون نیاز به بازگشت دو المان NavBar و main وجود داشت، از React.Fragment برای محصور کردن آن‌ها استفاده کردیم.

به علاوه به فایل index.css برنامه مراجعه کرده و padding این navBar را صفر می‌کنیم تا از بالای صفحه و بدون فاصله‌ای نمایش داده شود و container اصلی نیز اندکی از پایین آن فاصله پیدا کند:
body {
  margin: 0;
  padding: 0 0 0 0;
  font-family: sans-serif;
}

.navbar {
  margin-bottom: 30px;
}

.clickable {
  cursor: pointer;
}
با این تغییر، اکنون ظاهر برنامه به صورت زیر در خواهد آمد:


اگر دقت کنید چون آدرس http://localhost:3000/movies در حال نمایش است، در منوی راهبری، گزینه‌ی متناظر با آن، با رنگی دیگر مشخص (فعال) شده‌است.


لینک کردن عناوین فیلم‌های نمایش داده شده به کامپوننت movieForm

برای تبدیل عناوین نمایش داده شده‌ی در جدول فیلم‌ها به لینک، به کامپوننت src\components\moviesTable.jsx مراجعه کرده و تغییرات زیر را اعمال می‌کنیم:
- در قدم اول باید بجای ذکر خاصیت Title در آرایه‌ی ستون‌های جدول:
class MoviesTable extends Component {
  columns = [
    { path: "title", label: "Title" },
یک محتوای لینک شده را نمایش دهیم:
class MoviesTable extends Component {
  columns = [
    {
      path: "title",
      label: "Title",
      content: movie => <Link to={`/movies/${movie._id}`}>{movie.title}</Link>
    },
در اینجا خاصیت content اضافه شده‌است تا یک المان React را مانند Link، بازگشت دهد و چون می‌خواهیم id هر فیلم نیز در اینجا ذکر شود، آن‌را به صورت arrow function تعریف کرده‌ایم تا شیء movie را گرفته و لینک به آن‌را تولید کند. در اینجا از یک template literal برای تولید پویای رشته‌ی منتسب به to استفاده کرده‌ایم.
همچنین این Link را هم باید در بالای این ماژول import کرد:
import { Link } from "react-router-dom";
تا اینجا عناوین فیلم‌ها را تبدیل به لینک‌هایی کردیم:



تعریف مسیریابی نمایش جزئیات یک فیلم انتخابی

اگر به تصویر فوق دقت کنید، به آدرس‌هایی مانند http://localhost:3000/movies/5b21ca3eeb7f6fbccd47181a رسیده‌ایم که به همراه id هر فیلم هستند. اکنون می‌خواهیم کلیک بر روی این لینک‌ها را جهت فعالسازی صفحه‌ی نمایش جزئیات فیلم، تنظیم کنیم. به همین جهت به فایل app.js مراجعه کرده و مسیریابی زیر را به ابتدای Switch تعریف شده اضافه می‌کنیم:
<Route path="/movies/:id" component={MovieForm} />
که نیاز به این import را هم دارد:
import MovieForm from "./components/movieForm";


تکمیل کامپوننت نمایش جزئیات یک فیلم

اکنون می‌خواهیم صفحه‌ی نمایش جزئیات فیلم، به همراه نمایش id فیلم باشد و همچنین با کلیک بر روی دکمه‌ی Save آن، کاربر را به صفحه‌ی movies هدایت کند. به همین جهت فایل src\components\movieForm.jsx را به صورت زیر ویرایش می‌کنیم:
import React from "react";

const MovieForm = ({ match, history }) => {
  return (
    <div>
      <h1>Movie Form {match.params.id} </h1>
      <button
        className="btn btn-primary"
        onClick={() => history.push("/movies")}
      >
        Save
      </button>
    </div>
  );
};

export default MovieForm;
توضیحات:
- چون این کامپوننت، یک کامپوننت تابعی بدون حالت است، props را باید از طریق آرگومان خود دریافت کند و البته در همینجا امکان Object Destructuring خواصی که از آن نیاز داریم، مهیا است؛ مانند { match, history } که ملاحظه می‌کنید.
- سپس شیء match، امکان دسترسی به params ارسالی به صفحه را مانند id فیلم، میسر می‌کند.
- با استفاده از شیء history و متد push آن می‌توان علاوه بر به روز رسانی تاریخچه‌ی مرورگر، به مسیر مشخص شده بازگشت که در همینجا و به صورت inline، تعریف شده‌است.


کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید: sample-17.zip
مطالب
توسعه برنامه‌های Cross Platform با Xamarin Forms & Bit Framework - قسمت هجدهم
در این قسمت می‌خواهیم با Rest Api ارتباط برقرار کنیم. به جای نوشتن سمت سرور، از یک سرور آماده استفاده می‌کنیم که مثال اول آن، LIST USERS است و لیست کاربران را نمایش می‌دهد. توضیحات این قسمت به فراخوانی سرویس‌های Rest ارتباط دارد، با پروتکل HTTP و دیتای JSON. البته فراخوانی سرویس‌های SOAP نیز ساده است که در این آموزش به آنها نمی‌پردازیم.
برای این کار از HttpClient استفاده می‌کنیم. استفاده کردن از WebClient و WebRequest اشتباه محض هست و این دو را کلا فراموش کنید. مطمئن باشید هر کدی که با آن دو در اینترنت پیدا می‌کنید، با HttpClient هم قابلیت پیاده سازی را دارند و مطمئن باشید که اگر از آن دو کلاس استفاده کنید، حتما به دردسر بدی میافتید. در زمان استفاده از HttpClient هم در نظر بگیرید که نباید مدام HttpClient را new و dispose کنید. این کار اشتباه است و یک HTTP client برای شما کافی است. ساختن HTTP client نکات  بسیاری دارد که در همین سایت به آنها پرداخته شده‌است. در Xamarin دغدغه‌های استفاده از Network Stack هر سیستم عامل نیز به لیست مواردی که باید به آنها دقت کنید اضافه می‌شوند. می‌توانید درگیر تمامی این موارد شوید، یا برای سادگی بیشتر، ضمن نصب پکیج Bit.CSharpClient.Rest که کدهای آن نیز در GitHub قرار داده شده‌اند، صرفا HTTP Client را بگیرید و به هر جایی که دوست دارید Request بزنید. لزومی به اینکه در سمت سرور از Bit استفاده کرده باشید تا بتوانید از Bit.CSharpClient.Rest استفاده کنید نیست.

خب، پس Package مربوطه را نصب و در App.xaml.cs کدهای زیر را استفاده کنید:
//قرار دهید containerBuilder.RegisterRequiredServices(); این دو را بعد از
containerBuilder.RegisterHttpClient();
containerBuilder.RegisterIdentityClient();
در View Model ای که قصد استفاده از Http Client را دارید، یک Property از جنس Http Client تعریف کنید و برای خواندن اطلاعات مثال، کد زیر را بزنید:
توضیحات این کد در ادامه آمده است.
public virtual HttpClient HttpClient { get; set; } 

async Task CallUsersListApiUsingHttpClient()
{
    HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "https://reqres.in/api/users");
    // Use request.Headers to set jwt token, ...
    // Use request.Content to send body. You can use StringContent, StreamContent, etc.
    HttpResponseMessage response = await HttpClient.SendAsync(request);
    response.EnsureSuccessStatusCode();
    using (StreamReader streamReader = new StreamReader(await response.Content.ReadAsStreamAsync()))
    using (JsonReader jsonReader = new JsonTextReader(streamReader))
    {
        List<UserDto> users = (await JToken.LoadAsync(jsonReader))["data"].ToObject<List<UserDto>>();
    }
}
برای درک بهتر این کد، بعد از Clone/Pull کردن آخرین وضعیت پروژه XamApp به سراغ کلاس RestSamplesViewModel بروید. فراخوانی https://reqres.in/api/users چنین JSON ای را بر می‌گرداند: 
{
    "page": 2,
    "per_page": 3,
    "total": 12,
    "total_pages": 4,
    "data": [
        {
            "id": 4,
            "first_name": "Eve",
            "last_name": "Holt",
            "avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/marcoramires/128.jpg"
        },
        {
            "id": 5,
            "first_name": "Charles",
            "last_name": "Morris",
            "avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/stephenmoon/128.jpg"
        }
    ]
}

قسمت‌های مختلف این JSON برای ما اهمیتی ندارند و تنها قسمت data آن که اطلاعات user‌ها را شامل می‌شود، برای ما اهمیت دارند. صد البته که هر سروری، دیتای JSON را با ساختاری که دوست داشته باشد بر می‌گرداند. در کدی که نوشته‌ایم، ابتدا یک HttpRequestMessage را ساخته‌ایم. این HttpRequestMessage از نوع Get و به آدرس https://reqres.in/api/users است. می‌توان روی HttpRequestMessage هم هدرهای مختلفی را تنظیم نمود و هم می‌توان به آن Content داد.
سپس آن را با HttpClient.SendAsync ارسال می‌کنیم و با فراخوانی EnsureSuccessStatusCode مطمئن می‌شویم که خطا نداده‌است. برای خواندن Response با بالاترین Performance ممکن، ابتدا از StreamReader برای خواندن Stream دریافتی استفاده می‌کنیم. با توجه به JSON بودن Response دریافتی، از JsonTextReader و JToken استفاده می‌کنیم (این مورد هیچ ربطی به JWT یا Json Web Token ندارد!). بعد از Load کردن آن، قسمت ["data"] را به لیستی از کلاس UserDto تبدیل می‌کنیم. Dto مخفف Data Transfer Object است و دیتایی است که ما یا ارسال می‌کنیم یا در همین سناریو مثال، از سرور دریافت می‌کنیم. کد کلاس UserDto:
public class UserDto
{
    [JsonProperty("id")]
    public int Id { get; set; }
    [JsonProperty("first_name")]
    public string FirstName { get; set; }
    [JsonProperty("last_name")]
    public string LastName { get; set; }
    [JsonProperty("avatar")]
    public string Avatar { get; set; }
}
البته Http Client فقط برای ارسال یا دریافت JSON نیست. می‌توان با آن فایل و Xml و ... نیز ارسال و دریافت نمود. در این قسمت مهم نبود که سرور شما با چه تکنولوژی ای توسعه داده شده‌است. صرف بودن سرور روی پروتکل Http کافی است. واضح است که شما دارید از HttpClient استفاده می‌کنید. در صورتیکه سرور TCP باشد، شما در CSharp می‌توانید از TcpClient و Socket استفاده کنید. اگر سمت سرور شما Wcf یا OData یا Graphql باشد نیز کلاینت‌های خودشان را در CSharp دارید و می‌توانید در پروژه‌تان از تمامی آنها استفاده کنید که آموزش همه این موارد از حوصله این قسمت خارج است؛ اما در صورتیکه سمت سرور شما نیز با Bit توسعه داده شده باشد، می‌توانید با روش‌های خیلی بهتری به سرور خود وصل شوید که این موضوع قسمت‌های بعدی آموزش است.