Friday, March 6, 2009

Handling Postbacks using MenuItemTemplate

When using a MenuItemTemplate to perform a postback (instead of a navigate), handling the postback can be tricky. If you have several MenuItems, you will end up writing a lot of code to determine the menuitem that caused the postback and parsing the eventargument data.

Patrick Rodgers came up with a subclassed MenuItemTemplate in this post(http://www.thesug.org/blogs/patrickr/Lists/Posts/Post.aspx?ID=18) that targets itself for the postback and raises an event. You simply have to subscribe to the event and handle the postback there.

Here’s Patrick’s code:

using System;
using System.Web.UI;
using Microsoft.SharePoint.WebControls;

namespace Example
{
public class PostBackEventMenuItem : MenuItemTemplate, IPostBackEventHandler
{
public PostBackEventMenuItem()
: base() { }

public PostBackEventMenuItem(string text)
: base(text) { }

public PostBackEventMenuItem(string text, string imageUrl)
: base(text, imageUrl) { }

public PostBackEventMenuItem(string text, string imageUrl, string clientOnClickScript)
: base(text, imageUrl, clientOnClickScript) { }

protected override void EnsureChildControls()
{
if (!this.ChildControlsCreated)
{
base.EnsureChildControls();
if (string.IsNullOrEmpty(this.ClientOnClickUsingPostBackEvent))
{
this.ClientOnClickUsingPostBackEventFromControl(this);
}
}
}

#region IPostBackEventHandler Members

public void RaisePostBackEvent(string eventArgument)
{
EventHandler<EventArgs> handler = this.OnPostBackEvent;
if (handler != null)
{
handler(this, new EventArgs());
}
}

#endregion

public event EventHandler<EventArgs> OnPostBackEvent;
}
}

To use the control, register it in an aspx page, add the PostbackEventMenuItem and subscribe to the OnPostBackEvent.


<%@ Register TagPrefix="SharePoint" 
Namespace="Microsoft.SharePoint.WebControls"
Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral,
PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="Utilities"
Namespace="Microsoft.SharePoint.Utilities"
Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral,
PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="Example"
Namespace="Example" Assembly="Example, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=2bb7d29b4348a50b" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Control Language="C#" AutoEventWireup="true"
ClassName="Welcome" CompilationMode="Always" %>

<script runat="server">

protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
this.ExplicitLogout.Visible = true;
}
else
{
this.ExplicitLogin.Visible = true;
this.ExplicitLogin.Attributes.CssStyle.Add("display", "block");
}
}

protected void HandlePostback(object sender, EventArgs e)
{
//remove all cookies, redirect to login with current page url
FormsAuthentication.SignOut();

Response.Redirect(string.Format("/_layouts/Authenticate.aspx?Source={0}", HttpUtility.UrlEncode(HttpContext.Current.Request.Url.AbsoluteUri)));
}

</script>

<SharePoint:PersonalActions AccessKey="<%$Resources:wss,personalactions_menu_ak%>"
ToolTip="<%$Resources:wss,open_menu%>" runat="server"
ID="ExplicitLogout" Visible="false">
<CustomTemplate>
<SharePoint:FeatureMenuTemplate
runat="server" FeatureScope="Site"
Location="Microsoft.SharePoint.StandardMenu"
GroupId="PersonalActions" ID="ID_PersonalActionMenu" UseShortId="true">
<SharePoint:MenuItemTemplate
runat="server" ID="ID_PersonalInformation"
Text="<%$Resources:wss,personalactions_personalinformation%>"
Description="<%$Resources:wss,personalactions_personalinformationdescription%>"
MenuGroupId="100" Sequence="100" ImageUrl="/_layouts/images/menuprofile.gif"
UseShortId="true" />
<example:postbackeventmenuitem
runat="server" id="Example_LoginAsDifferentUser"
text="<%$Resources:wss,personalactions_loginasdifferentuser%>"
description="<%$Resources:wss,personalactions_loginasdifferentuserdescription%>"
menugroupid="200" sequence="100" useshortid="true" ononpostbackevent="HandlePostback" />
<SharePoint:MenuItemTemplate
runat="server" ID="ID_RequestAccess"
Text="<%$Resources:wss,personalactions_requestaccess%>"
Description="<%$Resources:wss,personalactions_requestaccessdescription%>" MenuGroupId="200"
UseShortId="true" Sequence="200" />
<SharePoint:MenuItemTemplate
runat="server" ID="ID_Logout"
Text="<%$Resources:wss,personalactions_logout%>"
Description="<%$Resources:wss,personalactions_logoutdescription%>" MenuGroupId="200"
Sequence="300" UseShortId="true" Visible="true" />
<SharePoint:MenuItemTemplate
runat="server" ID="ID_PersonalizePage"
Text="<%$Resources:wss,personalactions_personalizepage%>"
Description="<%$Resources:wss,personalactions_personalizepagedescription%>" ImageUrl="/_layouts/images/menupersonalize.gif"
ClientOnClickScript="javascript:MSOLayout_ChangeLayoutMode(true);" PermissionsString="AddDelPrivateWebParts,UpdatePersonalWebParts"
PermissionMode="Any" MenuGroupId="300" Sequence="100" UseShortId="true" />
<SharePoint:MenuItemTemplate
runat="server" ID="ID_SwitchView" MenuGroupId="300"
Sequence="200" UseShortId="true" />
<SharePoint:MenuItemTemplate
runat="server" ID="MSOMenu_RestoreDefaults"
Text="<%$Resources:wss,personalactions_restorepagedefaults%>"
Description="<%$Resources:wss,personalactions_restorepagedefaultsdescription%>"
ClientOnClickNavigateUrl="javascript:MSOWebPartPage_RestorePageDefault()" MenuGroupId="300"
Sequence="300" UseShortId="true" />
</SharePoint:FeatureMenuTemplate>
</CustomTemplate>
</SharePoint:PersonalActions>
<SharePoint:ApplicationPageLink runat="server" ID="ExplicitLogin" ApplicationPageFileName="Authenticate.aspx"
AppendCurrentPageUrl="true" Text="<%$Resources:wss,login_pagetitle%>" Style="display: none"
Visible="false" />

Wednesday, March 4, 2009

Hyper-V networking reset when copying VHD or creating ‘differencing VM’

Whenever you create a new Virtual Machine for an existing (previously configured) VHD (either by copying the VHD or using differencing disks), the networking configuration of the VM is reset.

This is because when creating a new VM, the Network Adapter(s) you assign receive a new Guid and are treated by the OS as new hardware.

The following post explains this behavior in detail:

http://blogs.technet.com/jhoward/archive/2008/07/22/hyper-v-why-is-networking-reset-in-my-vm-when-i-copy-a-vhd.aspx

Tuesday, March 3, 2009

MakeCab file length limitation

Apparently, there is a limitation to the maximum length of the source file in a DDF file that MakeCab can handle. When the file name exeeds 100 characters, you will receive a File not found error when running makecab.exe

See Michael Blumenthal's post at http://blumenthalit.net/blog/Lists/Posts/Post.aspx?ID=75 for full details.

Tuesday, February 17, 2009

SharePoint log files grow extremely large

Today I ran into a strange issue where the SharePoint log files (located in c:\program files\common files\microsoft shared\web server extensions\12\logs) on one of my development VPC’s would rapidly grow in size (5GB+) until I ran out of disk space.

The log file would fill up with the following message (up to 800 occurrences in just 3 thousands of a second!):

02/17/2009 10:57:14.96     OWSTIMER.EXE (0x0DF4)                       0x0E08    Windows SharePoint Services       Timer                             5uuf    Monitorable    The previous instance of the timer job 'Config Refresh', id '{1520A0E0-E8C6-47F8-BA89-5BEBE5774DFD}' for service '{25FB833C-D7DD-4776-AD50-58105B3A46F0}' is still running, so the current instance will be skipped.  Consider increasing the interval between jobs.

After searching the web for a little while, I found the solution was to clear the SharePoint Configuration Cache as described in this post by Joe Rodgers.

  1. Stop the OWSTIMER service on ALL of the MOSS servers in the farm.
  2. On the Index server, navigate to %ALLUSERSPROFILE% \Application Data\Microsoft\SharePoint\Config\<GUID> and delete all the XML files from the directory.
  3. Edit cache.ini and reset the number in the file to 1.
  4. Start the OWSTIMER service on the Index server and wait for XML files to begin to reappear in the directory.
  5. After you see XML files appearing on the Index server, repeat steps 2, 3 & 4 on the query server(s), waiting for XML files to appear before moving to subsequent servers.
  6. After the query servers have all been cleared, proceed to the WFE and Application servers in the farm, following steps 2, 3 & 4. for each server.