282 lines
13 KiB
C#
282 lines
13 KiB
C#
|
//------------------------------------------------------------------------------
|
||
|
// <copyright file="ProfileServiceManager.cs" company="Microsoft">
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
// </copyright>
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
namespace System.Web.UI {
|
||
|
using System;
|
||
|
using System.Collections;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Collections.ObjectModel;
|
||
|
using System.ComponentModel;
|
||
|
using System.Configuration;
|
||
|
using System.Diagnostics.CodeAnalysis;
|
||
|
using System.Globalization;
|
||
|
using System.Text;
|
||
|
using System.Web.ApplicationServices;
|
||
|
using System.Web;
|
||
|
using System.Web.Profile;
|
||
|
using System.Web.UI;
|
||
|
using System.Web.UI.WebControls;
|
||
|
using System.Web.Resources;
|
||
|
using System.Web.Script.Serialization;
|
||
|
using System.Web.Configuration;
|
||
|
|
||
|
[
|
||
|
DefaultProperty("Path"),
|
||
|
TypeConverter(typeof(EmptyStringExpandableObjectConverter))
|
||
|
]
|
||
|
public class ProfileServiceManager {
|
||
|
private string[] _loadProperties;
|
||
|
private string _path;
|
||
|
|
||
|
internal static void ConfigureProfileService(ref StringBuilder sb, HttpContext context, ScriptManager scriptManager, List<ScriptManagerProxy> proxies) {
|
||
|
string profileServiceUrl = null;
|
||
|
ArrayList loadedProperties = null;
|
||
|
ProfileServiceManager profileManager;
|
||
|
|
||
|
if(scriptManager.HasProfileServiceManager) {
|
||
|
profileManager = scriptManager.ProfileService;
|
||
|
|
||
|
// get ScriptManager.Path
|
||
|
profileServiceUrl = profileManager.Path.Trim();
|
||
|
if(profileServiceUrl.Length > 0) {
|
||
|
profileServiceUrl = scriptManager.ResolveClientUrl(profileServiceUrl);
|
||
|
}
|
||
|
|
||
|
// get ScriptManager.LoadProperties
|
||
|
if(profileManager.HasLoadProperties) {
|
||
|
loadedProperties = new ArrayList(profileManager._loadProperties);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// combine proxy Paths (find the first one that has specified one)
|
||
|
// combine loadedProperties collection (take the union of all)
|
||
|
if(proxies != null) {
|
||
|
foreach(ScriptManagerProxy proxy in proxies) {
|
||
|
if(proxy.HasProfileServiceManager) {
|
||
|
profileManager = proxy.ProfileService;
|
||
|
|
||
|
// combine urls
|
||
|
profileServiceUrl = ApplicationServiceManager.MergeServiceUrls(profileManager.Path, profileServiceUrl, proxy);
|
||
|
|
||
|
// combine LoadProperties
|
||
|
if(profileManager.HasLoadProperties) {
|
||
|
if(loadedProperties == null) {
|
||
|
loadedProperties = new ArrayList(profileManager._loadProperties);
|
||
|
}
|
||
|
else {
|
||
|
loadedProperties = ProfileServiceManager.MergeProperties(loadedProperties, profileManager._loadProperties);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ProfileServiceManager.GenerateInitializationScript(ref sb, context, scriptManager, profileServiceUrl, loadedProperties);
|
||
|
}
|
||
|
|
||
|
private static void GenerateInitializationScript(ref StringBuilder sb, HttpContext context, ScriptManager scriptManager, string serviceUrl, ArrayList loadedProperties) {
|
||
|
string defaultServicePath = null;
|
||
|
bool loadProperties = loadedProperties != null && loadedProperties.Count > 0;
|
||
|
|
||
|
if (ApplicationServiceHelper.ProfileServiceEnabled) {
|
||
|
if (sb == null) {
|
||
|
sb = new StringBuilder(ApplicationServiceManager.StringBuilderCapacity);
|
||
|
}
|
||
|
|
||
|
// The default path points to the built-in service (if it is enabled)
|
||
|
// Note that the client can't default to this path because it doesn't know what the app root is, we must tell it.
|
||
|
// We must specify the default path to the proxy even if a custom path is provided, because on the client they could
|
||
|
// reset the path back to the default if they want.
|
||
|
defaultServicePath = scriptManager.ResolveClientUrl("~/" + System.Web.Script.Services.WebServiceData._profileServiceFileName);
|
||
|
sb.Append("Sys.Services._ProfileService.DefaultWebServicePath = '");
|
||
|
sb.Append(HttpUtility.JavaScriptStringEncode(defaultServicePath));
|
||
|
sb.Append("';\n");
|
||
|
}
|
||
|
|
||
|
if (!String.IsNullOrEmpty(serviceUrl)) {
|
||
|
// DevDiv Bug 72257:When custom path is set and loadProperties=True, we shouldn't use the default path
|
||
|
// loadProperties script always retrieves the properties from default profile provider, which is not correct if ProfileService
|
||
|
// points to non default path. Hence throw when non default path and loadProperties both are specified.
|
||
|
if (defaultServicePath == null){
|
||
|
defaultServicePath = scriptManager.ResolveClientUrl("~/" + System.Web.Script.Services.WebServiceData._profileServiceFileName);
|
||
|
}
|
||
|
if (loadProperties && !String.Equals(serviceUrl, defaultServicePath, StringComparison.OrdinalIgnoreCase)) {
|
||
|
throw new InvalidOperationException(AtlasWeb.ProfileServiceManager_LoadProperitesWithNonDefaultPath);
|
||
|
}
|
||
|
if (sb == null) {
|
||
|
sb = new StringBuilder(ApplicationServiceManager.StringBuilderCapacity);
|
||
|
}
|
||
|
sb.Append("Sys.Services.ProfileService.set_path('");
|
||
|
sb.Append(HttpUtility.JavaScriptStringEncode(serviceUrl));
|
||
|
sb.Append("');\n");
|
||
|
}
|
||
|
|
||
|
if (loadProperties) {
|
||
|
if (sb == null) {
|
||
|
sb = new StringBuilder(ApplicationServiceManager.StringBuilderCapacity);
|
||
|
}
|
||
|
if (scriptManager.DesignMode) {
|
||
|
// Dev10 757178: context is null at design time, so we cannot access ProfileBase.
|
||
|
// But at DesignTime this method is only important because if it produces any init script,
|
||
|
// it prompts AddFrameworkScripts to add the MicrosoftAjaxApplicationServices.js script reference.
|
||
|
// So just append a comment to ensure at least some script is generated.
|
||
|
sb.Append("// loadProperties\n");
|
||
|
}
|
||
|
else if (context != null) {
|
||
|
// get values for all properties to be pre-loaded.
|
||
|
// GetSettingsProperty puts each property into either the top level settings dictionary or if its part of a group,
|
||
|
// it creates an entry for the group in the group collection and puts the setting in the dictionary for the group.
|
||
|
SortedList<string, object> topLevelSettings = new SortedList<string, object>(loadedProperties.Count);
|
||
|
SortedList<string, SortedList<string, object>> profileGroups = null;
|
||
|
|
||
|
ProfileBase profile = context.Profile;
|
||
|
foreach(string propertyFullName in loadedProperties) {
|
||
|
GetSettingsProperty(profile, propertyFullName, topLevelSettings, ref profileGroups, /* ensure exists */ true);
|
||
|
}
|
||
|
|
||
|
RenderProfileProperties(sb, topLevelSettings, profileGroups);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal static ArrayList MergeProperties(ArrayList existingProperties, string[] newProperties) {
|
||
|
//
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
foreach(string property in newProperties) {
|
||
|
if(!String.IsNullOrEmpty(property)) {
|
||
|
string trimmedProperty = property.Trim();
|
||
|
if((trimmedProperty.Length > 0) && !existingProperties.Contains(trimmedProperty)) {
|
||
|
existingProperties.Add(trimmedProperty);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return existingProperties;
|
||
|
}
|
||
|
|
||
|
internal static void GetSettingsProperty(
|
||
|
ProfileBase profile,
|
||
|
string fullPropertyName,
|
||
|
SortedList<string, object> topLevelSettings,
|
||
|
ref SortedList<string, SortedList<string, object>> profileGroups,
|
||
|
bool ensureExists) {
|
||
|
// Gets a setting off the profile, putting top level settings into the topLevelSettings list,
|
||
|
// and putting grouped properties into a group-specific list that is contained within a sortedlist of groups.
|
||
|
// if ensureExists is true and the given property name doesn't exist on the profile, an exception is thrown.
|
||
|
|
||
|
int dotIndex = fullPropertyName.IndexOf('.');
|
||
|
string groupName;
|
||
|
string propertyName;
|
||
|
SortedList<string, object> containingObject;
|
||
|
|
||
|
if(dotIndex == -1) {
|
||
|
groupName = null;
|
||
|
propertyName = fullPropertyName;
|
||
|
containingObject = topLevelSettings;
|
||
|
}
|
||
|
else {
|
||
|
groupName = fullPropertyName.Substring(0, dotIndex);
|
||
|
propertyName = fullPropertyName.Substring(dotIndex + 1);
|
||
|
|
||
|
if(profileGroups == null) {
|
||
|
profileGroups = new SortedList<string, SortedList<string, object>>();
|
||
|
containingObject = new SortedList<string, object>();
|
||
|
profileGroups.Add(groupName, containingObject);
|
||
|
}
|
||
|
else {
|
||
|
containingObject = profileGroups[groupName];
|
||
|
if(containingObject == null) {
|
||
|
containingObject = new SortedList<string, object>();
|
||
|
profileGroups.Add(groupName, containingObject);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool exists = ProfileBase.Properties[fullPropertyName] != null;
|
||
|
if(ensureExists && !exists) {
|
||
|
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, AtlasWeb.AppService_UnknownProfileProperty, fullPropertyName));
|
||
|
}
|
||
|
|
||
|
if(exists) {
|
||
|
containingObject[propertyName] = profile == null ? null : profile[fullPropertyName];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static void RenderProfileProperties(StringBuilder sb, SortedList<string, object> topLevelSettings, SortedList<string, SortedList<string, object>> profileGroups) {
|
||
|
JavaScriptSerializer serializer = new JavaScriptSerializer();
|
||
|
|
||
|
// 1. render top level settings
|
||
|
sb.Append("Sys.Services.ProfileService.properties = ");
|
||
|
//
|
||
|
|
||
|
sb.Append(serializer.Serialize(topLevelSettings, JavaScriptSerializer.SerializationFormat.JavaScript));
|
||
|
sb.Append(";\n");
|
||
|
|
||
|
// 2. render each group as a ProfileGroup object
|
||
|
// These could be done as just the value of the PropertyName in topLevelSettings but the serializer wouldn't recognize PropertyGroup.
|
||
|
if(profileGroups != null) {
|
||
|
foreach(KeyValuePair<string, SortedList<string, object>> group in profileGroups) {
|
||
|
sb.Append("Sys.Services.ProfileService.properties.");
|
||
|
sb.Append(group.Key); // group name
|
||
|
sb.Append(" = new Sys.Services.ProfileGroup(");
|
||
|
sb.Append(serializer.Serialize(group.Value, JavaScriptSerializer.SerializationFormat.JavaScript));
|
||
|
sb.Append(");\n");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal bool HasLoadProperties {
|
||
|
get {
|
||
|
return _loadProperties != null && _loadProperties.Length > 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[
|
||
|
DefaultValue(null),
|
||
|
Category("Behavior"),
|
||
|
NotifyParentProperty(true),
|
||
|
TypeConverter(typeof(StringArrayConverter)),
|
||
|
ResourceDescription("ProfileServiceManager_LoadProperties"),
|
||
|
SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",
|
||
|
Justification="Required by ASP.NET parser.")
|
||
|
]
|
||
|
public string[] LoadProperties {
|
||
|
get {
|
||
|
if(_loadProperties == null) {
|
||
|
_loadProperties = new string[0];
|
||
|
}
|
||
|
return (string[]) _loadProperties.Clone();
|
||
|
}
|
||
|
set {
|
||
|
if(value != null) {
|
||
|
value = (string[])value.Clone();
|
||
|
}
|
||
|
_loadProperties = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[
|
||
|
DefaultValue(""),
|
||
|
Category("Behavior"),
|
||
|
NotifyParentProperty(true),
|
||
|
ResourceDescription("ApplicationServiceManager_Path"),
|
||
|
UrlProperty()
|
||
|
]
|
||
|
public string Path {
|
||
|
get {
|
||
|
return _path ?? String.Empty;
|
||
|
}
|
||
|
set {
|
||
|
_path = value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|