مطالب
با رویه‌های ذخیره شده خود، وب سرویس ایجاد کنید

قابلیت جالبی از SQL Server 2005 به بعد به این محصول اضافه شده است که امکان ایجاد یک وب سرویس بومی را بر اساس رویه‌های ذخیره شده و یا توابع تعریف شده در دیتابیس‌های موجود، فراهم می‌سازد. این قابلیت نیازی به IIS یا هر هاست دیگری برای اجرا ندارد و توسط خود اس کیوال سرور راه اندازی و مدیریت می‌شود.
توضیحات مفصل آن‌‌را در MSDN می‌توانید ملاحظه کنید و در اینجا یک مثال عملی از آن را با هم مرور خواهیم کرد:

الف) ایجاد یک جدول آزمایشی به همراه تعدادی رکورد دلخواه در آن

CREATE TABLE [tblWSTest](
[id] [int] IDENTITY(1,1) NOT NULL,
[f1] [nvarchar](50) NULL,
[f2] [nvarchar](500) NULL,
CONSTRAINT [PK_tblWSTest] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

SET IDENTITY_INSERT [tblWSTest] ON
INSERT [tblWSTest] ([id], [f1], [f2]) VALUES (1, N'a1', N'a2')
INSERT [tblWSTest] ([id], [f1], [f2]) VALUES (2, N'b1', N'b2')
INSERT [tblWSTest] ([id], [f1], [f2]) VALUES (3, N'c1', N'c2')
INSERT [tblWSTest] ([id], [f1], [f2]) VALUES (4, N'd1', N'd2')
INSERT [tblWSTest] ([id], [f1], [f2]) VALUES (5, N'e1', N'e2')
SET IDENTITY_INSERT [dbo].[tblWSTest] OFF
ب) ایجاد یک رویه ذخیره شده در دیتابیس جاری

CREATE PROCEDURE GetAllData
AS
SELECT f1,
f2
FROM tblWSTest
ج) ایجاد یک HTTP Endpoint

CREATE ENDPOINT GetDataService
STATE = STARTED
AS HTTP(
PATH = '/GetData',
AUTHENTICATION = (INTEGRATED),
PORTS = (CLEAR),
CLEAR_PORT = 8080,
SITE = '*'
)
FOR SOAP(
WEBMETHOD 'GetAllData'
(NAME = 'testdb2009.dbo.GetAllData'),
WSDL = DEFAULT,
DATABASE = 'testdb2009',
NAMESPACE = DEFAULT
)

توضیحات:
Ports در حالت clear و یا ssl می‌تواند باشد. همچنین برای اینکه با IIS موجود بر روی سیستم هم تداخل نکند CLEAR_PORT به 8080 تنظیم شده است. سایر پارامترهای آن بسیار واضح هستند. برای مثال تعیین دیتابیسی که این رویه ذخیره شده در آن قرار دارد و همچنین مسیر کامل دسترسی به آن دقیقا مشخص می‌گردند.


این وب سرویس هم اکنون آغاز به کار کرده است. برای مشاهده wsdl آن، آدرس زیر را در مرورگر وب خود وارد نمائید (PATH و CLEAR_PORT معرفی شده در endPoint اینجا بکار می‌رود):

http://localhost:8080/GetData?wsdl

د) استفاده از این وب سرویس در یک برنامه ویندوزی
یک برنامه ساده winForms را شروع کنید. سپس یک DataGridView را بر روی فرم قرار دهید (بدیهی است این مورد می‌تواند یک برنامه ASP.Net هم باشد و موارد مشابه دیگر). سپس از منوی پروژه، یک service reference را در VS2008 بر اساس آدرس wdsl فوق اضافه کنید (شکل زیر):


برای اینکه این مثال در VS2008 درست کار کند باید فایل app.config ایجاد شده را کمی ویرایش کرد. قسمت security آن را یافته و تغییرات زیر را با توجه به AUTHENTICATION مورد نیاز تغییر دهید:

<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
سپس کد برنامه ما به صورت زیر خواهد بود:

using System;
using System.Data;
using System.Windows.Forms;

namespace WebServiceTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
ServiceReference1.GetDataServiceSoapClient data =
new ServiceReference1.GetDataServiceSoapClient();
dataGridView1.DataSource = (data.GetAllData()[0] as DataSet).Tables[0];
}
}
}




مسیرراه‌ها
SQL Server
آخرین تاریخ بروزرسانی 93/10/21


SQL Server 2005

SQL Server 2008

SQL Server 2012

SQL Serve 2014


مطالب
بررسی روش نصب و استفاده از پیش نمایش NET Core 2.2.

نسخه net core 2.2. Preview 3.، روز چهارشنبه 25 مهر، مطابق با 17 اکتبر منتشر شد. این نسخه شامل ویژگی‌های جدیدی از جمله موارد زیر می‌باشد:

  • تغییرات عمده در API 
  • Authorization Server
  • بهبود کارآیی و سرعت
  • پشتیبانی از Spatial Data برای SQL Server و SQLite
  • پشتیبانی از Cosmos DB
  • جایگزینی Bootstrap 4, Angular 6

مهمترین ویژگی مربوط به EF Core برای گروهی از برنامه نویسان، پشتیبانی از فیلدهای جغرافیایی یا همان Spatial Data می‌باشد.

نسخه‌ی net core 2.2 RTM.،  قبل از انتهای سال میلادی جاری منتشر خواهد شد و پس از آن آغاز به کار بر روی net core 3. خواهد بود. برای  نسخه‌ی net Core 3.، هدف بهبود برنامه‌های مبتنی بر Desktop و سازگاری آن با فرمت جدید csproj، اعلام شده‌است.


برای استفاده از ویژگی‌های net core 2.2. باید نسخه‌ی visual studio 2017 preview، یعنی ورژن Version 15.9.0 به بعد را نصب کنید. اگر صرفا dotnet core 2.2 را نصب کنید و از ویژوال استودیوی جاری قصد استفاده را داشته باشید، به شما پیغام می‌دهد که این نسخه قابلیت استفاده از دات نت 2.2 به بعد را ندارد.



برای تست و استفاده از net core 2.2 preview 3. مراحل زیر را طی کنید:

1- ابتدا آخرین انتشار ویژوال استودیو 2017، یعنی نسخه‌ی ‌پیش‌نمایش preview را از اینجا دریافت و نصب کنید. نسخه Enterprise را انتخاب کنید تا installer دانلود شود وشروع به نصب کند. حجم این نسخه، از نسخه‌ی اصلی کمتر می‌باشد.

                                                 پس از نصب، این نسخه را می‌توانید در کنار نسخه‌ی اصلی، همزمان بر روی سیستم داشته باشید. 

2- سپس net core 2.2. را به یکی از روش‌های زیر نصب کنید:
  • برای نصب کلی بر روی سیستم،  اینجا کلیک کنید و نسخه‌ی SDK Installer مناسب دستگاه خود را دانلود کنید (64 یا 32 بیتی).
         در صورت موفقیت آمیز بودن، صفحه‌ی پایانی را به شکل زیر خواهید دید:

  • برای استفاده‌ی از EF Core آن در پروژه جاری می‌توانید آن‌‌را از اینجا  دانلود و یا بوسیله‌ی دستور زیر نصب کنید:
Install-Package Microsoft.EntityFrameworkCore -Version 2.2.0-preview3-35497

3- پس از نصب، ویژوال استودیوی preview را از همان مسیر visual studio، اجرا کنید. یک پروژه‌ی جدید از نوع وب را ایجاد کنید و فریمورک را بر روی بالاترین مقدار آن قرار دهید؛ مثل تصویر زیر:


بعد از ایجاد پروژه، می‌توانید در solution Explorer، ارجاعات جدید را مشاهده کنید:


مطالب
سیستم‌های توزیع شده در NET. - بخش هشتم- راه اندازی Apache Kafka
در این بخش نحوه راه اندازی Apache Kafka را در Ubuntu مورد بررسی قرار می‌دهیم و می‌بینیم که هر یک از تعاریف و اصطلاحاتی که در بخش قبل معرفی شد، چگونه پیاده سازی می‌شوند (در صورتی که امکان استفاده از Ubuntu را ندارید و می‌خواهید مراحل این بخش را در windows انجام دهید می‌توانید از راهنمای راه اندازی Kafka در windows استفاده کنید تا بتوانید بخشهای بعدی این سری مقالات را پیگیری و اجرا کنید).

بروز رسانی Ubuntu:
قبل از هرچیزی باید مطمئن شوید که Ubuntu بصورت کامل بروز رسانی شده است. برای این کار یک ترمینال جدید را باز و دستورهای زیر را در آن وارد کنید:
sudo apt-get update -y
sudo apt-get upgrade -y
نصب java:
نکته:درصورتی که قبلا java را نصب کرده‌اید نیازی به انجام این مرحله نیست و برای اطمینان از نصب java می‌توانید دستور زیر را در خط فرمان terminal ایجاد شده وارد کنید:
sudo java -version
قبل از دانلود و نصب Apache Kafka، باید ابتدا java را نصب کنید. برای این کار دستور زیر را اجرا کنید:
sudo add-apt-repository -y ppa:webupd8team/java
باید خروجی زیر به شما نمایش داده شود:
gpg: keyring `/tmp/tmpkjrm4mnm/secring.gpg' created
gpg: keyring `/tmp/tmpkjrm4mnm/pubring.gpg' created
gpg: requesting key EEA14886 from hkp server keyserver.ubuntu.com
gpg: /tmp/tmpkjrm4mnm/trustdb.gpg: trustdb created
gpg: key EEA14886: public key "Launchpad VLC" imported
gpg: no ultimately trusted keys found
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)
OK
برای بروز رسانی metadata‌های repository جدید باید دستور زیر را وارد کنید:
sudo apt-get update
و در پایان دستور زیر را برای نصب java اجرا کنید:
sudo apt-get install oracle-java8-installer -y
برای اطمینان از نصب java دستور زیر را وارد کنید:
sudo java -version
در صورتیکه خروجی زیر به شما نمایش داده شود به این معنا است که عملیات نصب java با موفقیت انجام شده‌است:
java version "1.8.0_66"
Java(TM) SE Runtime Environment (build 1.8.0_66-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode)

                                            
دانلود Apache Kafka :
آخرین نگارش پایدار از Apache Kafka، نگارش 1.0.0 می‌باشد که می‌توانید آن را از طریق صفحه دریافت Apache Kafka ، دریافت کنید.

دانلود Apache Kafka


پس از دریافت Apache Kafka، از طریق یک terminal جدید وارد پوشه Downloads شوید. سپس فایل مورد نظر را از حالت فشرده خارج کنید و وارد پوشه اصلی آن شوید. برای این کار از دستورات زیر استفاده کنید:

tar -xzf kafka_2.11-1.0.0.tgz
cd kafka_2.11-1.0.0

 سپس با استفاده از دستور "ls " لیست تمامی فایلها و فولدر‌های موجود در فولدر kafka_2.11-1.0.0  و   را نمایش دهید:

در لیست نمایش داده شده دو فولد اصلی bin و config وجود دارند که به ترتیب فایلهای اجرایی و کانفیگهای پیشفرض و مورد نیاز، در آنها قرار دارند.


اجرای Apache ZooKeeper:

همانطور که در بخش قبل توضیح داده شد، Apache Kafka هیچ Stateی را در خود ذخیره و مدیریت نمی‌کند و اصطلاحا Stateless می‌باشد و مدیریت تمامی این Stateها را بر عهده  Apache ZooKeeper قرار می‌دهد. بنابراین قبل از اینکه بخواهیم Kafka را اجرا کنیم، ابتدا باید Apache ZooKeeper را اجرا کنیم. برای اجرای Apache ZooKeeper در terminalی که قبلا باز کرده‌اید، دستور زیر را اجرا کنید:

bin/zookeeper-server-start.sh config/zookeeper.properties

با اجرای فایل zookeeper-server-start.sh و ارسال کانفیگ پیشفرضش در فولدر config با نام  zookeeper.properties، قسمت مدیریت کننده Stateهای Kafka  اجرا می‌شود.


اجرای Apache Kafka:

پس از اجرای Apache ZooKeeper، باید یک terminal جدید را باز کنید و با استفاده از دستور زیر kafka-server را با استفاده از کانفیگ پیشفرضش اجرا کنید:

 bin/kafka-server-start.sh config/server.properties


به همین راحتی Kafka Server اجرا شده و آماده‌ی استفاده است. برای ادامه و نمایش دادن سایر قابلیت‌های Kafka باید یک Topic جدید را ایجاد کنیم.


ایجاد Topic:

همانطور که می‌دانید تمامی پیامهای شما در Partition‌های Topic ذخیره می‌شوند؛ پس قبل از اینکه بخواهیم توسط یک Producer پیامی را ارسال کنیم یا اینکه بخواهیم توسط Consumer پیامی را دریافت کنیم، ابتدا باید Topic مربوطه را ایجاد کنیم. بهترین و عمومی‌ترین مثال برای نمایش قابلیت‌های Publish-Subscribe در Kafka، مثال چت بین کاربران است که در آن یک کاربر به عنوان Producer عمل می‌کند و پیامهایی را برای سایر کاربران که نقش Consumer را دارند ارسال می‌کند. kafka-topics .sh در Kafka ابزاریست برای مدیریت Topic ها  که با استفاده از آن می‌توانید Topic‌های مورد نیاز را تعریف، ویرایش و یا حذف کنید.

یک terminal جدید را آغاز و با استفاده از دستور زیر یک Topic را با نام userChat ایجاد کنید:

bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic userChat

با این دستور یک Topic در Kafka با نام userChat ایجاد می‌شود و مشخصات آن (منظور stateهای مرتبط با آن است)، در zookeeper نیز ثبت می‌شود.


توضیحات Optionها و  آرگومانهایی که در دستور ایجاد Topic استفاده شدند به شرح زیر است:

create-- :

مشخص کننده این است که شما می‌خواهید یک Topic جدید را ایجاد کنید.

zookeeper localhost:2181--:

مشخص کننده آدرس سرور zookeeper است (سرور zookeeper بصورت پیشفرض از پورت 2181 استفاده می‌کند).

replication-factor 1--:

مشخص کننده این است که تنها یک کپی از این Topic در سرور ایجاد شود. البته در این مثال به دلیل اینکه تنها یک سرور از Kafka را اجرا کرده‌ایم در صورتیکه این مقدار را بیش از عدد 1 در نظر بگیریم، با خطا مواجه می‌شویم. 

partitions 1--

تعداد Partition‌های این Topic را مشخص می‌کند. مقدار Partition در حالتیکه حتی یک سرور را نیز اجرا کرده‌ایم، می‌تواند بیش از 1 باشد؛ اما در این حالت Primary Broker برای تمام Partition‌های همین سرور در نظر گرفته می‌شود. 

topic userChat--

نام Topic را مشخص می‌کند.


پس از اینکه Topic مورد نظر ایجاد شد، با استفاده از دستور زیر می‌توانیم لیست Topic‌های ایجاد شده را مشاهده کنیم:

 bin/kafka-topics.sh --list --zookeeper localhost:2181


توضیحات Optionها و آرگومانهایی که در دستور نمایش لیست  Topicها استفاده شدند به شرح زیر است: 

list--:

شما می‌خواهید لیست topic‌ها را مشاهده کنید.

zookeeper localhost:2181--:

همانند دستور ایجاد، مشخص کننده سرور zookeeper می‌باشد.


تا اینجا برای ارسال و دریافت پیام در بین Application‌های مختلف همه چیز آماده‌است. البته همانطور که در بخش‌های بعدی این سری مقالات می‌بینیم، در عمل Producer‌ها و Consumer‌ها زیرسیستمهایی هستند که خود ما با استفاده از هر زبان برنامه نویسی پیاده سازی می‌کنیم. اما در این قسمت برای نمایش و تکمیل مثالمان، از ابزارهایی که خود Kafka در اختیار ما قرار داده استفاده می‌کنیم.


اجرای یک Producer و ارسال پیام به Kafka:

kafka-console-producer.sh ابزاریست که با استفاده از آن می‌توانید به راحتی یک Producer را ایجاد کنید. در terminalی که قبلا برای مدیریت Topicها باز کرده‌اید با استفاده از دستور زیر، Producer را اجرا می‌کنیم:

bin/kafka-console-producer.sh --broker-list localhost:9092 --topic userChat


توضیحات Optionها و آرگومانهایی که در دستور ایجاد Producer استفاده شدند به شرح زیر است:  

broker-list localhost:9092--:

نشان دهنده لیست Broker‌ها می‌باشد و در صورتیکه تعداد آنها بیش از یک باشد، می‌توان آنها را با "," از هم جدا کرد (پورت پیشفرض Kafka server برای دریافت دستورات، 9092 می‌باشد).

topic userChat--:

Topicی از Kafka server را مشخص می‌کند که این Producer می‌خواهد پیامهای خود را برایش ارسال کند.


پس از اجرای دستور فوق، با تایپ کردن و زدن کلید Enter، پیام مورد نظر به Broker موردنظر یعنی localhost:9092 ارسال و در تنها Partition تاپیک userChat ذخیره می‌شود.


اجرای یک Consumer و دریافت پیامهای موجود در Topic مورد نظر:

kafka-console-consumer.sh ابزاریست که خود Kafka در اختیار ما قرار داده است و با استفاده از آن می‌توانیم به راحتی یک Consumer برای  userChat ،Topic ایجاد کنیم.

در یک terminal جدید با استفاده از دستور زیر یک Consumer را ایجاد کنید که userChat  ،Topic را Subscribe می‌کند:

 bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic userChat --from-beginning


توضیحات Optionها و آرگومانهایی که در دستور ایجاد یک Consumer استفاده شدند به شرح زیر است:  

bootstrap-server localhost:9092-- :

مشخص کننده Kafka serverی است که می‌خواهیم از طریق آن به تمامی اعضای Cluster دسترسی داشته باشیم. در صورتیکه بیش از یک سرور را بخواهیم وارد کنیم، باید آنها را با  "," از هم جدا کنیم.

topic userChat --:

مشخص کننده Topicی است که این Consumer میخواهد روی آن Subscribe کند.

from-beginning--:

 مشخص کننده این است که Consumer ایجاد شده می‌خواهد تمامی پیامهای موجود در userChat ، Topic را از اولین offset تا آخرین offset دریافت کند.

پس از اجرای کد فوق مشاهده می‌کنید که پیامهایی که قبلا Producer در تاپیک userChat ثبت کرده‌است، برای این Consumer ارسال می‌شوند.


از اینجا به بعد هر لحظه که در terminal ارسال کننده یا Producer پیامی تایپ کنید و کلید Enter را بزنید، بلافاصله پیام مورد نظر برای Consumer ارسال می‌شود و در terminal آن نمایش داده می‌شود. حتی می‌توانیم چندین Consumer را در terminal ‌های مختلفی اجرا کنیم. در این صورت با ارسال هر پیام از طرف Producer، تمامی Consumer‌ها آن را نمایش می‌دهند.


با استفاده از سادگی راه اندازی و قابلیتهای بسیار زیادی که Apache Kafka در مدیریت  جریان داده‌ای بین سیستم‌هایمان به ما می‌دهد، می‌توانیم به سادگی در سیستم‌هایمان   قابلیتهای مقیاس پذیری افقی، تحمل در برابر خطا، در دسترس بودن، کارآیی بالا و سادگی مدیریت ارتباطات بخشهای مختلف را اضافه کنیم. در بخشهای بعدی به نحوه ایجاد یک Cluster و اینکه چگونه می‌توان از این بستر در Net. استفاده کرد، می‌پردازیم.

نظرات مطالب
مستند سازی ASP.NET Core 2x API توسط OpenAPI Swagger - قسمت ششم - تکمیل مستندات محافظت از API
HandleChallengeAsync  رو در حالت دیباگ تست کردم اصلا اجرا نمیشه!
private readonly SignInKeysOption _signInKeyOptions;
private string failReason;

public CredentialAuthenticationHandler(
  IOptionsMonitor < CustomAuthenticationOptions > options,
  IOptionsMonitor < SignInKeysOption > signInKeyOptions,
  ILoggerFactory logger,
  UrlEncoder encoder,
  ISystemClock clock): base(options, logger, encoder, clock) {
  _signInKeyOptions = signInKeyOptions.CurrentValue ??
    throw new ArgumentNullException(nameof(signInKeyOptions));
}

protected override Task HandleChallengeAsync(AuthenticationProperties properties) {
  Response.StatusCode = 401;

  if (failReason != null) {
    Response.HttpContext.Features.Get < IHttpResponseFeature > () !.ReasonPhrase = failReason;
  }

  return Task.CompletedTask;
}

protected async override Task < AuthenticateResult > HandleAuthenticateAsync() {
  string authorizationHeader = Request.Headers["Authorization"];
  if (authorizationHeader == null) {
    Logger.LogWarning("Authorization key in header is null or empty");
    //string result;
    //Context.Response.StatusCode = StatusCodes.Status401Unauthorized;
    //result = JsonConvert.SerializeObject(new { error = "Authorization key in header is null or empty" });
    //Context.Response.ContentType = "application/json";
    //await Context.Response.WriteAsync(result);
    failReason = "Authorization key in header is null or empty";
    return AuthenticateResult.Fail("request doesn't contains header");

    //return await Task.FromResult(AuthenticateResult.Fail("UnAuthenticate"));
  }
}
نظرات مطالب
تنظیمات کش توزیع شده‌ی مبتنی بر SQL Server در ASP.NET Core
- اگر با SQL Server کار کرده باشید، حتما دیده‌اید که سرعت اجرای یک کوئری در بار دوم و پس از آن، بسیار بسیار بیشتر از اجرای اول آن است. یکی از مهم‌ترین دلایل آن، به buffer cache مرتبط می‌شود که کارش کش کردن صفحات اطلاعات مرتبط با داده‌های کوئری‌های انجام شده‌است. هر زمانیکه در SQL Server اطلاعاتی از بانک اطلاعاتی خوانده می‌شود، این اطلاعات در RAM سرور هم کپی می‌شوند. نکته‌ی مهم اینجا است که SQL Server هرچقدر RAM را که بتواند برای این منظور مورد استفاده قرار می‌دهد و در این حالت اگر کسی با این نکته آشنایی نداشته باشد یا تصور می‌کند که SQL Server دچار نشتی حافظه شده‌‌است و یا پس از مدتی با کمبود RAM در سرور مواجه خواهد شد. اطلاعات بیشتر
نظرات مطالب
ارتقاء به ASP.NET Core 1.0 - قسمت 2 - بررسی ساختار جدید Solution
ارتقاء به ASP.NET Core 3.0 و تغییرات نقطه‌ی آغازین برنامه

ASP.NET Core 3.0 از Generic Host بجای Web Host قبلی استفاده می‌کند. در این حالت فایل Program.cs آن از:
public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}
در نگارش 2.2، به حالت زیر در نگارش 3 تغییر یافته‌است:
public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}
البته باید درنظر داشت که روش قبلی 2.2، هنوز هم در نگارش 3 کار می‌کند، اما به صورت deprecated و منسوخ شده معرفی خواهد شد و در نگارش‌های بعدی حذف می‌گردد.
در این حالت هاستینگ برنامه دیگر به Kestrel و یا حتی خود ASP.NET Core وابسته نخواهد بود. یعنی می‌توان هاستی را ایجاد کرد که به همراه راه اندازی وب سرور Kestrel نباشد. علت این جنریک شدن چیست؟
در نگارش سوم، هاست‌های دیگری هم معرفی شده‌اند؛ مانند امکان اجرای یک worker service بدون راه اندازی یک وب سرور و یا Blazor از روش هاستینگ متفاوتی درون یک web assembly استفاده می‌کند: «ارتقاء به NET Core 3.0.: پشتیبانی از ایجاد سرویس‌های پس‌زمینه»

یک نکته: جزئیات متد CreateDefaultBuilder و سرویس‌هایی را که به صورت خودکار اضافه می‌کند، در اینجا در فایل src/DefaultBuilder/src/WebHost.cs می‌توانید مشاهده کنید.
مطالب
اتصال Node.js به SQL Server با استفاده از Edge.js
اگر خواسته باشید که با استفاده از Node.js به SQL Server متصل شوید، احتمالا متوجه شده‌اید ماژولی که مایکروسافت منتشر کرده است، ناقص بوده و به صورت پیش نمایش است که بسیاری از ویژگی‌ها و مسائل مهم، در آن در نظر گرفته نشده است.

یکی دیگر از ماژول‌هایی که امکان اتصال 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 را مشاهده کنید.

ایجاد پوشه پروژه

سپس پوشه‌ای را برای پروژه 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
فرمان اول باعث نصب Edge.js و دومین فرمان سبب نصب پشتیبانی از SQL Server می‌شود.

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.js application از طریق command prompt کافی است به صورت زیر عمل کنید:
node server.js
همانطور که مشاهده می‌کنید "!Hello World" در خروجی چاپ شد.

ایجاد پایگاه داده تست

در مثال‌های بعدی، نیاز به یک پایگاه داده داریم تا query‌ها را اجرا کنیم. در صورتی که SQL Server بر روی سیستم شما نصب نیست، می‌توانید نسخه‌ی رایگان آن را از اینجا دانلود و نصب کنید. همچنین SQL Management Studio Express را نیز نصب کنید.

  1. در SQL Management Studio، یک پایگاه داده را با نام node-test با تنظیمات پیش فرض ایجاد کنید.
  2. بر روی پایگاه داده node-test راست کلیک کرده و New Query را انتخاب کنید.
  3. اسکریپت زیر را 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');
نتیجه‌ی اجرای کد بالا، ایجاد جدولی با نام SampleUsers و درج 5 رکورد در آن می‌شود.

تنظیمات 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
این متغیر تنها برای command prompt جاری تعریف شده است و با بستن آن از دست می‌رود. در صورتیکه از Node.js Tools for Visual Studio استفاده می‌کنید، نیاز به ایجاد یک متغیر محیطی دائمی و راه اندازی مجدد VS دارید. همچنین در صورتیکه بخواهید متغیر محیطی دائمی ایجاد کنید، فرمان زیر را اجرا کنید:
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);
سپس با استفاده از command prompt، فرمان زیر را اجرا کنید:
node server-sql-query.js
حال مرورگر خود را باز و سپس آدرس http://localhost:8080 را باز کنید. در صورتی که همه چیز به درستی انجام گرفته باشد لیستی از 3 کاربر را خواهید دید.

روش دوم: اجرای کد دات نت برای 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; }
    }
}
سپس ذخیره و کامپایل کنید. فایل DLL خروجی که در مسیر
[project]/bin/Debug/EdgeSampleLibrary.dll
قرار دارد را در پوشه‌ی پروژه Node کپی کنید. فایل جدیدی را با نام server-dotnet-query.js در پروژه Node ایجاد کنید و کد زیر را در آن وارد کنید:
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);
سپس از طریق command prompt آن را اجرا کنید:
node server-dotnet-query.js
حال مرورگر خود را باز کرده و به آدرس http://localhost:8080 بروید. در صورتیکه همه چیز به درستی انجام گرفته باشد، لیستی از 3 کاربر را خواهید دید. مقادیر pageNumber و pageSize را در فایل جاوااسکریپت تغییر دهید و تاثیر آن را بر روی خروجی مشاهده کنید.
 
نکته: برای ایجاد pageNumber و pageSize داینامیک با استفاده از ارسال مقادیر توسط QueryString، می‌توانید از ماژول connect استفاده کنید.
اشتراک‌ها
سرفصل‌هایی برای معتبر باقی ماندن به عنوان یک توسعه دهنده‌ی NET.

First it is important to recognize that the .NET Framework is not the same as .NET Core. The .NET Framework is effectively now in maintenance mode , and all innovation is occurring in the open source .NET Core now and into the future. So step one to remaining relevant is to understand .NET Core (and the closely related .NET Standard). 

سرفصل‌هایی برای معتبر باقی ماندن به عنوان یک توسعه دهنده‌ی NET.