« January 2007 | Main | March 2007 »

February 2007 Archives

February 2, 2007

ASP.NET AJAX Extensions, Source Available

Microsoft released the source for the AJAX extensions for ASP.NET. Get the source here.

Technorati tags: , , , ,

February 4, 2007

Microsoft.com, built on MOSS

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

Technorati tags: , ,

February 5, 2007

Workflow in Non-Workflow Visual Studio 2005 Project

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:

  1. <ProjectTypeGuids>{14822709-B5A1-4724-98CA-57A101D1B079};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>

    Open the destination project with a text editor and paste the above node in the same <PropertyGroup/> as the <AssemblyName/> node.
  2. <Import Project="$(MSBuildExtensionsPath)\Microsoft\Windows Workflow Foundation\v3.0\Workflow.Targets" />

    Paste the above node at the same level as any existing <Import/> nodes.
  3. Make sure that you have all the proper references in your project.

SharePoint 2003 Recycle Bin Links

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).

Technorati tags: , , ,

February 11, 2007

James blunt

He didn't win any Grammys and my wife is super mad :(

Technorati tags: , , ,

February 19, 2007

Example: Call Private Method w/ Reflection

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");

   }

}


Technorati tags: , , , ,

AjaxBasePart: Easy ASP.NET 2.0 AJAX Extensions 1.0 and Office SharePoint Server 2007

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.

  1. Download and install ASP.NET 2.0 AJAX Extensions 1.0
  2. Configure your MOSS web.config to support ASP.NET AJAX 1.0
    Mike's post covers most of the configuration you need to support AjaxBasePart within your own MOSS environment. I've listed below a couple of points that you should be aware of when reading his article if you are using the AjaxBasePart
    • You can skip the "Adding a ScriptManager into a SharePoint MasterPage" section. No modification of the .master page is necessary with AjaxBasePart
    • Leave the EnsureUpdatePanelFixups method out of your custom web parts, that is handled by the AjaxBasePart.
  3. Add the AjaxBasePart class (at the end of this post) to your solution and derive all custom web parts from CapDes.SharePoint.AjaxBasePart instead of Microsoft.SharePoint.WebPartPages.WebPart.

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.");

            }

        }

   }

}

February 22, 2007

SmartPart and AjaxBasePart get Together

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.

About

View Eric Schoonover's profile on LinkedIn
 

Follow me on Twitter
 
© Copyright 2007, Eric Schoonover

Search

About February 2007

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.

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.