ASP.NET Ajaxを利用したWebPartのサンプル

RSSリーダASP.NET Ajaxのクライアントサイドフレームワークで作成しWebPart化するシナリオです。
クライアントサイドでコントロールを作成するのはASP.NET Ajaxの知識範囲でOK。WebPart化する場合のポイントはScriptManagerの取扱い方法に工夫が必要な程度で、それほど特別な点はなし。

以下参考書籍です。

Inside Microsoft Windows SharePoint Services Version 3.0

作成手順

  1. ASP.NET Ajaxクライアントサイドフレームワークでクライアントサイドのコントロール(.jsファイル)を作成
  2. 作成したコントロールのファイルをアセンブリに埋め込まれるように指定
  3. 作成したクライアントサイドのコントロールをWebPart化する

例)

ASP.NET Ajaxクライアントサイドフレームワークでクライアントサイドのコントロールを作成

以下のようなJavaScriptファイルを作成し、ビルドアクションを"埋め込まれたリソース"にする

//名前空間の登録
Type.registerNamespace('SampleAjaxWebPart');

//クラス(コンストラクタ関数)の宣言
SampleAjaxWebPart.AjaxRssControl = function(element) { 
	SampleAjaxWebPart.AjaxRssControl.initializeBase(this, [element]);
    	this._element = element;
    	this._feedCount = 3;
	this._url = null;
}

//メソッドの定義(プロトタイプに定義)
SampleAjaxWebPart.AjaxRssControl.prototype = {

	initialize : function() {
		SampleAjaxWebPart.AjaxRssControl.callBaseMethod(this, 'initialize');
		this.request();	
	},

	// 後処理
	dispose : function() {
		SampleAjaxWebPart.AjaxRssControl.callBaseMethod(this, 'dispose');
	},

	request : function() {
		if (this.get_Url() == null) return;
		if (this.get_Url() == "") return;
        		var wRequest =  new Sys.Net.WebRequest();
        		wRequest.set_url(this.get_Url());  
        		wRequest.set_httpVerb("GET");           
        		this._webRequestCompletedHandler
			= Function.createDelegate(this, this._onWebRequestCompleted);
        		wRequest.add_completed(this._webRequestCompletedHandler);
        		wRequest.invoke();  	
	},
	
	_onWebRequestCompleted : function(executor, eventArgs) 
	{
        		if(executor.get_responseAvailable()) 
        		{
            		var displayElement = this._element;
            		var items = executor.get_xml();        
	        		var items_count;
	        		if ((this._feedCount == 0) 
				|| (this._feedCount > items.selectNodes('//item').length)) {
		        		items_count=items.selectNodes('//item').length;
	        		} else {
		        		items_count=this._feedCount;
	        		}

	            	var divHtml = "";
		        	for(var i=0; i<items_count; i++) {

			        	var node;
			        	var title;
			        	node = items.selectNodes('//item')[i];
		        		title = node.selectSingleNode('title').text;
			        	link = node.selectSingleNode('link').text;
			        	if (this.checkVisited(link)) {
    			        		divHtml= divHtml+ "<a href='"+link+"'>■" + title +"</a><br/>";
		        		} else {
    		        			divHtml= divHtml+ "<a href='"+link+"'>□" + title +"</a><br/>";
		        		}
	        		}
	 	       	displayElement.innerHTML = divHtml;
        		}
        		else
        		{
            		if (executor.get_timedOut()) displayElement.innerText = "Timed Out";
        	    		else if (executor.get_aborted()) displayElement.innerText = "Aborted";
        		}
	},

	checkVisited : function(url)
	{
        		//IE限定の処理ロジック

	    	var id = 'checkVisitedLinkId';	
	    	var style = document.createElement('style');
	    	document.body.appendChild(style);
        		var sheet = style.styleSheet;
        		sheet.addRule( '#' + id + ':visited', '{display:none;position:absolute;top:0px}');
 
 	    	var link = document.createElement('a');
	    	link.id = id
	    	document.body.appendChild(link);
		link.href = url;
   	    	var ret = (link.offsetTop == 0);
	
	    	document.body.removeChild(link);
		document.body.removeChild(style);	

	    	return ret;
	},
	
	// プロパティ
	get_Url : function() {
		return this._url;
	},
	set_Url : function(value) {
		if (this._url != value) {
			this._url = value;
			this.raisePropertyChanged('Url');
		}
	},

	get_FeedCount : function() {
		return this._feedCount;
	},
	set_FeedCount : function(value) {
		if (this._feedCount != value) {
			this._feedCount = value;
			this.raisePropertyChanged('FeedCount');
		}
	}

}

SampleAjaxWebPart.AjaxRssControl.registerClass('SampleAjaxWebPart.AjaxRssControl', Sys.UI.Control);
作成したクライアントサイドのコントロールをWebPart化する
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI;

[assembly: WebResource("SampleAjaxWebPart.Controls.AjaxRssControl.js", "application/x-javascript")]


namespace SampleAjaxWebPart.Controls
{
    public class AjaxRssWebPart : WebPart
    {
        public ScriptManager AjaxScriptManager
        {
            get 
            {
                if (_ajaxScriptManager == null)
                {
                    _ajaxScriptManager = ScriptManager.GetCurrent(this.Page);
                    if (_ajaxScriptManager == null)
                    {
                        _ajaxScriptManager = new ScriptManager();
                        this.Controls.AddAt(0, _ajaxScriptManager);
                    }
                }
                return _ajaxScriptManager; 
            }
        }
        private ScriptManager _ajaxScriptManager;

        private Panel div;

        [Personalizable(), WebBrowsable(), WebDisplayName("RSSのURL")]
        public string Url
        {
            get { return _url; }
            set { _url = value; }
        }
        private string _url;

        [Personalizable(), WebBrowsable(), WebDisplayName("表示数")]
        public int Count
        {
            get { return _count; }
            set { _count = value; }
        }
        private int _count;

        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            div = new Panel();
            this.Controls.Add(div);
            ScriptReference controlScript = new ScriptReference(
                "SampleAjaxWebPart.Controls.AjaxRssControl.js", "SampleAjaxWebPart.Controls");
            this.AjaxScriptManager.Scripts.Add(controlScript);

            StringBuilder sb = new StringBuilder();
            sb.AppendLine("<script language=\"javascript\">");
            sb.Append("  $create(SampleAjaxWebPart.AjaxRssControl, {");
            sb.Append("\"Url\":\"" + _url + "\",");
            sb.Append("\"FeedCount\":" + _count);
            sb.Append("}, null, null, $get(\"" + div.ClientID + "\"));");
            sb.AppendLine();
            sb.AppendLine("</script>");

            this.Page.ClientScript.RegisterStartupScript(
                this.GetType(), "AjaxRssControl" + div.ClientID, sb.ToString());
       
        }

        protected override void Render(HtmlTextWriter writer)
        {
            if (base.DesignMode)
            {
                this.EnsureChildControls();
            }
            this.RenderContents(writer);
        }
    }
}

補足

このサンプルでは、クライアントサイドでRSSデータを取得しているため直接他サイトのRSSデータを読み込むことはできません。他サイトはサーバ経由でRSSデータを読み込む必要があります。
ただ、NTMLで同じサイトのMOSSのRSSデータを権限に応じて読みだすことができるメリットはあるかな。

追記

MOSSではリストアイテムの既読・未読がマークされません。
リンクのvisitedを利用した簡易的な既読/未読の判定を行うためのロジックを追加しました。これでMOSSでも既読・未読が表示できるようになるはずです。