اعتبارسنجی دادههای ورودی
شاید بسیار اتفاق افتاده باشد در فیلد ورودی یک فرم با پیغام “آدرس ایمیل شما نامعتبر است”، روبرو شده باشید. اعتبارسنجی یکی از پایهایترین مکانیزمهایی است که توسط برنامهنویسان مورد استفاده قرار میگیرد. اعتبارسنجی نه تنها به شما کمک میکند برنامه قدرتمندی را طراحی کنید؛ بلکه در بسیاری از موارد از بروز مشکلات امنیتی ممانعت میکند. حملات تزریق کد SQL بارزترین مثالی است که در این زمینه میتوان به آن اشاره کرد. در این مدل حملات اگر تیم برنامهنویسی از مکانیزمهای درستی برای اعتبارسنجی استفاده نکرده باشند، یک هکر به راحتی توانایی ناپدید ساختن جدولها یا حتی یک بانک اطلاعات را از روی یک سرور، خواهد داشت. برای پیشگیری از بروز چنین مشکلاتی داتنت مکانیزم اعتبارسنجی دادههای ورودی را با عبارت با قاعده و از طریق کلاس Regex پیشنهاد داده است. در این فرآیند رشتههای ورودی با الگویی که توسط برنامهنویس آماده میشود، مورد بررسی قرار میگیرد تا از صحت آنها اطمینان حاصل شود؛ اما پیادهسازی یک الگوی با قاعده و درست که توانایی ارزیابی ساختار و محتوای دادهای را داشته باشد، کار چندان سادهای نیست. بهترین ابزاری که در این زمینه توصیه میشود، Regulator است. (این ابزار روی این مخزن قرار دارد). ابزاری که توانایی ساخت عبارات با قاعده قدرتمند را دارد. بهطور کلی یک عبارت با قاعده از دو بخش تشکیل میشود: literals برای نشان دادن کاراکترهای ویژهای است که در یک الگو مورد استفاده قرار میگیرد و دوم Mecacharacters که برای پشتیبانی از گروهبندی تکرارها، شرطها، Wildcardها، حوزهها (Scope) و دیگر مکانیزمهای کنترلی مورد استفاده قرار میگیرد. قطعه کدی که در فهرست شماره یک مشاهده میکنید، برای اعتبارسنجی یک آدرس ایمیل مورد استفاده قرار گرفته است.
using System;
using System.Text.RegularExpressions;
static void Main(string[] args)
{
Console.Write(“Enter your email address: “);
string readaddress = Console.ReadLine();
string regularexpression = @”^[\w-]+@([\w-]+\.)+[\w-]+$”;
Console.WriteLine(“Regular Expression is : {0}\nYour value:{1}”, regularexpression, readaddress);
Regex r = new Regex(regularexpression);
Console.WriteLine(“Valid = {0}”, r.IsMatch(readaddress));
}
شکل۱: فرآیند ارزیابی یک آدرس ایمیل معتبر و یک آدرس ایمیل نامعتبر را با استفاده از این قطعه کد، نشان میدهد.
فرآیند خواندن و نوشتن به فایلهای باینری
بعضی مواقع ضرورت ایجاب میکند به جای نوشتن دادهها در یک فایل متنی، دادهها در یک فایل باینری نوشته شوند. فرآیند خواندن و نوشتن فایلها با کلاس FileStream انجام میشود. برای این منظور ابتدا از سازنده این کلاس برای ایجاد فایل باینری استفاده میکنیم؛ در ادامه فرآیند نوشتن به فایل با استفاده از متدهای BianaryWrite و Write انجام میشود. در نقطه مقابل برای خواندن دادهها از فایلهای باینری از متدهای Read و ReadBianary استفاده میکنیم. در زمان کار با فایلهای باینری به یکسان بودن نوع دادههای تعریف شده در برنامه کاربردی و نوع دادههایی که از فایل باینری خوانده میشوند، دقت کنید؛ بهطور مثال اگر در زمان نوشتن به یک فایل باینری از نوع Decimal استفاده کردهاید، دقت کنید در زمان خواندن باید از متد RealDecimal استفاده کنید. فهرست شماره ۲ فرآیند خواندن و نوشتن به یک فایل باینری را نشان میدهد.
using System.IO;
static void Main(string[] args)
{
using (FileStream fs = new FileStream(“c:\\binaryfile.bin”, FileMode.Create))
{
using (BinaryWriter w = new BinaryWriter(fs))
{
w.Write(156.55M);
w.Write(“Hi every one!”);
w.Write(‘D’);
}
}
Console.WriteLine(“*******Reading from binary file********\n”);
using (FileStream fs = new FileStream(“c:\\binaryfile.bin”, FileMode.Open))
{
using (StreamReader SReader = new StreamReader(fs))
{
using (BinaryReader brinary = new BinaryReader(fs))
{
Console.WriteLine(brinary.ReadDecimal());
Console.WriteLine(brinary.ReadString());
Console.WriteLine(brinary.ReadChar());
}
}
}
}
نمایش فایلها در یک قالب درختی
برنامههای حرفهای به جای آنکه فایلها و پوشهها را به صورت ساده و معمولی به کاربر نشان دهند، از یک کنترل TreeView برای نمایش آنها در قالب درختی و سلسلهوار استفاده میکنند. این موضوع نه تنها باعث دسترسی سادهتر به فایلها میشود؛، بلکه برنامه کاربردی را حرفهایتر نشان میدهد. این تکنیک به سادگی پیادهسازی میشود؛ ابتدا باید پوشهها را به کنترل TreeView اضافه و در ادامه، گرههای مرتبط با شاخههایی که به پوشهها منصوب شدهاند را اضافه کنید. فهرست شماره ۳، نحوه پیادهسازی این مکانیزم را نشان میدهد.
using System.Windows.Forms;
using System.IO;
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
TreeNode rootNode = new TreeNode(@”C:\Windows”);
ShowFolders.Nodes.Add(rootNode);
FillNode(rootNode);
ShowFolders.Nodes[0].Expand();
}
private void FillNode(TreeNode dirNode)
{
DirectoryInfo dir = new DirectoryInfo(dirNode.FullPath);
foreach (DirectoryInfo myItems in dir.GetDirectories())
{
TreeNode newNode = new TreeNode(myItems.Name);
dirNode.Nodes.Add(newNode);
newNode.Nodes.Add(“*”);
}
}
private void treeView1_AfterExpand(object sender, TreeViewEventArgs e)
{
if (e.Node.Nodes[0].Text == “*”)
{
e.Node.Nodes.Clear();
FillNode(e.Node);
}
}
}
خروجی فهرست شماره ۲ را در شکل شماره ۳ مشاهده میکنید.
کپی کردن فایلها و پوشهها
داتنت برای کپی کردن فایلها کلاسهای DirectoryInfo و FileInfo را در اختیار برنامهنویسان قرار داده است. با استفاده از متدهای قرار گرفته شده در این کلاسها به راحتی توانایی کپی کردن فایلها و پوشهها را خواهید داشت. (فهرست شماره ۴)
static void Main(string[] args)
{
DirectoryInfo source = new DirectoryInfo(@”c:\01″);
DirectoryInfo destination = new DirectoryInfo(@”c:\02″);
CopyFolder(source, destination);
}
static void CopyFolder(DirectoryInfo path1, DirectoryInfo path2)
{
if (!path2.Exists)
{
path2.Create();
}
foreach (FileInfo file in path1.EnumerateFiles())
{
file.CopyTo(Path.Combine(path2.FullName, file.Name));
}
foreach (DirectoryInfo dir in path2.EnumerateDirectories())
{
string destinationDir = Path.Combine(path2.FullName, dir.Name);
CopyFolder(dir, new DirectoryInfo(destinationDir));
}
}
پردازهها
پردازهها اصلیترین مؤلفه هر سیستمعاملی به شمار میروند. تمامی کاربران دنیای کامپیوتر به طور مستقیم و غیر مستقیم از پردازهها استفاده میکنند. زمانی که برنامهای اجرا میشود، سیستمعامل پردازهای برای برنامه کاربردی ایجاد میکند. درون این پردازه، دریایی از اطلاعات وجود دارد که توسط پردازنده مرکزی کامپیوتر و ریسمان اصلی ویندوز کنترل میشوند.
ایجاد پردازه
پردازهها با استفاده از کلاس Process و متد Start ایجاد میشوند. متد Start این توانایی را دارد تا یک برنامه را بهطور مستقل اجرا یا برنامه را مجبور سازد فایلی را اجرا کند. در فهرست شماره ۵ اگر یک فایل تصویری به نام myimage.Jpg در مسیر C:\ وجود داشته باشد، برنامه mspaint آن فایل را باز خواهد کرد. فهرست ۵ فایل myimage.Jpg را در برنامه نقاشی ویندوز باز خواهد کرد. ( اگر از ساختار ProcessStartInfo همراه با متد start استفاده کنید، کنترل بیشتری بر روند ساخت یک پردازه خواهید داشت).
using System.Diagnostics;
….
static void Main(string[] args)
{
ProcessStartInfo processinfo = new ProcessStartInfo();
processinfo.Arguments = “c:\\myimage.jpg”;
processinfo.FileName = “mspaint.exe”;
processinfo.WindowStyle = ProcessWindowStyle.Maximized;
Process.Start(processinfo);
}
به دست اطلاعاتی درباره یک پردازه
متد GetProcessesByName این توانایی را دارد تا نام یک پردازه را دریافت کند و اطلاعات مرتبط با پردازه موجود در حافظه اصلی را نشان دهد. خروجی متد GetProcessesByName آرایهای از نوع Process است که جزییات مرتبط با یک پردازه را نشان میدهد. (فهرست ۶) متد GetProcessesByName نام یک پردازه را به عنوان پارامتر ورودی خود دریافت میکند.
static void Main(string[] args)
{
Process.Start(“chrome.exe”);
String name = “chrome.exe”;
Process[] processes = Process.GetProcessesByName(name);
Console.WriteLine(“{0} has {1} processes”, name, processes.Length);
foreach (Process p in processes)
Console.WriteLine(“process name: {0} , process ID: {1} Threads: {2} Handles: {3}”, p.ProcessName, p.Id, p.Threads.Count, p.HandleCount);
}
یک پردازه از چه ماژولهایی استفاده میکند؟
ماژولهای یک پردازه کتابخانههای پویا (dll) و دیگر مؤلفههایی هستند که در مدت زمان اجرا توسط یک برنامه مورد استفاده قرار میگیرند؛ اما همانگونه که در بخش قبل به آن اشاره کردیم، ابتدا باید نام پردازه مورد نظر خود را به دست آورید. سادهترین راه دسترسی به نام یک پردازه با استفاده از شماره شناسایی منحصر به فردی است که ویندوز به پردازهها اختصاص میدهد. این شماره منحصر به فرد PID نام دارد. ابزار Task Manager ویندوز PID مربوط به هر پردازه را به شما نشان میدهد؛ بهطور مثال فهرست شماره ۷، ماژولهای مورد استفاده در برنامه جاری ( برنامه کنسول) را نشان میدهد.
static void Main(string[] args)
{
Process process = null;
try
{
process = Process.GetCurrentProcess();
}
catch (ArgumentException ex)
{
Console.WriteLine(ex.Message);
}
Console.WriteLine(” These modules are loaded with: {0}”, process.ProcessName);
foreach (ProcessModule pm in process.Modules)
{
Console.WriteLine(“\tModule Name: {0}”, pm.ModuleName);
}
}
خروجی قطعه کد شماره ۷ را در شکل ۳ مشاهده می کنید.
اجرای تنها یک نمونه از یک برنامه کاربردی
بسیاری از شرکتهای تولید کننده نرمافزارهای کاربردی، برنامه خود را به گونهای طراحی میکنند که در یک لحظه تنها یک نمونه از یک برنامه کاربردی اجرا شود. تکنیکهای مختلفی برای پیادهسازی این روش وجود دارد. کلاس Mutex که در فضای نام threading قرار دارد، برای این منظور طراحی شده است. کلاس Mutex قبل از آن که برنامهای اجرا شود، حافظه اصلی را برای یک نمونه دیگر مورد بررسی قرار میدهد. برای این منظور کلاس Mutex یک پارامتر رشتهای دارد که در آن نام برنامه مورد نظر را دریافت میکند (فهرست شماره ۸).
using System.Threading;
static void Main(string[] args)
{
bool BMutex;
using (Mutex mutex = new Mutex(true, “MyApplication”, out BMutex))
{
if (BMutex)
{
Console.WriteLine(“No problems.”);
Console.ReadLine();
mutex.ReleaseMutex();
}
else
{
Console.WriteLine(“Another example of this application is running”);
}
}
}
در فهرست شماره ۸، اگر یک نمونه از این برنامه کاربردی در حال اجرا باشد و کاربر سعی کند نمونه دیگری را اجرا کند، پیغام خطایی دریافت خواهد کرد