4dc972c402001e6c55688d8e8f942ff0f20a4c50
[mono.git] / mcs / class / referencesource / System.Web.Extensions / ui / ProfileServiceManager.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="ProfileServiceManager.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6  
7 namespace System.Web.UI {
8     using System;
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;
16     using System.Text;
17     using System.Web.ApplicationServices;
18     using System.Web;
19     using System.Web.Profile;
20     using System.Web.UI;
21     using System.Web.UI.WebControls;
22     using System.Web.Resources;
23     using System.Web.Script.Serialization;
24     using System.Web.Configuration;
25
26     [
27     DefaultProperty("Path"),
28     TypeConverter(typeof(EmptyStringExpandableObjectConverter))
29     ]
30     public class ProfileServiceManager {
31         private string[] _loadProperties;
32         private string _path;
33
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;
38
39             if(scriptManager.HasProfileServiceManager) {
40                 profileManager = scriptManager.ProfileService;
41
42                 // get ScriptManager.Path
43                 profileServiceUrl = profileManager.Path.Trim();
44                 if(profileServiceUrl.Length > 0) {
45                     profileServiceUrl = scriptManager.ResolveClientUrl(profileServiceUrl);
46                 }
47
48                 // get ScriptManager.LoadProperties
49                 if(profileManager.HasLoadProperties) {
50                     loadedProperties = new ArrayList(profileManager._loadProperties);
51                 }
52             }
53
54             // combine proxy Paths (find the first one that has specified one)
55             // combine loadedProperties collection (take the union of all)
56             if(proxies != null) {
57                 foreach(ScriptManagerProxy proxy in proxies) {
58                     if(proxy.HasProfileServiceManager) {
59                         profileManager = proxy.ProfileService;
60
61                         // combine urls
62                         profileServiceUrl = ApplicationServiceManager.MergeServiceUrls(profileManager.Path, profileServiceUrl, proxy);
63
64                         // combine LoadProperties
65                         if(profileManager.HasLoadProperties) {
66                             if(loadedProperties == null) {
67                                 loadedProperties = new ArrayList(profileManager._loadProperties);
68                             }
69                             else {
70                                 loadedProperties = ProfileServiceManager.MergeProperties(loadedProperties, profileManager._loadProperties);
71                             }
72                         }
73                     }
74                 }
75             }
76
77             ProfileServiceManager.GenerateInitializationScript(ref sb, context, scriptManager, profileServiceUrl, loadedProperties);
78         }
79
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;
83
84             if (ApplicationServiceHelper.ProfileServiceEnabled) {
85                 if (sb == null) {
86                     sb = new StringBuilder(ApplicationServiceManager.StringBuilderCapacity);
87                 }
88
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));
96                 sb.Append("';\n");
97             }
98
99             if (!String.IsNullOrEmpty(serviceUrl)) {
100                 // DevDiv 
101
102
103                 if (defaultServicePath == null){
104                     defaultServicePath = scriptManager.ResolveClientUrl("~/" + System.Web.Script.Services.WebServiceData._profileServiceFileName);
105                 }
106                 if (loadProperties && !String.Equals(serviceUrl, defaultServicePath, StringComparison.OrdinalIgnoreCase)) {
107                     throw new InvalidOperationException(AtlasWeb.ProfileServiceManager_LoadProperitesWithNonDefaultPath);
108                 }
109                 if (sb == null) {
110                     sb = new StringBuilder(ApplicationServiceManager.StringBuilderCapacity);
111                 }
112                 sb.Append("Sys.Services.ProfileService.set_path('");
113                 sb.Append(HttpUtility.JavaScriptStringEncode(serviceUrl));
114                 sb.Append("');\n");
115             }
116
117             if (loadProperties) {
118                 if (sb == null) {
119                     sb = new StringBuilder(ApplicationServiceManager.StringBuilderCapacity);
120                 }
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");
127                 }
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;
134
135                     ProfileBase profile = context.Profile;
136                     foreach(string propertyFullName in loadedProperties) {
137                         GetSettingsProperty(profile, propertyFullName, topLevelSettings, ref profileGroups, /* ensure exists */ true);
138                     }
139
140                     RenderProfileProperties(sb, topLevelSettings, profileGroups);
141                 }
142             }
143         }
144
145         internal static ArrayList MergeProperties(ArrayList existingProperties, string[] newProperties) {
146             // 
147
148
149
150
151
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);
157                     }
158                 }
159             }
160
161             return existingProperties;
162         }
163
164         internal static void GetSettingsProperty(
165             ProfileBase profile,
166             string fullPropertyName,
167             SortedList<string, object> topLevelSettings,
168             ref SortedList<string, SortedList<string, object>> profileGroups,
169             bool ensureExists) {
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.
173
174             int dotIndex = fullPropertyName.IndexOf('.');
175             string groupName;
176             string propertyName;
177             SortedList<string, object> containingObject;
178
179             if(dotIndex == -1) {
180                 groupName = null;
181                 propertyName = fullPropertyName;
182                 containingObject = topLevelSettings;
183             }
184             else {
185                 groupName = fullPropertyName.Substring(0, dotIndex);
186                 propertyName = fullPropertyName.Substring(dotIndex + 1);
187
188                 if(profileGroups == null) {
189                     profileGroups = new SortedList<string, SortedList<string, object>>();
190                     containingObject = new SortedList<string, object>();
191                     profileGroups.Add(groupName, containingObject);
192                 }
193                 else {
194                     containingObject = profileGroups[groupName];
195                     if(containingObject == null) {
196                         containingObject = new SortedList<string, object>();
197                         profileGroups.Add(groupName, containingObject);
198                     }
199                 }
200             }
201
202             bool exists = ProfileBase.Properties[fullPropertyName] != null;
203             if(ensureExists && !exists) {
204                 throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, AtlasWeb.AppService_UnknownProfileProperty, fullPropertyName));
205             }
206
207             if(exists) {
208                 containingObject[propertyName] = profile == null ? null : profile[fullPropertyName];
209             }
210         }
211
212         private static void RenderProfileProperties(StringBuilder sb, SortedList<string, object> topLevelSettings, SortedList<string, SortedList<string, object>> profileGroups) {
213             JavaScriptSerializer serializer = new JavaScriptSerializer();
214
215             // 1. render top level settings
216             sb.Append("Sys.Services.ProfileService.properties = ");
217             // 
218
219             sb.Append(serializer.Serialize(topLevelSettings, JavaScriptSerializer.SerializationFormat.JavaScript));
220             sb.Append(";\n");
221
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));
230                     sb.Append(");\n");
231                 }
232             }
233         }
234
235         internal bool HasLoadProperties {
236             get {
237                 return _loadProperties != null && _loadProperties.Length > 0;
238             }
239         }
240
241         [
242         DefaultValue(null),
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.")
249         ]
250         public string[] LoadProperties {
251             get {
252                 if(_loadProperties == null) {
253                     _loadProperties = new string[0];
254                 }
255                 return (string[]) _loadProperties.Clone();
256             }
257             set {
258                 if(value != null) {
259                     value = (string[])value.Clone();
260                 }
261                 _loadProperties = value;
262             }
263         }
264
265         [
266         DefaultValue(""),
267         Category("Behavior"),
268         NotifyParentProperty(true),
269         ResourceDescription("ApplicationServiceManager_Path"),
270         UrlProperty()
271         ]
272         public string Path {
273             get {
274                 return _path ?? String.Empty;
275             }
276             set {
277                 _path = value;
278             }
279         }
280     }
281 }