File: ClientServices\Providers\ClientSettingsProvider.cs
Project: ndp\fx\src\xsp\system\Extensions\System.Web.Extensions.csproj (System.Web.Extensions)
//------------------------------------------------------------------------------
// <copyright file="ClientSettingsProvider.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
 
namespace System.Web.ClientServices.Providers
{
    using System;
    using System.Collections;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Configuration;
    using System.Configuration.Provider;
    using System.Diagnostics;
    using System.Globalization;
    using System.IO;
    using System.Security;
    using System.Security.Principal;
    using System.Security.Permissions;
    using System.Net;
    using System.ServiceModel;
    using System.ServiceModel.Activation;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Dispatcher;
    using System.Web.ClientServices;
    using System.Web.Resources;
    using System.Web.Security;
    using System.Threading;
    using System.Data;
    using System.Data.Common;
    using System.Reflection;
    using System.Collections.ObjectModel;
    using System.Collections.Generic;
    using System.Web.ApplicationServices;
    using System.Web.Script.Serialization;
    using System.Diagnostics.CodeAnalysis;
 
    [SecurityCritical]
    [PermissionSet(SecurityAction.InheritanceDemand, Name="FullTrust")]
    public class ClientSettingsProvider : SettingsProvider, IApplicationSettingsProvider
    {
        private string  _ConnectionString           = null;
        private string  _ConnectionStringProvider   = "";
        private bool    _NeedToDoReset              = false;
        private bool    _HonorCookieExpiry          = false;
        private bool    _firstTime                  = true;
        private string  _UserName                   = "";
 
        private SettingsPropertyValueCollection     _PropertyValues = new SettingsPropertyValueCollection();
        private SettingsPropertyCollection          _Properties     = null;
        private static  Hashtable                   _KnownTypesHashtable = null;
        private static  Type []                     _KnownTypesArray     = null;
 
        [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
        public override string ApplicationName      { 
            [SecuritySafeCritical]
            get { return ""; } 
            [SecuritySafeCritical]
            set { } }
        private static  string _ServiceUri          = "";
        private static  object _lock                = new object();
        private static  bool   _UsingFileSystemStore = false;
        private static  bool   _UsingIsolatedStore   = true;
        private static  bool   _UsingWFCService      = false;
        private static  ApplicationSettingsBase _SettingsBaseClass = null;
 
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
 
        [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId="0#", Justification="Reviewed and approved by feature crew"),
         SuppressMessage("Microsoft.Security", "CA2116:AptcaMethodsShouldOnlyCallAptcaMethods", Justification="Reviewed and approved by feature crew")]
        public static SettingsPropertyCollection GetPropertyMetadata(string serviceUri)
        {
            CookieContainer                  cookies        = null;
            IIdentity                        id             = Thread.CurrentPrincipal.Identity;
            SettingsPropertyCollection       retColl        = new SettingsPropertyCollection();
 
 
            if (id is ClientFormsIdentity)
                cookies = ((ClientFormsIdentity)id).AuthenticationCookies;
 
            if (serviceUri.EndsWith(".svc", StringComparison.OrdinalIgnoreCase)) {
                throw new NotImplementedException();
 
//                 CustomBinding                    binding        = ProxyHelper.GetBinding();
//                 ChannelFactory<ProfileService>   channelFactory = new ChannelFactory<ProfileService>(binding, new EndpointAddress(serviceUri));
//                 ProfilePropertyMetadata[]        props          = null;
//                 ProfileService                   clientService  = channelFactory.CreateChannel();
 
//                 using (new OperationContextScope((IContextChannel)clientService)) {
//                     ProxyHelper.AddCookiesToWCF(cookies, serviceUri, id.Name, null, null);
//                     props = clientService.GetPropertiesMetadata();
//                     ProxyHelper.GetCookiesFromWCF(cookies, serviceUri, id.Name, null, null);
//                 }
//                 if (props == null)
//                     return retColl;
 
//                 for(int iter=0; iter<props.Length; iter++) {
//                     AddToColl(props[iter], retColl, id.IsAuthenticated);
//                 }
 
            } else {
                object o = ProxyHelper.CreateWebRequestAndGetResponse(serviceUri + "/GetPropertiesMetadata",
                                                           ref cookies,
                                                           id.Name,
                                                           null,
                                                           null,
                                                           null,
                                                           null,
                                                           typeof(Collection<ProfilePropertyMetadata>));
 
                Collection<ProfilePropertyMetadata> props2 = (Collection<ProfilePropertyMetadata>) o;
                if (props2 != null)   {
                    foreach(ProfilePropertyMetadata p in props2)
                        AddToColl(p, retColl, id.IsAuthenticated);
                }
            }
            return retColl;
        }
        private static void AddToColl(ProfilePropertyMetadata p, SettingsPropertyCollection retColl, bool isAuthenticated) {
            string propName = p.PropertyName;
            Type   propType = Type.GetType(p.TypeName, false, true);
            bool   allowAnon = p.AllowAnonymousAccess;
            bool   readOnly = p.IsReadOnly;
 
            if (!allowAnon && !isAuthenticated)
                return;
 
            SettingsSerializeAs serializeAs = (SettingsSerializeAs)p.SerializeAs;
            SettingsAttributeDictionary dict = new SettingsAttributeDictionary();
            dict.Add("AllowAnonymous", allowAnon);
            retColl.Add(new SettingsProperty(propName, propType, null, readOnly,p.DefaultValue, serializeAs, dict, true, true));
        }
 
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
        [SecuritySafeCritical]
        public override void Initialize(string name, NameValueCollection config) {
 
            _UsingIsolatedStore = false;
 
            // Initialize using appSettings section
            string temp = System.Configuration.ConfigurationManager.AppSettings["ClientSettingsProvider.ServiceUri"];
            if (!string.IsNullOrEmpty(temp))
                ServiceUri = temp;
 
            temp = System.Configuration.ConfigurationManager.AppSettings["ClientSettingsProvider.ConnectionStringName"];
            if (!string.IsNullOrEmpty(temp)) {
                if (ConfigurationManager.ConnectionStrings[temp] != null) {
                    _ConnectionStringProvider = ConfigurationManager.ConnectionStrings[temp].ProviderName;
                    _ConnectionString = ConfigurationManager.ConnectionStrings[temp].ConnectionString;
                } else {
                    _ConnectionString = temp;
                }
            } else {
                _ConnectionString = SqlHelper.GetDefaultConnectionString();
            }
 
 
            temp = System.Configuration.ConfigurationManager.AppSettings["ClientSettingsProvider.HonorCookieExpiry"];
            if (!string.IsNullOrEmpty(temp))
                _HonorCookieExpiry = (string.Compare(temp, "true", StringComparison.OrdinalIgnoreCase) == 0);
            if (name == null)
                name = this.GetType().ToString();
 
            base.Initialize(name, config);
 
            if (config != null) {
                temp = config["serviceUri"];
                if (!string.IsNullOrEmpty(temp))
                    ServiceUri = temp;
 
                temp = config["connectionStringName"];
                if (!string.IsNullOrEmpty(temp)) {
                    if (ConfigurationManager.ConnectionStrings[temp] != null) {
                        _ConnectionStringProvider = ConfigurationManager.ConnectionStrings[temp].ProviderName;
                        _ConnectionString = ConfigurationManager.ConnectionStrings[temp].ConnectionString;
                    } else {
                        _ConnectionString = temp;
                    }
                }
                config.Remove("name");
                config.Remove("description");
                config.Remove("connectionStringName");
                config.Remove("serviceUri");
                foreach (string attribUnrecognized in config.Keys)
                    if (!String.IsNullOrEmpty(attribUnrecognized))
                        throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, AtlasWeb.AttributeNotRecognized, attribUnrecognized));
            }
 
            switch(SqlHelper.IsSpecialConnectionString(_ConnectionString))
            {
            case 1:
                _UsingFileSystemStore = true;
                break;
            case 2:
                _UsingIsolatedStore = true;
                break;
            default:
                break;
            }
 
 
        }
 
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
 
        [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
        [SecuritySafeCritical]
        public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection propertyCollection) {
            if (propertyCollection == null || propertyCollection.Count < 1)
                return new SettingsPropertyValueCollection();
            lock(_lock) {
                if (_SettingsBaseClass == null && context != null) {
                    Type oType = context["SettingsClassType"] as Type;
                    if (oType != null) {
                        _SettingsBaseClass = oType.InvokeMember("Default", BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Static,
                                                                null, null, null, CultureInfo.InvariantCulture) as ApplicationSettingsBase;
                    }
                }
                _PropertyValues = new SettingsPropertyValueCollection();
                _Properties = propertyCollection;
 
                StoreKnownTypes(propertyCollection);
                GetPropertyValuesCore();
                return _PropertyValues;
            }
        }
        private void GetPropertyValuesCore()
        {
            _UserName = Thread.CurrentPrincipal.Identity.Name;
            if (_firstTime) {
                _firstTime = false;
                _NeedToDoReset = GetNeedToReset();
                RegisterForValidateUserEvent();
            }
 
            if (_NeedToDoReset) {
                _NeedToDoReset = false;
                SetNeedToReset(false);
                _PropertyValues = new SettingsPropertyValueCollection();
                SetRemainingValuesToDefault();
                SetPropertyValuesCore(_PropertyValues, false);
            }
 
            bool isCacheMoreFresh = GetIsCacheMoreFresh();
 
            GetPropertyValuesFromSQL(); // Always start with the local copy
 
            if (!ConnectivityStatus.IsOffline) {
                if (isCacheMoreFresh) {
                    SetPropertyValuesWeb(_PropertyValues, isCacheMoreFresh); // local copy is fresher, so update the web-copy
                } else {
                    GetPropertyValuesFromWeb();
                    SetPropertyValuesSQL(_PropertyValues, false);
                }
            }
            if (_PropertyValues.Count < _Properties.Count)
                SetRemainingValuesToDefault();
        }
 
 
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
 
        [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
        [SecuritySafeCritical]
        public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection propertyValueCollection) {
            if (propertyValueCollection == null || propertyValueCollection.Count < 1)
                return;
            lock(_lock) {
                StoreKnownTypes(propertyValueCollection);
                SetPropertyValuesCore(propertyValueCollection, true);
            }
        }
        private void SetPropertyValuesCore(SettingsPropertyValueCollection values, bool raiseEvent) {
            lock(_lock) {
                bool isCacheMoreFresh = GetIsCacheMoreFresh();
                // First store in SQL
                SetPropertyValuesSQL(values, true);
 
                Collection<string> errorList = null;
                // Store in web if it is offline
                if (!ConnectivityStatus.IsOffline)
                    errorList = SetPropertyValuesWeb(values, isCacheMoreFresh);
 
                if (raiseEvent && SettingsSaved != null) {
                    if (errorList == null)
                        errorList = new Collection<string>();
                    SettingsSaved(this, new SettingsSavedEventArgs(errorList));
                }
            }
        }
 
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        [SecuritySafeCritical]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
        public void Reset(SettingsContext context) {
            lock(_lock) {
                if (_Properties == null) {
                    SetNeedToReset(true);
                } else {
                    _PropertyValues = new SettingsPropertyValueCollection();
                    SetRemainingValuesToDefault();
                    SetPropertyValues(context, _PropertyValues);
                    _NeedToDoReset = false;
                    SetNeedToReset(false);
                }
            }
        }
        [SecuritySafeCritical]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
        public void Upgrade(SettingsContext context, SettingsPropertyCollection properties) {
            return;
        }
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        [SecuritySafeCritical]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
        public SettingsPropertyValue GetPreviousVersion(SettingsContext context, SettingsProperty property) {
            if (_Properties == null)
                _Properties = new SettingsPropertyCollection();
            if (_Properties[property.Name] == null)
                _Properties.Add(property);
            GetPropertyValuesCore();
            return _PropertyValues[property.Name];
        }
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
 
        private string GetServiceUri()
        {
            if (string.IsNullOrEmpty(_ServiceUri))
                throw new ArgumentException(AtlasWeb.ServiceUriNotFound);
            return _ServiceUri;
        }
 
        [SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings", Justification = "Reviewed and approved by feature crew")]
        public static string ServiceUri
        {
            [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "2#", Justification = "Reviewed and approved by feature crew")]
            get
            {
                return _ServiceUri;
            }
            [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "2#", Justification = "Reviewed and approved by feature crew")]
            set {
                _ServiceUri = value;
                if (string.IsNullOrEmpty(_ServiceUri)) {
                    _UsingWFCService = false;
                } else {
                    _UsingWFCService = _ServiceUri.EndsWith(".svc", StringComparison.OrdinalIgnoreCase);
                }
            }
        }
 
        public event EventHandler<SettingsSavedEventArgs> SettingsSaved;
 
 
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        internal static Type[] GetKnownTypes(ICustomAttributeProvider knownTypeAttributeTarget)
        {
            if (_KnownTypesArray == null)
                InitKnownTypes();
            return _KnownTypesArray;
        }
        static private void InitKnownTypes()
        {
            _KnownTypesHashtable = new Hashtable();
            _KnownTypesArray = new Type[]{ typeof(bool),
                                             typeof(string),
                                             typeof(ArrayList),
                                             typeof(ProfilePropertyMetadata),
                                             typeof(IDictionary<string, object>),
                                             typeof(Collection<string>)
                                           };
 
            for(int iter=0; iter<_KnownTypesArray.Length; iter++)
                _KnownTypesHashtable.Add(_KnownTypesArray[iter], string.Empty);
        }
 
        static private void StoreKnownTypes(SettingsPropertyValueCollection propertyValueCollection)
        {
            if (_KnownTypesHashtable == null)
                InitKnownTypes();
 
            ArrayList al = null;
            foreach(SettingsPropertyValue p in propertyValueCollection) {
                if (!_KnownTypesHashtable.Contains(p.Property.PropertyType)) {
                    _KnownTypesHashtable.Add(p.Property.PropertyType, string.Empty);
                    if (al == null)
                        al = new ArrayList();
                    al.Add(p.Property.PropertyType);
                }
            }
 
            if (al != null) {
                Type [] temp = new Type[_KnownTypesArray.Length + al.Count];
                _KnownTypesArray.CopyTo(temp, 0);
                al.CopyTo(temp, _KnownTypesArray.Length);
                _KnownTypesArray = temp;
            }
        }
 
        static private void StoreKnownTypes(SettingsPropertyCollection propertyCollection)
        {
            if (_KnownTypesHashtable == null)
                InitKnownTypes();
 
            ArrayList al = null;
            foreach(SettingsProperty p in propertyCollection) {
                if (!_KnownTypesHashtable.Contains(p.PropertyType)) {
                    _KnownTypesHashtable.Add(p.PropertyType, string.Empty);
                    if (al == null)
                        al = new ArrayList();
                    al.Add(p.PropertyType);
                }
            }
 
            if (al != null) {
                Type [] temp = new Type[_KnownTypesArray.Length + al.Count];
                _KnownTypesArray.CopyTo(temp, 0);
                al.CopyTo(temp, _KnownTypesArray.Length);
                _KnownTypesArray = temp;
            }
        }
 
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        private void GetPropertyValuesFromWeb()
        {
            GetPropertyValuesFromWebCore(_HonorCookieExpiry);
 
            // Any failures?
            bool anyFailures = (_PropertyValues.Count < _Properties.Count);
 
            if (!_HonorCookieExpiry && anyFailures) {
                // if there were failures, try re-validating the ClientFormsIdentity
                //    and try again
 
                ClientFormsIdentity id = Thread.CurrentPrincipal.Identity as ClientFormsIdentity;
 
                if (id != null) {
                    id.RevalidateUser();
                    GetPropertyValuesFromWebCore(true);
                }
            }
        }
 
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        [SuppressMessage("Microsoft.Security", "CA2116:AptcaMethodsShouldOnlyCallAptcaMethods", Justification="Reviewed and approved by feature crew")]
        private void GetPropertyValuesFromWebCore(bool bubbleExceptionFromSvc) {
            string []                        propertyNames  = new string[_Properties.Count];
            int                              iter           = 0;
            CookieContainer                  cookies        = null;
            IIdentity                        id             = Thread.CurrentPrincipal.Identity;
 
            foreach (SettingsProperty setting in _Properties) {
                propertyNames[iter++] = setting.Name;
            }
 
            if (id is ClientFormsIdentity)
                cookies = ((ClientFormsIdentity)id).AuthenticationCookies;
 
            if (_UsingWFCService) {
                throw new NotImplementedException();
 
//                 CustomBinding                    binding        = ProxyHelper.GetBinding();
//                 ChannelFactory<ProfileService>   channelFactory = new ChannelFactory<ProfileService>(binding, new EndpointAddress(GetServiceUri()));
//                 ProfileService                   clientService  = channelFactory.CreateChannel();
//                 Dictionary<string, object>       propertyValues = null;
 
 
//                 using (new OperationContextScope((IContextChannel)clientService)) {
//                     ProxyHelper.AddCookiesToWCF(cookies, GetServiceUri(), id.Name, GetConnectionString(), _ConnectionStringProvider);
//                     propertyValues = clientService.GetPropertiesForCurrentUser(propertyNames, id.IsAuthenticated && (id is ClientFormsIdentity));
//                     ProxyHelper.GetCookiesFromWCF(cookies, GetServiceUri(), id.Name, GetConnectionString(), _ConnectionStringProvider);
//                 }
 
//                 for(iter = 0; iter<propertyNames.Length; iter++) {
//                     string name = propertyNames[iter];
//                     if (!propertyValues.ContainsKey(name))
//                         continue;
//                     SettingsProperty setting = _Properties[name];
//                     if (setting == null)
//                         continue; // Bad -- why wasn't it found?
//                     bool mustAdd = false;
//                     SettingsPropertyValue value = _PropertyValues[setting.Name];
//                     if (value == null) {
//                         value = new SettingsPropertyValue(setting);
//                         mustAdd = true;
//                     }
 
//                     //if ((value.SerializedValue is string) && ((string)value.SerializedValue == "(null)")) {
//                     value.PropertyValue = propertyValues[name];
//                     value.Deserialized = true;
//                     //                 } else if (setting.SerializeAs == SettingsSerializeAs.Binary)
//                     //                     value.SerializedValue = Convert.FromBase64String(propertyValues[iter]);
//                     //                 else
//                     //                     value.SerializedValue = propertyValues[iter];
//                     //                 value.Deserialized = false;
//                     value.IsDirty = false;
//                     if (mustAdd)
//                         _PropertyValues.Add(value);
//                 }
            } else {
 
                string [] paramNames  = new string [] {"properties", "authenticatedUserOnly" };
                object [] paramValues = new object [] {propertyNames, id.IsAuthenticated && (id is ClientFormsIdentity) };
                object    obj         = null;
                try {
                    obj = ProxyHelper.CreateWebRequestAndGetResponse(
                            GetServiceUri() + "/GetPropertiesForCurrentUser",
                            ref cookies,
                            id.Name,
                            _ConnectionString,
                            _ConnectionStringProvider,
                            paramNames,
                            paramValues,
                            typeof(Dictionary<string, object>));
 
                } catch {
                    if (bubbleExceptionFromSvc)
                        throw;
                }
 
                if (obj != null) {
                    Dictionary<string, object> ret = (Dictionary<string, object>) obj;
 
                    foreach(KeyValuePair<string,object> de in ret) {
                        SettingsProperty setting = _Properties[(string) de.Key];
                        if (setting == null)
                            continue; // Bad -- why wasn't it found?
                        bool mustAdd = false;
                        SettingsPropertyValue value = _PropertyValues[setting.Name];
                        if (value == null) {
                            value = new SettingsPropertyValue(setting);
                            mustAdd = true;
                        }
 
                        if (de.Value != null && !setting.PropertyType.IsAssignableFrom(de.Value.GetType()))
                        {
                            object convertedValue = null;
                            if (!ObjectConverter.TryConvertObjectToType(de.Value,
                                                                        setting.PropertyType,
                                                                        new JavaScriptSerializer(),
                                                                        out convertedValue))
                            {
                                // Failure to convert!
                                continue;
                            }
                            value.PropertyValue = convertedValue;
                        } else {
                            value.PropertyValue = de.Value;
 
                        }
 
                        value.Deserialized = true;
                        value.IsDirty = false;
                        if (mustAdd)
                            _PropertyValues.Add(value);
                    }
                }
            }
        }
 
 
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        private Collection<string> SetPropertyValuesWeb(SettingsPropertyValueCollection values, bool cacheIsMoreFresh)
        {
            bool anyFailures = false;
            Collection<string> errorList = null;
            ClientFormsIdentity id = Thread.CurrentPrincipal.Identity as ClientFormsIdentity;
            try {
                errorList = SetPropertyValuesWebCore(values, cacheIsMoreFresh);
                anyFailures = (errorList != null && errorList.Count > 0);
            }
            catch (WebException) {
                if (id == null || _HonorCookieExpiry) {
                    throw;
                }
                anyFailures = true;
            }
 
            if (!_HonorCookieExpiry && anyFailures) {
                // if there were failures, try re-validating the ClientFormsIdentity
                //    and try again
                if (id != null) {
                    id.RevalidateUser();
                    errorList = SetPropertyValuesWebCore(values, cacheIsMoreFresh);
                }
            }
            return errorList;
        }
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        [SuppressMessage("Microsoft.Security", "CA2116:AptcaMethodsShouldOnlyCallAptcaMethods", Justification="Reviewed and approved by feature crew")]
        private Collection<string> SetPropertyValuesWebCore(SettingsPropertyValueCollection values, bool cacheIsMoreFresh)
        {
            Dictionary<string, object>       propertyValues = new Dictionary<string, object>();
            Collection<string> errorList   = null;
            foreach(SettingsPropertyValue value in values) {
                if (cacheIsMoreFresh || value.IsDirty) {
                    propertyValues.Add(value.Property.Name, value.PropertyValue);
                }
            }
 
            CookieContainer                  cookies           = null;
            IIdentity                        id                = Thread.CurrentPrincipal.Identity;
 
            if (id is ClientFormsIdentity)
                cookies = ((ClientFormsIdentity)id).AuthenticationCookies;
 
 
            if (_UsingWFCService) {
                throw new NotImplementedException();
 
//                 CustomBinding                    binding           = ProxyHelper.GetBinding();
//                 ChannelFactory<ProfileService>   channelFactory    = new ChannelFactory<ProfileService>(binding, new EndpointAddress(GetServiceUri()));
//                 ProfileService                   clientService     = channelFactory.CreateChannel();
//                 using (new OperationContextScope((IContextChannel)clientService)) {
//                     ProxyHelper.AddCookiesToWCF(cookies, GetServiceUri(), id.Name, GetConnectionString(), _ConnectionStringProvider);
//                     errorList = clientService.SetPropertiesForCurrentUser(propertyValues, id.IsAuthenticated && (id is ClientFormsIdentity));
//                     ProxyHelper.GetCookiesFromWCF(cookies, GetServiceUri(), id.Name, GetConnectionString(), _ConnectionStringProvider);
//                 }
            } else {
                // Collection<string> SetPropertiesForCurrentUser(IDictionary<string, object> values, bool authenticatedUserOnly)
                string [] paramNames = new string [] {"values", "authenticatedUserOnly" };
                object [] paramValues = new object [] {propertyValues, id.IsAuthenticated && (id is ClientFormsIdentity) };
 
                object o = ProxyHelper.CreateWebRequestAndGetResponse(GetServiceUri() + "/SetPropertiesForCurrentUser",
                                                                      ref cookies,
                                                                      id.Name,
                                                                      _ConnectionString,
                                                                      _ConnectionStringProvider,
                                                                      paramNames,
                                                                      paramValues,
                                                                      typeof(Collection<string>));
                errorList = (Collection<string>) o;
            }
            SetIsCacheMoreFresh(false);
            return errorList;
        }
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        private void GetPropertyValuesFromSQL()
        {
            if (_UsingFileSystemStore || _UsingIsolatedStore)
            {
                ClientData cd = ClientDataManager.GetUserClientData(Thread.CurrentPrincipal.Identity.Name, _UsingIsolatedStore);
                if (cd.SettingsNames == null || cd.SettingsValues == null)
                    return;
                int len = cd.SettingsNames.Length;
                if (cd.SettingsNames.Length != cd.SettingsStoredAs.Length || cd.SettingsValues.Length != cd.SettingsStoredAs.Length)
                {
                    return; // Bad!
                }
                for(int iter=0; iter<len; iter++) {
                    AddProperty(cd.SettingsNames[iter], cd.SettingsStoredAs[iter], cd.SettingsValues[iter]);
                }
                return;
            }
 
            using (DbConnection conn = SqlHelper.GetConnection(Thread.CurrentPrincipal.Identity.Name,
                                                                        GetConnectionString(), _ConnectionStringProvider))
            {
                DbTransaction trans = null;
                try {
                    trans = conn.BeginTransaction();
                    DbCommand cmd = conn.CreateCommand();
                    cmd.CommandText = "SELECT PropertyName, PropertyStoredAs, PropertyValue FROM Settings";
                    cmd.Transaction = trans;
                    using(DbDataReader reader = cmd.ExecuteReader()) {
                        while(reader.Read()) {
                            string   name       = reader.GetString(0);
                            string   storedAs   = reader.GetString(1);
                            string   propVal    = (reader.IsDBNull(2) ? null : reader.GetString(2));
 
                            AddProperty(name, storedAs, propVal);
                        }
                    }
                } catch {
                    if (trans != null) {
                        trans.Rollback();
                        trans = null;
                    }
                    throw;
                } finally {
                    if (trans != null)
                        trans.Commit();
                }
            }
        }
 
        private void AddProperty(string name, string storedAs, string propVal)
        {
            if (storedAs != "S" && storedAs != "B" && storedAs != "N")
                return;
 
            SettingsProperty prop = _Properties[name];
            if (prop == null)
                return;
            SettingsPropertyValue value    = _PropertyValues[name];
            bool                  mustAdd  = false;
            if (value == null) {
                value = new SettingsPropertyValue(prop);
                mustAdd = true;
            }
 
            switch(storedAs) {
            case "S":
                value.SerializedValue = propVal;
                break;
            case "B":
                value.SerializedValue = Convert.FromBase64String(propVal);
                break;
            case "N":
                value.SerializedValue = null;
                break;
            }
            value.Deserialized = false;
            value.IsDirty = false;
            if (mustAdd)
                _PropertyValues.Add(value);
        }
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        private void SetPropertyValuesSQL(SettingsPropertyValueCollection values, bool updateSaveTime)
        {
            string username = Thread.CurrentPrincipal.Identity.Name;
 
            if (_UsingFileSystemStore || _UsingIsolatedStore)
            {
                ClientData cd = ClientDataManager.GetUserClientData(username, _UsingIsolatedStore);
                cd.SettingsNames = new string[values.Count];
                cd.SettingsStoredAs = new string[values.Count];
                cd.SettingsValues = new string[values.Count];
 
                int iter=0;
 
                foreach(SettingsPropertyValue value in values) {
 
                    cd.SettingsNames[iter] = value.Property.Name;
 
                    object val = value.SerializedValue;
                    if (val == null) {
                        cd.SettingsStoredAs[iter] = "N";
                    } else if (val is string) {
                        cd.SettingsStoredAs[iter] = "S";
                        cd.SettingsValues[iter] = (string) val;
                    } else {
                        cd.SettingsStoredAs[iter] = "B";
                        cd.SettingsValues[iter] = Convert.ToBase64String((byte[])val);
                    }
 
                    iter++;
                }
                if (updateSaveTime)
                    cd.SettingsCacheIsMoreFresh = true;
                cd.Save();
                return;
            }
 
            using (DbConnection conn = SqlHelper.GetConnection(username, GetConnectionString(), _ConnectionStringProvider)) {
                DbTransaction trans = null;
                try {
                    trans = conn.BeginTransaction();
                    foreach(SettingsPropertyValue value in values) {
                        DbCommand cmd = conn.CreateCommand();
                        cmd.Transaction = trans;
                        cmd.CommandText = "DELETE FROM Settings WHERE PropertyName = @PropName";
                        SqlHelper.AddParameter(conn, cmd, "@PropName", value.Property.Name);
                        cmd.ExecuteNonQuery();
 
                        cmd = conn.CreateCommand();
                        cmd.Transaction = trans;
                        object val = value.SerializedValue;
                        if (val == null) {
                            cmd.CommandText = "INSERT INTO Settings (PropertyName, PropertyStoredAs, PropertyValue) VALUES (@PropName, 'N', '')";
                            SqlHelper.AddParameter(conn, cmd, "@PropName", value.Property.Name);
                        } else if (val is string) {
                            cmd.CommandText = "INSERT INTO Settings (PropertyName, PropertyStoredAs, PropertyValue) VALUES (@PropName, 'S', @PropVal)";
                            SqlHelper.AddParameter(conn, cmd, "@PropName", value.Property.Name);
                            SqlHelper.AddParameter(conn, cmd, "@PropVal", (string) val);
                        } else {
                            cmd.CommandText = "INSERT INTO Settings (PropertyName, PropertyStoredAs, PropertyValue) VALUES (@PropName, 'B', @PropVal)";
                            SqlHelper.AddParameter(conn, cmd, "@PropName", value.Property.Name);
                            SqlHelper.AddParameter(conn, cmd, "@PropVal", Convert.ToBase64String((byte[])val));
                        }
                        cmd.ExecuteNonQuery();
                    }
                } catch {
                    if (trans != null) {
                        trans.Rollback();
                        trans = null;
                    }
                    throw;
                } finally {
                    if (trans != null)
                        trans.Commit();
                }
            }
            if (updateSaveTime)
                SetIsCacheMoreFresh(true);
        }
 
        private bool GetNeedToReset()
        {
            if (_UsingFileSystemStore || _UsingIsolatedStore) {
                ClientData cd = ClientDataManager.GetUserClientData(Thread.CurrentPrincipal.Identity.Name, _UsingIsolatedStore);
                return cd.SettingsNeedReset;
            } else {
                string temp = GetTagValue("NeeedToDoReset");
                return (temp != null && temp == "1");
            }
        }
        private void SetNeedToReset(bool fSet)
        {
            if (_UsingFileSystemStore || _UsingIsolatedStore) {
                ClientData cd = ClientDataManager.GetUserClientData(Thread.CurrentPrincipal.Identity.Name, _UsingIsolatedStore);
                cd.SettingsNeedReset = fSet;
                cd.Save();
            } else {
                SetTagValue("NeeedToDoReset", fSet ? "1" : "0");
            }
        }
        private bool GetIsCacheMoreFresh()
        {
            if (_UsingFileSystemStore || _UsingIsolatedStore) {
                ClientData cd = ClientDataManager.GetUserClientData(Thread.CurrentPrincipal.Identity.Name, _UsingIsolatedStore);
                return cd.SettingsCacheIsMoreFresh;
            } else {
                string temp = GetTagValue("IsCacheMoreFresh");
                return (temp != null && temp == "1");
            }
        }
        private void SetIsCacheMoreFresh(bool fSet)
        {
            if (_UsingFileSystemStore || _UsingIsolatedStore) {
                ClientData cd = ClientDataManager.GetUserClientData(Thread.CurrentPrincipal.Identity.Name, _UsingIsolatedStore);
                cd.SettingsCacheIsMoreFresh = fSet;
                cd.Save();
            } else {
                SetTagValue("IsCacheMoreFresh", fSet ? "1" : "0");
            }
        }
        private string GetTagValue(string tagName)
        {
            string username = Thread.CurrentPrincipal.Identity.Name;
            using (DbConnection conn = SqlHelper.GetConnection(username, GetConnectionString(), _ConnectionStringProvider))
            {
                DbCommand cmd = conn.CreateCommand();
                cmd.CommandText = @"SELECT PropertyValue FROM Settings WHERE PropertyName = @PropName AND PropertyStoredAs='I'";
                SqlHelper.AddParameter(conn, cmd, "@PropName", tagName);
                return cmd.ExecuteScalar() as string;
            }
        }
        private void SetTagValue(string tagName, string tagValue)
        {
            string username = Thread.CurrentPrincipal.Identity.Name;
            using (DbConnection conn = SqlHelper.GetConnection(username, GetConnectionString(), _ConnectionStringProvider)) {
                DbCommand cmd = conn.CreateCommand();
                cmd.CommandText = @"DELETE FROM Settings WHERE PropertyName = @PropName AND PropertyStoredAs='I'";
                SqlHelper.AddParameter(conn, cmd, "@PropName", tagName);
                cmd.ExecuteNonQuery();
                if (tagValue != null) {
                    cmd = conn.CreateCommand();
                    cmd.CommandText = @"INSERT INTO Settings (PropertyName, PropertyStoredAs, PropertyValue) VALUES  (@PropName, 'I', @PropValue)";
                    SqlHelper.AddParameter(conn, cmd, "@PropName", tagName);
                    SqlHelper.AddParameter(conn, cmd, "@PropValue", tagValue);
                    cmd.ExecuteNonQuery();
                 }
            }
        }
 
        private void RegisterForValidateUserEvent()
        {
            foreach(MembershipProvider provider in Membership.Providers) {
                EventInfo ei = provider.GetType().GetEvent("UserValidated");
                if (ei == null)
                    continue;
 
                MethodInfo addMethod = ei.GetAddMethod();
                if (addMethod == null)
                    continue;
 
                ParameterInfo[] addMethodParams = addMethod.GetParameters();
                Delegate handlerDelegate = Delegate.CreateDelegate(addMethodParams[0].ParameterType, this, "OnUserValidated");
                addMethod.Invoke(provider, new Object[1]{handlerDelegate});
            }
 
        }
 
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification="Called via Reflection")]
        private void OnUserValidated(object src, UserValidatedEventArgs e)
        {
            _NeedToDoReset = GetNeedToReset();
            if (_Properties != null && _Properties.Count > 0 && string.Compare(e.UserName, _UserName, StringComparison.OrdinalIgnoreCase) != 0) {
                try {
                    if (_SettingsBaseClass != null)
                        _SettingsBaseClass.Reload();
                    // _PropertyValues = new SettingsPropertyValueCollection();
                    // GetPropertyValuesCore(); // refresh the collection
                } catch {
                    // it's possible that the (new) user doesn't have the same props
                    // if (_PropertyValues.Count < _Properties.Count)
                    //    SetRemainingValuesToDefault();
                }
            }
        }
 
        private void SetRemainingValuesToDefault()
        {
            foreach (SettingsProperty prop in _Properties) {
                SettingsPropertyValue value = _PropertyValues[prop.Name];
                if (value == null) {
                    value = new SettingsPropertyValue(prop);
                    value.SerializedValue = prop.DefaultValue;
                    value.Deserialized = false;
                    object o = value.PropertyValue;
                    value.PropertyValue = o;
                    _PropertyValues.Add(value);
                }
            }
        }
        private string GetConnectionString()
        {
            if (_ConnectionString == null)
                _ConnectionString = SqlHelper.GetDefaultConnectionString();
            return _ConnectionString;
        }
    }
}