ASP.Net ile Online Test

Yazar: Gökhan BAĞCI
Kategori: ASP.NET
Eklenme Tarihi: 22.1.2008 14:45:21



Bu makalemizde Online Test Sistemi konusuna değineceğiz. Kısaca Test, bir ölçme aracıdır. Bizde yapacağımız sistemle Online Sınav, Test, Anket gibi işlemleri yapabileceğiz. Bilgilerimizi dinamik olarak veritabanımızdan alacağız.

Bu makalemizde Online Test Sistemi konusuna değineceğiz. Kısaca Test, bir ölçme aracıdır. Bizde yapacağımız sistemle Online Sınav, Test,  Anket gibi işlemleri yapabileceğiz. Bilgilerimizi dinamik olarak veritabanımızdan alacağız.  Bunun için öncelikle veritabanımızı aşama aşama oluşturalım.




Tablo: Testler

TestID int  = Tekil değerimiz
Adi varchar(50) = Test Adı, Başlığı vs?
BaslangicTarihi smalldatetime = Testin başlayacağı tarih
BitisTarihi smalldatetime = Testin biteceği tarih



Tablo: TestSorulari

TestSoruID int = Tekil değerimiz
TestID int = Sorunun hangi test?e ait olduğunu tuttuğumuz alan
Baslik varchar(100) = Soru Başlığı...
 SoruTipi varchar(50) = Soru cevabı için kullanılacak control tipi. Ör: RadioButtonList, TextBox

 

Tablo: SoruSecenekleri

SoruSecenekID int = Tekil değerimiz
TestSoruID int = Seçeneğin hangi soru?ya ait olduğunu tuttuğumuz alan
Baslik varchar(100) = Seçenek Başlığı...
DogruCevap bit = Seçeneğin doğru olup olmadığını tuttuğumuz alan

 

Tablo: TestCevaplari

TestCevapID int = Tekil değerimiz
TestSoruID int = Cevabın hangi soru?ya ait olduğunu tuttuğumuz alan
SoruSecenekID int = Cevabı tutulduğu alan
SoruText varchar(100) = Metin olarak girilecek cevaplar için
UserID int = Cevabı veren kişi bilgisi için
KayitTarihi smalldatetime = Cevabın kayıt tarihi

Kısaca veritabanımızı özetleyelim, Testler tablosunda testin genel bilgilerini tutacağız. Daha sonra TestSorulari tablosu ile teste ait soruları tutacağız. Bu kısımda dikkat edilmesi gereken nokta SoruTipi olacak. Bu alanda RadioButtonList, TextBox hatta çoklu seçimler için CheckBoxList bile kullanabiliriz. Seçtiğimiz tipe göre SoruSecenekleri tablosunu kullanarak soruların detaylarını tutacağız. Son olarakta kullanıcının verdiği bilgileri göre TestCevaplari tablosunu kullanarak bilgileri db?mize kaydedeceğiz.

Ben aşağıdaki gibi bilgileri veritabanına kayıt ettim. Makale sonunda SQL Script?i ile sizde örneklere göz atabileceksiniz.

Testler.jpg

TestSorular.jpg

TestSecenekler.jpg

Gelelim HTML Dizayn ve kodlarımıza?

Defaut.aspx


<
asp:ScriptManager ID="ScriptManager1" runat="server" />
<asp:UpdatePanel ID="upTestPanel" runat="server">
  <ContentTemplate>
    <asp:Repeater ID="rptTest" runat="server" OnItemDataBound="rptTest_ItemDataBound">
      <ItemTemplate>
        <div style="height: 25px; width: 100%; background-color: #f8f8f8; 
        vertical-align: middle; border-bottom: solid 1px #808080">
          <%#Eval("Baslik") %> <asp:LinkButton ID="lnkTemizle" runat="server" 
          OnClick="lnkTemizle_Click" Text="Temizle"></asp:LinkButton>
        </div>
        <div style="padding: 3px 0px 3px 0px;">
          <asp:RadioButtonList ID="rbl" runat="server" Visible="false" />
          <asp:TextBox ID="txt" runat="server" Visible="false" />
          <asp:HiddenField ID="TestSoruID" runat="server" Value='<%#Eval("TestSoruID") %>' />
          <asp:HiddenField ID="SoruTipi" runat="server" Value='<%#Eval("SoruTipi") %>' />                    
        </div>
      </ItemTemplate>
      <FooterTemplate>
        <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Oyla" />
      </FooterTemplate>
    </asp:Repeater>
  </ContentTemplate>
</asp:UpdatePanel>
   

HTML Görünüm

 
HtmlGorunum.jpg
  

 

Default.aspx.cs

 
private
int TestID;

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        GetAktifTest();
        GetTestSorulari();
    }
}

private
void GetAktifTest()
{
    SqlConnection con = new SqlConnection("ConnectionString...");
    //Başlangıç tarihinden Büyük, Bitiş tarihinden küçük geçerli testi buluyoruz
    //Mantıken bir tane kayıt geri dönmeli, eğer birden fazla kayıt dönerse 
    //ilk değeri almış oluruz. Bu yüzden test eklerken tarihlere dikkat etmelisiniz!
    SqlCommand com = new SqlCommand("Select * From Testler Where BaslangicTarihi < GetDate() and BitisTarihi > GetDate()", con);
    SqlDataReader dr;
    con.Open();
    dr = com.ExecuteReader();
    if (dr.HasRows)
    {
        dr.Read();
        //Geçerli testin ID'sini alıyoruz, bu değere göre biraz sonra soruları dolduracağız...
        //Değişken global tanımlı diğer methodlardada kullanacağız...
        TestID = Convert.ToInt32(dr["TestID"].ToString());
        dr.Close();
    }
    else
    {
        //Geçerli testin bulunmadığı blok...
        Response.Redirect("blabla...aspx");
    }
    con.Close();
}

private
void GetTestSorulari()
{
    SqlConnection con = new SqlConnection("ConnectionString...");
    //Teste ait soruları çekiyoruz
    SqlDataAdapter da = new SqlDataAdapter("Select * From TestSorulari Where TestID=@TestID", con);
    da.SelectCommand.Parameters.AddWithValue("@TestID", TestID);
    DataTable dt = new DataTable();
    da.Fill(dt);
    rptTest.DataSource = dt;
    //Soruları Repeatırımıza eşitledikten sonra ItemDatabound eventında 
    //Seçenekleri oluşturmaya başlayacağız...
    rptTest.DataBind();
}

private
DataTable GetSoruSecenekleri(int TestSoruID)
{
    SqlConnection con = new SqlConnection("ConnectionString...");
    //Soruya göre seçeneklerini yüklüyoruz...
    SqlDataAdapter da = new SqlDataAdapter("Select SoruSecenekID, Baslik From SoruSecenekleri Where TestSoruID=@TestSoruID", con);
    da.SelectCommand.Parameters.AddWithValue("@TestSoruID", TestSoruID);
    DataTable dt = new DataTable();
    da.Fill(dt);
    return dt;
}

protected
void rptTest_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
    if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
    {
        //Databind() eventından sonra eşitlediğimiz değerlere erişiyoruz
        int TestSoruID = Convert.ToInt32((e.Item.FindControl("TestSoruID") as HiddenField).Value);
        //Makalede söylediğimiz gibi SoruTipi'ni hangi controle seçenekleri
        //yükleyeceğimizi kontrol edeceğiz...
        string SoruTipi = (e.Item.FindControl("SoruTipi") as HiddenField).Value;
        if (SoruTipi == "RadioButtonList")
        {
            //Item içindeki RadioButtonListi kontrolünü buluyoruz
            RadioButtonList rbl = e.Item.FindControl("rbl") as RadioButtonList;
            //Bulduğumuz controle seçenekleri yüklüyoruz...
            rbl.DataSource = GetSoruSecenekleri(TestSoruID);
            rbl.DataTextField = "Baslik";
            rbl.DataValueField = "SoruSecenekID";
            rbl.DataBind();
            //Daha önce yaratılan ancak gizli olan RadioButtonListimizi gösteriyoruz...
            rbl.Visible = true;
        }
        else if (SoruTipi == "TextBox")
        {
            //Item içindeki TextBox kontrolünü buluyoruz
            TextBox txt = e.Item.FindControl("txt") as TextBox;
            //Daha önce yaratılan ancak gizli olan TextBoxımızı gösteriyoruz...
            txt.Visible = true;
        }
    }
}

protected void Button1_Click(object sender, EventArgs e)
{
    //Bu kısımda Repeater içinde oluşturulan sorular içinde dönüyoruz
    foreach (RepeaterItem RI in rptTest.Items)
    {
        //DataBound işleminde yaptığımız gibi Soru bilgilerine erişiyoruz...
        int TestSoruID = Convert.ToInt32((RI.FindControl("TestSoruID") as HiddenField).Value);
        string SoruTipi = (RI.FindControl("SoruTipi") as HiddenField).Value;
        //Aynı şekilde soru tipine göre cevaba nasıl erişeceğimizi belirliyoruz
        //Ör. Bu kısımda CheckBoxList kullanmış olsaydık kontrolü bulduktan sonra
        //onun içindede dönüp seçili olanları bulup kayıt işlemini gerçekleştirecektik...
        if (SoruTipi == "RadioButtonList")
        {
            RadioButtonList rbl = RI.FindControl("rbl") as RadioButtonList;
            //Eğer seçili bir değer varsa bunu rbl.SelectedValue ile alıp
            //Veritabanımızdaki TestCevaplari tablosundaki SoruSecenekID kolonuna yazacağız.
            if (rbl.SelectedIndex != -1)
            {
                int SoruSecenekID = Convert.ToInt32(rbl.SelectedValue);
                Oyla(TestSoruID, SoruSecenekID, "", "1");
            }
            //Boş ise değer göndermiyoruz...
            else
            { Oyla(TestSoruID, 0, "", "1"); }
        }
        else if (SoruTipi == "TextBox")
        {
            //RadioButtonList'deki gibi aynı kontrolleri yapıp cevaplama işlemini gerçekleştiriyoruz.
            TextBox txt = RI.FindControl("txt") as TextBox;
            if (!String.IsNullOrEmpty(txt.Text))
            {
                string SoruText = txt.Text;
                //Ancak bu kısımda SoruText alanına kayıt yapıyoruz...
                Oyla(TestSoruID, 0, SoruText, "1");
            }
            else
            { Oyla(TestSoruID, 0, "", "1"); }
        }
    }
}

private
void Oyla(int TestSoruID, int SoruSecenekID, string SoruText, string UserID)
{
    SqlConnection con = new SqlConnection("ConnectionString...");
    //Gelen değerleri veritabnımıza kayıt ediyoruz...
    SqlCommand com = new SqlCommand("INSERT TestCevaplari VALUES(@TestSoruID, @SoruSecenekID, @SoruText, @UserID, GetDate())", con);
    com.Parameters.AddWithValue("@TestSoruID", TestSoruID);
    if (SoruSecenekID > 0) { com.Parameters.AddWithValue("@SoruSecenekID", SoruSecenekID); }
    else { com.Parameters.AddWithValue("@SoruSecenekID", DBNull.Value); }
    if (!String.IsNullOrEmpty(SoruText)) { com.Parameters.AddWithValue("@SoruText", SoruText); }
    else { com.Parameters.AddWithValue("@SoruText", DBNull.Value); }
    com.Parameters.AddWithValue("@UserID", UserID);
    con.Open();
    com.ExecuteNonQuery();
    con.Close();
}

protected
void lnkTemizle_Click(object sender, EventArgs e)
{
    //Bu kısmı seçtiğimiz değerleri temizlemek için kullanacağız
    //Repeater içinden gelen Butonu yakalıyoruz...
    LinkButton lnkTemizle = (LinkButton)sender;
    //Hangi Itemdan geldiğini buluyoruz...
    RepeaterItem RI = (RepeaterItem)lnkTemizle.NamingContainer;
    //Yine aynı şekilde DataBound ve Oylama işlemindeki gibi SoruTipine göre
    //kontrolü yakalayıp seçili yada yazılı değerleri siliyoruz...
    string SoruTipi = (RI.FindControl("SoruTipi") as HiddenField).Value;
    if (SoruTipi == "RadioButtonList")
    {
        RadioButtonList rbl = RI.FindControl("rbl") as RadioButtonList;
        rbl.SelectedIndex = -1;
    }
    else if (SoruTipi == "TextBox")
    {
        TextBox txt = RI.FindControl("txt") as TextBox;
        txt.Text = "";
    }
}
 
  

Sonuç?

TestCevaplar.jpg

Bu tabloya göre anket, test, sınav vs.. gibi sistemlerde sonuçlarınızı yorumlayabilirsiniz?

Ör. Belli bir kullanıcının verdiği cevapların kaç yanlış ya da doğru yaptığını öğrenmek için aşağıdaki gibi bir sorgu kullanabilirsiniz.

Select TC.TestSoruID, TC.SoruSecenekID, TC.SoruText, SS.DogruCevap
From TestCevaplari as TC
Left Join SoruSecenekleri as SS On SS.SoruSecenekID = TC.SoruSecenekID
Where TC.UserID='1'

Cevap2.jpg

Yorumlayacak olursak 1 no?lu kullanıcı 1 yanlış, 1 doğru cevap verdiğini. Yorum olarakta ?Güzel test?? mesajını bize yolladığını görebiliriz...

Başka bir makalemde görüşmek dileğiyle...

Gökhan BAĞCI
Microsoft Certified Professional


Gökhan BAĞCI

2003 yilindan itibaren .Net teknolojilerini takip etmektedir. Freelance olarak bir çok sahis ve firma için proje gelistirmistir.

emir can - 3.6.2011 1
Resimler görünmüyor :D

deniz - 23.3.2011
Sırf teşekkür etmek için üye oldum. Sağol çok işime yaradı

atilla - 10.2.2011
Resimler görünmüyor, dolasıyla karmaşık kodları anlayamadım. Bu projenin dosyasını eklemeniz mümkün mü?

cihan yılmaz - 11.12.2009
gerekli bütün değişiklikleri yapmama rağmen program doğru şekilde çalışmıyor. Ekrana bir tane "oyla" diye bir buton ve "temizle" diye linkbutton geliyor ve onlarda çalışmıyor. biraz daha açıklayıcı olsaydınız sanırım çok daha güzel olurdu.. ayrıca, koyduğunuz resimler görünmüyor..sorun bende diyeceğim ama diğer makalelerdeki resimleri görebiliyorum..

Osman Gültepe - 28.11.2008
Çok güzel bir örnek olmuş teşekkür ederim. yanlız çalıştırmayı başaramadım daha 0.1 düzeydeyim biraz bu örnekle uçayım dedim olmadı :) Başarılar dierlim.

Yorumunuz