باز کردن پنجره Popup در ASP.NET با استفاده از Code Behind
قطعا در بسیاری از Applicationهای شما مواردی پیش آمده است که شما نیاز داشتید صفحهای خاص را در یک پنجره Popup باز کنید. این کار به سادگی با استفاده از یک خط کدنویسی ساده جاوا اسکریپت امکان پذیر است. حتی در صورتی که فایلی که کد جاوا اسکریپت شما در آن قرار می گیرد یک فایل Server Side باشد نیز به علت اینکه در تمامی زبانهای Server Side پیش از ASP.NET کلیه کدها به صورت Block Script و لابلای کدهای HTML قرار می گرفت منعی در استفاده از بلاکهای جاوا اسکریپت نیز وجود نداشت. با ظهور ASP.NET و قابلیت قدرتمند آن یعنی Code Behind برنامه نویسان از کلنجار رفتن با کدهای تو در توی طولانی رها شده و کلیه کدهای Server Side خود را در Code Behind می نویسند و حاصل کار آنها یک فایل aspx. است که در آن اثری از کدنویسی غیر از تگهای HTML (و تگهای توسعه یافته ASP.NET) دیده نمیشود. حال اگر شما بخواهید یک Popup باز کنید چه میکنید؟ آیا تابع جاوا اسکریپت بازکننده Popup را لابلای کدهای HTML صفحه خود مینویسید؟ این روش به نظر صحیح نمی آید. چرا که ما خود را از قابلیت خوانانویسی کدهای HTML محروم کرده و باز قسمتی از برنامه نویسی خود را به درون فایل اصلی خود انتقال دادهایم. چه می توان کرد؟ آیا راهی برای اینکه ما با استفاده از کدنویسی در Code Behind یک Popup باز کنیم هست؟ پاسخ مثبت است. در ادامه مقاله به این موضوع می پردازیم: در این روش در واقع ما کدهای جاوا اسکریپت خود را به صورت یک attribute به کنترل مورد نظر خود Add می کنیم. اما برای اینکه برای هر کنترل کدنویسی را تکرار نکنیم این قسمت را درون یک ساب روتین قرار می دهیم:
using System.Web.UI.WebControls; public void OpenPopUp(WebControl opener, string PagePath) { string clientScript; clientScript = "window.open('" + PagePath + "')"; opener.Attributes.Add("OnClick", clientScript); }
طرز کار بسیار ساده است! مقادیر ورودی یک کنترل و صفحهای است که باید باز شود. کد جاوا اسکریپت در یک متغیر رشتهای به نام clinetString قرار داده میشود و با استفاده از متد Add به کنترل اضافه میشود. متد Add دو مقدار دریافت میکند: ابتدا نام property و یا event و سپس مقدار آن که پس از Generate شدن صفحه به تگ HTML تولید شده اضافه میشود.
حال شما میتوانید به راحتی به صورت زیر از این روتین استفاده کنید:
OpenPopup(Button1, "http://www.google.com");
که در آن Butoon1 یک کنترل از نوع asp:button است. طرز کار بدین صورت است که پنجره بلافاصله پس از فراخوانی روتین باز نمیشود بلکه کنترل شما را برای رویداد مورد نظر تنظیم میکند و در هنگام وقوع رویداد (مثلا کلیک کردن روی دکمه) روتین اجرا میشود.
با کمی کدنویسی اضافه میتوان ظاهر پنجره باز شده را نیز کنترل کرد. برای مثال شما می توانید طول و عرض پنجره، عنوان آن، اسکرول بار و... را تنظیم کنید:
public shared void OpenPopUp(WebControl opener, string PagePath,string windowName, int width, int height) { string windowAttribs; string clientScript ; windowAttribs = "width=" + width + "px," + "height=" + height + "px," "left='+((screen.width -" & width & ") / 2)+'," + "top='+ (screen.height - " & height & ") / 2+'"; clientScript = "window.open('" + PagePath + "','" + windowName + "','" + windowAttribs + "'); return false;"; opener.Attributes.Add("OnClick", clientScript); }
مزیت استفاده از این روش این است که به علت اینکه شما این تابع را یک بار و آن هم در کلاس و یا Code Behind قرار میدهید میتوانید به راحتی خطاهای برنامه نویسی خود را قبل از اینکه اجرای کد خود را آغاز نمایید، پیدا کنید.
در این مقاله ابتدا به بررسی کوکیها (Cookies) پرداخته و سپس جلسات (Sessions) را بررسی خواهیم کرد. به دلیل نزدیکی بسیار زیاد این دو مفهوم تصمیم گرفتم همه آنها را در یک مقاله جمعآوری کنم. اگر مفاهیم فوق را به درستی درک کنید و طرز استفاده از آنها را یاد بگیرید، می توانید به قدرت برنامههای کاربردی وب خود بیفزایید. اما استفاده نابجا از این مفاهیم در وب سایتهای مختلف می تواند به شدت روی عملکرد سایت تاثیر گذاشته و از مخاطبان و کارایی آن بکاهد. در نتیجه با مطالعه این مقاله در مورد این دو مفهوم، باید بتوانید تصمیم بگیرید که کدامیک برای وب سایت شما مناسبتر می باشد. در هر حال مثالهایی را در این مقاله خواهید دید که به طور حتم به شما کمک زیادی خواهند کرد. لازم به ذکر است که بیشتر سعی در انتقال مفاهیمی کردهام که پایه کار نمی باشند و سعی کردم به بیان نکاتی بپردازم که راحت پیدا نمیشوند.
کوکیها (Cookies)
استفان والتر در کتاب ASP.NET Unleashed در ابتدای بخش کوکیها اینگونه میگوید: "پروتکل HTTP هیچ امکانی را در اختیار وب سرور قرار نمیدهد تا بتواند به کمک آن تشخیص دهد درخواست جدید از همان مرورگری صادر شده که در خواست قبلی را فرستاده یا از مرورگر دیگری آمده است. از این جهت به HTTP صفت ناپایداری (Stateless) را میدهند. از نقطه نظر وب سرور هر درخواستی که برای دریافت یک صفحه صادر شده است از طرف کاربری جدید ارسال شده است." این به طور قطع آن چیزی نیست که ما می خواهیم! وقتی میخواهیم اطلاعات کاربر را در هر صفحه به او نشان بدهیم (از قبیل شناسه کاربری، کلمه عبور، سبد خرید و...) باید بتوانیم وضعیت آن را حفط کنیم یکی از راههای بسیار خوب در این زمینه استفاده از کوکیها میباشد.
اولین بار Netscape کوکیها را در مرورگر خود به کار برد و به تدریج کنسرسیوم وب (W3C) نیز آن را پذیرفت و امروزه اکثر مرورگرها از کوکیها پشتیبانی می کنند. بر اساس مستندات اولیه Netscape، یک کوکی نمیتواند حجمی بیشتر از 4 کیلوبایت داشته باشد و با بستن صفحه مرورگر کوکیها نیز از بین می روند. البته نگران نباشید اینها کوکیهایی هستند که پارامتر Expires آنها تنظیم نشده است. اما اگر این پارامتر را تنظیم کنید، کوکیها باقی مانده و دائمی می شوند. اما تا کی؟ تا آن تاریخی که در خاصیت Expires تنظیم کردهاید. مرورگرهایی که می توانند با کوکیها کار کنند دارای چند فایل ویژه میباشند که در ویندوز به آنها فایلهای کوکی و در مکینتاش فایلهای جادویی می گویند. کوکیها از طریق هدرهای HTTP بین مرورگر و سرور جابجا می شوند. سرور با استفاده از هدر Set Cookie یک کوکی جدید ایجاد کرده و در درخواستهای بعدی این کوکی به سرور فرستاده می شود.
در مقالهای از سایت ASPFREE در مورد خواندن و نوشتن کوکیها اینگونه نوشته شده است: "برای نوشتن کوکی یک شیئ جدید HttpCookie بسازید و مقدار یک رشته را به آن اختصاص دهید (به خاصیت Value آن) و سپس متد ()Add را در Response.Cookies فرا بخوانید. شما همچنین می توانید مقدار Expires را به یک مقدار تاریخ تغییر دهید تا زمان انقضاء برای کوکیتان تایین کرده باشید."
باید توجه داشته باشید که کوکیها فقط مقادیر رشتهای را ذخیره می کنند و برای نوشتن مقادیر دیگر در کوکیها باید هر آنها را به یک رشته تبدیل کنید. این کد از سایت CodeToad برای یادگیری نحوه استفاده کوکیها بسیار مناسب می باشد:
Using System.Web; // نوشتن
Response.Cookies["BackgroundColor"].Value = "Red"; // خواندن
Response.Write(Request.Cookies["BackgroundColor"].Value);
به دلایل امنیتی شما میتوانید فقط کوکیهایی را بخوانید که از یک دامنه آمده باشند. همچنین ممکن است شما نیاز به کوکیهایی داشته باشید که چند آیتم را در خود نگهداری کنند، یک مثال برای این کار در زیر می بینید:
HttpCookieCollection cookies = Request.Cookies; for (int n = 0; n < cookies.Count; n++) { HttpCookie cookie = cookies[n]; Response.Write("<hr/>Name: <b>" + cookie.Name + "</b><br />"); Response.Write("Expiry: " + cookie.Expires + "<br />"); Response.Write("Address1: " + cookie.Address1+ "<br />"); Response.Write("Address2: " + cookie.Address2+ "<br />"); Response.Write("City: " + cookie.City+ "<br />"); Response.Write("Zip: " + cookie.Zip+ "<br />");}
یک مثال درباره کوکیهای تو در تو به زبان VB.NET:
If Request.Form("savecookie") = "Yes" and ValidLogin = "Yes" Then Response.Cookies("member")("username") = Request.Form("username") Response.Cookies("member")("password") = Request.Form("password") Response.Cookies("member").Expires = DATE + 365End if
جدول زیر بعضی از خصوصیات پیشرفته کوکیها را نمایش میدهد:
|
خاصیت |
توضیحات |
|
Domain |
دامنهای که محدوده کوکی را تعیین می کند. |
|
Path |
مسیر منتسب به کوکی. |
|
Secure |
مقدار بولینی که تعیین می کند آیا کوکی باید فقط روی یک اتصال رمز شده ارسال گردد یا نه؟ |
|
HasKeys |
مقدار بولینی که تعیین می کند که آیا کوکی مربوط به یک کوکی دیکشنری است یا نه؟ |
بطور خلاصه، کوکیها چه خوبیهایی دارند؟ اشغال فضا روی کلاینت که باعث کاهش ترافیک و اشغال فضا روی سرور می شود و اطمینان کار. کوکیها چه بدیهایی دارند؟ بعضی از مرورگرها از کوکیها پشتیبانی نمی کند، بعضی از کاربران کوکیها را پاک می کنند یا نمی پذیرند و این که فقط داده نوع رشتهای را ذخیره می کنند.
جلسات (Sessions)
فریم ورک دات نت برای رد گیری حرکت کاربر ما را تنها نگذاشته و یک امکان خوب به نام Session State را در اختیار ما قرار داده است. به طور پیش فرض وقتی کاربر اولین بار صفحهای را از یک وب سایت ساخته شده با ASP.NET درخواست می کند یک کوکی جلسه به نام ASP.NET_SessionID ساخته شده و به مرورگر او ارسال میشود. با این کار ASP.NET قادر به پیگیری کاربر شده و میتواند در درخواستهای بعدی او را شناسایی کند.
بر این اساس در ASP.NET یک شیء به نام Session قرار داده شده است که میتوانید از آن برای نگهداری اطلاعات مربوط به هر کاربر استفاده کنید. برای مثال دستور زیر یک آیتم با نام MyItem ایجاد کرده و Hello را به آن نسبت میدهد:
Session("MyItem")="Hello!"
هنگام کار با Sessionها باید به نکات زیر توجه کنید:
1. هر Session اگر کاریر مرورگر را ببندد یا 20 دقیقه از سرور درخواست نکند از بین می رود.
2. Session هر کاربر جدا از Session بقیه کاربران است.
3. در Session بر خلاف کوکیها می توان شیئ هم ذخیره کرد.
جدول زیر بعضی از خصوصیات و متدهای شیئ Session را نمایش میدهد:
|
خاصیت/متد |
توضیحات |
|
Remove |
پاک کردن Session |
|
RemoveAll |
پاک کردن تمام Sessionها |
|
SessionID |
ID منحصر به فرد جلسه فعلی را برمیگرداند. |
|
Abandon |
Session فعلی را خاتمه میدهد. اگر کاربر پس از دستور فوق درخواست یک صفحه جدید کند به عنوان کاربر جدید در نظر گرفته می شود. |
|
TimeOut |
تغییر مهلت پیش فرض ختم جلسه. این خصوصیت هر عددی که باشد بعد از همان قدر دقیقه اگر کاربر درخواستی به سرور نفرستد Session ختم می شود. |
نکته: از طریق فایل web.config نیز میتوان مهلت ختم جلسه را تغییر داد:
<configuration> <system.web> <sessionstate timeout="60" /> </system.web></configuration>
Eventها یا وقایع جلسهها دو مورد هستند: Session_Start و Session_End. که Session_Start وقتی رخ می دهد که جلسه آغاز و Session_End وقتی رخ می دهد که جلسه خاتمه پیدا کند. این Eventها را باید در فایل Global.asax تعریف کرد.
در زیر یک مثال عملی از این رویدادها را خواهید دید:
<html> <head> <title>SessionCount.aspx</title> <Script Runat="Server"> Sub Page_Load() lblSessionCount.Text = Application("SessionCount") End Sub </Script> </head> <body> Current Sessions: <asp:Label ID="lblSessionCount" Runat="Server" /> </body></html>Default.aspx
<Script Runat="Server"> Sub Session_Start() If Application("SessionCount") Is Nothing Then Application("SessionCount") = 0 End If Application("SessionCount") += 1 End Sub Sub Session_End() Application("SessionCount") -= 1 End Sub</Script>Global.asax
بطور کلی برای نگهداری مقادیر Sessionها در ASP.NET سه روش وجود دارد: درون پروسه (In Process)، ذخیره در سرویس ویندوز و ذخیره در SQL Server.
Sessionها به طور پیش فرض در داخل پروسه مدیریت می شود و تمام آیتمهایی که در Sessionها میسازیم در همان پروسه وب سرور ذخیره می شوند. مهمترین مشکل این روش این است که اگر به هر دلیل سرور از کار بیفتد و یا Web Applicationما دستکاری شود، تمام دادهها از بین میرود و از طرف دیگر بسط پذیری را در سایت محدود می کند و نمی توان آن را به اشتراک گذاشت.
اما با استفاده از تکنیک ذخیره در پایگاه داده SQL Server میتوان حتی در صورت از کار افتادن سرور نیز اطلاعات را حفظ کرد. تعریف اشیای ضروری در SQL Server به منظور مدیریت دادههای جلسه با اجرای بچ فایل InstallSqlState.sql صورت می گیرد. بعد از این کار باید فایل web.config را نیز به شکل زیر تغییر داد:
<configuration> <system.web> <sessionstate mode="SqlServer" sqlConnectionString="Server=127.0.0.1;UID=sa;Pwd=YourPassword" /> </system.web></configuration
در بسیاری مواقع ما نیاز به افزودن تصویر به پایگاه داده داریم. از آنجایی که دسترسی به فایلهای موجود در سرور جهت استفاده هکرها بسیار سهل الوصول است، برخی مواقع نمیتوانیم اطلاعات حساس را در قالب فایلهای تصویری در سرور ذخیره کنیم. به همین جهت بهتر آن است که در قالب نوع داده image در بانک اطلاعاتی ذخیره شود.
در این قسمت موارد زیر بررسی می شوند:
بررسی پیش نیازهای اضافه نمودن فایل تصویری
دو مورد اصلی که قبل از شروع آپلود نیاز داریم عبارتند از:
1. - تنظیم خاصیت enctype فرم مربوطه (در برچسبForm) به enctype="multipart/form-data"
- داشتن <input type=file> که به کاربر اجازه انتخاب فایل مورد نظرش را می دهد. (فایلی که در پایگاه داده باید ذخیره شود) و یک Submit button جهت اجرای عملیات مربوط به آپلود کردن فای
- استفاده از فضانام System.IO جهت سروکار داشتن با شیء Stream
2. سه پارامتر بالا در یک صفحه aspx بکار می روند.ما همچنین به پیش نیازهای زیر در SQL Server نیازمندیم:
- داشتن حداقل یک جدول با فیلدی از نوع image
- بهتر است که فیلد دیگری از نوع varchar جهت ذخیره تایپ تصویر داشته باشیم
روند کار بدین صورت است که در ابتدا محتویات فایل تصویر خوانده میشود و سپس تصویر به جدول افزوده میشود. در زیر کد مربوط به رویداد OnClick مربوط به Submit button که تصویر را خوانده و به جدول SQL اضافه میکند، میپردازیم:
Public Sub AddPerson(sender As Object, e As EventArgs) Dim intImageSize As Int64 Dim strImageType As String Dim ImageStream As Stream ' Gets the Size of the Image intImageSize = PersonImage.PostedFile.ContentLength ' Gets the Image Type strImageType = PersonImage.PostedFile.ContentType ' Reads the Image ImageStream = PersonImage.PostedFile.InputStream Dim ImageContent(intImageSize) As Byte Dim intStatus As Integer intStatus = ImageStream.Read(ImageContent, 0, intImageSize) ' Create Instance of Connection and Command Object Dim myConnection As New SqlConnection(ConfigurationSettings.AppSettings("ConnectionString")) Dim myCommand As New SqlCommand("sp_person_isp", myConnection) ' Mark the Command as a SPROC myCommand.CommandType = CommandType.StoredProcedure ' Add Parameters to SPROC Dim prmPersonImage As New SqlParameter("@PersonImage", SqlDbType.Image) prmPersonImage.Value = ImageContent myCommand.Parameters.Add(prmPersonImage) Dim prmPersonImageType As New SqlParameter("@PersonImageType",SqlDbType.VarChar, 255) prmPersonImageType.Value = strImageType myCommand.Parameters.Add(prmPersonImageType) Try myConnection.Open() myCommand.ExecuteNonQuery() myConnection.Close() Response.Write("New person successfully added!") Catch SQLexc As SqlException Response.Write("Insert Failed. Error Details are: " & SQLexc.ToString()) End TryEnd Sub
شیء PersonImage نام کنترل HTMLInputFile است. در ابتدا ما نیاز داریم که اندازه تصویری که جهت اضافه کردن انتخاب شده را بدانیم که توسط کد زیر قابل اندازه گیری است:
intImageSize = PersonImage.PostedFile.ContentLength
سپس نوع تصویر را با استفاده از خاصیت ContentType دریافت می کنیم. حال باید یک استریم از تصویر مربوطه دریافت شود:
ImageStream = PersonImage.PostedFile.InputStream
در اینجا ما یک آرایه از بایتها بنام ImageContent که آماده نگهداری محتویات تصویر است، داریم. تصویر ورودی توسط متد Read از شیء Stream خوانده می شود. متد Read سه آرگومان می گیرد:
1. موقعیت مکانی که محتویات تصویر در آن باید کپی شود
2. مکان شروع جهت خواندن
3. تعداد بایتهایی که باید خوانده شود
و دستور مربوط به خواندن هم به شکل زیر است:
intStatus = ImageStream.Read(ImageContent, 0, intImageSize)
حالا ما می خواهیم محتویات تصویر ورودی را که خوانده ایم به یک جدول SQL اضافه کنیم. به همین منظور از یک زیرروال ذخیره شده که تصویر و نوع آن را به یک جدول اضافه می کند، بهره می بریم. حالا ما می خواهیم محتویات تصویر ورودی را که خوانده ایم به یک جدول SQL اضافه کنیم. به همین منظور از یک زیرروال ذخیره شده که تصویر و نوع آن را به یک جدول اضافه می کند، بهره می بریم.
فایل aspx مربوطه:
<%@ Page Language="vb" %><%@ Import Namespace="System.Data" %><%@ Import Namespace="System.Data.SqlClient" %><%@ Import Namespace="System.IO" %><html> <head> <title>Inserting Image to a SqlServer</title> <script runat=server> Public Sub AddPerson(sender As Object, e As EventArgs) ' above code End Sub </script> </head> <body> <form enctype="multipart/form-data" runat="server"> <input type="file" id="PersonImage" runat=server /> <asp:Button Text="Add Person" OnClick="AddPerson" Runat=server /> </form> </body></html>
جدول و زیرروال استفاده شده:
Drop Table PersonGo Create Table Person(PersonID Int Identity,PersonEmail Varchar(255),PersonName Varchar(255),PersonSex Char(1),PersonDOB DateTime,PersonImage Image,PersonImageType Varchar(255)) Drop Proc sp_person_ispGo Create Proc sp_person_isp@PersonEmail Varchar(255),@PersonName Varchar(255),@PersonSex Char(1),@PersonDOB DateTime,@PersonImage Image,@PersonImageType Varchar(255)AsBegin Insert into Person (PersonEmail, PersonName, PersonSex, PersonDOB, PersonImage, PersonImageType) Values (@PersonEmail, @PersonName, @PersonSex, @PersonDOB, @PersonImage, @PersonImageType)End Go
بازیابی تصاویر از SQL Server در ASP.NET:
در مقایسه با اضافه کردن تصویر، بازیابی آن بسیار ساده است. تنها چیز جدید برای این قسمت استفاده از متد BinaryWrite موجود در شیء Response است.
کدهای مورد استفاده جهت بازیابی تصاویر از SQL Server:
Public Sub Page_Load(sender As Object, e As EventArgs) Dim myConnection As New SqlConnection(ConfigurationSettings.AppSettings("ConnectionString")) Dim myCommand As New SqlCommand("Select * from Person", myConnection) Try myConnection.Open() Dim myDataReader as SqlDataReader myDataReader = myCommand.ExecuteReader(CommandBehavior.CloseConnection) Do While (myDataReader.Read()) Response.ContentType = myDataReader.Item("PersonImageType") Response.BinaryWrite(myDataReader.Item("PersonImage")) Loop myConnection.Close() Response.Write("Person info successfully retrieved!") Catch SQLexc As SqlException Response.Write("Read Failed : " & SQLexc.ToString()) End TryEnd Sub
تمام کار این مرحله اجرای یک دستور SQL و تکرار آن برای همه ردیفهاست. قبل از نمایش تصویر، نوع آن هم مشخص می شود.