首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在线学习考试门户网站

在线学习考试门户网站
EN

Code Review用户
提问于 2017-03-23 08:28:42
回答 1查看 646关注 0票数 3

我是ASP.NET的新手,我刚刚开发了一个简单的在线考试门户来学习。我使用了ADO.NET,MySQL,并在VS 2010中开发。

我有一个登录页面,用户可以在其中登录并为新用户注册。成功登录后,用户将被重定向到问题页,我从数据库中获取第一个问题。我在标签中填写了问题,在单选按钮列表中填充了选项。用户可以选择一个选项并单击“下一步”按钮。在“下一步”按钮的单击事件中,我计算标记。我只存储会话中的所有值。当用户单击最后一个问题的下一个(即4个用户)时,将重定向到结果页并打印标记。

代码语言:javascript
复制
 public partial class Questions : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Response.Cache.SetCacheability(HttpCacheability.NoCache);
        Response.Cache.SetExpires(DateTime.Now.AddSeconds(-1));
        Response.Cache.SetNoStore();
        if (!IsPostBack)
        {
            renderQuestions(1);
            Session["buttonIndex"] = 1;
            Session["Marks"] = 0;
        }

    }
    public void renderQuestions(int index)
    {

        MySqlConnection con = null;
        string conString = ConfigurationManager.ConnectionStrings["conString"].ConnectionString;
        string qry = "SELECT * FROM QUESTIONS WHERE QUESTION_ID="+index+"";
        try
        {
            using (con = new MySqlConnection(conString))
            {
                con.Open();
                using (MySqlCommand cmd = new MySqlCommand(qry, con))
                {
                    using (MySqlDataAdapter ada = new MySqlDataAdapter(cmd))
                    {
                        DataTable dt = new DataTable();
                        ada.Fill(dt);
                        if (dt.Rows.Count > 0)
                        {
                                clsQuestion ques = new clsQuestion();
                                ques.QuestionId = Convert.ToInt32(dt.Rows[0][0]);
                                ques.Question = Convert.ToString(dt.Rows[0][1]);
                                ques.Option1 = Convert.ToString(dt.Rows[0][2]);
                                ques.Option2 = Convert.ToString(dt.Rows[0][3]);
                                ques.Option3 = Convert.ToString(dt.Rows[0][4]);
                                ques.Option4 = Convert.ToString(dt.Rows[0][5]);
                                ques.Answer = Convert.ToInt32(dt.Rows[0][6]);
                                renderQuesAndAnswers(ques);
                        }
                    }
                }
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
        finally
        {
            con.Close();
        }
    }
    public void renderQuesAndAnswers(clsQuestion quest)
    {


            lblQuestion.Text = quest.Question;
            RadioButtonList1.Items.Clear();
            RadioButtonList1.Items.Add(quest.Option1);
            RadioButtonList1.Items.Add(quest.Option2);
            RadioButtonList1.Items.Add(quest.Option3);
            RadioButtonList1.Items.Add(quest.Option4);               
            Session["QuestionNumber"] = quest.QuestionId ;
            Session["Answer"] = quest.Answer;
    }
    public   class clsQuestion
    {
        private int questionId;
        private string question;
        private string  option1;
        private string  option2;
        private string  option3;
        private string  option4;
        private int answer;
        public int QuestionId
        {
            get { return questionId; }
            set { questionId = value; }
        }
        public string Question
        {
            get { return question; }
            set { question = value; }
        }
        public string  Option1
        {
            get { return option1; }
            set { option1 = value; }
        }
        public string  Option2
        {
            get { return option2; }
            set { option2 = value; }
        }
        public string  Option3
        {
            get { return option3; }
            set { option3 = value; }
        }
        public string  Option4
        {
            get { return option4; }
            set { option4 = value; }
        }
        public int Answer
        {
            get { return answer; }
            set { answer = value; }
        }


    }

    protected void option1_CheckedChanged(object sender, EventArgs e)
    {
        if (Convert.ToInt32 (Session["Answer"]) == 1)
        {
           int marks=Convert.ToInt32 (Session["Marks"]);
           marks++;
           Session["Marks"] = marks;
        }

    }

    protected void option2_CheckedChanged(object sender, EventArgs e)
    {
        if (Convert.ToInt32(Session["Answer"]) == 2)
        {

            int marks = Convert.ToInt32(Session["Marks"]);
            marks++;
            Session["Marks"] = marks;
        }
    }

    protected void option3_CheckedChanged(object sender, EventArgs e)
    {
        if (Convert.ToInt32(Session["Answer"]) == 3)
        {
            int marks = Convert.ToInt32(Session["Marks"]);
            marks++;
            Session["Marks"] = marks;
        }
    }

    protected void option4_CheckedChanged(object sender, EventArgs e)
    {
        if (Convert.ToInt32(Session["Answer"]) == 4)
        {

        }
    }

    protected void btnNext_Click(object sender, EventArgs e)
    {



    }

    protected void btnNext_Click1(object sender, EventArgs e)
    {
        int buton = Convert.ToInt32(Session["buttonIndex"]);
        if (buton < 5)
        {
            if (RadioButtonList1.SelectedIndex + 1 == Convert.ToInt32(Session["Answer"]))
            {
                int marks = Convert.ToInt32(Session["Marks"]);
                marks++;
                Session["Marks"] = marks;
            }

            Session["buttonIndex"] = Convert.ToInt32(Session["buttonIndex"]) + 1;
            renderQuestions(Convert.ToInt32(Session["buttonIndex"]));
            if (buton == 4)
            {
                Server.Transfer("Results.aspx");
                Session.RemoveAll();
            }
        }

    }

}
}

HTML

代码语言:javascript
复制
<form id="form1" runat="server">
<div>
<h3>Please choose the right answer</h3>
</div>

<table class="style1">
    <tr>
        <td class="style3">
            <asp:Panel ID="Panel1" runat="server">
                <asp:Label ID="lblQuestion" runat="server" Text=""></asp:Label>
            </asp:Panel>
             </td>
        <td class="style4">
            </td>
    </tr>
    <tr>
        <td class="style2">
            Answers:</td>
        <td>
             </td>
    </tr>
    <tr>
        <td class="style2">
            <asp:Panel ID="Panel2" runat="server">
                <asp:RadioButtonList ID="RadioButtonList1" runat="server">
                </asp:RadioButtonList>
                <asp:RadioButton ID="option1" runat="server" Checked="false" AutoPostBack="True" 
                    GroupName="Option" oncheckedchanged="option1_CheckedChanged" />
                <asp:RadioButton ID="option2" runat="server" Checked="false" AutoPostBack="True" 
                    GroupName="Option" oncheckedchanged="option2_CheckedChanged" />
                <asp:RadioButton ID="option3" runat="server" Checked="false" AutoPostBack="True" 
                    GroupName="Option" oncheckedchanged="option3_CheckedChanged" />
                <asp:RadioButton ID="option4" runat="server" Checked="false" AutoPostBack="True" 
                    GroupName="Option" oncheckedchanged="option4_CheckedChanged" />
            </asp:Panel>
        </td>
        <td>
             </td>
    </tr>
    <tr>
        <td class="style2">
             </td>
        <td>
             </td>
    </tr>
    <tr>
        <td class="style2">
            <asp:Button ID="btnNext" runat="server" onclick="btnNext_Click1" Text="Next" />
        </td>
        <td>
             </td>
    </tr>
</table>

</form>

我得到了完美的结果,还没有任何问题。但我想确保我这样做是最好的方式,如果我的代码符合标准,如果有任何安全问题。

EN

回答 1

Code Review用户

回答已采纳

发布于 2017-03-25 05:08:38

总的来说,我认为这是一个伟大的第一次尝试。也就是说,它在简化和提高可读性方面还有很大的改进余地。

顺便说一句,我不确定您是否有使用Visual 2010的强烈动机,但如果没有,我建议您考虑使用更最新的版本。Visual 2017最近发布了。

命名约定

方法的命名应该是PascalCase,而不是缩写。例如,不要使用renderQuesAndAnswers,而是使用RenderQuestionAndAnswers。这提高了可读性,并与C#约定保持一致。

问题类也使用匈牙利符号。我也要指出,这是一种模式。而不是clsQuestion,它应该是QuestionModel

有关参考,请参见https://msdn.microsoft.com/en-us/library/ms229045(v=vs.110).aspxhttps://msdn.microsoft.com/en-us/library/ms229043(v=vs.110).aspx。在这些文档中有一些很棒的地方。

使用C#自动实现的属性

Question类可以使用C#自动实现的属性大大简化.使用public string Property { get; set; }而不是创建您自己的备份字段。参考见https://msdn.microsoft.com/en-us/library/bb384054.aspx。我还将问题属性重命名为QuestionText,以避免混淆。

这样,问题类可能非常简单:

代码语言:javascript
复制
public class QuestionModel {
    public int QuestionId { get; set; }
    public string QuestionText { get; set; }
    public string Option1 { get; set; }
    public string Option2 { get; set; }
    public string Option3 { get; set; }
    public string Option4 { get; set; }
    public int Answer { get; set; }
}

捕获并抛出

代码语言:javascript
复制
catch (Exception ex) {
    throw ex;
}

这是不必要的。如果没有它,它将传播异常,就像手动重新抛出异常一样。

删除不需要的控件

你似乎同时有一个单选按钮列表和4个单选按钮。我们只需要单选按钮列表。也有一些面板是不需要的。

使用ViewState而不是会话

我们可以使用ViewState,而不是使用会话来存储问题之间的数据。ViewState不将数据保存在服务器上,而是存储在客户端。因为我们不需要使用内部状态数据(比如当前的问题),所以我们可以将其存储在ViewState中。使用ViewState还允许用户在不同的窗口中一次进行多个问题会话,而会话数据则会在它们之间混合。

我们也可以使用属性来简化这种访问。与使用字符串访问变量不同,我们可以在属性中实现访问,这将防止我们意外地使用错误的键。例如:

代码语言:javascript
复制
private int QuestionNumber {
    get {
        return (int)ViewState["QuestionNumber"];
    }
    set {
        ViewState["QuestionNumber"] = value;
    }
}

我们还可以将整个当前问题存储在ViewState中,以避免存储单个属性,例如答案索引。我们可以通过将[Serializable]属性添加到QuestionModel类来做到这一点。请注意,如果我们确实使用ViewState,我们也应该加密它,以避免泄露答案和其他内部信息。为此,我们可以将ViewStateEncryptionMode="Always"添加到.aspx文件的Page指令中。

还要注意,我们需要找到一种方法来提供对Results.aspx正确计数的访问。为了简单起见,我们可以在这种特殊情况下使用会话数据:

代码语言:javascript
复制
Session["CorrectCount"] = CorrectCount.ToString();
Server.Transfer("Results.aspx");
Session.Contents.Remove("CorrectCount");

理想情况下,最好有一个我们可以序列化和传递的结果信息类,其中可能包括百分比,答案是对的/错的,等等。注意:它真的不应该在这里使用会话(参见上面的推理),但是传输数据的架构不在这个问题的范围之内,所以这里是为了证明概念。

将数据访问与呈现

分开

目前,renderQuestions既处理数据访问,又调用呈现方法。我会提取对它自己的方法的数据访问,类似于:

代码语言:javascript
复制
private QuestionModel GetQuestion(int index) {
    // Data Access Logic
}

这使我们有了一个更清晰的呈现逻辑:

代码语言:javascript
复制
private void RenderQuestion() {
    CurrentQuestion = GetQuestion(QuestionNumber);

    lblQuestion.Text = CurrentQuestion.QuestionText;

    rblOptions.Items.Clear();
    rblOptions.Items.Add(CurrentQuestion.Option1);
    rblOptions.Items.Add(CurrentQuestion.Option2);
    rblOptions.Items.Add(CurrentQuestion.Option3);
    rblOptions.Items.Add(CurrentQuestion.Option4);
}

只处理下一个单击

上的答案检查

在选中所选选项时,没有充分的理由检查它;我们只关心用户何时单击next。这大大简化了逻辑,因为我们可以删除所有这些方法,并在next按钮单击方法中实现所有的逻辑。例如:

代码语言:javascript
复制
protected void btnNext_Click(object sender, EventArgs e)
{
    if (rblOptions.SelectedIndex + 1 == CurrentQuestion.Answer) {
        CorrectCount++;
    }

    if (QuestionNumber == 4) {
        Server.Transfer("Results.aspx");
    }
    else {
        QuestionNumber++;
        RenderQuestion();
    }
}

把所有的东西放在一起,

有了所有这些,我们就得出了以下结论。注意,我们已经将类的大小减少了近一半,并使其更具可读性。

CodeBehind

代码语言:javascript
复制
using System;
using System.Web;
using System.Data;
using System.Configuration;
using MySql.Data.MySqlClient;

namespace questions
{
    public partial class Question : System.Web.UI.Page
    {
        [Serializable]
        protected class QuestionModel
        {
            public int QuestionId { get; set; }
            public string QuestionText { get; set; }
            public string Option1 { get; set; }
            public string Option2 { get; set; }
            public string Option3 { get; set; }
            public string Option4 { get; set; }
            public int Answer { get; set; }
        }

        private int QuestionNumber { get { return (int)ViewState["QuestionNumber"]; } set { ViewState["QuestionNumber"] = value; } }
        private int CorrectCount { get { return (int)ViewState["CorrectCount"]; } set { ViewState["CorrectCount"] = value; } }
        private QuestionModel CurrentQuestion { get { return ViewState["CurrentQuestion"] as QuestionModel; } set { ViewState["CurrentQuestion"] = value; } }

        protected void Page_Load(object sender, EventArgs e) {
            Response.Cache.SetCacheability(HttpCacheability.NoCache);
            Response.Cache.SetExpires(DateTime.Now.AddSeconds(-1));
            Response.Cache.SetNoStore();

            if (!IsPostBack) {
                QuestionNumber = 1;
                CorrectCount = 0;
                RenderQuestion();
            }
        }

        private QuestionModel GetQuestion(int index) {
            MySqlConnection connection = null;
            var connectionString = ConfigurationManager.ConnectionStrings["conString"].ConnectionString;
            var query = "SELECT * FROM QUESTIONS WHERE QUESTION_ID=" + index;

            try
            {
                using (connection = new MySqlConnection(connectionString))
                {
                    connection.Open();

                    using (var command = new MySqlCommand(query, connection))
                    {
                        using (var adapter = new MySqlDataAdapter(command))
                        {
                            var dataTable = new DataTable();
                            adapter.Fill(dataTable);
                            if (dataTable.Rows.Count > 0)
                            {
                                return new QuestionModel
                                {
                                    QuestionId = Convert.ToInt32(dataTable.Rows[0][0]),
                                    QuestionText = Convert.ToString(dataTable.Rows[0][1]),
                                    Option1 = Convert.ToString(dataTable.Rows[0][2]),
                                    Option2 = Convert.ToString(dataTable.Rows[0][3]),
                                    Option3 = Convert.ToString(dataTable.Rows[0][4]),
                                    Option4 = Convert.ToString(dataTable.Rows[0][5]),
                                    Answer = Convert.ToInt32(dataTable.Rows[0][6])
                                };
                            }
                            else
                            {
                                return null;
                            }
                        }
                    }
                }
            }
            finally
            {
                connection.Close();
            }
        }

        private void RenderQuestion() {
            CurrentQuestion = GetQuestion(QuestionNumber);

            lblQuestion.Text = CurrentQuestion.QuestionText;

            rblOptions.Items.Clear();
            rblOptions.Items.Add(CurrentQuestion.Option1);
            rblOptions.Items.Add(CurrentQuestion.Option2);
            rblOptions.Items.Add(CurrentQuestion.Option3);
            rblOptions.Items.Add(CurrentQuestion.Option4);
        }


        protected void btnNext_Click(object sender, EventArgs e)
        {
            if (rblOptions.SelectedIndex + 1 == CurrentQuestion.Answer) {
                CorrectCount++;
            }

            if (QuestionNumber == 4) {
                Session["CorrectCount"] = CorrectCount.ToString();
                Server.Transfer("Results.aspx");
                Session.Contents.Remove("CorrectCount");
            }
            else {
                QuestionNumber++;
                RenderQuestion();
            }
        }
    }
}

HTML

代码语言:javascript
复制
<form id="form1" runat="server">
    <div>
        <h3>Please choose the right answer</h3>
    </div>
    <table class="style1">
        <tr>
            <td class="style3">
                <asp:Label ID="lblQuestion" runat="server" Text=""></asp:Label>
            </td>
            <td class="style4"> </td>
        </tr>
        <tr>
            <td class="style2">Answers:</td>
            <td> </td>
        </tr>
        <tr>
            <td class="style2">
                <asp:RadioButtonList ID="rblOptions" runat="server"></asp:RadioButtonList>
            </td>
            <td> </td>
        </tr>
        <tr>
            <td class="style2"> </td>
            <td> </td>
        </tr>
        <tr>
            <td class="style2">
                <asp:Button ID="btnNext" runat="server" onclick="btnNext_Click" Text="Next" />
            </td>
            <td> </td>
        </tr>
    </table>
</form>
票数 5
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/158591

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档