1 //------------------------------------------------------------------------------
2 // <copyright file="ProfileServiceManager.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
7 namespace System.Web.UI {
9 using System.Collections;
10 using System.Collections.Generic;
11 using System.Collections.ObjectModel;
12 using System.ComponentModel;
13 using System.Configuration;
14 using System.Diagnostics.CodeAnalysis;
15 using System.Globalization;
17 using System.Web.ApplicationServices;
19 using System.Web.Profile;
21 using System.Web.UI.WebControls;
22 using System.Web.Resources;
23 using System.Web.Script.Serialization;
24 using System.Web.Configuration;
27 DefaultProperty("Path"),
28 TypeConverter(typeof(EmptyStringExpandableObjectConverter))
30 public class ProfileServiceManager {
31 private string[] _loadProperties;
34 internal static void ConfigureProfileService(ref StringBuilder sb, HttpContext context, ScriptManager scriptManager, List<ScriptManagerProxy> proxies) {
35 string profileServiceUrl = null;
36 ArrayList loadedProperties = null;
37 ProfileServiceManager profileManager;
39 if(scriptManager.HasProfileServiceManager) {
40 profileManager = scriptManager.ProfileService;
42 // get ScriptManager.Path
43 profileServiceUrl = profileManager.Path.Trim();
44 if(profileServiceUrl.Length > 0) {
45 profileServiceUrl = scriptManager.ResolveClientUrl(profileServiceUrl);
48 // get ScriptManager.LoadProperties
49 if(profileManager.HasLoadProperties) {
50 loadedProperties = new ArrayList(profileManager._loadProperties);
54 // combine proxy Paths (find the first one that has specified one)
55 // combine loadedProperties collection (take the union of all)
57 foreach(ScriptManagerProxy proxy in proxies) {
58 if(proxy.HasProfileServiceManager) {
59 profileManager = proxy.ProfileService;
62 profileServiceUrl = ApplicationServiceManager.MergeServiceUrls(profileManager.Path, profileServiceUrl, proxy);
64 // combine LoadProperties
65 if(profileManager.HasLoadProperties) {
66 if(loadedProperties == null) {
67 loadedProperties = new ArrayList(profileManager._loadProperties);
70 loadedProperties = ProfileServiceManager.MergeProperties(loadedProperties, profileManager._loadProperties);
77 ProfileServiceManager.GenerateInitializationScript(ref sb, context, scriptManager, profileServiceUrl, loadedProperties);
80 private static void GenerateInitializationScript(ref StringBuilder sb, HttpContext context, ScriptManager scriptManager, string serviceUrl, ArrayList loadedProperties) {
81 string defaultServicePath = null;
82 bool loadProperties = loadedProperties != null && loadedProperties.Count > 0;
84 if (ApplicationServiceHelper.ProfileServiceEnabled) {
86 sb = new StringBuilder(ApplicationServiceManager.StringBuilderCapacity);
89 // The default path points to the built-in service (if it is enabled)
90 // Note that the client can't default to this path because it doesn't know what the app root is, we must tell it.
91 // We must specify the default path to the proxy even if a custom path is provided, because on the client they could
92 // reset the path back to the default if they want.
93 defaultServicePath = scriptManager.ResolveClientUrl("~/" + System.Web.Script.Services.WebServiceData._profileServiceFileName);
94 sb.Append("Sys.Services._ProfileService.DefaultWebServicePath = '");
95 sb.Append(HttpUtility.JavaScriptStringEncode(defaultServicePath));
99 if (!String.IsNullOrEmpty(serviceUrl)) {
103 if (defaultServicePath == null){
104 defaultServicePath = scriptManager.ResolveClientUrl("~/" + System.Web.Script.Services.WebServiceData._profileServiceFileName);
106 if (loadProperties && !String.Equals(serviceUrl, defaultServicePath, StringComparison.OrdinalIgnoreCase)) {
107 throw new InvalidOperationException(AtlasWeb.ProfileServiceManager_LoadProperitesWithNonDefaultPath);
110 sb = new StringBuilder(ApplicationServiceManager.StringBuilderCapacity);
112 sb.Append("Sys.Services.ProfileService.set_path('");
113 sb.Append(HttpUtility.JavaScriptStringEncode(serviceUrl));
117 if (loadProperties) {
119 sb = new StringBuilder(ApplicationServiceManager.StringBuilderCapacity);
121 if (scriptManager.DesignMode) {
122 // Dev10 757178: context is null at design time, so we cannot access ProfileBase.
123 // But at DesignTime this method is only important because if it produces any init script,
124 // it prompts AddFrameworkScripts to add the MicrosoftAjaxApplicationServices.js script reference.
125 // So just append a comment to ensure at least some script is generated.
126 sb.Append("// loadProperties\n");
128 else if (context != null) {
129 // get values for all properties to be pre-loaded.
130 // GetSettingsProperty puts each property into either the top level settings dictionary or if its part of a group,
131 // it creates an entry for the group in the group collection and puts the setting in the dictionary for the group.
132 SortedList<string, object> topLevelSettings = new SortedList<string, object>(loadedProperties.Count);
133 SortedList<string, SortedList<string, object>> profileGroups = null;
135 ProfileBase profile = context.Profile;
136 foreach(string propertyFullName in loadedProperties) {
137 GetSettingsProperty(profile, propertyFullName, topLevelSettings, ref profileGroups, /* ensure exists */ true);
140 RenderProfileProperties(sb, topLevelSettings, profileGroups);
145 internal static ArrayList MergeProperties(ArrayList existingProperties, string[] newProperties) {
152 foreach(string property in newProperties) {
153 if(!String.IsNullOrEmpty(property)) {
154 string trimmedProperty = property.Trim();
155 if((trimmedProperty.Length > 0) && !existingProperties.Contains(trimmedProperty)) {
156 existingProperties.Add(trimmedProperty);
161 return existingProperties;
164 internal static void GetSettingsProperty(
166 string fullPropertyName,
167 SortedList<string, object> topLevelSettings,
168 ref SortedList<string, SortedList<string, object>> profileGroups,
170 // Gets a setting off the profile, putting top level settings into the topLevelSettings list,
171 // and putting grouped properties into a group-specific list that is contained within a sortedlist of groups.
172 // if ensureExists is true and the given property name doesn't exist on the profile, an exception is thrown.
174 int dotIndex = fullPropertyName.IndexOf('.');
177 SortedList<string, object> containingObject;
181 propertyName = fullPropertyName;
182 containingObject = topLevelSettings;
185 groupName = fullPropertyName.Substring(0, dotIndex);
186 propertyName = fullPropertyName.Substring(dotIndex + 1);
188 if(profileGroups == null) {
189 profileGroups = new SortedList<string, SortedList<string, object>>();
190 containingObject = new SortedList<string, object>();
191 profileGroups.Add(groupName, containingObject);
194 containingObject = profileGroups[groupName];
195 if(containingObject == null) {
196 containingObject = new SortedList<string, object>();
197 profileGroups.Add(groupName, containingObject);
202 bool exists = ProfileBase.Properties[fullPropertyName] != null;
203 if(ensureExists && !exists) {
204 throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, AtlasWeb.AppService_UnknownProfileProperty, fullPropertyName));
208 containingObject[propertyName] = profile == null ? null : profile[fullPropertyName];
212 private static void RenderProfileProperties(StringBuilder sb, SortedList<string, object> topLevelSettings, SortedList<string, SortedList<string, object>> profileGroups) {
213 JavaScriptSerializer serializer = new JavaScriptSerializer();
215 // 1. render top level settings
216 sb.Append("Sys.Services.ProfileService.properties = ");
219 sb.Append(serializer.Serialize(topLevelSettings, JavaScriptSerializer.SerializationFormat.JavaScript));
222 // 2. render each group as a ProfileGroup object
223 // These could be done as just the value of the PropertyName in topLevelSettings but the serializer wouldn't recognize PropertyGroup.
224 if(profileGroups != null) {
225 foreach(KeyValuePair<string, SortedList<string, object>> group in profileGroups) {
226 sb.Append("Sys.Services.ProfileService.properties.");
227 sb.Append(group.Key); // group name
228 sb.Append(" = new Sys.Services.ProfileGroup(");
229 sb.Append(serializer.Serialize(group.Value, JavaScriptSerializer.SerializationFormat.JavaScript));
235 internal bool HasLoadProperties {
237 return _loadProperties != null && _loadProperties.Length > 0;
243 Category("Behavior"),
244 NotifyParentProperty(true),
245 TypeConverter(typeof(StringArrayConverter)),
246 ResourceDescription("ProfileServiceManager_LoadProperties"),
247 SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",
248 Justification="Required by ASP.NET parser.")
250 public string[] LoadProperties {
252 if(_loadProperties == null) {
253 _loadProperties = new string[0];
255 return (string[]) _loadProperties.Clone();
259 value = (string[])value.Clone();
261 _loadProperties = value;
267 Category("Behavior"),
268 NotifyParentProperty(true),
269 ResourceDescription("ApplicationServiceManager_Path"),
274 return _path ?? String.Empty;