在本文中,流牛木马为大家演示一个完整的Azure程序开发实例:在线日程表。跟上一个实例Stick Love 的仅能新增、读取实体相比,本次的数据实体稍微复杂,对数据的操作包括完整的增、删、改、查(CRUD),并增加了与Windows Live Id集成验证身份的功能。
本项目的前身是给老婆的一个办公系统里的小巧私用日程表,现将其提取出来,集合LiveId使之通用。老婆大人功不可没。
(如果你以前从未了解过Azure,请查看这里。)
在线演示:http://live.cloudapp.net/
界面截图:
重点步骤:
一、集成Live Services
在以前的文章中我们提到过,Live Services是Azure Services Platform的组成部分。Live Services包括了很多内容,今天我们要使用的是Windows Live Tools 里的集成LiveId身份验证功能。
其实在Azure发布前,Live就开放了其LiveId的API接口。不过那时比较麻烦,今天的Windows Live Tools跟Azure配合的天衣无缝,为开发人员省力不少。
- 首先,打开VS2008,新建一个空白Cloud应用程序。
- 在Roles上单击右键,选择“New Web Role Project”,并选择Windows Live Web Role,如下两图所示。
- 此时,设计视图的工具栏(Toolbar)中将出现Windows Live的控件组。包含各种很酷的服务。最好玩当然是MessagerChat了,是网页MSN聊天的控件!当然今天不介绍它。今天我们使用能够快捷集成LiveId身份验证的IDLoginStatus控件。如下图:将IDLoginStatus控件拖放到右侧的页面中。
- 拖完控件后,只需要做简单的配置就可以使用了。方法是点击IDLoginStatus控件右侧的小箭头,选择“Configure Application ID”,将这个控件与你Azure平台上的应用程序ID进行绑定。
- 搞定了!在之后的开发中,就不用维护登录状态了。为了使没有放置IDLoginStatus控件的页面能够使用LiveId,我们需要在用户登录时,把用户的信息写入Session中。我的方法如下:
protected void IDLoginStatus1_ServerSignIn(object sender, Microsoft.Live.ServerControls.AuthEventArgs e) { Session["LiveId"] = IDLoginStatus1.ApplicationUserID; }这样,在未放置IDLoginStatus控件的页面,我们可以通过判断Session["LiveId"]的值来取得用户的身份信息。
二、创建实体和数据服务
和Stick Love类似,我们需要创建实体和数据服务。(详细的步骤请参考基础章节)
- 数据实体Schedule.cs
public class Schedule: Microsoft.Samples.ServiceHosting.StorageClient.TableStorageEntity
{
publicSchedule()
{
PartitionKey = "000000";
RowKey = (DateTime.MaxValue.Ticks - DateTime.Now.Ticks).ToString();
}
public stringId { get; set; }
public stringTask { get; set; }
publicDateTimeBuildDate { get; set; }
public stringLiveId { get; set; }
} - 创建数据服务ScheduleDataServiceContext.cs(增删改查功能)
public class ScheduleDataServiceContext: TableStorageDataServiceContext { public ScheduleDataServiceContext(StorageAccountInfo accountInfo) : base(accountInfo) { } //定义公共属性Schedules public IQueryable<Schedule> Schedules { get { return this.CreateQuery<Schedule>("Schedules"); } } //添加一个Schedule public void AddSchedule(Schedule c) { this.AddObject("Schedules", c); this.SaveChanges(); } //删除一个Schedule public void DelSchedule(Schedule c) { this.AttachTo("Schedules", c, "*"); this.DeleteObject(c); this.SaveChanges(); } //修改一个Schedule public void UpdateSchedule(Schedule c) { this.AttachTo("Schedules", c, "*"); this.UpdateObject(c); this.SaveChanges(); } }
大家注意到,删除操作和修改操作的时候,需要先使用this.AttachTo("Schedules", c, "*")指明实体的位置。
三、AJAX前台调用
前台采用jquery实现简单的AJAX,包括“增删改查”数据的前台调用。修改、删除、增加数据都大同小异,以更新数据为例,前台js函数为:
//更新任务信息 function updateTask() { var taskId = $("#taskId").val(); //任务编号 var taskInfo = $("#editTaskInfo").val(); //任务内容 //检查任务信息是否为空 if ($.trim(taskInfo)=="") { alert("Please input task information."); } else { $.post("Calendar.aspx", //服务器页面地址 { action: "updateTask", //action参数 taskId: taskId, //年月参数 taskInfo: taskInfo //任务信息参数 }, function() { //回调函数 $("#task" + taskId).html(taskInfo); //更新页面任务内容 closeEditBox(); //关闭编辑box } ); }
其中Calendar.aspx页面是AJAX调用的页面,即后台主功能页面。此外,前台还需要做的工作是通过AJAX读取JSON格式的数据并填充。/从服务器获取任务信息 function getTasks() { $.getJSON("Calendar.aspx", //服务器页面地址 { action: "getTasks", //action参数 month: year + "-" + (month + 1) //年月参数 }, function(json) { //回调函数 //遍历JSON数组,建立任务信息 $(json).each(function(i){ buildTask(json[i].builddate, json[i].id, json[i].task); }); } ); } //根据日期、任务编号、任务内容在页面上创建任务节点 function buildTask(buildDate, taskId, taskInfo) { $("#" + buildDate).parent().append("<div id='task" + taskId + "' class='task' onclick='editTask(this)'>" + taskInfo + "</div>"); }
四、AJAX后台处理
AJAX后台处理页面的左右就是根据前台通过js函数post的参数进行处理,再输出返回结果。AJAX后台处理页的制作方式很多,比如使用WebServices,ashx(HttpHandler)等等,我们这里使用最普通的aspx页面。
- 新建一个aspx页面Calendar.aspx.将页面代码全部删除。仅保留
<%@PageLanguage="C#"AutoEventWireup="true"CodeBehind="Calendar.aspx.cs"Inherits="AzureCalendar.Calendar"%> - 在后台的Page_Load函数中处理post参数,并选择合适的函数进一步处理数据并输出。
protected void Page_Load(objectsender, EventArgse)
{
if(Session["LiveId"] == null)
{
Response.Redirect("Default.aspx");
}//设置页面无缓存 Response.Cache.SetCacheability(HttpCacheability.NoCache);
Request.ContentEncoding = Encoding.UTF8; string action = Request.Params["action"]; //根据action不同执行不同的操作 if ("addTask".Equals(action)) { //新建任务 String taskInfo = Request.Params["taskInfo"]; String buildDate = Request.Params["buildDate"]; Response.Write(addTask(taskInfo, buildDate)); } else if ("getTasks".Equals(action)) { //获取整月任务信息 String month = Request.Params["month"]; String result = getTasks(month); Response.Write(result); } else if ("delTask".Equals(action)) { //删除任务 String taskId = Request.Params["taskId"]; delTask(taskId); } else if ("updateTask".Equals(action)) { //更新任务信息 String taskId = Request.Params["taskId"]; String taskInfo = Request.Params["taskInfo"]; updateTask(taskId, taskInfo); } }
写入protected string getTasks(string month)。
这步很关键,我们采用JSON返回数据,前台通过AJAX调用得到JSON对象并填充前台页面外观。
protected string getTasks(string month) { StorageAccountInfo accountInfo = StorageAccountInfo.GetAccountInfoFromConfiguration("TableStorageEndpoint"); TableStorage.CreateTablesFromModel(typeof(ScheduleDataServiceContext), accountInfo); ScheduleDataServiceContext context = new ScheduleDataServiceContext(accountInfo); List<Schedule> list= context.Schedules.Where(p=>p.LiveId==Session["LiveId"].ToString()).ToList(); string json="[\n"; //开始封装JSON格式 foreach (Schedule s in list) { if (s.BuildDate.ToString("yyyy-MM-dd").Replace("-0","-").Contains(month)) { string strSchedule = "{\"id\":\"" + s.Id + "\",\"builddate\":\"" + s.BuildDate.ToString("yyyy-MM-dd") + "\",\"task\":\"" + s.Task + "\"}"; json = json + strSchedule + ",\n"; } } json = json.Substring(0, json.Length - 2); json += "\n]"; if (json.Length < 10) return "[\n{\"id\":\"0\",\"builddate\":\"0\",\"task\":\"0\"}\n]";//如果没有数据,则返回一个废数据保证格式正确 return json.Replace("-0", "-"); }
为了配合前台,我们把形如"2009-07-01”的字符串替换成"2009-7-1”。实现方法比较丑,相信大家有更优雅的方法。其他的增加、修改、删除数据都大同小异。以删除数据为例:
//删除任务 protected void delTask(string taskId) { StorageAccountInfo accountInfo = StorageAccountInfo.GetAccountInfoFromConfiguration("TableStorageEndpoint"); TableStorage.CreateTablesFromModel(typeof(ScheduleDataServiceContext), accountInfo); ScheduleDataServiceContext context = new ScheduleDataServiceContext(accountInfo); Schedule s = new Schedule(); s.RowKey = taskId; context.DelSchedule(s); }
这里有两个问题需要说明:在修改和删除数据时,需要指明对象的主键。
在Azure Storage中,对象的主键是RowKey和PatitionKey。由于本例里PatitionKey相同,我们只需要指明RowKey即可。
好了,大功告成!再慢慢增加一些细节吧!
PS:全部源代码稍后将放到CodePlex上,谢谢大家的支持!
更多的Azure技术文章在这里。(转载请保留作者博客链接,http://azure.cnblogs.com/)