★★★本博客欢迎转载,但请注明版权、原文链接,谢谢。
Memento..
My stories in my way..

在本文中,流牛木马为大家演示一个完整的Azure程序开发实例:在线日程表。跟上一个实例Stick Love 的仅能新增、读取实体相比,本次的数据实体稍微复杂,对数据的操作包括完整的增、删、改、查(CRUD),并增加了与Windows Live Id集成验证身份的功能。

本项目的前身是给老婆的一个办公系统里的小巧私用日程表,现将其提取出来,集合LiveId使之通用。老婆大人功不可没。

(如果你以前从未了解过Azure,请查看这里。)

在线演示:http://live.cloudapp.net/

界面截图:

6

 

重点步骤:

一、集成Live Services

    在以前的文章中我们提到过,Live Services是Azure Services Platform的组成部分。Live Services包括了很多内容,今天我们要使用的是Windows Live Tools 里的集成LiveId身份验证功能。

    其实在Azure发布前,Live就开放了其LiveId的API接口。不过那时比较麻烦,今天的Windows Live Tools跟Azure配合的天衣无缝,为开发人员省力不少。

  1.    首先,打开VS2008,新建一个空白Cloud应用程序。
  2. 在Roles上单击右键,选择“New Web Role Project”,并选择Windows Live Web Role,如下两图所示。12
  3. 此时,设计视图的工具栏(Toolbar)中将出现Windows Live的控件组。包含各种很酷的服务。最好玩当然是MessagerChat了,是网页MSN聊天的控件!当然今天不介绍它。今天我们使用能够快捷集成LiveId身份验证的IDLoginStatus控件。如下图:将IDLoginStatus控件拖放到右侧的页面中。3
  4. 拖完控件后,只需要做简单的配置就可以使用了。方法是点击IDLoginStatus控件右侧的小箭头,选择“Configure Application ID”,将这个控件与你Azure平台上的应用程序ID进行绑定。
    5
  5. 搞定了!在之后的开发中,就不用维护登录状态了。为了使没有放置IDLoginStatus控件的页面能够使用LiveId,我们需要在用户登录时,把用户的信息写入Session中。我的方法如下:
    protected void IDLoginStatus1_ServerSignIn(object sender, Microsoft.Live.ServerControls.AuthEventArgs e)
          {
              Session["LiveId"] = IDLoginStatus1.ApplicationUserID;
          }
    这样,在未放置IDLoginStatus控件的页面,我们可以通过判断Session["LiveId"]的值来取得用户的身份信息。

二、创建实体和数据服务

           和Stick Love类似,我们需要创建实体和数据服务。(详细的步骤请参考基础章节)

    1. 数据实体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; }
        }
    2. 创建数据服务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页面。

  1. 新建一个aspx页面Calendar.aspx.将页面代码全部删除。仅保留
    <%@PageLanguage="C#"AutoEventWireup="true"CodeBehind="Calendar.aspx.cs"Inherits="AzureCalendar.Calendar"%>
  2. 在后台的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);
               }
           }
  3. 写入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”。实现方法比较丑,相信大家有更优雅的方法。
  4. 其他的增加、修改、删除数据都大同小异。以删除数据为例:
    //删除任务 
          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/


     
     
     
     
     
     

     

posted on 2009-07-07 13:51  流牛木马  阅读(5209)  评论(5编辑  收藏  举报