public MembershipTable CreateMembershipTable()
        {
            var table = new MembershipTable();

            table.Version = membershipVersion;
            table.Rows    = new List <MembershipRow>();
            foreach (var activation in activations.Values)
            {
                if (activation.Identity.Category == Identity.Categories.Service)
                {
                    var service = (IService)activation.Addressable;
                    var row     = new MembershipRow();
                    row.Identity    = activation.Identity;
                    row.ServiceType = activation.InterfaceType.AssemblyQualifiedName;
                    if (service.Metadata != null)
                    {
                        row.Metadata = binarySerializer.Serialize(service.Metadata);
                    }
                    table.Rows.Add(row);
                }
            }
            return(table);
        }
        private void CreateOrUpdateUserAndProfile(string username, bool authenticated, DateTime now, string blobName, int size)
        {
            Debug.Assert(now.Kind == DateTimeKind.Utc);
            SecUtility.CheckParameter(ref username, true, true, true, Constants.MaxTableUsernameLength, "username");

            _providerRetry(() => 
            {
                TableServiceContext context = CreateDataServiceContext();
                DataServiceQuery<MembershipRow> queryObj = context.CreateQuery<MembershipRow>(_tableName);
                var query = (from user in queryObj
                             where user.PartitionKey == SecUtility.CombineToKey(_applicationName, username)
                             select user).AsTableServiceQuery();
                IEnumerable<MembershipRow> users = query.Execute();

                // instantiate results
                List<MembershipRow> userList = null;
                if (users != null)
                {
                    userList = new List<MembershipRow>(users);
                }
                if (userList != null && userList.Count > 0)
                {
                    MembershipRow current = userList.First();
                    if (current.IsAnonymous != !authenticated)
                    {
                        // this is an error because we would need to create a user with the same name
                        // this should not happen
                        throw new ProviderException("A user with the same name but with a different authentication status already exists!");
                    }
                    current.LastActivityDateUtc = now;
                    current.ProfileBlobName = blobName;
                    current.ProfileSize = size;
                    current.ProfileLastUpdatedUtc = now;
                    context.UpdateObject(current);
                }
                else
                {
                    if (authenticated)
                    {
                        Log.Write(EventKind.Warning, "The authenticated user does not exist in the database.");
                    }
                    MembershipRow member = new MembershipRow(_applicationName, username);
                    member.LastActivityDateUtc = now;
                    member.IsAnonymous = !authenticated;
                    member.ProfileBlobName = blobName;
                    member.ProfileSize = size;
                    member.ProfileLastUpdatedUtc = now;
                    member.ProfileIsCreatedByProfileProvider = true;
                    context.AddObject(_tableName, member);
                }
                context.SaveChanges();
            });            
        }
        // we don't use _providerRetry here because of the out parameter prof
        private bool DoesProfileExistAndUpdateUser(string username, out MembershipRow prof)
        {
            SecUtility.CheckParameter(ref username, true, true, true, Constants.MaxTableUsernameLength, "username");

            int curRetry = 0;
            bool retry = false;
            do
            {
                retry = false;
                try
                {
                    TableServiceContext context = CreateDataServiceContext();
                    DataServiceQuery<MembershipRow> queryObj = context.CreateQuery<MembershipRow>(_tableName);
                    var query = (from profile in queryObj
                                 where profile.PartitionKey == SecUtility.CombineToKey(_applicationName, username)
                                 select profile).AsTableServiceQuery();
                    IEnumerable<MembershipRow> profiles = query.Execute();
                    if (profiles == null)
                    {
                        prof = null;
                        return false;
                    }

                    // instantiate results
                    List<MembershipRow> profileList = new List<MembershipRow>(profiles);

                    if (profileList.Count > 1)
                    {
                        throw new ProviderException("Multiple profile rows for the same user!");
                    }
                    if (profileList.Count == 1)
                    {
                        prof = profileList.First();
                        if (!string.IsNullOrEmpty(prof.ProfileBlobName))
                        {
                            prof.LastActivityDateUtc = DateTime.UtcNow;
                            context.UpdateObject(prof);
                            context.SaveChangesWithRetries();
                            return true;
                        }
                        else
                        {
                            return false;
                        }
                    }
                    else
                    {
                        prof = null;
                        return false;
                    }
                }
                catch (InvalidOperationException e)
                {
                    if (e.InnerException is DataServiceClientException && (e.InnerException as DataServiceClientException).StatusCode == (int)HttpStatusCode.PreconditionFailed)
                    {
                        retry = true;
                    }
                    else
                    {
                        throw new ProviderException("Error accessing storage.", e);
                    }
                }
            } while (curRetry++ < NumRetries && retry);
            prof = null;
            return false;
        }
        public override void Initialize(string name, NameValueCollection config)
        {
            // Verify that config isn't null
            if (config == null)
            {
                throw new ArgumentNullException("config");
            }

            // Assign the provider a default name if it doesn't have one
            if (String.IsNullOrEmpty(name))
            {
                name = "TableStorageProfileProvider";
            }

            // Add a default "description" attribute to config if the
            // attribute doesn't exist or is empty
            if (string.IsNullOrEmpty(config["description"]))
            {
                config.Remove("description");
                config.Add("description", "Table storage-based profile provider");
            }

            // Call the base class's Initialize method
            base.Initialize(name, config);

            bool allowInsecureRemoteEndpoints = Configuration.GetBooleanValue(config, "allowInsecureRemoteEndpoints", false);

            // structure storage-related properties
            ApplicationName = Configuration.GetStringValueWithGlobalDefault(config, "applicationName",
                                                            Configuration.DefaultProviderApplicationNameConfigurationString,
                                                            Configuration.DefaultProviderApplicationName, false);

            _account =
                CloudStorageAccount.Parse(
                    RoleEnvironment.GetConfigurationSettingValue(Configuration.ConfigurationStorageConnectionStringName));

            // profile information are stored in the membership table
            _tableName = Configuration.GetStringValueWithGlobalDefault(config, "membershipTableName",
                                                           Configuration.DefaultMembershipTableNameConfigurationString,
                                                           Configuration.DefaultMembershipTableName, false);

            _containerName = Configuration.GetStringValueWithGlobalDefault(config, "containerName",
                                                           Configuration.DefaultProfileContainerNameConfigurationString,
                                                           Configuration.DefaultProfileContainerName, false);

            if (!SecUtility.IsValidContainerName(_containerName))
            {
                throw new ProviderException("The provider configuration for the TableStorageProfileProvider does not contain a valid container name. " +
                                            "Please refer to the documentation for the concrete rules for valid container names." +
                                            "The current container name is" + _containerName);
            }
            _blobServiceBaseUri = Configuration.GetStringValue(config, "blobServiceBaseUri", null, true);

            // remove required attributes
            config.Remove("allowInsecureRemoteEndpoints");
            config.Remove("applicationName");
            config.Remove("membershipTableName");
            config.Remove("containerName");
            config.Remove("tableServiceBaseUri");
            config.Remove("blobServiceBaseUri");

            // Throw an exception if unrecognized attributes remain
            if (config.Count > 0)
            {
                string attr = config.GetKey(0);
                if (!String.IsNullOrEmpty(attr))
                {
                    throw new ProviderException(string.Format(CultureInfo.InstalledUICulture, "Unrecognized attribute: {0}", attr));
                }
            }

            // profiles are stored within the membership table
            _tableStorage = _account.CreateCloudTableClient();
            var blobClient = _account.CreateCloudBlobClient();
            try
            {
                if (_account == null)
                    throw new ConfigurationErrorsException("Account information incomplete!");

                _tableStorage.RetryPolicy = _tableRetry;

                SecUtility.CheckAllowInsecureEndpoints(allowInsecureRemoteEndpoints, _tableStorage.BaseUri);

                if (_tableStorage.CreateTableIfNotExist(_tableName))
                {
                    var ctx = _tableStorage.GetDataServiceContext();
                    var dummyRow = new MembershipRow("dummy", "none");
                    ctx.AddObject(_tableName, dummyRow);
                    ctx.SaveChangesWithRetries();
                    ctx.DeleteObject(dummyRow);
                    ctx.SaveChangesWithRetries();
                }

                SecUtility.CheckAllowInsecureEndpoints(allowInsecureRemoteEndpoints, blobClient.BaseUri);
                _blobProvider = new BlobProvider(blobClient, _containerName);
            }
            catch (SecurityException)
            {
                throw;
            }
            // catch InvalidOperationException and StorageException
            catch (Exception e)
            {
                string exceptionDescription = Configuration.GetInitExceptionDescription(blobClient, _tableStorage);
                string tableName = _tableName ?? "no profile table name specified";
                string containerName = _containerName ?? "no container name specified";
                Log.Write(EventKind.Error, "Initialization of data service structures (tables and/or blobs) failed!" + Environment.NewLine +
                                            exceptionDescription + Environment.NewLine +
                                            "Configured blob container: " + containerName + Environment.NewLine +
                                            "Configured table name: " + tableName + Environment.NewLine +
                                            e.Message + Environment.NewLine + e.StackTrace);
                throw new ProviderException("Initialization of data service structures (tables and/or blobs) failed! " +
                                            "The most probable reason for this is that " +
                                            "the storage endpoints are not configured correctly. Please look at the configuration settings " +
                                            "in your .cscfg and Web.config files. More information about this error " +
                                            "can be found in the logs when running inside the hosting environment or in the output " +
                                            "window of Visual Studio.", e);
            }
            Debug.Assert(_blobProvider != null);
        }
        public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context,
                                                                          SettingsPropertyCollection collection)
        {
            if (collection == null)
            {
                throw new ArgumentNullException("collection");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            SettingsPropertyValueCollection settings = new SettingsPropertyValueCollection();

            // Do nothing if there are no properties to retrieve
            if (collection.Count < 1)
            {
                return(settings);
            }

            // For properties lacking an explicit SerializeAs setting, set
            // SerializeAs to String for strings and primitives, and XML
            // for everything else
            foreach (SettingsProperty property in collection)
            {
                if (property.SerializeAs == SettingsSerializeAs.ProviderSpecific)
                {
                    if (property.PropertyType.IsPrimitive || property.PropertyType == typeof(String))
                    {
                        property.SerializeAs = SettingsSerializeAs.String;
                    }
                    else
                    {
                        property.SerializeAs = SettingsSerializeAs.Xml;
                    }
                }
                settings.Add(new SettingsPropertyValue(property));
            }

            // Get the user name or anonymous user ID
            string username = (string)context["UserName"];

            if (string.IsNullOrEmpty(username))
            {
                return(settings);
            }

            if (!VerifyUsername(ref username))
            {
                return(settings);
            }

            MembershipRow profile = null;

            if (!DoesProfileExistAndUpdateUser(username, out profile))
            {
                // the profile does not exist
                // we update the last activity time of the user only if the profile does exist
                // so we can just return here
                return(settings);
            }

            Debug.Assert(profile != null);

            // We are ready to go: load the profile
            // Note that we do not have to deal with write locks here because we use a
            // different blob name each time we write a new profile
            StreamReader      reader = null;
            MemoryStream      stream = null;
            sqlBlobProperties blobProperties;

            string[] names;
            string   values;

            byte[] buf = null;
            string line;

            try
            {
                // Open the blob containing the profile data
                stream = new MemoryStream();
                if (!_blobProvider.GetBlobContentsWithoutInitialization(profile.ProfileBlobName, stream, out blobProperties) || blobProperties.Length == 0)
                {
                    // not an error if the blob does not exist
                    return(settings);
                }
                stream.Seek(0, SeekOrigin.Begin);
                reader = new StreamReader(stream);

                // Read names, values, and buf from the blob
                line   = reader.ReadLine();
                names  = line.Split(':');
                values = reader.ReadLine();
                if (!string.IsNullOrEmpty(values))
                {
                    UnicodeEncoding encoding = new UnicodeEncoding();
                    values = encoding.GetString(Convert.FromBase64String(values));
                }
                string temp = reader.ReadLine();
                if (!String.IsNullOrEmpty(temp))
                {
                    buf = Convert.FromBase64String(temp);
                }
                else
                {
                    buf = new byte[0];
                }
            }
            catch (InvalidOperationException se)
            {
                throw new ProviderException("Error accessing blob storage when getting property values!", se);
            }
            catch (Exception e)
            {
                throw new ProviderException("Error getting property values.", e);
            }
            finally
            {
                if (reader != null)
                {
                    reader.Close();
                }
                if (stream != null)
                {
                    stream.Close();
                }
            }
            // Decode names, values, and buf and initialize the
            // SettingsPropertyValueCollection returned to the caller
            DecodeProfileData(names, values, buf, settings);

            return(settings);
        }
        // we don't use _providerRetry here because of the out parameter prof
        private bool DoesProfileExistAndUpdateUser(string username, out MembershipRow prof)
        {
            prof = null;
            return(false);
            //SecUtility.CheckParameter(ref username, true, true, true, Constants.MaxTableUsernameLength, "username");

            //int curRetry = 0;
            //bool retry = false;
            //do
            //{
            //    retry = false;
            //    try
            //    {
            //        TableServiceContext context = CreateDataServiceContext();
            //        DataServiceQuery<MembershipRow> queryObj = context.CreateQuery<MembershipRow>(_tableName);
            //        var query = (from profile in queryObj
            //                     where profile.PartitionKey == SecUtility.CombineToKey(_applicationName, username)
            //                     select profile).AsTableServiceQuery();
            //        IEnumerable<MembershipRow> profiles = query.Execute();
            //        if (profiles == null)
            //        {
            //            prof = null;
            //            return false;
            //        }

            //        // instantiate results
            //        List<MembershipRow> profileList = new List<MembershipRow>(profiles);

            //        if (profileList.Count > 1)
            //        {
            //            throw new ProviderException("Multiple profile rows for the same user!");
            //        }
            //        if (profileList.Count == 1)
            //        {
            //            prof = profileList.First();
            //            if (!string.IsNullOrEmpty(prof.ProfileBlobName))
            //            {
            //                prof.LastActivityDateUtc = DateTime.UtcNow;
            //                context.UpdateObject(prof);
            //                context.SaveChangesWithRetries();
            //                return true;
            //            }
            //            else
            //            {
            //                return false;
            //            }
            //        }
            //        else
            //        {
            //            prof = null;
            //            return false;
            //        }
            //    }
            //    catch (InvalidOperationException e)
            //    {
            //        if (e.InnerException is DataServiceClientException && (e.InnerException as DataServiceClientException).StatusCode == (int)HttpStatusCode.PreconditionFailed)
            //        {
            //            retry = true;
            //        }
            //        else
            //        {
            //            throw new ProviderException("Error accessing storage.", e);
            //        }
            //    }
            //} while (curRetry++ < NumRetries && retry);
            //prof = null;
            //return false;
        }