使用 Atlas 的简单 AJAX 测验
使用 Atlas 控件和 Web 服务创建测验的简单方法。
引言
作为我在 Code Project 上的第一篇文章,我想谈谈我围绕 AJAX/Atlas 技术创建的一个小小的概念验证。当我看到 这个截屏时,我认为它可以很容易地用于一个简单的 AJAX 测验系统,所以我就在这里了 :) 代码确实很简单,而且没有错误管理,但也许以后,我会更新此代码以创建一个更完整的解决方案。
必备组件
为了能够使用此代码,您需要执行以下操作
- 安装 Atlas。
- 创建一个名为 AjaxQuiz 的 SQL 数据库,并执行源代码附带的 SQL 脚本。
- 添加对 Atlas DLL 的引用(通常位于 C:\Program Files\Microsoft ASP.NET\Atlas\v2.0.50727\Atlas)。
- 修改 web.config 中的
AjaxQuiz
连接字符串。
SQL 代码
AjaxQuiz 数据库包含三个表:t_Questions、t_Answers 和 t_UserAnswers。还有一个由我们的 Web 方法调用的存储过程来处理数据
CREATE PROCEDURE dbo.ProcessNextQuestion
(
@intQuestionID int = 0,
@intAnswerID int = 0,
@intUserID int = 0
)
AS
IF @intQuestionID > 0 AND @intAnswerID > 0 AND @intUserID > 0
BEGIN
INSERT INTO t_UserAnswers(UserID, AnswerID, QuestionID)
VALUES(@intUserID, @intAnswerID, @intQuestionID)
END
SELECT TOP 1 QuestionID, QuestionText
FROM t_Questions
WHERE QuestionID > @intQuestionID
如您所见,如果 SQL 输入参数不为 null,存储过程会在数据库中插入上一个问题的结果。然后,它返回下一个问题的文本和 ID。由于 QuestionID
是自动递增的,因此始终返回下一个问题,但它假设 ID 对应于所需的问题顺序。
标记代码
在这个小项目中只有一个网页:Default.aspx。首先,我必须描述 ScriptManager
元素
<atlas:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="true">
<Scripts>
<atlas:ScriptReference Path="AjaxQuiz.js" />
</Scripts>
<Services>
<atlas:ServiceReference Path="QuestionService.asmx" />
</Services>
</atlas:ScriptManager>
这就是 Atlas 真正好的地方:我们只需要引用我们的 JS 客户端脚本和我们的 Web 服务,Atlas 就会完成剩下的工作(用于使用 WS 的客户端代码等)。在我们的 JS 代码中,我们还将能够创建在服务器代码中定义的类的实例。Atlas 将为我们进行对应。
<div id="StartForm">
<input id="btnStart" type="button" value="Start the Ajax Quiz !" onclick="Callback()" />
</div>
<div id="QuizForm" style="display: none;">
<div id="QuestionText"></div><br />
<input type="radio" id="YesAnswer" name="Answer" checked="checked" /> Yes
<input type="radio" id="NoAnswer" name="Answer" /> No
<input type="radio" id="DontKnowAnswer" name="Answer" /> ?<br /><br />
<input id="btnCallBack" type="button" value="Next" onclick="Callback()" />
<img id="imgUpdate" src="Images/spinner.gif" alt="Updating data" style="display: none;" />
<input id="QuestionID" type="hidden" value="0" />
</div>
<div id="EndForm" style="display: none;">
Thank you, this quiz is now finished !
</div>
然后,我们添加一些 HTML 控件来创建我们的表单。首先,有三个 DIV
:一个在启动时显示,另一个用于测验问题,最后一个在测验完成后显示。主部分 QuizForm
包含三个用于答案的单选按钮、一个用于调用我们的 Web 服务的按钮以及在 AJAX 调用期间显示的图像。
Web服务
Web 服务只包含一个 WebMethod,StoreAnswer
/// <summary>
/// That's the only Web Method used. It both stores the answer to the current question
/// and sends data for the next one.
/// </summary>
/// <param name="previousQuestion">A Question object containing user answer.</param>
/// <returns>Returns a Question object containing data
/// for the next question (question ID, question Text)</returns>
[WebMethod]
public Question StoreAnswer(Question previousQuestion)
{
// We initialize a Question object to null. It will be our return value.
Question nextQuestion = null;
if (previousQuestion == null)
{
// If no previous question is submitted, we create a new one with default values.
previousQuestion = new Question(0, "", 0);
}
// SQL connection initialization (connection string is in web.config file)
using (SqlConnection cn = new SqlConnection(
ConfigurationManager.ConnectionStrings["AjaxQuizConnectionString"].ConnectionString))
{
try
{
// Then we call our stored procedure
SqlCommand cmd = new SqlCommand("dbo.ProcessNextQuestion", cn);
cmd.CommandType = CommandType.StoredProcedure;
// First parameter for question ID.
SqlParameter parm = new SqlParameter("@intQuestionID", SqlDbType.Int);
parm.Value = previousQuestion.QuestionID;
parm.Direction = ParameterDirection.Input;
cmd.Parameters.Add(parm);
// Second parameter for answer ID.
SqlParameter parm2 = new SqlParameter("@intAnswerID", SqlDbType.Int);
parm2.Value = previousQuestion.AnswerID;
parm2.Direction = ParameterDirection.Input;
cmd.Parameters.Add(parm2);
// Third parameter for user ID.
SqlParameter parm3 = new SqlParameter("@intUserID", SqlDbType.Int);
parm3.Value = userID;
parm3.Direction = ParameterDirection.Input;
cmd.Parameters.Add(parm3);
// Opening sql connection
cn.Open();
using (SqlDataReader rd =
cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
while (rd.Read())
{
// We read data returned by our SP. It only returns one row.
nextQuestion = new Question(rd.GetInt32(0), rd.GetString(1));
}
}
// We make the web service sleep for one second,
// so that we can see the spinner image appear.
// This line should be removed
// if you seriously think about using this code ^^
Thread.Sleep(1000);
}
finally
{
// Important : we always have to close the sql connection
cn.Close();
}
}
return nextQuestion;
}
WebMethod 调用一个存储过程,然后将下一个问题作为 Question
对象返回。我让线程休眠一秒钟,这样我就可以看到旋转图像。
JavaScript 代码
JavaScript 代码可能是最难的部分,因为我们必须引用我们所有的 HTML 对象并获取/设置它们的值。肯定有更简单的方法来完成这项工作,所以请不要犹豫,在评论部分提出一些建议。OnTimeout
和 OnError
函数未包含在内,但存在于 Zip 文件中。
// Called on 'Next' button click event.
function Callback()
{
// Gets a reference to the hidden field containing the question ID
var questionID = document.getElementById('QuestionID');
// Gets references to the 3 possible answers
var answer1 = document.getElementById('YesAnswer');
var answer2 = document.getElementById('NoAnswer');
var answer3 = document.getElementById('DontKnowAnswer');
// Initializes a variable to hold the user answer
var answerID = 0;
// Gets user answer
if(answer1.checked) answerID = 1;
if(answer2.checked) answerID = 2;
if(answer3.checked) answerID = 3;
// Creates a new Question object. Atlas makes
// the translation for us : JS and ASP.NET
// know exactly the same class !
var object = new Question();
object.QuestionID = questionID.value;
object.AnswerID = answerID;
// Displays a image during the AJAX call
DisplayUpdateImage(true);
// Ajax call. QuestionService is the Web Service
// we registered in Atlas ScriptManager
// and as you can see, we can directly
// call our WebMethod. Isn't it nice ? :)
// We also add 3 events : one when process is completed,
// another when a timeout occurs,
// and a last one if an error occurs.
QuestionService.StoreAnswer(object, OnComplete, OnTimeout, OnError);
}
// Called when Ajax request is done
function OnComplete(response)
{
// 3 references to our 3 DIVs
var StartForm = document.getElementById('StartForm');
var QuizForm = document.getElementById('QuizForm');
var EndForm = document.getElementById('EndForm');
// A reference to the hidden field used to hold the question ID
var questionID = document.getElementById('QuestionID');
// A reference to the DIV which will contain the next question text
var questionText = document.getElementById('QuestionText');
// If there is a next question
if(response != null)
{
StartForm.style.display = 'none';
EndForm.style.display = 'none';
QuizForm.style.display = 'block';
questionID.value = response.QuestionID;
questionText.innerHTML = response.QuestionText;
}
// If there's no more questions, we display the EndForm div.
else
{
EndForm.style.display = 'block';
QuizForm.style.display = 'none';
}
// We hide the updating image
DisplayUpdateImage(false);
}
结论
就是这样!当用户单击“开始”按钮时,他会看到第一个问题出现。由于输入 Question
对象为空,因此不会将结果插入数据库。然后,当他单击“下一步”按钮时,结果会存储在数据库中,我们的存储过程会发送下一个问题……等等,直到存储过程没有任何返回。在这种情况下,最后,用户会看到结束消息。
好的,我知道这是一篇相当简单的文章,但我认为它可以说明您可以使用 Atlas 做什么以及它有多么容易。我也希望我的英语不是太差 :)