舜亚科技

Providing Custom Software Solution Since 1997

导航

[项目总结-原创]InternetRadio项目Ajax技术方案选型


1 综述


InternetRadio项目是一个基于Web2.0理念的面向大众的音乐共享站点,其大量使用了Ajax功能来提高用户的体验效果,并提高数据传输的效率,典型的比如Autosuggest、添加音乐评论等。为了便于相关代码的集中控制,InternetRadio项目从底层封装、Ajax框架选型、代码管理等方面加以控制。
  Ajax框架选型:Prototype提供Ajax封装,Script.aculo.us提供UI封装。
  代码集中管理:在App_Code/BusinessHandler.cs中统一控制Ajax内容的输出。
  Server端底层实现:利用C#的反射机制,实现Ajax客户端对Server端API的调用。


1.1 Ajax和UI框架选型


InternetRadio选用Prototype(http://www.prototypejs.org/)作为底层Ajax底层框架,包括Ajax API封装和 Javascript扩展;另外选择Script.aculo.us(http://script.aculo.us/)作为UI框架,利用其包括Autosuggest等在内的UI特性。
另外,作为辅助,增加Javascript/AjaxPublic.js进一步封装Prototype API,提供一系列方法简化Ajax客户端调用,比如PreparePostData()、AjaxGetFromUrl()、AjaxGetFromUrlSynchronous()等。


1.2 基于反射的Ajax远程调用实现


与Ajax.NET Professional(http://www.ajaxpro.info/)类似,InternetRadio项目也支持Ajax客户端对Server端API的直接调用,比如:
    function Init() {
        new Ajax.Autocompleter(
            '<%=KeywordTextBox.ClientID %>',
            'AutoSuggestion',
            '../BusinessHandler/AutosuggestForKeywordSearch.ajax',
            {
                tokens:",",
                paramName:"ajax_keyword",
                callback: AutoSuggestionCallback
            }
        );
}
在上述代码中,Ajax直接调用Server端BusinessHandler类的AutosuggestForKeywordSearch方法。Suryani.Ajax Project提供了上述调用的支持和实现。
  提供Suryani.Ajax.Service.ServiceManager.Register(string package, Type serviceType)方法,用于注册要开放给客户端Ajax调用的类。ServiceManager将所注册的类保存在全局变量modules中。
  开放Suryani.Ajax.Utility.AjaxConfiguration.Register(Dictionary<string, Type> source)供Global.asax调用,用于在Website启动时向Server注册全部要开放给客户端调用的类。AjaxConfiguration.Register()方法调用ServiceManager.Register()方法完成所有类的注册。
  增加Suryani.Ajax.Service.AjaxMethodAttribute自定义标签类,用于标识要开放给客户端调用的类方法。Suryani.Ajax.Service.ServiceManager.Register()方法将遍历所注册类的全部方法,将附加AjaxMethod自定义标签的所有方法保存在modules全局变量中,以备客户端Ajax调用。
  提供Suryani.Ajax.Service.AjaxHttpHandler自定义HttpHandler类,拦截来自客户端的所有Ajax 请求(该请求的URL以".ajax"结尾),解析URL,利用反射的原理从全局变量modules中获取已注册的类和方法,并将执行结果输出到客户端。

 

初始化并注册类

 

Ajax远程调用Server端API的过程

 

1.3 Ajax代码集中管理


由于InternetRadio项目中大量用到Ajax功能,客户端Ajax可以直接调用Server端的API,而且每一个Ajax请求都需要Server端根据请求组织要交付Browser端的内容。为了对这些代码集中管理,我们在App_Code中增加了BusinessHandler类,作为Browser端与Server端的中介,负责请求的响应和内容的组织。而且整个项目中,只开放BusinessHandler供客户端直接调用调用。比如:
/// <summary>
/// 根据标签关键词搜索对应的标签
/// </summary>
/// <param name="keyword"></param>
 [AjaxMethod]
public string FindTagsByKeyword(string keyword)
{
    StringBuilder builder = new StringBuilder();
    try
    {
       IList<Tag> tags = TagManager.FindTagsByKeyword(keyword);
       if (tags != null)
       {
           builder.Append("<ul>");
           foreach (Tag tag in tags)
           {
                builder.Append(string.Format(CultureInfo.CurrentCulture, "<li>{0}</li>", tag.TagName));
           }
           builder.Append("</ul>");
       }
     }
     catch { }
     return builder.ToString();
}


1.4 典型应用


1.4.1 简单的Ajax应用:添加歌曲标签


URL:http://nyxm.vicp.net:5052/Music/Music.aspx?MusicId=26553
功能描述:为当前歌曲添加相应的自定义标签
程序主文件:UserControl/MusicInfoControl.ascx
代码流程:
  单击"保存"按钮:SaveTagButtonOnClick()
function SaveTagButtonOnClick()
{
    var tagName = $('<%= TagNameTextBox.ClientID %>').value;
    var musicId=$('<%= MusicIdHiddenField.ClientID %>').value;
    var url = "/BusinessHandler/AddTag.ajax?ajax_tagName=" + encodeURIComponent(tagName) + "&ajax_musicId="+musicId;
    AjaxGetFromUrl(url,SaveTagCallBack);
    $('<%= TagNameTextBox.ClientID %>').value="";
}
调用AjaxGetFromUrl()方法,通过Prototype向Server端发起Ajax请求。
  AjaxHttpHandler拦截到Ajax请求,执行BusinessHandler.AddTag()方法,向Browser输出以<span>形式组织的标签列表:
/// <summary>
/// 添加歌曲的标签
/// </summary>
/// <param name="tagName"></param>
/// <param name="musicId"></param>
[AjaxMethod]
public string AddTag(string tagName, int musicId)
{
    int userId = ContextAccessor.Current.UserId;
    string createBy = ContextAccessor.Current.UserName;
    TagManager.Add(tagName, createBy, musicId, userId);
    IList<Tag> tags = TagManager.FindTagsByMusicId(musicId);
    StringBuilder returnString = new StringBuilder();
    foreach (Tag tag in tags)
    {
 returnString.Append("<span>");
 returnString.Append(PageContentBuilder.BuildTagSearchLink(tag.TagName, tag.TagName));
 returnString.Append("</span>&nbsp;&nbsp;\n");
    }
    return returnString.ToString();
}
  回调函数SaveTagCallBack()检测到 Server端返回的标签列表,将其呈现在页面上:
function SaveTagCallBack(request)
{   
    $('TagListDiv').innerHTML = request.responseText;
}
 

 

1.4.2 结合Script.aculo.us的应用:Autosuggest


URL:http://nyxm.vicp.net:5052/Index.aspx
功能描述:根据关键词框的输入,自动提示补录。
程序主文件:UserControl/ QuickSearchControl.ascx
代码流程:
  页面初始化:
当页面载入的时候,利用Script.aculo.us的Autocompleter控件实现对关键词输入框的监控。
function Init() {
    new Ajax.Autocompleter(
        '<%=KeywordTextBox.ClientID %>',
        'AutoSuggestion',
        '../BusinessHandler/AutosuggestForKeywordSearch.ajax',
        {
            tokens:",",
            paramName:"ajax_keyword",
            callback: AutoSuggestionCallback
 }
    );
}
Event.observe(window,'load',Init);
  当用户在关键词输入框输入关键词时,Autocompleter控件向Server端发起Ajax请求,检索提示内容。AjaxHttpHandler拦截该请求,执行BusinessHandler.AutosuggestForKeywordSearch()方法:
/// <summary>
/// 根据关键词检索对应的音频
/// </summary>
/// <param name="searchType"></param>
/// <param name="keyword"></param>
/// <returns></returns>
[AjaxMethod]
public string AutosuggestForKeywordSearch(string searchType, string keyword)
{
    if (searchType.Equals(WebConstants.Search_Player, StringComparison.OrdinalIgnoreCase))
    {
        return FindPlayersByKeyword(keyword);
    }
    else if (searchType.Equals(WebConstants.Search_Music, StringComparison.OrdinalIgnoreCase))
    {
        return FindMusicByKeyword(keyword);
    }
    else if (searchType.Equals(WebConstants.Search_Tag))
    {
        return FindTagsByKeyword(keyword);
    }
    return string.Empty;
}
Server端以无序列表<ul>的形式组织返回给Browser端的Autosuggest内容列表。
  回调函数AutoSuggestionCallback()将Autosuggest内容呈现在页面上:
function AutoSuggestionCallback(obj) {
    var searchType = "Player";
    if($("<%=PlayerRadioButton.ClientID %>").checked == true) searchType = "Player";
    else if($("<%=MusicRadioButton.ClientID %>").checked == true) searchType = "Music";
    else if($("<%=TagRadioButton.ClientID %>").checked == true) searchType = "Tag";
    return "ajax_searchType="+searchType+"&ajax_keyword="+ encodeURIComponent(obj.value);
}
 

 

posted on 2008-09-03 10:32  Suryani  阅读(1969)  评论(3编辑  收藏  举报