NOSQL قسمت سوم
در مطلب قبلی با نوع اول پایگاههایداده NoSQL یعنی Key/Value Store آشنا شدیم و در این مطلب به معرفی دسته دوم یعنی Document Database خواهیم پرداخت.
در این نوع پایگاه داده ، دادهها مانند نوع اول در قالب
کلید/مقدار ذخیره میشوند و بازگردانی مقادیر نیز دقیقا مشابه نوع اول یعنی Key/Value Store بر اساس کلید میباشد. اما
تفاوت این سیستم با نوع اول در دستهبندی دادههای مرتبط با یکدیگر در قالب یک Document میباشد. سعی کردم در این مطلب با ذکر مثال مطالب را شفافتر بیان کنم:
به عنوان مثال اگر بخواهیم جداول مربوط به پستهای یک سیستم CMS را بصورت رابطهای پیاده کنیم ، یکی از سادهترین حالات پایه برای پستهای این سیستم در حالت نرمال به صورت زیر میباشد.
جداول واضح بوده و نیازی به توضیح ندارد ، حال نحوهی ذخیرهسازی دادهها در سیستم Document Database برای چنین مثالی را بررسی میکنیم:
{ _id: ObjectID(‘4bf9e8e17cef4644108761bb’), Title: ‘NoSQL Part3’, url: ‘https://www.dntips.ir/yyy/xxxx’, author: ‘hamid samani’, tags: [‘databases’,’mongoDB’], comments:[ {user: ‘unknown user’, text:’unknown test’ }, {user:unknown user2’, text:’unknown text2 } ] }
همانگونه که مشاهد میکنید نحوهی ذخیرهسازی دادهها بسیار با سیستم رابطهای متفاوت میباشد ، با جمعبندی تفاوت نحوهی نگهداری دادهها در این سیستم و RDBMS و بررسی این سیستم نکات اصلی به شرح زیر میباشند:
۱-فرمت ذخیره سازی دادهها مشابه فرمت JSON میباشد.
۲-به مجموعه دادههای مرتبط به یکدیگر Document گفته میشود.
۳-در این سیستم JOIN ها وجود ندارند و دادههای مرتبط کنار یکدیگر قرار میگیرند ، و یا به تعریف دقیقتر دادهها در یک داکیومنت اصلی Embed میشوند.
به عنوان مثال در اینجا مقدار commentها برابر با آرایهای از Documentها میباشد.
۴-مقادیر میتوانند بصورت آرایه نیز در نظر گرفته شوند.
۵-در سیستمهای RDBMS در صورتی که بخواهیم از وجود JOINها صرفنظر کنیم. به عدم توانایی در نرمالسازی برخواهیم خورد که یکی از معایب عدم نرمالسازی وجود مقادیر Null در جداول میباشد؛ اما در این سیستم به دلیل Schema free بودن میتوان ساختارهای متفاوت برای Documentها در نظر گرفت.
به عنوان مثال برای یک پست میتوان مقدار n کامنت تعریف کرد و برای پست دیگر هیچ کامنتی تعریف نکرد.
۶-در این سیستم اصولا نیازی به تعریف ساختار از قبل موجود
نمیباشد و به محض اعلان دستور قرار دادن دادهها در پایگاهداده ساختار متناسب
ایجاد میشود.
با مقایسه دستورات CRUD در هر دو نوع پایگاه داده با نحوهی کوئری گرفتن از Document Database آشنا میشویم:
در SQL برای ایجاد جدول خواهیم داشت:
CREATE TABLE posts ( id INT NOT NULL AUTO_INCREMENT, author_id INT NOT NULL, url VARCHAR(50), PRIMARY KEY (id) )
دستور فوق در Document Database معادل است با:
db.posts.insert({id: “256” , author_id:”546”,url:"http://example.com/xxx"}) // با قرار دادن مقدار نوع ساختار مشخص میشود
در SQL جهت خواندن خواهیم داشت:
SELECT * from posts WHERE author_id > 100
db.posts.find({author_id:{$gt:”1000”}})
در SQL جهت بروزرسانی داریم:
UPDATE posts SET author_id= "123"
db.posts.update({ $set: { author_id: "123" }})
در SQL جهت حذف خواهیم داشت:
DELETE FROM posts WHERE author_id= "654"
که معادل است با:
db.posts.remove( { author_id: "654" } )
همانگونه که مشاهده میفرمایید نوشتن کوئری برای این پایگاه داده ساده بوده و زبان آن نیز بر پایه جاوا اسکریپت میباشد که برای اکثر برنامهنویسان قابل درک است.
تاکنون توسط شرکتهای مختلف پیادهسازیهای مختلفی از این سیستم انجام شده است که از مهمترین و پر استفادهترین آنها میتوان به موارد زیر اشاره کرد:
کتابخانه Hangfire
An easy way to perform background job processing in your .NET and .NET Core applications. No Windows Service or separate process required. CPU and I/O intensive, long-running and short-running jobs are supported. Backed by Redis, SQL Server, SQL Azure and MSMQ.
PM> Install-Package Hangfire
After installation, update your existing OWIN Startup file with the following lines of code. If you do not have this class in your project or don't know what is it, please read the Quick start guide to learn about how to install Hangfire.
public void Configuration(IAppBuilder app)
{
GlobalConfiguration.Configuration.UseSqlServerStorage("<connection string or its name>");
app.UseHangfireServer();
app.UseHangfireDashboard();
}
یافتن مقادیر نال در Entity framework
ممنون از مطلب مفیدتون راستش من به این نکته ای که فرمودین توجه نکرده بودم. من دستوراتی را روی دیتابیس northwind اجرا کردم که اولین دستور به این صورت بود:
rg = ent.regions.where(x => x.regionid != null).tolist();
این دستور در sql server به اینصورت تبدیل میشود :
select [extent1].[regionid] as [regionid], [extent1].[regiondescription] as [regiondescription] from [dbo].[region] as [extent1]
آیا اینکه اصلا در دستور sql ما چک کردن برای null نداریم به این خاطر است که ef بطور اتوماتیک
چک میکند که فیلد regionid از نوع nullable هست و چنانچه نباشه اصلا شرط رو دخالت نمیده؟
من در گام بعدی این دستور را اجرا کردم :
rg = ent.regions.where(x => x.regiondescription == null).tolist();
که خروجی آن به این صورت بود:
select cast(null as int) as [c1], cast(null as varchar(1)) as [c2] from ( select 1 as x ) as [singlerowtable1] where 1 = 0
میخواستم اگر ممکنه کمی راجع به این دستور توضیح بفرمایید آیا این دستور همون کار is null رو انجام میده یا خیر.
باز هم سپاسگزارم
مایکروسافت سه ابزار امنیتی رایگان جدید را جهت توسعه دهندگان وب ارائه داده است که فعلا در مرحله آزمایش به سر میبرند و قرار است این مجموعه به صورت جرئی از مجموعه power tools ویژوال استودیو 2010 ارائه شوند. این سه ابزار به شرح زیر هستند:
الف) CAT.NET 2.0 CTP
CAT.NET کاملا از صفر بازنویسی شده و از موتور جدیدی کمک میگیرد. نگارش CTP فعلی آن فقط از طریق خط فرمان قابل اجرا است.
دریافت
ب) WACA 1.0 CTP
نام این ابزار مخفف Web Application Configuration Analyzer است که جهت بررسی تنظیمات برنامههای وب شما، همچنین IIS و SQL Server بکار میرود و نقایص امنیتی آنها را گوشزد خواهد کرد.
دریافت
ج) WPL 1.0 CTP
نام این ابزار مخفف Web Protection Library است. این ابزار شبیه به یک فایروال جهت برنامههای وب شما در مقابل حملات XSS و SQL injection عمل میکند و بدون نیاز به تغییر کد (با کمک یک HTTP Module)، محافظت قابل توجهی را ارائه خواهد داد.
دریافت
معرفی سرویسهای ارائه شده توسط شرکتهای گوگل، آمازون و مایکروسافت در قالب رایانش ابری - قسمت دوم
سرویسها و اجزای وب سرویس آمازون:
وب سرویسهای آمازون دارای اجزای زیادی میباشند. تعدادی از این سرویسها برای ارائه خدمات پردازشی و تعداد دیگری برای ارائه فضای ذخیرهسازی، عرضه شدهاند. در ادامه گروهی از این سرویسها معرفی میگردد:
- ابر محاسباتی توسعه پذیر آمازون (EC2)
- سرویس صف ساده آمازون(Simple Queue Service): یک صف پیام یا سیستم تراکنش برای برنامههای مبتنی بر اینترنت توزیع شده میباشد. این سرویس تضمین میکند که پیامها حتی در زمانی که مؤلفهای موجود نیست، گم نشود و برای انتقال پیام میان مؤلفههای مختلف که هرکدام کار جداگانهای را انجام میدهند، بسیار مناسب است.
- سرویس
آگاه سازی ساده آمازون(Simple Notification Service): ): وب سرویسی است که میتواند پیام
یک برنامه را منتشر کند و آنها را به برنامهها یا مشترکین دیگر منتقل کند. SNS متدی
را برای راهاندازی فعالیتها ارائه مینماید که برنامهها را قادر میسازد تا در
مورد اطلاعات جدید یا تغییر یافته از آنها نظرسنجی شود یا به روز رسانیها را
انجام دهند.
- سرویس
نظارت ابر آمازون(Amazon Cloud Watch): کنسولی
را فراهم میکند که در آن مصرف منابع، شاخصهای کلیدی عملکرد سایت و نشانگرهای
عملیاتی برای عواملی همچون تقاضای پردازشگر، مصرف دیسک و ورودی و خروجی شبکه را
ارائه میدهد. نتایج
معیارهایی که توسط آن کسب میشود برای فعالسازی قابلیتی به نام Auto Scaling مورد
استفاده قرار میگیرد که به صورت خودکار میتواند یک سایت EC2 را بر مبنای مجموعهای از قوانین
که توسعه دهنده ایجاد میکند، توسعه دهد.
- توازن بار منعطف(Elastic Load Balancing): نمونههای ماشین آمازون(Amazon Machine Image) با استفاده از این قابلیت، دارای امکان توازن بار ترافیکی میشوند. این قابلیت هنگامی که نمونهای دچار شکست میشود آن را کشف کرده و ترافیک را به یک نمونه سالم حتی نمونهای در محیطهای دیگر AWS مسیریابی مجدد میکند.
قیمت گذاری انواع مختلف نمونه ماشین آمازون به سه پارامتر وابسته است. اولین مورد سیستم عامل مورد استفاده است. دومین عامل مرکز دادهای است که در آن قرار گرفته و سومین عامل مدت زمانی است که اجرا میشود. نرخها بر مبنای ساعت محاسبه میشوند. علاوه بر آن مبالغ اضافی نیز بابت موارد زیر اخذ میشود:
- میزان داده
منتقل شده
- آدرسهای IP اختصاصی
- استفاده
سرور اختصاصی مجازی از فضای ذخیرهسازی بلوکی توسعه پذیر آمازون
- استفاده از توازن بار توسعه پذیر برای دو یا چند سرور
- سایر
ویژگیهای مورد نیاز
- نمونه
مبتنی بر تقاضا: نرخ
ساعتی بدون التزام طولانی مدت
-
نمونه رزرو شده: خرید قراردادی هر نمونه با هزینه به مراتب پایینتر به ازای هر ساعت بعد از رزرو اولیه
-
نمونه نقطهای: این متد برای قیمت گذاری بر روی ظرفیت استفاده نشده EC2 بر مبنای قیمت نقطه فعلی است. این قابلیت، قیمتهای بسیار پایین را به همراه خواهد داشت اما در زمانهای مختلف فرق میکند یا در زمانی که ظرفیت مازادی نباشد، در دسترس نخواهد بود.
نوع | موتور محاسبه | حافظه اصلی(GB) | ذخیره سازی(GB) | سکو |
ریز نمونه | تا دو واحد محاسباتی در انفجار بار | 0.613 | EBS | 32 یا 64 بیتی |
نمونه کوچک | یک واحد محاسباتی | 1.7 | 160 | 32 بیتی |
نمونه بزرگ | چهار واحد محاسباتی | 7.5 | 850 | 64 بیتی |
نمونه بسیار بزرگ | هشت واحد محاسباتی | 15 | 1690 | 64 بیتی |
بررسی روش ارتقاء به NET Core 1.1.
آخرین نگارشی را که میتوانید بدون مشکل با VS 2015 اجرا کنید، 1.0.0-preview2-1-003177 است (واقع در پوشهی C:\Program Files\dotnet\sdk). پس از آن، این سیستم از نگارش JSON ایی فعلی به XML ایی تغییر کردهاست و ابزارهای آن فقط برای VS 2017 ارائه شدهاند و VS 2015 از این لحاظ دیگر هیچ پشتیبانی نخواهد داشت (حتی NuGet 4.0 هم برای آن به روز رسانی نشدهاست).
اگر برای مثال SDK مربوط به .NET Core 1.1.1. را نصب کنید و سپس فایل global.json را به 1.0.1 تغییر دهید:
C:\Users\Vahid>dotnet --version 1.0.1
The following error occurred attempting to run the project model server process (1.0.1). Unable to start the process. No executable found matching command "dotnet-projectmodel-server"
اگر برای مثال SDK مربوط به .NET Core 1.1.1. را نصب کنید، درون VS 2015 قادر به Restore بستههای نیوگت نخواهید شد و با پیام خطای ذیل مواجه میشوید:
\.vs\restore.dg(1,1): error MSB4025: The project file could not be loaded. Data at the root level is invalid. Line 1, position 1.
1- ارتقاء به VS 2017 و فراموش کردن VS 2015
2- استفاده از VS 2015 و بازیابی بستهها از طریق خط فرمان (چون دیگر ابزارهای VS 2015 با نگارش جدید SDK سازگار نیستند)
برای این منظور دقت کنید در پنجرهی output ویژوال استودیوی 2015، چه فرمانی صادر شدهاست که سبب بروز خطای فوق گردیدهاست:
"C:\Program Files\dotnet\dotnet.exe" restore "D:\project1\.vs\restore.dg"
پس از آن پروژه بدون مشکل Build میشود (در داخل VS 2015).
3- و یا ... این SDK جدید 1.0.1 را حذف کنید از سیستم (اگر میخواهید با VS 2015 بدون دردسر کار کنید).
و یا کلا به VSCode مهاجرت کنید و VS کامل را فراموش کنید. VSCode با ابزارهای خط فرمان NET Core. کار میکند و در این حالت به سادگی میتوان همواره آخرین نگارش NET Core. را مورد استفاده قرار داد؛ بدون نگرانی از سازگاری ابزارهای ویژوال استودیو با آن. چون اساسا هیچ نوع وابستگی به این ابزارها ندارد. همچنین حجم بسیار کمتری هم داشته و اگر با دریافت VS 2017 مشکل دارید، مهاجرت به VSCode انتخاب بسیار مناسبی است.
خلاصهی بحث
از این پس برای کار کردن بدون دردسر با نگارشهای جدید NET Core. تنها دو راه را پیش رو دارید: مهاجرت به VS 2017 و یا مهاجرت به VSCode.
یکی دیگر از ماژولهایی که امکان اتصال Node.js را به SQL Server ممکن میکند، Edge.js است. Edge.js یک ماژول Node.js است که امکان اجرای کدهای دات نت را در همان پروسه توسط Node.js فراهم میکند. این مسئله، توسعه دهندگان Node.js را قادر میسازد تا از فناوریهایی که به صورت سنتی استفادهی از آنها سخت یا غیر ممکن بوده است را به راحتی استفاده کنند. برای نمونه:
- SQL Server
- Active Directory
- Nuget packages
- استفاده از سخت افزار کامپیوتر (مانند وب کم، میکروفن و چاپگر)
نصب Node.js
اگر Node.js را بر روی سیستم خود نصب ندارید، میتوانید از اینجا آن را دانلود کنید. بعد از نصب برای اطمینان از کارکرد آن، command prompt را باز کرده و دستور زیر را تایپ کنید:
node -v
ایجاد پوشه پروژه
سپس پوشهای را برای پروژه Node.js خود ایجاد کنید. مثلا با استفاده از command prompt و دستور زیر:
md \projects\node-edge-test1 cd \projects\node-edge-test1
نصب Edge.js
Node با استفاده از package manager خود دانلود و نصب ماژولها را خیلی آسان کرده است. برای نصب، در command prompt عبارت زیر را تایپ کنید:
npm install edge npm install edge-sql
Hello World
ایجاد یک فایل متنی با نام server.js و نوشتن کد زیر در آن:var edge = require('edge'); // The text in edge.func() is C# code var helloWorld = edge.func('async (input) => { return input.ToString(); }'); helloWorld('Hello World!', function (error, result) { if (error) throw error; console.log(result); });
node server.js
ایجاد پایگاه داده تست
در مثالهای بعدی، نیاز به یک پایگاه داده داریم تا queryها را اجرا کنیم. در صورتی که SQL Server بر روی سیستم شما نصب نیست، میتوانید نسخهی رایگان آن را از اینجا دانلود و نصب کنید. همچنین SQL Management Studio Express را نیز نصب کنید.
- در SQL Management Studio، یک پایگاه داده را با نام node-test با تنظیمات پیش فرض ایجاد کنید.
- بر روی پایگاه داده node-test راست کلیک کرده و New Query را انتخاب کنید.
- اسکریپت زیر را copy کرده و در آنجا paste کنید، سپس بر روی Execute کلیک کنید.
IF EXISTS(SELECT 1 FROM sys.tables WHERE object_id = OBJECT_ID('SampleUsers')) BEGIN; DROP TABLE SampleUsers; END; GO CREATE TABLE SampleUsers ( Id INTEGER NOT NULL IDENTITY(1, 1), FirstName VARCHAR(255) NOT NULL, LastName VARCHAR(255) NOT NULL, Email VARCHAR(255) NOT NULL, CreateDate DATETIME NOT NULL DEFAULT(getdate()), PRIMARY KEY (Id) ); GO INSERT INTO SampleUsers(FirstName,LastName,Email,CreateDate) VALUES('Orla','Sweeney','nunc@convallisincursus.ca','Apr 13, 2014'); INSERT INTO SampleUsers(FirstName,LastName,Email,CreateDate) VALUES('Zia','Pickett','porttitor.tellus.non@Duis.com','Aug 31, 2014'); INSERT INTO SampleUsers(FirstName,LastName,Email,CreateDate) VALUES('Justina','Ayala','neque.tellus.imperdiet@temporestac.com','Jul 28, 2014'); INSERT INTO SampleUsers(FirstName,LastName,Email,CreateDate) VALUES('Levi','Parrish','adipiscing.elit@velarcueu.com','Jun 21, 2014'); INSERT INTO SampleUsers(FirstName,LastName,Email,CreateDate) VALUES('Pearl','Warren','In@dignissimpharetra.org','Mar 3, 2014');
تنظیمات ConnectionString
قبل از استفاده از Edge.js با SQL Server، باید متغیر محیطی (environment variable) با نام EDGE_SQL_CONNECTION_STRING را تعریف کنید.
set EDGE_SQL_CONNECTION_STRING=Data Source=localhost;Initial Catalog=node-test;Integrated Security=True
SETX EDGE_SQL_CONNECTION_STRING "Data Source=localhost;Initial Catalog=node-test;Integrated Security=True"
روش اول: اجرای مستقیم SQL Server Query در Edge.js
فایلی با نام server-sql-query.js را ایجاد کرده و کد زیر را در آن وارد کنید:
var http = require('http'); var edge = require('edge'); var port = process.env.PORT || 8080; var getTopUsers = edge.func('sql', function () {/* SELECT TOP 3 * FROM SampleUsers ORDER BY CreateDate DESC */}); function logError(err, res) { res.writeHead(200, { 'Content-Type': 'text/plain' }); res.write("Error: " + err); res.end(""); } http.createServer(function (req, res) { res.writeHead(200, { 'Content-Type': 'text/html' }); getTopUsers(null, function (error, result) { if (error) { logError(error, res); return; } if (result) { res.write("<ul>"); result.forEach(function(user) { res.write("<li>" + user.FirstName + " " + user.LastName + ": " + user.Email + "</li>"); }); res.end("</ul>"); } else { } }); }).listen(port); console.log("Node server listening on port " + port);
node server-sql-query.js
روش دوم: اجرای کد دات نت برای SQL Server Query
Edge.js تنها از دستورات Update، Insert، Select و Delete پشتیبانی میکند. در حال حاضر از store procedures و مجموعهای از کد SQL پشتیبانی نمیکند. بنابراین، اگر چیزی بیشتر از عملیات CRUD میخواهید انجام دهید، باید از دات نت برای این کار استفاده کنید.یادتان باشد، همیشه async
مدل اجرایی Node.js به صورت یک حلقهی رویداد تک نخی است. بنابراین این بسیار مهم است که کد دات نت شما به صورت async باشد. در غیر اینصورت یک فراخوانی به دات نت سبب مسدود شدن و ایجاد خرابی در Node.js میشود.
ایجاد یک Class Library
اولین قدم، ایجاد یک پروژه Class Library در Visual Studio که خروجی آن یک فایل DLL است و استفاده از آن در Edge.js است. پروژه Class Library با عنوان EdgeSampleLibrary ایجاد کرده و فایل کلاسی با نام Sample1 را به آن اضافه کنید و سپس کد زیر را در آن وارد کنید:
using System; using System.Collections.Generic; using System.Data; using System.Data.SqlClient; using System.Threading.Tasks; namespace EdgeSampleLibrary { public class Sample1 { public async Task<object> Invoke(object input) { // Edge marshalls data to .NET using an IDictionary<string, object> var payload = (IDictionary<string, object>) input; var pageNumber = (int) payload["pageNumber"]; var pageSize = (int) payload["pageSize"]; return await QueryUsers(pageNumber, pageSize); } public async Task<List<SampleUser>> QueryUsers(int pageNumber, int pageSize) { // Use the same connection string env variable var connectionString = Environment.GetEnvironmentVariable("EDGE_SQL_CONNECTION_STRING"); if (connectionString == null) throw new ArgumentException("You must set the EDGE_SQL_CONNECTION_STRING environment variable."); // Paging the result set using a common table expression (CTE). // You may rather do this in a stored procedure or use an // ORM that supports async. var sql = @" DECLARE @RowStart int, @RowEnd int; SET @RowStart = (@PageNumber - 1) * @PageSize + 1; SET @RowEnd = @PageNumber * @PageSize; WITH Paging AS ( SELECT ROW_NUMBER() OVER (ORDER BY CreateDate DESC) AS RowNum, Id, FirstName, LastName, Email, CreateDate FROM SampleUsers ) SELECT Id, FirstName, LastName, Email, CreateDate FROM Paging WHERE RowNum BETWEEN @RowStart AND @RowEnd ORDER BY RowNum; "; var users = new List<SampleUser>(); using (var cnx = new SqlConnection(connectionString)) { using (var cmd = new SqlCommand(sql, cnx)) { await cnx.OpenAsync(); cmd.Parameters.Add(new SqlParameter("@PageNumber", SqlDbType.Int) { Value = pageNumber }); cmd.Parameters.Add(new SqlParameter("@PageSize", SqlDbType.Int) { Value = pageSize }); using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior.CloseConnection)) { while (await reader.ReadAsync()) { var user = new SampleUser { Id = reader.GetInt32(0), FirstName = reader.GetString(1), LastName = reader.GetString(2), Email = reader.GetString(3), CreateDate = reader.GetDateTime(4) }; users.Add(user); } } } } return users; } } public class SampleUser { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Email { get; set; } public DateTime CreateDate { get; set; } } }
[project]/bin/Debug/EdgeSampleLibrary.dll
var http = require('http'); var edge = require('edge'); var port = process.env.PORT || 8080; // Set up the assembly to call from Node.js var querySample = edge.func({ assemblyFile: 'EdgeSampleLibrary.dll', typeName: 'EdgeSampleLibrary.Sample1', methodName: 'Invoke' }); function logError(err, res) { res.writeHead(200, { 'Content-Type': 'text/plain' }); res.write("Got error: " + err); res.end(""); } http.createServer(function (req, res) { res.writeHead(200, { 'Content-Type': 'text/html' }); // This is the data we will pass to .NET var data = { pageNumber: 1, pageSize: 3 }; // Invoke the .NET function querySample(data, function (error, result) { if (error) { logError(error, res); return; } if (result) { res.write("<ul>"); result.forEach(function(user) { res.write("<li>" + user.FirstName + " " + user.LastName + ": " + user.Email + "</li>"); }); res.end("</ul>"); } else { res.end("No results"); } }); }).listen(port); console.log("Node server listening on port " + port);
node server-dotnet-query.js
نکته: برای ایجاد pageNumber و pageSize داینامیک با استفاده از ارسال مقادیر توسط QueryString، میتوانید از ماژول connect استفاده کنید.
اولا، اجازه بدهید نگاهی به تنظیم یک دامنه محلی داشته باشیم. زمانیکه شما برنامه محلی را اجرا میکنید IIS Express به صورت محلی، پورتی خاص را به برنامه اختصاص میدهد:
فرض کنید میخواهیم برای سایت خود، درگاه بانک را راه اندازی کنیم. برنامه را به صورت محلی اجرا کرده و زمانیکه قصد ارتباط با بانک را دارید، با پیامی که دامنه شما در سیستم پرداخت بانکی ثبت نشده، مواجه میشوید. در اینجا بانک انتظار دارد که ما از طریق دامنهای که قبلا در سیستم پرداخت بانک ثبت کردهایم برای مثال (www.elemarket.ir) با آن ارتباط برقرار کنیم؛ ولی به دلیل ارتباط به صورت محلی با یکچنین دامنهای (localhost:59395) روبهرو شده و پیغام عدم امکان برقراری ارتباط را میدهد.
حال قصد داریم با تغییر دامنه به صورت سفارشی، این مشکل را برطرف کرده، تا درحقیقت قبل از قرار دادن سایت بر روی سرور و تست عملیات بتوانیم به صورت محلی نتیجه را دریافت کنیم.
استفاده از Telerik Fiddler برای ایجاد یک دامنهی سفارشی
برای این کار میتوانید از برنامهی سبک وزن Telerik Fiddler استفاده کنید و تنها کافیست به قسمت Tools>Host برنامه بروید و آدرس محلی برنامه (localhost:59395 ) و آدرس دامنهی مورد نظر را وارد کنید تا برنامه هم به صورت local و هم توسط یک دامنهی سفارشی، در دسترس باشد. برنامهی Fiddler را باز نگه داشته و به ویژوال استودیو بازگرید.
در نهایت، پیکربندی IIS Express خود را با اتصالهای جدید به روز کنید. شما معمولا میتوانید پیکربندی IIS Express Application خود را در این مسیر پیدا کنید .
C: \ Users \ YOUR_USERNAME \ Documents \ IISExpress \ config / applicationhost.config
در دسترس است.
فایل را باز کرده و گره <sites> را جستجو کنید. شما باید بتوانید درخواست خود را در فهرست سایتها مشاهده کنید. ما قصد داریم HTTP binding را با تغییر localhost به نام دامنهی سفارشی خود بهروز رسانی کنیم. در اینجا HTTP binding به صورت پیشفرض بر روی localhost میباشد:
پس از تغییر localhost و ذخیره کردن تنظیمات، بررسی کنید تا IIS Express در حال اجرا نباشد. حال برنامه را اجرا کنید.
نکته: اگر هنگام اجرای برنامه با خطای
“Unable to create the virtual directory. You must use specify ‘localhost’ for the server name”
" Invalid URL:the hostame could not be parsed "
بعد از اجرای برنامه به طور پیشفرض بر روی همان پورت localhost اجرا شده، حال به دامنهی مورد نظر که ایجاد کردهاید بروید:
در اینجا بعد از تلاش برای ارتباط با بانک، دیگر با پیام «دامنه شما در سیستم پرداخت بانکی ثبت نشدهاست» مواجه نشده و با موفقیت امکان تست برنامه را داریم:
مدیریت رجیستری در #C
رجیستری یک پایگاه دادهی سیستمی است که برنامهها، اجزای سیستم و اطلاعات پیکربندی در آن ذخیره و بازیابی میشود. دادههای ذخیره شده در رجیستری مطابق با نسخه ویندوز فرق میکنند. نرمافزارها برای بازیابی، تغییر و پاک کردن رجیستری از API های مختلفی استفاده میکنند. خوشبختانه .NET نیز امکانات لازم برای مدیریت رجیستری را فراهم کرده است.
در صورت رخداد خطا در رجیستری، امکان خراب شدن ویندوز وجود دارد در نتیجه با احتیاط عمل کنید و قبل از هر کاری از رجیستری پشتیبان تهیه نمایید. قبل از شروع به کدنویسی قدری با ساختار رجیستری آشنا شویم تا در ادامه قادر به درک مفاهیم باشیم.
ساختار رجیستری
رجیستری اطلاعات را در ساختار درختی نگاه میدارد. هر گره در درخت، یک کلید ( key ) نامیده میشود. هر کلید میتواند شامل چندین زیرکلید ( subkey ) و چندین مقدار ( value ) باشد. در برخی موارد، وجود یک کلید تمام اطلاعاتی است که نرم افزار بدان نیاز دارد و در برخی موارد، برنامه کلید را باز کرده و مقادیر مربوط به آن کلید را میخواند. یک کلید میتواند هر تعداد مقدار داشته باشد و مقادیر به هر شکلی میتوانند باشند. هر کلید شامل یک یا چند کاراکتر است. نام کلیدها نمیتوانند کاراکتر “\” را داشته باشند. نام هر زیرکلید یکتاست و وابسته به کلیدی است که در سلسله مراتب، بلافاصله بالای آن میآید. نام کلیدها باید انگلیسی باشند اما مقادیر را به هر زبانی میتوان نوشت. در زیر یک نمونه از ساختار رجیستری را مشاهده میکنید که در نرمافزار registry editor به نمایش در آمده است.
هر کدام از درختهای زیر my computer یک کلید است. HKEY_LOCAL_MACHINE دارای زیرکلیدهایی مثل HARDWARE ، SAM و SECURITY است. هر مقدار شامل یک اسم، نوع و دادههای درون آن است. برای مثال MaxObjectNumber از مقادیر زیرکلید HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\VIDEO است. دادههای درون هر مقدار میتواند از انواع باینری، رشتهای و عددی باشد؛ برای مثال MaxObjectNumber یک عدد ۳۲ بیتی است.
محدودیتهای فنی برای نوع و اندازهی اطلاعاتی که در رجیستری ذخیره میگردد، وجود دارد. برنامهها باید اطلاعات اولیه و پیکربندی را در رجیستری نگه دارند وسایر دادهها را در جای دیگر ذخیره کنند. معمولا دادههای بیشتر از یک یا دو کیلوبایت باید در یک فایل ذخیره شوند و با استفاده از یک کلید در رجیستری به آن فایل رجوع کرد. برای حفظ فضای ذخیره سازی باید دادههای شبیه به هم در یک ساختار جمع آوری گردند و ساختار را به عنوان یک مقدار ذخیره کرد؛ به جای آن که هر عضو ساختار را به عنوان یک کلید ذخیره کرد. ذخیره سازی اطلاعات به صورت باینری این امکان را میدهد که اطلاعات را در یک مقدار ذخیره کنید.
اطلاعات رجیستری در پیج فایل ( Page File ) ذخیره میشوند. پیج فایل ناحیهای از حافظه RAM است که میتواند در زمانی که استفاده نمیشود به Hard منتقل شود. اندازهی پیج فایل به وسیلهی مقدار PagedPoolSize در کلید HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management مطابق با جدول زیر تنظیم میگردد.
مقدار | توضیحات |
0×00000000 | سیستم یک مقدار بهینه را تعیین میکند |
0x1–0x20000000 | یک اندازه مشخص برحسب بایت که در این بازه باشد |
0xFFFFFFFF | سیستم بیشترین مقدار ممکن را تشخیص میدهد |
کلیدهای از پیش تعریف شده
یک برنامه قبل از آن که اطلاعاتی را در رجیستری درج کند باید یک کلید را باز کند. برای باز کردن یک کلید میتوان از سایر کلیدهایی که باز هستند، استفاده کرد. سیستم کلیدهایی را از پیش تعریف کرده که همیشه باز هستند. در ادامه کلیدهای از پیش تعریف شده را قدری بررسی میکنیم.
HKEY_CLASSES_ROOT
زیرشاخههای این کلید، انواع اسناد و خصوصیات مربوط به آنها را مشخص میکنند. این شاخه نباید در یک سرویس یا برنامهای که کاربران متعدد دارد، مورد استفاده قرار گیرد.
HKEY_CURRENT_USER
زیرشاخههای این کلید، تنظیمات مربوط به کاربر جاری را مشخص میکنند. این تنظیمات شامل متغیرهای محیطی، اطلاعات دربارهی برنامهها، رنگها، پرینترها، ارتباطات شبکه و تنظیمات برنامههاست. به طور مثال مایکروسافت اطلاعات مربوط به برنامههای خود را در کلید HKEY_CURRENT_USER\Software\Microsoft ذخیره میکند. هر کدام از برنامهها یک زیرکلید در کلید مزبور را به خود اختصاص دادهاند. این شاخه نیز نباید در یک سرویس یا برنامهای که کاربران متعدد دارد، مورد استفاده قرار گیرد.
HKEY_LOCAL_MACHINE
زیرشاخههای این کلید، وضعیت فیزیکی کامپیوتر را مشخص میکنند که شامل حافظهی سیستم، سختافزار و نرمافزارهای نصب شده بر روی سیستم، اطلاعات پیکربندی، تنظیمات ورود به سیستم، اطلاعات امنیتی شبکه و اطلاعات دیگر سیستم است.
HKEY_USERS
زیرشاخههای این کلید، پیکربندی کاربران پیش فرض، جدید، جاری سیستم و به طور کلی همهی کاربران را مشخص میکند.
HKEY_CURRENT_CONFIG
زیرشاخههای این کلید، اطلاعاتی درباره وضعیت سختافزار کامپیوتر در اختیار ما میگذارند. در واقع این کلید نام مستعاری برای کلید HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Hardware Profiles\Current است که در ویندوزهای قبل از ۳.۵۱ NT وجود نداشته است.
کندوهای رجیستری
یک کندو ( Hive ) یک گروه از کلیدها، زیرکلیدها و مقادیر در رجیستری است که یک مجموعه از فایلهای پشتیبان را به همراه دارد. در هنگام بوت ویندوز، اطلاعات از این فایلها استخراج میشوند. شما هم چنین میتوانید با استفاده از Import در منوی فایل registry editor به صورت دستی این کار را انجام دهید. زمانی که ویندوز را خاموش میکنید، اطلاعات کندوها در فایلهای پشتیبان نوشته میشوند. شما میتوانید این کار را به طور دستی با Export در منوی فایل registry editor نیز انجام دهید.
فایلهای پشتیبان همه کندوها به جز HKEY_CURRENT_USER در شاخهی Windows Root\System32\config قرار دارند. فایلهای پشتیبان HKEY_CURRENT_USER در شاخهی System Root\Documents and Settings\Username قرار دارند. پسوند فایلها در این شاخهها، نوع دادههایی که در بر دارند را نشان میدهند. در جدول زیر برخی کندوها و فایلهای پشتیبانشان آمده است.
کندوی رجیستری | فایلهای پشتیبان |
HKEY_CURRENT_CONFIG | System, System.alt, System.log, System.sav |
HKEY_CURRENT_USER | Ntuser.dat, Ntuser.dat.log |
HKEY_LOCAL_MACHINE\SAM | Sam, Sam.log, Sam.sav |
HKEY_LOCAL_MACHINE\Security | Security, Security.log, Security.sav |
HKEY_LOCAL_MACHINE\Software | Software, Software.log, Software.sav |
HKEY_LOCAL_MACHINE\System | System, System.alt, System.log, System.sav |
HKEY_USERS\.DEFAULT | Default, Default.log, Default.sav |
دسته بندی اطلاعات
قبل از قرار دادن اطلاعات در رجیستری باید آنها را به دو دسته اطلاعات کامپیوتر و اطلاعات کاربر تقسیم کرد. با این تقسیم بندی، چندین کاربر میتوانند از یک برنامه استفاده کنند و یا اطلاعات را بر روی شبکه قرار دهند. زمانی که یک برنامه نصب میشود، باید اطلاعات کامپیوتری خود را در شاخه فرضی HKEY_LOCAL_MACHINE\Software\MyCompany\MyProduct\1.0 به گونهای تعریف کند که نام شرکت، نام محصول و نسخه برنامه به خوبی مشخص گردند و هم چنین اطلاعات مربوط به کاربران را در شاخه فرضی HKEY_CURRENT_USER\Software\MyCompany\MyProduct\1.0 نگاه دارد.
باز کردن، ساختن و بستن کلیدها
قبل از آن که بتوانیم یک اطلاعات را در رجیستری درج کنیم، باید یک کلید بسازیم و یا یک کلید موجود را باز کنیم. یک برنامه همیشه به یک کلید به عنوان زیرکلیدی از یک کلید باز رجوع میکند. کلیدهای از پیش تعریف شده همیشه باز هستند.
کلاسهای تعریف شده برای کار با رجیستری در فضانام Microsoft.Win32 قرار دارند. کلاس Microsoft.Win32.Registry مربوط به کلاسهای از پیش تعریف شده و کلاس Microsoft.Win32.RegistryKey برای کار با رجیستری است. برای باز کردن یک کلید از متد RegistryKey.OpenSubKey استفاده میکنیم. به یاد داشته باشید که کلیدهای از پیش تعریف شده همیشه باز هستند و نیازی به باز کردن ندارند. برای ساختن یک کلید از متد RegistryKey.CreateSubKey استفاده میکنیم. دقت کنید زیرکلیدی که میخواهید بسازید، باید به یک کلید باز رجوع کند. برای خاتمه دسترسی به یک کلید، باید آن را ببندیم. برای بستن یک کلید از متد RegistryKey.Close استفاده میکنیم.
اکنون که با ساختار رجیستری و کلاسهای مربوطه در .NET برای کار با رجیستری آشنا شدیم، به کدنویسی میپردازیم.
ساختن یک زیرکلید جدید
برای ساختن یک زیرکلید جدید از متد RegistryKey.CreateSubKey به صورت زیر استفاده میکنیم.
public RegistryKey CreateSubKey( string subkey);
subkey نام و مسیر کلیدی که میخواهید بسازید را مشخص میکند که معمولا به فرم فرضی key name\Company Name\Application Name\version است. این متد یک زیرکلید را برمیگرداند و در صورت بروز خطا مقدار null را برمیگرداند و یک exception را فرا میخواند. خطا به دلایلی چون عدم داشتن مجوز، وجود نداشتن مسیر درخواستی و غیره رخ میدهد. برای بررسی exception ها میتوانید از بلوک try-catch استفاده کنید.
RegistryKey MyReg = Registry .CurrentUser.CreateSubKey( "SOFTWARE\\SomeCompany\\SomeApp\\SomeVer" );
برای دست یابی به کلیدهای از پیش تعریف شده از کلاس Registry مطابق جدول زیر استفاده میکنیم.
فیلد | کلید |
ClassesRoot | HKEY_CLASSES_ROOT |
CurrentUser | HKEY_CURRENT_USER |
LocalMachine | HKEY_LOCAL_MACHINE |
Users | HKEY_USERS |
CurrentConfig | HKEY_CURRENT_CONFIG |
باز کردن زیرکلید موجود
برای باز کردن یک زیرکلید موجود از متد RegistryKey.OpenSubKey به دو صورت استفاده میکنیم.
public RegistryKey OpenSubKey( string name); public RegistryKey OpenSubKey( string name, bool writable);
RegistryKey MyReg = Registry .CurrentUser.OpenSubKey( "SOFTWARE\\SomeCompany\\SomeApp\\SomeVer" , true );
مثال فوق کلید مشخص شده را در شاخهی HKEY_CURRENT_USER و در حالت ویرایش باز میکند.
خواندن اطلاعات از رجیستری
اگر یک شیء RegistryKey سالم داشته باشید میتوانید به مقادیر و اطلاعات درون مقادیر آن دسترسی داشته باشید. برای دست یابی به اطلاعات درون یک مقدار مشخص در کلید از متد RegistryKey.GetValue به دو صورت استفاده کنیم.
public object GetValue( string name); public object GetValue( string name, object defaultValue);
نوشتن اطلاعات در رجیستری
برای نوشتن اطلاعات در یک مقدار از متد RegistryKey.SetValue به صورت زیر استفاده میکنیم.
public void SetValue( string name, object value);
بستن یک کلید
زمانی که دیگر با کلید کاری ندارید و میخواهید تغییرات در رجیستری ثبت گردد باید فرآیندی به نام flushing را انجام دهید. برای انجام این کار به راحتی از متد RegistryKey.Close استفاده کنید.
RegistryKey MyReg = Registry .CurrentUser.CreateSubKey( "SOFTWARE\\SomeCompany\\SomeApp\\SomeVer" ); int nSomeVal = ( int )MyReg.GetValue( "SomeVal" , 0); MyReg.SetValue( "SomeValue" , nSomeVal + 1); MyReg.Close();
پاک کردن یک کلید
برای پاک کردن یک زیرکلید از متد RegistryKey.DeleteSubKey به دو صورت استفاده میکنیم.
public void DeleteSubKey( string subkey); public void DeleteSubKey( string subkey, bool throwOnMissingSubKey);
پاک کردن کل یک درخت
برای پاک کردن کل یک درخت با همهی کلیدهای فرزند و مقادیر آنها از متد RegistryKey.DeleteSubKeyTree به دو صورت استفاده میکنیم.
public void DeleteSubKeyTree( string subkey); public void DeleteSubKeyTree( string subkey, bool throwOnMissingSubKey);
پاک کردن یک مقدار
برای پاک کردن یک مقدار از متد RegistryKey.DeleteValue به دو صورت زیر استفاده میکنیم.
public void DeleteValue( string name); public void DeleteValue( string name, bool throwOnMissingValue);
لیست کردن زیرکلیدها
برای به دست آوردن یک لیست از همه زیرکلیدهای یک شیء RegistryKey از متد RegistryKey.GetSubKeyNames به صورت زیر استفاده میکنیم که یک آرایه رشتهای از نام زیرکلیدها را برمیگرداند.
public string [] GetSubKeyNames();
لیست کردن نام مقادیر
برای به دست آوردن یک لیست از همه مقادیری که در یک شیء RegistryKey وجود دارند از متد RegistryKey.GetValueNames به صورت زیر استفاده میکنیم که یک آرایه رشتهای از نام مقادیر را برمیگرداند.
public string [] GetSubKeyNames();
ثبت تغییرات به صورت دستی
برای ثبت تغییرات یا به اصطلاح فلاش کردن به صورت دستی میتوانید از متد RegistryKey.Flush به صورت زیر استفاده نمایید. زمانی که از RegistryKey.Close استفاده میکنید فرآیند فلاش کردن به طور اتوماتیک انجام میگیرد.
public void Flush();