فرخوانی توابع وب سرویس در SQL Server با استفاده از  اسمبلی ها

فرخوانی توابع وب سرویس در SQL Server با استفاده از اسمبلی ها

نوشته شده توسط: محمد رضا موسائی سجزی
۰۷ فروردین ۱۳۹۵
زمان مطالعه: 30 دقیقه
۲.۳
(۳)

مقدمه

در اینجا قصد دارم در ابتدا به طرح یک سناریو پرداخته و سپس راهکاری که از دید بنده حقیر مناسب بوده و آن را در پروژه های خود مورد استفاده قرار می دهم برای شما دوستان گام به گام توضیح دهم.
سناریو: شاید برای شما هم پیش آمده باشد که در پروژه های خود برای تعامل اطلاعات، با وب سرویس ها روبرو شده باشید. به عنوان مثال وب سرویس دریافت اطلاعات پرسنل یک شرکت که ممکن است از یک برنامه دیگر به واسطه وب سرویس در اختیار شما قرار داد شود و شما قصد دارید این عمل را در فواصل زمانی معین شده از وب سرویس خوانده و در پایگاه داده خود بروزرسانی نمائید.
 
یکی از روش های انجام این امر می تواند این باشد که لیستی از مشخصات مربوط به افراد را از وب سرویس دریافت نمود و سپس در پایگاه داده SQL Server برای ارجاعات بعدی ذخیره نمائیم.
این در حالی است که با استفاده از امکانات برنامه نویسی و پایگاه داده به راحتی می توان تمام این کارها و فراخوانی وب سرویس ها را در پایگاه داده SQL Server با استفاده از Assembly ها انجام داد که در ادامه سعی می کنم تمامی مراحل را برای شما دوستان عزیز با جزئیات شرح داده اما قبل از آن بررسی چند نکته حائز اهمیت می باشد

۱- آیا فراخوانی وب سرویس ها در پایگاه داده باعث کندی پایگاه داده می شود؟

هم بله و هم خیر، بستگی به وب سرویس و نوع عملیات داشته همچنین باید خاطر نشان شد وب سرویس مربوطه چه میزان زمانی را برای برگرداندن پاسخ
صرف می نماید که در صورتی که این مدت زمان زیاد باشد بتوان مدت زمان انجام آن پردازش را تخمین زده تا فواصل زمانی اجرای آن را با تدبیر بهتری انتخاب نمائیم.

۲- آیا فراخوانی وب سرویس ها در پایگاه داده باعث کاهش امنیت در پایگاه داده می شود؟

باید در پاسخ به این سوال که توسط یکی از شاگردانم از من پرسیده شده بگویم که تمامی رد و بدل شدن اطلاعات با استفاده از متد POST انجام می پذیرد
ولی با این حال امنیت وب سرویس مقابل را استفاده کننده نمی تواند تضمین نماید و از جهتی دیگر بعد از دریافت اطلاعات باید در پایگاه داده ذخیره شوند پس رابط برنامه خود را برای ارجاع خروجی وب سرویس به پایگاه داده حذف نموده که این کار می تواند باعث بالا رفتن امنیت گردد ولی با این حال می توان گفت امنیت انجام این کار تا حد قابل قبولی می تواند مناسب و قابل اعتماد در پروژه های بزرگ باشد.

۳- آیا در صورت فراخوانی وب سرویس و عدم دریافت پاسخ از آن در یک بازه زمانی طولانی مدت ارتباط با وب سرویس، سربار پایگاه داده در انجام عملیات های دیگر نخواهد شد؟

همانگونه که تمام برنامه نویسانی که با وب سرویس آشنایی دارند، برای وب سرویس ها می توان مدت زمان TimeOut مشخص نمود پس ما هم می توانیم در استفاده از آن یک زمان TimeOut را مشخص نمائیم تا در صورت انتظار بیش از حد برای دریافت پاسخ از سمت وب سرویس پردازش مربوطه به پایان رسد.(حتی می توان این امر را در زمان فراخوانی وب سرویس به صورت پارامتریک برای آن مشخص نمود تا در هر بار تغییر در زمان مربوطه نیاز به تغییر Assembly آن نباشیم)

۴- بعد از فراخوانی وب سرویس، خروجی ها به دو دسته تقسیم می شوند: یکی مقادیر استاندارد موجود در برنامه نویسی(int, float,….) و دیگری یک نوع ساختار یافته و پیچیده که خود یک موجودیت(کلاس) می باشد. حال برای پردازش روش دوم راه حل چیست؟

بله در صورتی که با خروجی های استاندارد و متداول مواجه شویم می توانیم آن ها را بدون هیچگونه پردازش اضافه ای برای استفاده در پایگاه داده برگردانیم. اما این در صورتی است که با مواجه شدن با یک نوع خاص و پیچیده تعریف شده توسط ارائه دهنده وب سرویس می بایست برای برگرداندن اطلاعات دریافتی از وب سرویس یک سری پردازش بر روی آن سطر های اطلاعاتی اطلاعات انجام و سپس اطلاعات را برگردانیم. (این اطلاعات می تواند در قالب جدول یا Scalar باشد)

۵- آیا می توان راه حلی برای تغییر لینک وب سرویس داشته باشیم تا در صورت تغییر لینک وب سرویس بدون نیاز به تغییر در کد Assembly مربوطه این امر را مرتفع نمود؟

بله، این امر را می توان به راحتی مرتفع گرداند بدین صورت که در زمان واکشی اطلاعات از وب سرویس لینک آن را نیز به صورت پارامتریک برای آن ارسال تا در زمان تغییر لینک وب سرویس نیازی به اعمال تغییرات زیاد نباشد.
ولی نکته بسیارحائز اهمیت این می باشد که نوع خروجی توابع آن نباید دستخوش تغییر باشند.

۶- آیا برای هر وب سرویس باید در اسمبلی تغییراتی برای وب سرویس جدید اعمال کنیم و راه حلی برای اینکه یک اسمبلی نوشته شود تا نیازی به تغییر اسمبلی نباشد وجود ندارد؟ (یعنی یک روش کلی و عمومی مشترک بین تمام وب سرویس ها)

اجازه دهید جواب این سوال را در انتها بررسی کنیم.
همانگونه که قبلا اشاره شد، یکی از روش های تبادل اطلاعات با وب سرویس در پایگاه داده SQL Server استفاده از اسمبلی ها می باشد. برای استفاده از اسمبلی ها و ساخت آن ها من از Visual Studio 2010 و Netframework 3.5 استفاده می کنم. (برای اینکه در SQL Server 2008 نیز این گونه اسمبلی ها قابل استفاده می باشند)
محیط Visual Studio2010 را باز نمائید. و پروژه جدیدی را از قسمت Database و از نوع SQL CLR Database Project ایجاد نمائید.(همانند تصویر زیر)
پس از ایجاد پروژه مربوطه با پنجره ای مشابه تصویر زیر روبرو می شویم که در پنجره Solution Explorer مشاهده می نمائید فایل های مورد نیاز برای Assembly مربوطه ساخته شده است. (در صورت مواجه شدن با پنجره دیگری به غیر از شکل زیر آن را Cancel نمائید)
حال نوبت به آن رسیده است که از قسمت مشخص شده در تصویر بالا بر روی شاخه References کلیک راست نموده و گزینه Add Service Reference را انتخاب نمائیم تا وب سرویس مورد نظر را برای استفاده به این پروژه اضافه نمائیم. (همانند تصویر زیر)
 
بعد از انجام عمل مشخص شده در تصویر بالا برای اینکه بتوانیم از تنظیمات و ارتباط بهتری با وب سرویس برخوردار باشیم بهتر است بر روی دکمه Advanced کلیک نمائیم.(همانند تصویر زیر)
 
با کلیک بر روی دکمه Advanced پنجره ای همانند شکل زیر برای ما به نمایش در خواهد آمد و برای اضافه نمودن وب سرویس همانند مراحل معین شده در شکل عمل نمائید.
 
همانگونه که در تضویر بالا مشاهده می شود در ابتدا بر روی دکمه Add Web Reference کلیک تا پنجره مربوط به آن، که در تصویر بالا قابل مشاهده است باز شود و سپس در قسمت URL لینک مربوط به وب سرویس را وارد نمائید.(درست است لینکی که برای وب سرویس استفاده شده است برای local می باشد که بعدا این امر را اصلاح می کنیم) بعد از وارد نمودن لینک وب سرویس بر روی دکمه GO (مرحله شماره ۳ تصویر بالا) کلیک می کنیم تا صفحه تست وب سرویس برای ما باز شود.
سپس همانگونه که در قسمت شماره ۴ تصویر فوق مشخص شده است نامی را به این سرویس اختصاص می دهیم و در نهایت بر روی دکمه Add Reference کلیک می کنیم با این کار وب سرویس مربوطه به پروژه اضافه می گردد.در صورتی که تمام مراحل فوق را به درستی انجام داده باشید وب سرویس مذکور به پروژه اضافه خواهد گشت. این امر را می توانید در تصویر زیر مشاهده نمائید.
حال نوبت به آن رسیده است که بر روی نام پروژه (در اینجا ReadDataFromWebService) راست کلیک نموده و از منو add گزینه User-Defined Function را انتخاب نمائید.(همانند شکل زیر)
با انجام عمل مشخص شده در تصویر بالا پنجره ای همانند زیر باز خواهد شد که باید نام کلاسی را در آن می خواهید ساخته شود را مشخص نمائید. که در اینجا نام این کلاس را ReadFromPersonWS گذاشته و سپس بر روی دکمه Add کلیک می کنیم (همانند شکل زیر)
با انجام این کار کلاسی با نام ReadFromPersonWS ساخته شده که در آن یک تابع به عنوان نمونه مثال موجود می باشد آن را حذف و یک تابع به نام GetPersonData برای خواندن اطلاعات پرسنل به آن اضافه می نمائیم. (همانند قطعه کد زیر)
[csharp] // DataAccess = سطح دسترسی برای اطلاعات
// SystemDataAccess = سطح دسترسی سیستمی اطلاعات
// FillRowMethodName = نام تابع پردازشگر جهت داده های برگشتی
// TableDefinition = ستون های جدول بازگشتی
[Microsoft.SqlServer.Server.SqlFunction(DataAccess= DataAccessKind.Read, SystemDataAccess = SystemDataAccessKind.Read,
FillRowMethodName = "GetPersonData_Row",
TableDefinition = "businessEntityID int, " +
"personType nvarchar(max), " +
"nameStyle bit, " +
"title nvarchar(max), " +
"firstName nvarchar(max), " +
"middleName nvarchar(max), " +
"lastName nvarchar(max), " +
"suffix nvarchar(max), " +
"emailPromotion int, " +
"additionalContactInfo nvarchar(max), " +
"demographics nvarchar(max) "
)]
public static IEnumerable GetPersonData(SqlString url, SqlInt32 timeOut, SqlString personType)
{
// url = لینک وب سرویس
// timeOut = مدت زمان انتظار برای وب سرویس به دقیقه
// personType = نوع پرسنل جهت ورودی وب سرویس
try
{
// ایجاد شی از وب سرویس
ReadDataFromWebService.WS_Person.WebServicePerson ws = new ReadDataFromWebService.WS_Person.WebServicePerson();
// تغییر لینک وب سرویس
ws.Url = url.Value;
// تبدیل دقیقه به میلی ثانیه
ws.Timeout = (1000 * 60) * timeOut.Value;
return ws.GetPersonInformation(personType.Value);
}
catch (Exception ex)
{
// در صورت بروز خطا یک پرسنل از نوع خطا بر می گرداند که متن خطا در ستون عنوان موجود می باشد
List<Person> lstError = new List<Person>();
lstError.Add(new Person()
{
Title = ex.ToString()
});
return lstError;
}
} [/csharp]
همانگونه که در سورس کد بالا مشاهده می فرمائید توضیحات مربوط به هر بخش نوشته شده است ولی با این حال برای اینکه پاسخ برخی از سوالات مطرح شده در ابتدا را بتوان به خوبی مورد بررسی قرار داد چند پارامتر ورودی این تابع را بررسی می نمائیم: ورودی اول تابع به نام url برای این می باشد که لینک وب سرویس را برای استفاده و اتصال تعیین نمائیم (پاسخ سوال ۵)، پارامتر دوم به نام timeOut بوده که مدت زمان timeOut را به صورت پارامتریک برای این تابع و فراخوانی وب سرویس معین شده مشخص می نماید(پاسخ سوال ۳)، پارامتر سوم به نام personType که ورودی تابع وب سرویس می باشد که برای بازگرداندن اطلاعات باید به تابع وب سرویس ارسال گردد.
 
اما نکته حائز اهمیت در خروجی تابع  وب سرویس فوق این می باشد که خروجی آن یک نوع پیچیده (لیستی از کلاس Person می باشد که این نوع برای SQL Server غیر قابل تجزیه بوده) می باشد از این رو می توان نتیجه گرفت خروجی این تابع یک جدول بوده که برای این امر باید ستون ها و نوع بازگشتی آن ستون ها مشخص گردد و همانگونه که در ابتدا مشاهده می نمائید نام ستون ها و نوع آن ها مشخص شده است ولی باید متذکر شد که برای معرفی نام ستون ها و Bind آن به نوع بازگشتی وب سرویس نیازمند یک تابع واسط می باشیم که نام آن را همانگونه که در قطعه کد بالا مشاهده می نمائید GetPersonData_Row قرار داده.(پاسخ سوال ۴)
در نتیجه برای Bind نمودن ستون های تعریف شده برای تابع GetPersonData و خصوصیات کلاس Person بازگشتی از وب سرویس، تابع زیر را تعریف می کنیم.
[csharp] [Microsoft.SqlServer.Server.SqlFunction]
public static void GetPersonData_Row(object objRow, out SqlInt32 businessEntityID, out SqlString personType,
out SqlBoolean nameStyle, out SqlString title, out SqlString firstName, out SqlString middleName, out SqlString lastName,
out SqlString suffix, out SqlInt32 emailPromotion, out SqlString additionalContactInfo, out SqlString demographics)
{
//تبدیل سطر اطلاعاتی به نوع داده ای پرسنل
Person row = (Person)objRow;
//ستون ها بازگشتی و نوع داده ای وب سرویس Bind
businessEntityID = new SqlInt32(row.BusinessEntityID);
personType = new SqlString(row.PersonType);
nameStyle = new SqlBoolean(row.NameStyle);
title = new SqlString(row.Title);
firstName = new SqlString(row.FirstName);
middleName = new SqlString(row.MiddleName);
lastName = new SqlString(row.LastName);
suffix = new SqlString(row.Suffix);
emailPromotion = new SqlInt32(row.EmailPromotion);
additionalContactInfo = new SqlString(row.AdditionalContactInfo);
demographics = new SqlString(row.Demographics);
} [/csharp]
با تعریف تابع فوق هر سطر اطلاعاتی به ستون های مربوطه بازگشتی Bind خواهد شد و همانطور که در تابع GetPersonData_Row مشاهده می نمائید سطر اطلاعاتی به نام objRow به عنوان پارامتر ورودی می باشد ولی سایر موارد به صورت خروجی تعریف شده است چرا که در زمان فراخوانی به query مربوطه بازگشت داده خواهند شد.
 
نکته مهم و حائز اهمیت در تعریف دو تابع بالا این می باشد که در پارامترهای ورودی معادل نوع SQL Server آن را ذکر کرده ایم چرا که مقادیر از پایگاه داده برای تابع فوق ارسال می گردد و در زمان بازگشت مقادیر در تابع دوم نیز عمل تبدیل به نوع SQL Server انجام شده است چرا که مقادیر باید برای پایگاه داده قابل فهم باشند.
 
در یک شمای کلی می توانید کل سورس برنامه را در تصویر زیر مشاهده نمائید.
در انتها برای اعمال تنظیمات نهایی بر روی نام پروژه در Solution Explorer راست کلیک نموده و Properties را انتخاب می کنیم و تنظیمات مشخص شده را اعمال می نمائیم.
با انجام مراحل ۱ تا ۳ مشخص شده در تصاویر بالا باعث می شویم xml مربوطه به وب سرویس برای تبدیل داده ها نیز ساخته شود و با انجام مراحل ۴ و ۵ باعث می شویم که این dll ها به صورت Safe در پایگاه داده مورد استفاده قرار گیرند.
بعد از انجام تغییبرات گفته شده پروژه را Build نموده تا dll های مربوطه برای واکشی اطلاعات از وب سرویس ساخته شود که نام آن ها تقریبا هم نام پروژه بوده که در این مثال یکی به نام ReadDataFromWebService.dll و دیگری به نام  ReadDataFromWebService.XmlSerializers.dll ساخته می شوند و هر دو را برای واکشی اطلاعات از وب سرویس نیاز داریم.
حال نوبت به آن رسیده است که اسمبلی ساخته شده را به پایگاه داده مورد نظر اضافه نمائیم اما قبل از آن برای این کار بر روی پایگاه داده مورد نظر یک Query باز نموده و دستورات زیر را در آن اجرا می نمائیم. با اجرای دستورات زیر، می توان در پایگاه داده فوق dll هایی از نوع اسمبلی که از نوع CLR می باشند را اضافه نمائیم.
 EXEC sp_configure 'show advanced options' , '1';
go
reconfigure;
go
EXEC sp_configure 'clr enabled' , '1'
go
reconfigure;
پس از اجرای دستورات بالا، قطعه کد زیر را برای پایگاه داده مورد نظر اجرا می نمائیم. (دقت نمائید که به جای TestWebService نام پایگاه داده خود را بنویسید)
ALTER DATABASE TestWebService SET TRUSTWORTHY ON;
GO
حال نوبت به آن رسیده است که dll های خود را به پایگاه داده مورد نظر اضافه نمائیم. برای این کار بر روی شاخه Assembly راست کلیک نموده و گزینه New را انتخاب می نمائیم. (همانند شکل زیر)
 
با انتخاب گزینه بالا با پنجره ای همانند زیر مواجه خواهید شد تنظیمات را برای دو dll فوق همانند تصاویر زیر اعمال نمائید.
 
بعد از انجام مراحل مشخص شده در تصاویر بالا هر دو dll به پایگاه داده مورد نظر  همانگونه که در تصویر زیر مشاهده می نمائید  اضافه می گردد.
حال برای ساخت تابع مورد نظر قطعه کد زیر را در یک Query اجرا تا تابع مورد نظر ما ساخته شود.
CREATE FUNCTION [dbo].[GetPersonData]
(
@url nvarchar(max),
@timeOut int,
@personType nvarchar(max)
)
RETURNS Table
(
businessEntityID int,
personType nvarchar(max),
nameStyle bit,
title nvarchar(max),
firstName nvarchar(max),
middleName nvarchar(max),
lastName nvarchar(max),
suffix nvarchar(max),
emailPromotion int,
additionalContactInfo nvarchar(max),
demographics nvarchar(max)
)
AS EXTERNAL NAME [ReadDataFromWebService].[ReadFromPersonWS].[GetPersonData];
GO
همانگونه که در قطعه کد بالا مشاهده می نمائید تابع فوق برای اجرا از Assembly با نام ReadDataFromWebService کلاس ReadFromPersonWS و تابع GetPersonData استفاده می نماید.
بعد از ساخت تابع مورد نظر خروجی آن همانند شکل زیر می باشد. (همانطور که مشاهده می نمائید از یک سرور دیگر که IP آن قابل مشاهده است وب سرویس فراخوانی شده است و زمان TimeOut آن ۵ دقیقه می باشد یعنی اگر بعد از گذشت ۵ دقیقه نتیجه ای دریافت نکرد عمل واکشی اطلاعات متوقف گردد)
همانگونه که در تصویر زیر مشهود است در مدت زمان ۵ ثانیه نزدیک به ۱۸ هزار سطر اطلاعات از وب سرویس واکشی شده است.
حال می توانید با استفاده از دستور select موجود در عکس بالا عمل درج را در جدول دلخواه انجام دهید. بهتر است عمل درج را در یک پروسیجر انجام دهید و با تعریف یک JOB در بازه زمانی معینی اطلاعات خود را در پایگاه داده خود بروزرسانی نمائید.
 
در انتها می توانم به مثال دیگری اشاره نمایم، که شما دوستان می توانید از وب سرویس ارسال پیامک در پایگاه داده SQL Server نیز به همین شکل استفاده نمائید و عمل ارسال را نحوی بهتر مدیریت نمائید.
 
اما در صورت نیاز فیلم آموزشی استفاده از وب سرویس را با هماهنگی لازمه با سایت نیک آموز و درخواست شما دوستان عزیز برای سایت نیک آموز ارسال تا به صورت رایگان در اختیار شما قرار دهند.
اما در جواب سوال ۶ سعی می کنم به زودی پاسخ را در قالب مطلبی دیگر در سایت برای شما دوستان نیک آموزی قرار دهم.
 

چه رتبه ای می‌دهید؟

میانگین ۲.۳ / ۵. از مجموع ۳

اولین نفر باش

title sign
معرفی نویسنده
محمد رضا موسائی سجزی
مقالات
2 مقاله توسط این نویسنده
محصولات
0 دوره توسط این نویسنده
محمد رضا موسائی سجزی
پروفایل نویسنده
title sign
دیدگاه کاربران

    •     سلام شریف جان

      در خصوص این قضیه در دوره SQL Server ویژه برنامه نویسان آموزش های لازم ارائه داده شده است.
      استفاده از Service Broker و External Activation برای ارسال SMS دقیقا همین مثال در جلسه آخر پیاده سازی شده است.
      گزارش جلسه ۱۵ دوره SQL Server ویژه برنامه نویسان را در سایت مطالعه کنید 
هر روز یک ایمیل، هر روز یک درس
آموزش SQL Server بصورت رایگان
همین حالا فرم زیر را تکمیل کنید
دانلود رایگان جلسه اول
نیک آموز علاوه بر آموزش، پروژه‌های بزرگ در حوزه هوش تجاری و دیتا انجام می‌دهد.
close-link
جشنواره عیدآموز نیک آموز، سال جدید رو با قدرت شروع کن
مشاهده تخفیف ها
close-image