نکاتی در باره Login page


شما هنگامی به صفحه Login نیاز دارید که اطلاعات کاربرانتان را به خصوص ID و Password آنها را در یک پایگاه داده ها ذخیره کرده باشید، این پایگاه داده ها می تواند  از انواع ساده مانند XML و یا انواع پیچیده RDBMS مانند SQL Database باشد.

در هر صورت به یاد داشته باشید که نگهداری از کلمات عبور بدون Encryption و یا Hash کردن به هیچ وجه قابل قبول نیست، من Hash را ترجیح می دهم چون در این مورد چیزی تحت عنوان DeHash وجود ندارد، شما می توانید در صفحه Registration که قرار است بواسطه آن یک رکورد برای هر کاربر جدید ثبت کنید، کلمات عبور را ابتدا Hash نموده و سپس ذخیره نمایید.

نکات Configuration

احتمالا می دانید که سه شیوه Authentication در .NET Framework پشتیبانی می شود، Windows، Forms و Passport، Windows Authentication هنگامی قابل استفاده خواهد بود که وظیفه  Authenticateکردن را به عهده Domain Controller بگذارید، در این صورت نیازی به Login page هم نخواهید داشت، Passport وقتی مناسب خواهد بود که سایتهای یکپارچه ای داشته باشید که Authentication مشترک داشته باشند مانند سایتهای مختلف Google که در همه آنها با یک نام کاربری و کلمه عبور شناخته می شوید، گزینه مناسب برای مثال ما Forms است.

کد XML مربوط به Forms Authentication در Web.config
<authentication mode="Forms">
                  <forms loginUrl="LoginPage.aspx" protection="All">
                  forms>
authentication>

کد فوق هر درخواست برای هر صفحه ای را فقط به شرطی پاسخ می دهد که درخواست دهنده قبلا در صفحه LoginPage.aspx عملیات login را انجام داده باشد در غیر این صورت او را به این صفحه هدایت کرده و پس از انجام Login مجددا صفحه درخواست شده را Load می کند.

در مورد Authorization نیز توجه داشته باشید که دسترسی کاربران Anonymous را محدود کنید:

<authorization>
      <deny users="?"/>
authorization>

Identity tag را هم فراموش نکنید، در این حالت حتی اگر IIS دسترسی Ananymous را مجاز بداند، Web.config آنرا Override می کند.





<identity impersonate="true"/>


تابعی که من برای انجام Validation در صفحه Login نوشته ام، البته پیشنهاد می کنم که Connection String را Hash کنید.

Boolean Validateit(string uid, string pwd)
{
System.Data.SqlClient.SqlConnection cn = new System.Data.SqlClient.SqlConnection("Data Source=.;Initial Catalog=Training;Persist Security Info=True;User ID=guser;Password=123");
            System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand("select id, fname, lname, uname, pwd from users", cn);
            cn.Open();
            System.Data.SqlClient.SqlDataReader dr = cmd.ExecuteReader();
            while (dr.Read())
            {
                if (txtUid.Text == dr.GetValue(3).ToString())
                {

                    if (System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(txtPwd.Text, "MD5").ToString() == dr.GetValue(4).ToString())
                    {
                        fullname = dr.GetValue(1).ToString() + " " + dr.GetValue(2).ToString();
                        return true;
                    }
                }
            }
            cn.Close();
            return false;
}
استفاده از این تابع در Click event یک Button

protected void btnLgn_Click(object sender, EventArgs e)
        {
            if (Validateit(txtUid.Text, txtPwd.Text) == true)
            {
                System.Web.Security.FormsAuthentication.RedirectFromLoginPage(fullname, false);
                Session["username"]=fullname;
            }
        }

در ضمن، fullname یک متغیر رشته ای است که در Class Scope تعریف شده است.






به نظر من بهتر است برای صفحاتی مانند Login امکان Cache غیر فعال گردد، یک روش ساده استفاده از شیئ Response در Page load event است:
Response.CacheControl = "no-cache";

نکته آخر اینکه می‌توانید از Component های حاضر و آماده FrameWork هم استفاده کنید، مثل LoginControl و غیره، در هر صورت مفاهیم اجرا تغییری نخواهد کرد فقط به کد نویسی کمتری نیاز خواهید داشت ولی فراموش نکنید که کار سخت شما هنگام پیاده‌سازی منجر به یک Maintenance راحت خواهد شد البته به شرط اینکه زحمت موثری کشیده شده باشد.

مفاهیم اولیه ADO.NET


می توان از ADO.NET به عنوان تکنولوژی دسترسی به داده ها نام برد، علی رغم تغییرات گسترده ای که در ADO.NET بواسطه Framework های 1 تا 4 بوجود آمده، مبانی این تکنولوژی تقریبا مشابه آنچه که بود باقی مانده.

در این مقاله تلاش می شود که مبانی مقدماتی  ADO.NET و برخی از Object های کلیدی آن به شیوه ای عملی و دور از پیچیدگیهای تئوریک ارائه شود.

همیشه پای یک DATABASE در میان است

ADO.NET تکنولوژی دسترسی به داده هاییست که در Database ها نگهداری می شوند، توجه داشته باشید که ADO.NET یک Syntax و یا زبان نیست که بوسیله آن بتوان برنامه ای نوشت بلکه مانند ASP.NET یک تکنولوژی است که توسط همه زبانهای .NET Platform مانند VB.NET یا C# قابل پیاده سازی می باشد.

برای دسترسی به یک Database پیش از هر چیز به یک Connection نیاز داریم، Connection به عبارتی پل ارتباطی بین کد برنامه نویسی شما و Database است، ما هنگامی که قصد دسترسی به داده ها در یک پایگاه داده ها (Database) را داریم یک Connection به آن Database باز می کنیم و هنگامیکه کارمان به انجام رسید آن Connection را می بندیم.

کارهایی که ما با داده های موجود در یک پایگاه داده ها انجام می دهیم عبارت هستند از:
  1. خواندن داده ها
  2. ایجاد داده های جدید
  3. ویرایش داده ها
  4. حذف کردن داده ها
فرض کنید که شما لیست دانش آموزان یک مدرسه را در یک پایگاه داده ها نگهداری می کنید، چهار عمل ذکر شده برای این مثال عبارت هستند از:
  1. خواندن لیست دانش آموزان
  2. اضافه کردن یک دانش آموز جدید
  3. تغییر آدرس محل سکونت یک دانش آموز بواسطه تغییر محل سکونت
  4. حذف کردن یک دانش آموز از لیست به دلیل عدم اشتغال به تحصیل در این مدرسه
هرکدام از این عملیات تحت عنوان یک Command (دستور) و با کمک Connection مربوطه در Database انجام می شوند.
تا اینجا با دو Object  از ADO.NET آشنا شده اید: Connection و Command

ممکن است که شما مایل باشید یک یا چند کار را در یک Database انجام بدهید، بنابراین ممکن است شما به چهار Command نیاز داشته باشید، در ADO.NET یک Interface برای سامان دادن به بعضی Object های مرتبط به هم در نظر گرفته شده، این Interface که خود نیز یک Object است، Object هایی نظیر Connection  و Command را مدیریت می کند تا شما انجام عملیات، مجبور به مراجعه مستقیم به خود آنها نباشید و تنها با این Interface که نامش Data Adapter می باشد کار کنید.

فرض می کنیم که قصد ما نمایش لیست دانش آموزان در یک Component دارای توانایی نمایش لیست داده ها مانند GridView و یا به قول برنامه نویسهای قدیمی DataGrid است، یعنی ما می خواهیم لیست دانش آموزان را در یک GridView نمایش بدهیم، برای این منظور لازم است که منبع داده ها (DataSource) را برای GridView آماده کنیم و به آن تحویل دهیم، این DataSource در حقیقت یکی دیگر از Object های ADO.NET می باشد که ما آنرا به وسیله DataAdapter و در حقیقت بوسیله Command مربوط به خواندن لیست و همچنین Connection مربوط به دستور خواندن، آماده می کنیم.

حالا به این سطرها دقت کنید:

برای برنامه نویسان C# :
            

تعریف یک Connction
System.Data.SqlClient.SqlConnection cn;

قابل استفاده کردن یاInstant کردن Connection
cn = new System.Data.SqlClient.SqlConnection();


دادن آدرس و و تعیین نوع دسترسی به Database یه Connection
cn.ConnectionString = "Data Source=.;Initial Catalog=SchoolDataBase;Integrated Security=True";


تعریف DataAdapter
System.Data.SqlClient.SqlDataAdapter da;

تعریف Command
System.Data.SqlClient.SqlCommand cmd;

قابل استفاده کردن یاInstant کردن Command
cmd = new System.Data.SqlClient.SqlCommand();

دادن متن دستور به Command
cmd.CommandText = "select * from StudentList";

تخصیص Connection به Command
cmd.Connection=cn;

قابل استفاده کردن یاInstant کردن DataAdapter
da = new System.Data.SqlClient.SqlDataAdapter();

تخصیص Command به DataAdapter
da.SelectCommand = cmd;

تعریف DataSet
System.Data.DataSet ds;

قابل استفاده کردن یاInstant کردن DataAdapter
ds = new System.Data.DataSet();

پر کردن DataSet توسط DataAdapter
da.Fill(ds);


تخصیص DataSet به GridView
MyGridView.DataSource = ds;

Load کردن  داده ها در GridView
MyGridView.DataBind();
برای برنامه نویسان VB.NET :
        'تعریف یک Connction
        Dim cn As System.Data.SqlClient.SqlConnection

        'قابل استفاده کردن یاInstant کردن Connection
        cn = New System.Data.SqlClient.SqlConnection()

        'دادن آدرس و و تعیین نوع دسترسی به Database یه Connection
        cn.ConnectionString = "Data Source=.;Initial Catalog=SchoolDataBase;Integrated Security=True"


        'تعریف DataAdapter
        Dim da As System.Data.SqlClient.SqlDataAdapter

        'تعریف Command
        Dim cmd As System.Data.SqlClient.SqlCommand

        'قابل استفاده کردن یاInstant کردن Command
        cmd = New System.Data.SqlClient.SqlCommand()

        'دادن متن دستور به Command
        cmd.CommandText = "select * from StudentList"

        'تخصیص Connection به Command
        cmd.Connection = cn

        'قابل استفاده کردن یاInstant کردن DataAdapter
        da = New System.Data.SqlClient.SqlDataAdapter()

        'تخصیص Command به DataAdapter
        da.SelectCommand = cmd

        'تعریف DataSet
        Dim ds As System.Data.DataSet

        'قابل استفاده کردن یاInstant کردن DataAdapter
        ds = New System.Data.DataSet()

        'پر کردن DataSet توسط DataAdapter
        da.Fill(ds)

        'تخصیص DataSet به GridView
        MyGridView.DataSource = ds

        ' پر کردن داده ها در GridView
        MyGridView.DataBind()

این مقاله، فقط یک معرفی اجمالی از  ADO.NET بود، خیلی طبیعی است که برای آنها که تاره به برنامه نویسی روی کرده اند کمی مبهم باشد، برای این دسته از دوستان همین که خطوط کد برنامه تا حدی مفهوم باشد کفایت می کند، با این حال می توانید این کدها را در یک پروژه در Visual Studio بنویسید و نتیجه آن را مشاهده کنید، البته فراموش نکنید که DataBase مورد نیاز را بسازید و همچنین  GridView را نیز روی صفحه قرار بدهید.

برای کسب اطلاعات بیشتر، این مقاله را به شما پیشنهاد می کنم:

Clone کردن یک Table Schema


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

روش اول
فرض کنیم که Table object الگوی ما با نام DT1 موجود است
dim DT2 as new datatable = DT1.Clone()
کد فوق یک table object جدید به نام DT2 با ساختار DT1 می سازد.

روش دوم
فرض کنیم که اصلا شیئ جدول الگو در code behind وجود ندارد و تنها خود جدول در SQL Server موجود می باشد و ما نیاز به یک Table Object با ساختار آن جدول موجود در SQL Server داریم:

Dim dt as new datatable
Dim ad as new sqlclient.sqldataadapter(“select top 0 * from MyTable”,”connection string”)
Ad.fill(tb)
ملاحظه کردید که top 0 کمک می کند که فقط ساختار منتقل شود.

روش دریافت اطلاعات Table Schema

اگر نیاز داشته باشیم که اطلاعاتی از ساختار یک جدول بدست بیاوریم می توانیم از Method های Datareader استفاده کنیم، در مثال زیر مجموعه از این اطلاعات را در یک Grid نمایش داده ام.

SqlConnection cn = new System.Data.SqlClient.SqlConnection("xxx");
            SqlCommand cmd = new SqlCommand("Select * from categories", cn);
            cn.Open();
            SqlDataReader dr = cmd.ExecuteReader(System.Data.CommandBehavior.SchemaOnly);
            System.Data.DataTable tbl = dr.GetSchemaTable();
            cn.Close();
            GridView1.DataSource = tbl;
            GridView1.DataBind();

خواندن Identity رکورد اضافه شده


در بسیاری از مواقع، نیاز داریم که primary key مربوط به رکوردی که به جدول اضافه می کنیم را بدانیم، یک راه حل این است که پس از اضافه کردن رکورد، رکورد آخر جدول را بخوانیم ولی اگر پس از شما کسان دیگری رکوردهای دیگری اضافه کرده باشند چه؟

به نظر من مطمئن ترن روش استفاده از پارامتر IdentID است، identid یکی از پارامترهای SQL Server است که هنگام  پایان یافتن عملیات Insert با مقدار موجود در فیلد identity و یا همان pk پر و بازگردانده می شود.

تابع زیر را به منظور انجام عملیات insert و همچنین دریافت فیلد identity به زبان vb.net نوشته ام که احتمالا برای تبدیل آن به C# مشکلی ندارید ولی اگر لازم باشد نسخه C# هم آماده خواهم کرد.

فقط این نکته را به خاطر داشته باشید که در صورت تمایل می توانید عملیات SQL را در یک Stored Procedure بنویسید و آن را در Code behind فراخوان و اجرا نمایید.


Public Function InsertDirectly(ByVal fieldname As String, ByVal fieldvalue As String, Optional ByVal tr As SqlClient.SqlTransaction = Nothing, Optional ByVal UserCN As SqlClient.SqlConnection = Nothing) As Integer
        'By Alireza
        Dim cmd As New SqlClient.SqlCommand
        If Not UserCN Is Nothing Then
            cmd.Connection = UserCN
        Else
            cn.Open() 'there was a cn object in the scope of the class
            cmd.Connection = cn
        End If

        cmd.CommandType = CommandType.Text
        cmd.Parameters.Add("@IdentID", SqlDbType.Int)
        cmd.Parameters("@IdentID").Direction = ParameterDirection.Output
        cmd.CommandText = "INSERT INTO " + TableName + " (" + fieldname + ") VALUES(" + fieldvalue + ")" & vbCrLf
        cmd.CommandText &= " SET @IdentID=(SELECT SCOPE_IDENTITY())" & vbCrLf

        If Not tr Is Nothing Then cmd.Transaction = tr

        cmd.ExecuteNonQuery()
        Dim retval As Integer
        Try
            retval = cmd.Parameters("@IdentID").Value
        Catch
        End Try
        cn.Close()
        Return retval
    End Function