ASP.NET: Fix for WebParts + UrlRewriting/UrlMapping Issue

The problem with using WebParts with UrlRewriting (or UrlMapping) is the WebPart PersonalizationProvider uses the path of the page being rendered to save/load the personalization state, not the path that was rewritten that the user sees. So, to fix this you just need to create a custom PersonalizationProvider and override all the methods that reference path, and call the base methods but pass in the path that was requested instead of the path being rendered.

Here’s a SqlPersonalizationProvider I wrote that does this:

public class SqlPersonalizationProvider : System.Web.UI.WebControls.WebParts.SqlPersonalizationProvider
{
    protected override void LoadPersonalizationBlobs(WebPartManager webPartManager, string path, string userName, ref byte[] sharedDataBlob, ref byte[] userDataBlob)
    {
        base.LoadPersonalizationBlobs(webPartManager, this.GetActualPath(), userName, ref sharedDataBlob, ref userDataBlob);
    }

    protected override void ResetPersonalizationBlob(WebPartManager webPartManager, string path, string userName)
    {
        base.ResetPersonalizationBlob(webPartManager, this.GetActualPath(), userName);
    }

    public override int ResetState(PersonalizationScope scope, string[] paths, string[] usernames)
    {
        return base.ResetState(scope, paths, usernames);
    }

    public override int ResetUserState(string path, DateTime userInactiveSinceDate)
    {
        return base.ResetUserState(this.GetActualPath(), userInactiveSinceDate);
    }

    protected override void SavePersonalizationBlob(WebPartManager webPartManager, string path, string userName, byte[] dataBlob)
    {
        base.SavePersonalizationBlob(webPartManager, this.GetActualPath(), userName, dataBlob);
    }

    protected string GetActualPath()
    {
        HttpApplication app = HttpContext.Current.ApplicationInstance;
        string p = app.Request.RawUrl;

        // Convert Absolute to Relative
        if (p.ToLowerInvariant().StartsWith(VirtualPathUtility.ToAbsolute("~/").ToLowerInvariant()))
        {
            p = "~/" + p.Substring(VirtualPathUtility.ToAbsolute("~/").Length);
        }

        // Remove QueryString Parameters
        if (p.Contains("?"))
            p = p.Substring(0, p.IndexOf("?"));

        return p;
    }   
}

Another implementation (possibly a better one) would be to create a custom WebPartManager and change the path that is sent to the PersonalizationProvider, but the way shown above was simpler for me to implement and it works.