ASP.NET AJAX Extensions, Source Available
Microsoft released the source for the AJAX extensions for ASP.NET. Get the source here.
« January 2007 | Main | March 2007 »
Microsoft released the source for the AJAX extensions for ASP.NET. Get the source here.
This is a really cool announcement. Microsoft.com will be running on the Microsoft Office SharePoint Server 2007 platform. Very cool!
http://marcd.spaces.live.com/Blog/cns!611216EE7EB3297A!993.entry
I was having some problems getting a composite workflow activity that I am developing working within an existing common project that I have in my Visual Studio solution.
The Error:
One or more errors encountered while loading the designer. The errors are listed below. Some errors can be fixed by rebuilding your project, while others may require code changes.
The service 'System.Workflow.ComponentModel.Compiler.ITypeProvider' must be installed for this operation to succeed. Ensure that this service is available.
The Answer:
I was ego surfing today and came upon the following links that related to the "Add A Recycle Bin To Windows SharePoint Services For Easy Document Recovery" artcile that I contributed to last year.
I'm working exclusively with MOSS these days and it has a Recycle Bin out of the box (and very nicely implemented).

He didn't win any Grammys and my wife is super mad :(
For some reason I was having issues with this today and wasn't able to find a very simple example. This is good mostly for Unit Testing private methods.
using System;
using System.Reflection;
using System.Collections.Generic;
public class MyClass
{
public static void Main()
{
try
{
Console.WriteLine("TestReflect started.");
TestReflect test = new TestReflect();
Console.WriteLine("TestReflect ended.");
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
ConsoleKeyInfo cki;
do
{
Console.WriteLine("Press the 'Q' key to exit.");
cki = Console.ReadKey(true);
} while (cki.Key != ConsoleKey.Q);
}
}
public class TestReflect
{
public TestReflect()
{
this.GetType().GetMethod("PublicMethod").Invoke(this, null);
this.GetType().GetMethod("PrivateMethod", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(this, null);
}
public void PublicMethod()
{
Console.WriteLine("PublicMethod called");
}
private void PrivateMethod()
{
Console.WriteLine("FTW!one1");
}
}
I have noticed quite a few posts/projects out there that focus on using ASP.NET AJAX within custom MOSS web parts. Mike Ammerlaan has a great post on some of the background around AJAX and MOSS
This post describes what my team and I have been using for the past couple of months. It is a simple base class called AjaxBasePart.
Background:
I developed a .NET class in early November that allowed my team to take advantage of the MS AJAX Extensions from custom MOSS web parts. There were a number of problems that I did not resolve on my own though.
For the next month or so I worked on and off with the AJAX Extensions and MOSS product teams and with our powers combined we were able to come up with the AjaxBasePart class that custom MOSS web parts can derive from and fully enables all AJAX Extensions functionality within MOSS.
Very Simple Setup:
There is no need to modify master pages after the AJAX Extensions have been installed and the web.config is setup your web parts will manage the registration of a shared ScriptManager or in the case that one exists use that. If I'm missing anything please notify me in the comments and I will update.
Support:
If you are looking for support I will do my best to assist via the comments on this post. This is in no way supported by Microsoft.
Credits:
The following Microsoft employees assisted me in the development of the AjaxBasePart. Thanks guys!
Bonus:
You will also notice a public RegisterError method on the AjaxBasePart. I find it to be a clean way to show users web part related error messages in a common way.
To use all you need to do is; from your custom web part call the RegisterError message and pass the string that you would like displayed to the user.
base.RegisterError("Some error message.");
Code:
using System;
using System.Xml.Serialization;
using System.Web.UI.WebControls;
using System.Web.UI;
using System.Drawing;
using System.Web;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.WebPartPages;
namespace CapDes.SharePoint
{
/// <summary>
/// AjaxBasePart allows Microsoft ASP.NET AJAX Extensions to work within Microsoft Office SharePoint Server 2007 webparts.
/// </summary>
[XmlRoot(Namespace = "CapDes.SharePoint.AjaxBasePart")]
[CLSCompliant(false)]
public abstract class AjaxBasePart : WebPart
{
private string _ValidationGroupId;
private ValidationSummary _ErrorContainer;
private ScriptManager _AjaxManager;
/// <summary>
/// Exposes the Page's script manager. The value is not set until after OnInit
/// </summary>
[WebPartStorage(Storage.None)]
public ScriptManager AjaxManager
{
get { return _AjaxManager; }
set { _AjaxManager = value; }
}
/// <summary>
/// Oninit fires before page load. Modifications to the page that are necessary to support Ajax are done here.
/// </summary>
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
//get the existing ScriptManager if it exists on the page
_AjaxManager = ScriptManager.GetCurrent(this.Page);
if (_AjaxManager == null)
{
//create new ScriptManager and EnablePartialRendering
_AjaxManager = new ScriptManager();
_AjaxManager.EnablePartialRendering = true;
// Fix problem with postbacks and form actions (DevDiv 55525)
Page.ClientScript.RegisterStartupScript(typeof(AjaxBasePart), this.ID, "_spOriginalFormAction = document.forms[0].action;", true);
//tag:"form" att:"onsubmit" val:"return _spFormOnSubmitWrapper()" blocks async postbacks after the first one
//not calling "_spFormOnSubmitWrapper()" breaks all postbacks
//returning true all the time, somewhat defeats the purpose of the _spFormOnSubmitWrapper() which is to block repetitive postbacks, but it allows MS AJAX Extensions to work properly
//its a hack that hopefully has minimal effect
if (this.Page.Form != null)
{
string formOnSubmitAtt = this.Page.Form.Attributes["onsubmit"];
if (!string.IsNullOrEmpty(formOnSubmitAtt) && formOnSubmitAtt == "return _spFormOnSubmitWrapper();")
{
this.Page.Form.Attributes["onsubmit"] = "_spFormOnSubmitWrapper();";
}
//add the ScriptManager as the first control in the Page.Form
//I don't think this actually matters, but I did it to be consistent with how you are supposed to place the ScriptManager when used declaritevly
this.Page.Form.Controls.AddAt(0, _AjaxManager);
}
}
}
/// <summary>
/// Needs to be called to ensure that the ValidationSummary control is registered on the page. Any child web parts will need to have base.CreateChildControls() at the top of their own CreateChildControls override.
/// </summary>
protected override void CreateChildControls()
{
base.CreateChildControls();
if (!this.Controls.Contains(_ErrorContainer))
{
_ValidationGroupId = Guid.NewGuid().ToString();
_ErrorContainer = new ValidationSummary();
_ErrorContainer.ID = "_ErrorContainer";
_ErrorContainer.ValidationGroup = _ValidationGroupId;
_ErrorContainer.BorderStyle = BorderStyle.Solid;
_ErrorContainer.BorderWidth = Unit.Pixel(3);
_ErrorContainer.BorderColor = Color.Red;
this.Controls.Add(_ErrorContainer);
}
}
/// <summary>
/// Used to provide a common way to display errors to the user of the current web part.
/// </summary>
/// <param name="message">Description of the error that occured.</param>
public void RegisterError(string message)
{
if (this.Controls.Contains(_ErrorContainer))
{
//this way of generating a unique control id is used in some of the OOB web parts
int uniqueCounter;
if (HttpContext.Current.Items["GetUniqueControlId"] != null)
{
uniqueCounter = (int)HttpContext.Current.Items["GetUniqueControlId"];
}
else
{
uniqueCounter = 0;
}
uniqueCounter++;
HttpContext.Current.Items["GetUniqueControlId"] = uniqueCounter;
//create a custom validator to register the current error message with the ValidationSummary control
CustomValidator cv = new CustomValidator();
cv.ID = string.Concat("_Error_", uniqueCounter);
cv.ValidationGroup = _ValidationGroupId;
cv.Display = ValidatorDisplay.None;
cv.IsValid = false;
cv.ErrorMessage = message;
this.Controls.Add(cv);
}
else
{
//if RegisterError is called before the CreateChildControls override in AjaxBasePart then transfer the user to an error page using the SPUtility
SPUtility.TransferToErrorPage("The CreateChildControls function of the AjaxBasePart has not been called. You probably need to add \"base.CreateChildControls()\" to the top of your CreateChildControls override.");
}
}
}
}
That was fast... Jan Tielens has implemented the AjaxBasePart in the SmartPart web part to add AJAX functionality.
From Jan Tielens' Bloggings:
I've created a version of the SmartPart that makes use of the Eric's technique, let me introduce you the SmartPart with AJAX! So basically said: you can create a Web User Control (ASCX) with the Visual Studio Designer, that uses the ASP.NET AJAX extensions and run that user control as a SharePoint web part.
That's awsome! Be sure not to miss the screencast that Jan has put together, it does a pretty good job of showing some of the interesting things you can do with AJAX inside of a web part.
The SmartPart is an excellent tool, especially for casual developers that would like to develop SharePoint web parts but don't want to give up the designer experience that you get with normal ASP.NET development.
This page contains all entries posted to Capital Design in February 2007. They are listed from oldest to newest.
January 2007 is the previous archive.
March 2007 is the next archive.
Many more can be found on the main index page or by looking through the archives.