e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
686 lines
28 KiB
C#
686 lines
28 KiB
C#
//------------------------------------------------------------------------------
|
|
// <copyright file="WebPartPersonalization.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
//------------------------------------------------------------------------------
|
|
|
|
namespace System.Web.UI.WebControls.WebParts {
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Specialized;
|
|
using System.ComponentModel;
|
|
using System.Configuration;
|
|
using System.Configuration.Provider;
|
|
using System.Security.Principal;
|
|
using System.Web;
|
|
using System.Web.Configuration;
|
|
using System.Web.UI;
|
|
using System.Web.Util;
|
|
using System.Web.Hosting;
|
|
|
|
[TypeConverterAttribute(typeof(EmptyStringExpandableObjectConverter))]
|
|
public class WebPartPersonalization {
|
|
|
|
public static readonly WebPartUserCapability ModifyStateUserCapability = new WebPartUserCapability("modifyState");
|
|
public static readonly WebPartUserCapability EnterSharedScopeUserCapability = new WebPartUserCapability("enterSharedScope");
|
|
|
|
private WebPartManager _owner;
|
|
|
|
// Properties
|
|
private bool _enabled;
|
|
private string _providerName;
|
|
private PersonalizationScope _initialScope;
|
|
|
|
// Computed state
|
|
private bool _initialized;
|
|
private bool _initializedSet;
|
|
private PersonalizationProvider _provider;
|
|
private PersonalizationScope _currentScope;
|
|
private IDictionary _userCapabilities;
|
|
private PersonalizationState _personalizationState;
|
|
private bool _scopeToggled;
|
|
private bool _shouldResetPersonalizationState;
|
|
|
|
/// <devdoc>
|
|
/// </devdoc>
|
|
public WebPartPersonalization(WebPartManager owner) {
|
|
if (owner == null) {
|
|
throw new ArgumentNullException("owner");
|
|
}
|
|
|
|
_owner = owner;
|
|
|
|
_enabled = true;
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Indicates whether the current user has the permissions to switch
|
|
/// into shared personalization scope.
|
|
/// </devdoc>
|
|
[
|
|
Browsable(false),
|
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
|
|
]
|
|
public bool CanEnterSharedScope {
|
|
get {
|
|
// We cannot cache this value, since UserCapabilities is protected virtual,
|
|
// and could return a different value at any time
|
|
IDictionary userCapabilities = UserCapabilities;
|
|
bool canEnterSharedScope = (userCapabilities != null) &&
|
|
(userCapabilities.Contains(WebPartPersonalization.EnterSharedScopeUserCapability));
|
|
return canEnterSharedScope;
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// </devdoc>
|
|
[
|
|
DefaultValue(true),
|
|
NotifyParentProperty(true),
|
|
WebSysDescription(SR.WebPartPersonalization_Enabled)
|
|
]
|
|
public virtual bool Enabled {
|
|
get {
|
|
return _enabled;
|
|
}
|
|
set {
|
|
if (!WebPartManager.DesignMode && _initializedSet && (value != Enabled)) {
|
|
throw new InvalidOperationException(
|
|
SR.GetString(SR.WebPartPersonalization_MustSetBeforeInit, "Enabled", "WebPartPersonalization"));
|
|
}
|
|
|
|
_enabled = value;
|
|
}
|
|
}
|
|
|
|
// Returns true if the current user in the current scope on the current page has personalization data
|
|
[
|
|
Browsable(false),
|
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
|
|
]
|
|
public virtual bool HasPersonalizationState {
|
|
get {
|
|
if (_provider == null) {
|
|
throw new InvalidOperationException(SR.GetString(SR.WebPartPersonalization_CantUsePropertyBeforeInit,
|
|
"HasPersonalizationState", "WebPartPersonalization"));
|
|
}
|
|
|
|
Page page = WebPartManager.Page;
|
|
if (page == null) {
|
|
throw new InvalidOperationException(SR.GetString(SR.PropertyCannotBeNull, "WebPartManager.Page"));
|
|
}
|
|
|
|
HttpRequest request = page.RequestInternal;
|
|
if (request == null) {
|
|
throw new InvalidOperationException(SR.GetString(SR.PropertyCannotBeNull, "WebPartManager.Page.Request"));
|
|
}
|
|
|
|
PersonalizationStateQuery query = new PersonalizationStateQuery();
|
|
query.PathToMatch = request.AppRelativeCurrentExecutionFilePath;
|
|
if (Scope == PersonalizationScope.User && request.IsAuthenticated) {
|
|
query.UsernameToMatch = page.User.Identity.Name;
|
|
}
|
|
|
|
return (_provider.GetCountOfState(Scope, query) > 0);
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Allows changing the initial personalization scope that is given
|
|
/// preference when requesting the page on its first request.
|
|
/// This must be set before personalization data is loaded into the
|
|
/// WebPartManager.
|
|
/// </devdoc>
|
|
[
|
|
DefaultValue(PersonalizationScope.User),
|
|
NotifyParentProperty(true),
|
|
WebSysDescription(SR.WebPartPersonalization_InitialScope)
|
|
]
|
|
public virtual PersonalizationScope InitialScope {
|
|
get {
|
|
return _initialScope;
|
|
}
|
|
set {
|
|
if ((value < PersonalizationScope.User) || (value > PersonalizationScope.Shared)) {
|
|
throw new ArgumentOutOfRangeException("value");
|
|
}
|
|
|
|
if (!WebPartManager.DesignMode && _initializedSet && (value != InitialScope)) {
|
|
throw new InvalidOperationException(
|
|
SR.GetString(SR.WebPartPersonalization_MustSetBeforeInit, "InitialScope", "WebPartPersonalization"));
|
|
}
|
|
|
|
_initialScope = value;
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// </devdoc>
|
|
[
|
|
Browsable(false),
|
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
|
|
]
|
|
public bool IsEnabled {
|
|
get {
|
|
return IsInitialized;
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Indicates whether personalization state has been loaded. Properties of this
|
|
/// object cannot be saved once this object is initialized.
|
|
/// </devdoc>
|
|
[
|
|
Browsable(false),
|
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
|
|
]
|
|
protected bool IsInitialized {
|
|
get {
|
|
return _initialized;
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Determines if personalization and the ability to modify personalization state is enabled
|
|
/// in the current request. This depends on whether a user is authenticated for this request,
|
|
/// and if that user has the rights to modify personalization state.
|
|
/// To check if just personalization is enabled at all, the IsEnabled property
|
|
/// should be used.
|
|
/// </devdoc>
|
|
[
|
|
Browsable(false),
|
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
|
|
]
|
|
public bool IsModifiable {
|
|
get {
|
|
// We cannot cache this value, since UserCapabilities is protected virtual,
|
|
// and could return a different value at any time
|
|
IDictionary userCapabilities = UserCapabilities;
|
|
bool isModifiable = (userCapabilities != null) &&
|
|
(userCapabilities.Contains(WebPartPersonalization.ModifyStateUserCapability));
|
|
return isModifiable;
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// </devdoc>
|
|
[
|
|
DefaultValue(""),
|
|
NotifyParentProperty(true),
|
|
WebSysDescription(SR.WebPartPersonalization_ProviderName)
|
|
]
|
|
public virtual string ProviderName {
|
|
get {
|
|
return (_providerName != null) ? _providerName : String.Empty;
|
|
}
|
|
set {
|
|
if (!WebPartManager.DesignMode && _initializedSet &&
|
|
!String.Equals(value, ProviderName, StringComparison.Ordinal)) {
|
|
throw new InvalidOperationException(
|
|
SR.GetString(SR.WebPartPersonalization_MustSetBeforeInit, "ProviderName", "WebPartPersonalization"));
|
|
}
|
|
|
|
_providerName = value;
|
|
}
|
|
}
|
|
|
|
[
|
|
Browsable(false),
|
|
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
|
|
]
|
|
public PersonalizationScope Scope {
|
|
get {
|
|
return _currentScope;
|
|
}
|
|
}
|
|
|
|
internal bool ScopeToggled {
|
|
get {
|
|
return _scopeToggled;
|
|
}
|
|
}
|
|
|
|
// True if the personalization data was reset this request. If so, we will not save data
|
|
// at the end of the request.
|
|
protected bool ShouldResetPersonalizationState {
|
|
get {
|
|
return _shouldResetPersonalizationState;
|
|
}
|
|
set {
|
|
_shouldResetPersonalizationState = value;
|
|
}
|
|
}
|
|
|
|
protected virtual IDictionary UserCapabilities {
|
|
get {
|
|
if (_userCapabilities == null) {
|
|
_userCapabilities = new HybridDictionary();
|
|
}
|
|
return _userCapabilities;
|
|
}
|
|
}
|
|
|
|
protected WebPartManager WebPartManager {
|
|
get {
|
|
return _owner;
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// </devdoc>
|
|
protected internal virtual void ApplyPersonalizationState() {
|
|
if (IsEnabled) {
|
|
EnsurePersonalizationState();
|
|
_personalizationState.ApplyWebPartManagerPersonalization();
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// </devdoc>
|
|
protected internal virtual void ApplyPersonalizationState(WebPart webPart) {
|
|
if (webPart == null) {
|
|
throw new ArgumentNullException("webPart");
|
|
}
|
|
|
|
if (IsEnabled) {
|
|
EnsurePersonalizationState();
|
|
_personalizationState.ApplyWebPartPersonalization(webPart);
|
|
}
|
|
}
|
|
|
|
// Helper method used by CopyPersonalizationState()
|
|
private void ApplyPersonalizationState(Control control, PersonalizationInfo info) {
|
|
ITrackingPersonalizable trackingPersonalizable = control as ITrackingPersonalizable;
|
|
IPersonalizable customPersonalizable = control as IPersonalizable;
|
|
|
|
if (trackingPersonalizable != null) {
|
|
trackingPersonalizable.BeginLoad();
|
|
}
|
|
|
|
// If customPersonalizable is null, then info.CustomProperties should also be null
|
|
Debug.Assert(!(customPersonalizable == null && info.CustomProperties != null));
|
|
|
|
if (customPersonalizable != null && info.CustomProperties != null && info.CustomProperties.Count > 0) {
|
|
customPersonalizable.Load(info.CustomProperties);
|
|
}
|
|
|
|
if (info.Properties != null && info.Properties.Count > 0) {
|
|
BlobPersonalizationState.SetPersonalizedProperties(control, info.Properties);
|
|
}
|
|
|
|
if (trackingPersonalizable != null) {
|
|
trackingPersonalizable.EndLoad();
|
|
}
|
|
}
|
|
|
|
protected virtual void ChangeScope(PersonalizationScope scope) {
|
|
PersonalizationProviderHelper.CheckPersonalizationScope(scope);
|
|
|
|
if (scope == _currentScope) {
|
|
return;
|
|
}
|
|
|
|
if ((scope == PersonalizationScope.Shared) && (!CanEnterSharedScope)) {
|
|
throw new InvalidOperationException(SR.GetString(SR.WebPartPersonalization_CannotEnterSharedScope));
|
|
}
|
|
|
|
_currentScope = scope;
|
|
_scopeToggled = true;
|
|
}
|
|
|
|
// Extracts the personalization state from webPartA, and applies it to webPartB.
|
|
// Assumes that webPartA and webPartB are the same type. If the WebParts are GenericWebParts,
|
|
// then copies the personalization state from the ChildControl of webPartA to the
|
|
// ChildControl of webPartB.
|
|
protected internal virtual void CopyPersonalizationState(WebPart webPartA, WebPart webPartB) {
|
|
if (webPartA == null) {
|
|
throw new ArgumentNullException("webPartA");
|
|
}
|
|
if (webPartB == null) {
|
|
throw new ArgumentNullException("webPartB");
|
|
}
|
|
if (webPartA.GetType() != webPartB.GetType()) {
|
|
throw new ArgumentException(SR.GetString(SR.WebPartPersonalization_SameType, "webPartA", "webPartB"));
|
|
}
|
|
|
|
CopyPersonalizationState((Control)webPartA, (Control)webPartB);
|
|
|
|
GenericWebPart genericWebPartA = webPartA as GenericWebPart;
|
|
GenericWebPart genericWebPartB = webPartB as GenericWebPart;
|
|
// Assert that the GenericWebParts are either both null or both non-null
|
|
Debug.Assert((genericWebPartA == null) == (genericWebPartB == null));
|
|
if (genericWebPartA != null && genericWebPartB != null) {
|
|
Control childControlA = genericWebPartA.ChildControl;
|
|
Control childControlB = genericWebPartB.ChildControl;
|
|
|
|
if (childControlA == null) {
|
|
throw new ArgumentException(SR.GetString(SR.PropertyCannotBeNull, "ChildControl"), "webPartA");
|
|
}
|
|
if (childControlB == null) {
|
|
throw new ArgumentException(SR.GetString(SR.PropertyCannotBeNull, "ChildControl"), "webPartB");
|
|
}
|
|
if (childControlA.GetType() != childControlB.GetType()) {
|
|
throw new ArgumentException(SR.GetString(SR.WebPartPersonalization_SameType, "webPartA.ChildControl", "webPartB.ChildControl"));
|
|
}
|
|
|
|
CopyPersonalizationState(childControlA, childControlB);
|
|
}
|
|
|
|
// IPersonalizable.IsDirty should always be false on the new WebPart, since the only data
|
|
// on the new WebPart was loaded via personalization, which should not cause the control
|
|
// to be dirty. However, we want to save the IPersonalizable data on this request, so
|
|
// we call SetDirty() to force the IPersonalizable data to be saved.
|
|
SetDirty(webPartB);
|
|
}
|
|
|
|
private void CopyPersonalizationState(Control controlA, Control controlB) {
|
|
PersonalizationInfo info = ExtractPersonalizationState(controlA);
|
|
ApplyPersonalizationState(controlB, info);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// </devdoc>
|
|
private void DeterminePersonalizationProvider() {
|
|
string providerName = ProviderName;
|
|
if (String.IsNullOrEmpty(providerName)) {
|
|
// Use the default provider
|
|
_provider = PersonalizationAdministration.Provider;
|
|
// The default provider can never be null
|
|
Debug.Assert(_provider != null);
|
|
}
|
|
else {
|
|
// Look for a provider with the specified name
|
|
PersonalizationProvider provider = PersonalizationAdministration.Providers[providerName];
|
|
if (provider != null) {
|
|
_provider = provider;
|
|
}
|
|
else {
|
|
throw new ProviderException(
|
|
SR.GetString(SR.WebPartPersonalization_ProviderNotFound, providerName));
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// </devdoc>
|
|
public void EnsureEnabled(bool ensureModifiable) {
|
|
bool value = (ensureModifiable ? IsModifiable : IsEnabled);
|
|
|
|
if (!value) {
|
|
string message;
|
|
if (ensureModifiable) {
|
|
message = SR.GetString(SR.WebPartPersonalization_PersonalizationNotModifiable);
|
|
}
|
|
else {
|
|
message = SR.GetString(SR.WebPartPersonalization_PersonalizationNotEnabled);
|
|
}
|
|
throw new InvalidOperationException(message);
|
|
}
|
|
}
|
|
|
|
private void EnsurePersonalizationState() {
|
|
if (_personalizationState == null) {
|
|
throw new InvalidOperationException(SR.GetString(SR.WebPartPersonalization_PersonalizationStateNotLoaded));
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// </devdoc>
|
|
protected internal virtual void ExtractPersonalizationState() {
|
|
// If we reset the personalization data on this request, we should not extract data since
|
|
// it will not be saved.
|
|
if (IsEnabled && !ShouldResetPersonalizationState) {
|
|
EnsurePersonalizationState();
|
|
_personalizationState.ExtractWebPartManagerPersonalization();
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// </devdoc>
|
|
protected internal virtual void ExtractPersonalizationState(WebPart webPart) {
|
|
// If we reset the personalization data on this request, we should not extract data since
|
|
// it will not be saved.
|
|
if (IsEnabled && !ShouldResetPersonalizationState) {
|
|
EnsurePersonalizationState();
|
|
_personalizationState.ExtractWebPartPersonalization(webPart);
|
|
}
|
|
}
|
|
|
|
// Helper method used by CopyPersonalizationState()
|
|
private PersonalizationInfo ExtractPersonalizationState(Control control) {
|
|
ITrackingPersonalizable trackingPersonalizable = control as ITrackingPersonalizable;
|
|
IPersonalizable customPersonalizable = control as IPersonalizable;
|
|
|
|
if (trackingPersonalizable != null) {
|
|
trackingPersonalizable.BeginSave();
|
|
}
|
|
|
|
PersonalizationInfo info = new PersonalizationInfo();
|
|
if (customPersonalizable != null) {
|
|
info.CustomProperties = new PersonalizationDictionary();
|
|
customPersonalizable.Save(info.CustomProperties);
|
|
}
|
|
info.Properties = BlobPersonalizationState.GetPersonalizedProperties(control, PersonalizationScope.Shared);
|
|
|
|
if (trackingPersonalizable != null) {
|
|
trackingPersonalizable.EndSave();
|
|
}
|
|
|
|
return info;
|
|
}
|
|
|
|
// Returns the AuthorizationFilter string for a WebPart before it is instantiated
|
|
// Returns null if there is no personalized value for AuthorizationFilter
|
|
protected internal virtual string GetAuthorizationFilter(string webPartID) {
|
|
if (String.IsNullOrEmpty(webPartID)) {
|
|
throw ExceptionUtil.ParameterNullOrEmpty("webPartID");
|
|
}
|
|
|
|
EnsureEnabled(false);
|
|
EnsurePersonalizationState();
|
|
return _personalizationState.GetAuthorizationFilter(webPartID);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// </devdoc>
|
|
internal void LoadInternal() {
|
|
if (Enabled) {
|
|
_currentScope = Load();
|
|
_initialized = true;
|
|
}
|
|
_initializedSet = true;
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Loads personalization information from its storage, and computes the initial personalization
|
|
/// scope. This method determines the provider type to be used, and the current user's capabilities.
|
|
/// </devdoc>
|
|
protected virtual PersonalizationScope Load() {
|
|
if (!Enabled) {
|
|
throw new InvalidOperationException(SR.GetString(SR.WebPartPersonalization_PersonalizationNotEnabled));
|
|
}
|
|
|
|
// Determine the provider early, as it is needed to continue execution.
|
|
// Provider is used to detect user's capabilities, load personalization state
|
|
// and determine initial scope.
|
|
DeterminePersonalizationProvider();
|
|
Debug.Assert(_provider != null);
|
|
|
|
Page page = WebPartManager.Page;
|
|
if (page == null) {
|
|
throw new InvalidOperationException(SR.GetString(SR.PropertyCannotBeNull, "WebPartManager.Page"));
|
|
}
|
|
|
|
HttpRequest request = page.RequestInternal;
|
|
if (request == null) {
|
|
throw new InvalidOperationException(SR.GetString(SR.PropertyCannotBeNull, "WebPartManager.Page.Request"));
|
|
}
|
|
|
|
// Ask the provider to load information about what are the capabilities of
|
|
// the current user
|
|
if (request.IsAuthenticated) {
|
|
_userCapabilities = _provider.DetermineUserCapabilities(WebPartManager);
|
|
}
|
|
|
|
// A derived WebPartPersonalization can have ignoreCurrentUser to be true.
|
|
_personalizationState = _provider.LoadPersonalizationState(WebPartManager, /* ignoreCurrentUser */ false);
|
|
if (_personalizationState == null) {
|
|
// We can't assume that _personalizationState will be non-null, because
|
|
// it depends on the provider implementation.
|
|
throw new ProviderException(SR.GetString(SR.WebPartPersonalization_CannotLoadPersonalization));
|
|
}
|
|
|
|
return _provider.DetermineInitialScope(WebPartManager, _personalizationState);
|
|
}
|
|
|
|
// Resets the personalization data for the current user in the current scope on the current page
|
|
public virtual void ResetPersonalizationState() {
|
|
EnsureEnabled(/* ensureModifiable */ true);
|
|
|
|
if (_provider == null) {
|
|
throw new InvalidOperationException(SR.GetString(SR.WebPartPersonalization_CantCallMethodBeforeInit,
|
|
"ResetPersonalizationState", "WebPartPersonalization"));
|
|
}
|
|
|
|
_provider.ResetPersonalizationState(WebPartManager);
|
|
ShouldResetPersonalizationState = true;
|
|
|
|
Page page = WebPartManager.Page;
|
|
if (page == null) {
|
|
throw new InvalidOperationException(SR.GetString(SR.PropertyCannotBeNull, "WebPartManager.Page"));
|
|
}
|
|
|
|
// Transfer execution to a new instance of the same page. The new page will execute
|
|
// after personalization data has been reset.
|
|
TransferToCurrentPage(page);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// </devdoc>
|
|
internal void SaveInternal() {
|
|
if (IsModifiable) {
|
|
Save();
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Saves personalization information back to its storage if necessary.
|
|
/// </devdoc>
|
|
protected virtual void Save() {
|
|
EnsureEnabled(/* ensureModifiable */ true);
|
|
|
|
EnsurePersonalizationState();
|
|
|
|
if (_provider == null) {
|
|
throw new InvalidOperationException(SR.GetString(SR.WebPartPersonalization_CantCallMethodBeforeInit,
|
|
"Save", "WebPartPersonalization"));
|
|
}
|
|
|
|
// If we reset the personalization data on this request, we should not save data to the
|
|
// DB on this request. It is likely we would not save data anyway, since the data probably
|
|
// did not change since the last request, but there are some scenarios where the data could
|
|
// have changed (like a WebPart using personalization as a cache).
|
|
if (_personalizationState.IsDirty && !ShouldResetPersonalizationState) {
|
|
_provider.SavePersonalizationState(_personalizationState);
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// </devdoc>
|
|
protected internal virtual void SetDirty() {
|
|
if (IsEnabled) {
|
|
EnsurePersonalizationState();
|
|
_personalizationState.SetWebPartManagerDirty();
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// </devdoc>
|
|
protected internal virtual void SetDirty(WebPart webPart) {
|
|
if (IsEnabled) {
|
|
EnsurePersonalizationState();
|
|
_personalizationState.SetWebPartDirty(webPart);
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// </devdoc>
|
|
public virtual void ToggleScope() {
|
|
EnsureEnabled(/* ensureModifiable */ false);
|
|
|
|
Page page = WebPartManager.Page;
|
|
if (page == null) {
|
|
throw new InvalidOperationException(SR.GetString(SR.PropertyCannotBeNull, "WebPartManager.Page"));
|
|
}
|
|
if (page.IsExportingWebPart) {
|
|
// If the page is exporting, the page determines the desired scope, and it is not meaningful
|
|
// to toggle the scope. Note that we no-op the call, rather than throwing because
|
|
// that would require exposing a CanToggleScope property, require page developers
|
|
// to check for it. Furthermore, we don't guarantee ToggleScope does toggle
|
|
// (eg. in the case of absense of user capability to enter shared scope), so
|
|
// simply no-op'ing isn't terribly bad...
|
|
return;
|
|
}
|
|
|
|
Page previousPage = page.PreviousPage;
|
|
if ((previousPage != null) &&
|
|
(previousPage.IsCrossPagePostBack == false)) {
|
|
WebPartManager previousWebPartManager = WebPartManager.GetCurrentWebPartManager(previousPage);
|
|
|
|
if ((previousWebPartManager != null) && (previousWebPartManager.Personalization.ScopeToggled)) {
|
|
// Looks like some sort of infinite recursion is going on
|
|
// and we're toggling again. Like the previous case, we're
|
|
// going to no-op and protect ourselves from "----" code...
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (_currentScope == PersonalizationScope.Shared) {
|
|
ChangeScope(PersonalizationScope.User);
|
|
}
|
|
else {
|
|
ChangeScope(PersonalizationScope.Shared);
|
|
}
|
|
|
|
// Transfer execution to a new instance of the same page. The new page will detect the scope
|
|
// it should run in, when it begins to load personalization data.
|
|
TransferToCurrentPage(page);
|
|
}
|
|
|
|
// Transfers execution to a new instance of the same page. We need to clear the form collection,
|
|
// since it should not carry over to the page in the new scope (i.e. ViewState). If the form
|
|
// method is GET, then we must not include the query string, since the entire form collection
|
|
// is in the query string. If the form method is POST (or there is no form), then we must
|
|
// include the query string, since the developer could be using the query string to drive the
|
|
// logic of their page (VSWhidbey 444385 and 527117).
|
|
private void TransferToCurrentPage(Page page) {
|
|
HttpRequest request = page.RequestInternal;
|
|
if (request == null) {
|
|
throw new InvalidOperationException(SR.GetString(SR.PropertyCannotBeNull, "WebPartManager.Page.Request"));
|
|
}
|
|
|
|
string path = request.CurrentExecutionFilePath;
|
|
if (page.Form == null || String.Equals(page.Form.Method, "post", StringComparison.OrdinalIgnoreCase)) {
|
|
string queryString = page.ClientQueryString;
|
|
if (!String.IsNullOrEmpty(queryString)) {
|
|
path += "?" + queryString;
|
|
}
|
|
}
|
|
|
|
IScriptManager scriptManager = page.ScriptManager;
|
|
if ((scriptManager != null) && scriptManager.IsInAsyncPostBack) {
|
|
request.Response.Redirect(path);
|
|
}
|
|
else {
|
|
page.Server.Transfer(path, /* preserveForm */ false);
|
|
}
|
|
}
|
|
|
|
private sealed class PersonalizationInfo {
|
|
public IDictionary Properties;
|
|
public PersonalizationDictionary CustomProperties;
|
|
}
|
|
}
|
|
}
|