Kaynağa Gözat

2007-12-08 Marek Habersack <[email protected]>

	* TranslationResources.resx: added - string resources for the
	Sqlite providers.
2007-12-08  Marek Habersack  <[email protected]>

	* SQLiteProviders_DatabaseSchema.sql: added
	* Makefile: added support for compiling .resx resources.
	Added SQLiteProviders_DatabaseSchema.sql to EXTRA_DISTFILES.
	Added new resource files to EXTRA_DISTFILES
2007-12-08  Marek Habersack  <[email protected]>

	* HttpRuntime.cs: initialize the Settings Mapping Manager once per
	application, just after initalizing the WebConfigurationManager
2007-12-08  Marek Habersack  <[email protected]>

	* SqliteProfileProvider.cs: added - a Profile Provider for
        Sqlite, based on PostgreSQL Profile Provider code from Daniel
        Nauck <[email protected]>
2007-12-08  Marek Habersack  <[email protected]>

	* TranslationProperties.Designer.cs: added - contains strongly
	typed properties referring to string resources used by the Sqlite
	providers.
2007-12-08  Marek Habersack  <[email protected]>

	* WebConfigurationManager.cs: GetSection now runs each section
	through a mapper (if any is defined for the section) before
	returning it to the caller.
2007-12-08  Marek Habersack  <[email protected]>

	* SqliteRoleProvider.cs: added - a Role Provider for
	Sqlite, based on PostgreSQL Role Provider code from Daniel
	Nauck <[email protected]>

	* SqliteMembershipProvider.cs: added - a Membership Provider for
	Sqlite, based on PostgreSQL Membership Provider code from Daniel
	Nauck <[email protected]>
2007-12-08  Marek Habersack  <[email protected]>

	* SerializationHelper.cs: added - serialization helper for the
	Sqlite Profile Provider.

	* RoleManagerSectionMapper.cs: added - section settings mapper for
	the RoleManager section.

	* MembershipSectionMapper.cs: added - section settings mapper for
	the Membership section.

	* ISectionSettingsMapper.cs: added - interface definition for
	section settings mappers.

	* SettingsMappingWhat.cs: added - describes a single 'what' tag
	instance inside the mapper definition in the settings.map file.

	* SettingsMapping.cs: added - represents a single mapper entry in
	the settings.map file.

	* SettingsMappingManager.cs: added - manages settings mapping as
	defined in the settings.map file.


svn path=/trunk/mcs/; revision=90972
Marek Habersack 18 yıl önce
ebeveyn
işleme
58eceab2ec
25 değiştirilmiş dosya ile 4566 ekleme ve 6 silme
  1. 7 0
      mcs/class/System.Web/ChangeLog
  2. 15 4
      mcs/class/System.Web/Makefile
  3. 81 0
      mcs/class/System.Web/SQLiteProviders_DatabaseSchema.sql
  4. 6 0
      mcs/class/System.Web/System.Web.Configuration_2.0/ChangeLog
  5. 2 1
      mcs/class/System.Web/System.Web.Configuration_2.0/WebConfigurationManager.cs
  6. 6 0
      mcs/class/System.Web/System.Web.Profile/ChangeLog
  7. 550 0
      mcs/class/System.Web/System.Web.Profile/SqliteProfileProvider.cs
  8. 6 0
      mcs/class/System.Web/System.Web.Properties/ChangeLog
  9. 388 0
      mcs/class/System.Web/System.Web.Properties/TranslationProperties.Designer.cs
  10. 10 0
      mcs/class/System.Web/System.Web.Security/ChangeLog
  11. 1651 0
      mcs/class/System.Web/System.Web.Security/SqliteMembershipProvider.cs
  12. 713 0
      mcs/class/System.Web/System.Web.Security/SqliteRoleProvider.cs
  13. 23 0
      mcs/class/System.Web/System.Web.Util/ChangeLog
  14. 41 0
      mcs/class/System.Web/System.Web.Util/ISectionSettingsMapper.cs
  15. 165 0
      mcs/class/System.Web/System.Web.Util/MembershipSectionMapper.cs
  16. 165 0
      mcs/class/System.Web/System.Web.Util/RoleManagerSectionMapper.cs
  17. 89 0
      mcs/class/System.Web/System.Web.Util/SerializationHelper.cs
  18. 112 0
      mcs/class/System.Web/System.Web.Util/SettingsMapping.cs
  19. 167 0
      mcs/class/System.Web/System.Web.Util/SettingsMappingManager.cs
  20. 119 0
      mcs/class/System.Web/System.Web.Util/SettingsMappingWhat.cs
  21. 11 0
      mcs/class/System.Web/System.Web.dll.sources
  22. 5 0
      mcs/class/System.Web/System.Web/ChangeLog
  23. 1 1
      mcs/class/System.Web/System.Web/HttpRuntime.cs
  24. 5 0
      mcs/class/System.Web/resources/ChangeLog
  25. 228 0
      mcs/class/System.Web/resources/TranslationResources.resx

+ 7 - 0
mcs/class/System.Web/ChangeLog

@@ -1,3 +1,10 @@
+2007-12-08  Marek Habersack  <[email protected]>
+
+	* SQLiteProviders_DatabaseSchema.sql: added
+	* Makefile: added support for compiling .resx resources.
+	Added SQLiteProviders_DatabaseSchema.sql to EXTRA_DISTFILES.
+	Added new resource files to EXTRA_DISTFILES
+
 2007-11-23  Daniel Nauck  <[email protected]>
 
         * System.Web.dll.sources: added

+ 15 - 4
mcs/class/System.Web/Makefile

@@ -135,10 +135,14 @@ TEST_RESOURCE_FILES = \
 	Test/mainsoft/NunitWebResources/TextBoxTestlPage.aspx \
 	Test/mainsoft/MainsoftWebTest/nunitweb_config.xml 
 
+ifeq (net_2_0, $(PROFILE))
+RESX_RES = resources/TranslationResources.resources
+endif
+
 NUNIT_RESOURCE_FILES = $(TEST_RESOURCE_FILES)
 ifeq (net_2_0, $(PROFILE))
 OTHER_RES += $(RESOURCE_FILES_2)
-OTHER_LIB_MCS_FLAGS = -nowarn:618 -r:System.Configuration.dll -r:System.Windows.Forms.dll
+OTHER_LIB_MCS_FLAGS = -nowarn:618 -r:System.Configuration.dll -r:System.Windows.Forms.dll -r:Mono.Data.Sqlite.dll
 endif
 
 LIB_MCS_FLAGS = \
@@ -151,12 +155,13 @@ LIB_MCS_FLAGS = \
 	-r:System.Xml.dll		\
 	-r:System.EnterpriseServices.dll \
 	$(OTHER_LIB_MCS_FLAGS) \
+	$(RESX_RES:%=/resource:%) \
 	$(OTHER_RES:%=/resource:%)
 
 ifneq ($(CYCLIC_DEPS:%=../lib/$(PROFILE)/%), $(CYCLIC_DEP_FILES))
 NO_SIGN_ASSEMBLY = yes
 NO_INSTALL = yes
-all-local: System.Web/UplevelHelper.cs echo-warning
+all-local: System.Web/UplevelHelper.cs resources/TranslationResources.resources echo-warning
 .PHONY: echo-warning
 
 ifeq   (, $(strip $(CYCLIC_DEP_FILES)))
@@ -167,8 +172,9 @@ endif
 
 TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) -doc:$(test_lib:.dll=.xml)  -nowarn:219 -nowarn:169 $(NUNIT_RESOURCE_FILES:%=/resource:%)
 
-EXTRA_DISTFILES = $(RESOURCE_FILES_2) $(RESOURCE_FILES_1) $(TEST_RESOURCE_FILES) UplevelHelperDefinitions.xml
-BUILT_SOURCES = System.Web/UplevelHelper.cs
+EXTRA_DISTFILES = $(RESOURCE_FILES_2) $(RESOURCE_FILES_1) $(TEST_RESOURCE_FILES) UplevelHelperDefinitions.xml $(RESX_RES:.resources=.resx) \
+		  SQLiteProviders_DatabaseSchema.sql
+BUILT_SOURCES = System.Web/UplevelHelper.cs 
 
 include ../../build/library.make
 
@@ -177,6 +183,11 @@ LIB_MCS_FLAGS += -define:WEBSERVICES_DEP -r:$(WEBSERVICES_DEP)
 $(the_lib): $(WEBSERVICES_DEP_FILE)
 endif
 
+$(the_lib): $(RESX_RES) $(RESOURCE_FILES2) $(RESOURCE_FILES_1)
+
+$(RESX_RES): %.resources: %.resx
+	$(RESGEN) `echo $< | $(PLATFORM_CHANGE_SEPARATOR_CMD)`
+
 System.Web/UplevelHelper.cs: UplevelHelperDefinitions.xml
 	$(TEST_RUNTIME) $(topdir)/class/lib/net_1_1_bootstrap/culevel.exe -o $@ $^
 

+ 81 - 0
mcs/class/System.Web/SQLiteProviders_DatabaseSchema.sql

@@ -0,0 +1,81 @@
+CREATE TABLE "Users" (
+	"pId"						character(36)		NOT NULL,
+	"Username"					character varying(255)	NOT NULL,
+	"ApplicationName"				character varying(255)	NOT NULL,
+	"Email"						character varying(128)	NULL,
+	"Comment"					character varying(128)	NULL,
+	"Password"					character varying(255)	NOT NULL,
+	"PasswordQuestion"				character varying(255)	NULL,
+	"PasswordAnswer"				character varying(255)	NULL,
+	"IsApproved"					boolean			NULL, 
+	"LastActivityDate"				timestamptz		NULL,
+	"LastLoginDate"					timestamptz		NULL,
+	"LastPasswordChangedDate"			timestamptz		NULL,
+	"CreationDate"					timestamptz		NULL, 
+	"IsOnLine"					boolean			NULL,
+	"IsLockedOut"					boolean			NULL,
+	"LastLockedOutDate"				timestamptz		NULL,
+	"FailedPasswordAttemptCount"			integer			NULL,
+	"FailedPasswordAttemptWindowStart"		timestamptz		NULL,
+	"FailedPasswordAnswerAttemptCount"		integer			NULL,
+	"FailedPasswordAnswerAttemptWindowStart"	timestamptz		NULL,
+	CONSTRAINT users_pkey PRIMARY KEY ("pId"),
+	CONSTRAINT users_username_application_unique UNIQUE ("Username", "ApplicationName")
+);
+
+CREATE INDEX users_email_index ON "Users" ("Email");
+CREATE INDEX users_islockedout_index ON "Users" ("IsLockedOut");
+
+CREATE TABLE "Roles" (
+	"Rolename"					character varying(255)	NOT NULL,
+	"ApplicationName"				character varying(255)	NOT NULL,
+	CONSTRAINT roles_pkey PRIMARY KEY ("Rolename", "ApplicationName")
+);
+
+CREATE TABLE "UsersInRoles" (
+	"Username"					character varying(255)	NOT NULL,
+	"Rolename"					character varying(255)	NOT NULL,
+	"ApplicationName"				character varying(255)	NOT NULL,
+	CONSTRAINT usersinroles_pkey PRIMARY KEY ("Username", "Rolename", "ApplicationName"),
+	CONSTRAINT usersinroles_username_fkey FOREIGN KEY ("Username", "ApplicationName") REFERENCES "Users" ("Username", "ApplicationName") ON DELETE CASCADE,
+	CONSTRAINT usersinroles_rolename_fkey FOREIGN KEY ("Rolename", "ApplicationName") REFERENCES "Roles" ("Rolename", "ApplicationName") ON DELETE CASCADE
+);
+
+CREATE TABLE "Profiles" (
+	"pId"						character(36)		NOT NULL,
+	"Username"					character varying(255)	NOT NULL,
+	"ApplicationName"				character varying(255)	NOT NULL,
+	"IsAnonymous"					boolean			NULL,
+	"LastActivityDate"				timestamptz		NULL,
+	"LastUpdatedDate"				timestamptz		NULL,
+	CONSTRAINT profiles_pkey PRIMARY KEY ("pId"),
+	CONSTRAINT profiles_username_application_unique UNIQUE ("Username", "ApplicationName"),
+	CONSTRAINT profiles_username_fkey FOREIGN KEY ("Username", "ApplicationName") REFERENCES "Users" ("Username", "ApplicationName") ON DELETE CASCADE
+);
+
+CREATE INDEX profiles_isanonymous_index ON "Profiles" ("IsAnonymous");
+
+CREATE TABLE "ProfileData" (
+	"pId"						character(36)		NOT NULL,
+	"Profile"					character(36)		NOT NULL,
+	"Name"						character varying(255)	NOT NULL,
+	"ValueString"					text			NULL,
+	"ValueBinary"					bytea			NULL,
+	CONSTRAINT profiledata_pkey PRIMARY KEY ("pId"),
+	CONSTRAINT profiledata_profile_name_unique UNIQUE ("Profile", "Name"),
+	CONSTRAINT profiledata_profile_fkey FOREIGN KEY ("Profile") REFERENCES "Profiles" ("pId") ON DELETE CASCADE
+);
+
+CREATE TABLE "Sessions" (
+	"SessionId"					character varying(80)	NOT NULL,
+	"ApplicationName"				character varying(255)	NOT NULL,
+	"Created"					timestamptz		NOT NULL,
+	"Expires"					timestamptz		NOT NULL,
+	"Timeout"					integer			NOT NULL,
+	"Locked"					boolean			NOT NULL,
+	"LockId"					integer			NOT NULL,
+	"LockDate"					timestamptz		NOT NULL,
+	"Data"						text			NULL,
+	"Flags"						integer			NOT NULL,
+	CONSTRAINT sessions_pkey PRIMARY KEY ("SessionId", "ApplicationName")
+);

+ 6 - 0
mcs/class/System.Web/System.Web.Configuration_2.0/ChangeLog

@@ -1,3 +1,9 @@
+2007-12-08  Marek Habersack  <[email protected]>
+
+	* WebConfigurationManager.cs: GetSection now runs each section
+	through a mapper (if any is defined for the section) before
+	returning it to the caller.
+
 2007-11-23  Marek Habersack  <[email protected]>
 
 	* TagPrefixCollection.cs: changed the collection type to

+ 2 - 1
mcs/class/System.Web/System.Web.Configuration_2.0/WebConfigurationManager.cs

@@ -34,6 +34,7 @@ using System.IO;
 using System.Collections;
 using System.Collections.Specialized;
 using System.Reflection;
+using System.Web.Util;
 using System.Xml;
 using System.Configuration;
 using System.Configuration.Internal;
@@ -270,7 +271,7 @@ namespace System.Web.Configuration {
 			if (section == null)
 				return null;
 
-			return get_runtime_object.Invoke (section, new object [0]);
+			return SettingsMappingManager.MapSection (get_runtime_object.Invoke (section, new object [0]));
 		}
 
 		static string GetCurrentPath (HttpContext ctx)

+ 6 - 0
mcs/class/System.Web/System.Web.Profile/ChangeLog

@@ -1,3 +1,9 @@
+2007-12-08  Marek Habersack  <[email protected]>
+
+	* SqliteProfileProvider.cs: added - a Profile Provider for
+        Sqlite, based on PostgreSQL Profile Provider code from Daniel
+        Nauck <[email protected]>
+
 2007-10-15  Marek Habersack  <[email protected]>
 
 	* ProfileBase.cs: use HttpApplication.LoadType instead of

+ 550 - 0
mcs/class/System.Web/System.Web.Profile/SqliteProfileProvider.cs

@@ -0,0 +1,550 @@
+//
+// $Id: PgProfileProvider.cs 36 2007-11-24 09:44:42Z dna $
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Copyright © 2006, 2007 Nauck IT KG		http://www.nauck-it.de
+//
+// Author:
+//	Daniel Nauck		<d.nauck(at)nauck-it.de>
+//
+// Adapted to Sqlite by Marek Habersack <[email protected]>
+//
+
+#if NET_2_0
+using System;
+using System.Data;
+using System.Data.Common;
+using System.Configuration;
+using System.Configuration.Provider;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Diagnostics;
+using System.Text;
+using System.Web.Hosting;
+using System.Web.Util;
+
+using Mono.Data.Sqlite;
+
+namespace System.Web.Profile
+{
+	internal class SqliteProfileProvider : ProfileProvider
+	{
+		private const string m_ProfilesTableName = "Profiles";
+		private const string m_ProfileDataTableName = "ProfileData";
+		private string m_ConnectionString = string.Empty;
+
+		private SerializationHelper m_serializationHelper = new SerializationHelper();
+
+		DbParameter AddParameter (DbCommand command, string parameterName)
+                {
+                        return AddParameter (command, parameterName, null);
+                }
+		
+		DbParameter AddParameter (DbCommand command, string parameterName, object parameterValue)
+                {
+                        return AddParameter (command, parameterName, ParameterDirection.Input, parameterValue);
+                }
+
+                DbParameter AddParameter (DbCommand command, string parameterName, ParameterDirection direction, object parameterValue)
+                {
+                        DbParameter dbp = command.CreateParameter ();
+                        dbp.ParameterName = parameterName;
+                        dbp.Value = parameterValue;
+                        dbp.Direction = direction;
+                        command.Parameters.Add (dbp);
+                        return dbp;
+                }
+
+                DbParameter AddParameter (DbCommand command, string parameterName, ParameterDirection direction, DbType type, object parameterValue)
+                {
+                        DbParameter dbp = command.CreateParameter ();
+                        dbp.ParameterName = parameterName;
+                        dbp.Value = parameterValue;
+                        dbp.Direction = direction;
+                        dbp.DbType = type;
+                        command.Parameters.Add (dbp);
+                        return dbp;
+                }
+		
+		/// <summary>
+		/// System.Configuration.Provider.ProviderBase.Initialize Method
+		/// </summary>
+		public override void Initialize(string name, NameValueCollection config)
+		{
+			// Initialize values from web.config.
+			if (config == null)
+				throw new ArgumentNullException("Config", Properties.Resources.ErrArgumentNull);
+
+			if (string.IsNullOrEmpty(name))
+				name = Properties.Resources.ProfileProviderDefaultName;
+
+			if (string.IsNullOrEmpty(config["description"]))
+			{
+				config.Remove("description");
+				config.Add("description", Properties.Resources.ProfileProviderDefaultDescription);
+			}
+
+			// Initialize the abstract base class.
+			base.Initialize(name, config);
+
+			m_ApplicationName = GetConfigValue(config["applicationName"], HostingEnvironment.ApplicationVirtualPath);
+
+			// Get connection string.
+			string connStrName = config["connectionStringName"];
+
+			if (string.IsNullOrEmpty(connStrName))
+			{
+				throw new ArgumentOutOfRangeException("ConnectionStringName", Properties.Resources.ErrArgumentNullOrEmpty);
+			}
+			else
+			{
+				ConnectionStringSettings ConnectionStringSettings = ConfigurationManager.ConnectionStrings[connStrName];
+
+				if (ConnectionStringSettings == null || string.IsNullOrEmpty(ConnectionStringSettings.ConnectionString.Trim()))
+				{
+					throw new ProviderException(Properties.Resources.ErrConnectionStringNullOrEmpty);
+				}
+
+				m_ConnectionString = ConnectionStringSettings.ConnectionString;
+			}
+		}
+
+		/// <summary>
+		/// System.Web.Profile.ProfileProvider properties.
+		/// </summary>
+		#region System.Web.Security.ProfileProvider properties
+		private string m_ApplicationName = string.Empty;
+
+		public override string ApplicationName
+		{
+			get { return m_ApplicationName; }
+			set { m_ApplicationName = value; }
+		}
+		#endregion
+
+		/// <summary>
+		/// System.Web.Profile.ProfileProvider methods.
+		/// </summary>
+		#region System.Web.Security.ProfileProvider methods
+
+		/// <summary>
+		/// ProfileProvider.DeleteInactiveProfiles
+		/// </summary>
+		public override int DeleteInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate)
+		{
+			throw new Exception("DeleteInactiveProfiles: The method or operation is not implemented.");
+		}
+
+		public override int DeleteProfiles(string[] usernames)
+		{
+			throw new Exception("DeleteProfiles1: The method or operation is not implemented.");
+		}
+
+		public override int DeleteProfiles(ProfileInfoCollection profiles)
+		{
+			throw new Exception("DeleteProfiles2: The method or operation is not implemented.");
+		}
+
+		public override ProfileInfoCollection FindInactiveProfilesByUserName(ProfileAuthenticationOption authenticationOption, string usernameToMatch, DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords)
+		{
+			throw new Exception("FindInactiveProfilesByUserName: The method or operation is not implemented.");
+		}
+
+		public override ProfileInfoCollection FindProfilesByUserName(ProfileAuthenticationOption authenticationOption, string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
+		{
+			throw new Exception("FindProfilesByUserName: The method or operation is not implemented.");
+		}
+
+		public override ProfileInfoCollection GetAllInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords)
+		{
+			throw new Exception("GetAllInactiveProfiles: The method or operation is not implemented.");
+		}
+
+		public override ProfileInfoCollection GetAllProfiles(ProfileAuthenticationOption authenticationOption, int pageIndex, int pageSize, out int totalRecords)
+		{
+			throw new Exception("GetAllProfiles: The method or operation is not implemented.");
+		}
+
+		public override int GetNumberOfInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate)
+		{
+			throw new Exception("GetNumberOfInactiveProfiles: The method or operation is not implemented.");
+		}
+		#endregion
+
+		/// <summary>
+		/// System.Configuration.SettingsProvider methods.
+		/// </summary>
+		#region System.Web.Security.SettingsProvider methods
+
+		/// <summary>
+		/// 
+		/// </summary>
+		public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection)
+		{
+			SettingsPropertyValueCollection result = new SettingsPropertyValueCollection();
+			string username = (string)context["UserName"];
+			bool isAuthenticated = (bool)context["IsAuthenticated"];
+			Dictionary<string, object> databaseResult = new Dictionary<string, object>();
+
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("SELECT \"Name\", \"ValueString\", \"ValueBinary\" FROM \"{0}\" WHERE \"Profile\" = (SELECT \"pId\" FROM \"{1}\" WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName AND \"IsAnonymous\" = @IsAuthenticated)", m_ProfileDataTableName, m_ProfilesTableName);
+
+					AddParameter (dbCommand, "@Username", username);
+					AddParameter (dbCommand, "@ApplicationName", m_ApplicationName);
+					AddParameter (dbCommand, "@IsAuthenticated", !isAuthenticated);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						using (SqliteDataReader reader = dbCommand.ExecuteReader())
+						{
+							while (reader.Read())
+							{
+								object resultData = null;
+								if(!reader.IsDBNull(1))
+									resultData = reader.GetValue(1);
+								else if(!reader.IsDBNull(2))
+									resultData = reader.GetValue(2);
+
+								databaseResult.Add(reader.GetString(0), resultData);
+							}
+						}
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+
+			foreach (SettingsProperty item in collection)
+			{
+				if (item.SerializeAs == SettingsSerializeAs.ProviderSpecific)
+				{
+					if (item.PropertyType.IsPrimitive || item.PropertyType.Equals(typeof(string)))
+						item.SerializeAs = SettingsSerializeAs.String;
+					else
+						item.SerializeAs = SettingsSerializeAs.Xml;
+				}
+
+				SettingsPropertyValue itemValue = new SettingsPropertyValue(item);
+
+				if ((databaseResult.ContainsKey(item.Name)) && (databaseResult[item.Name] != null))
+				{
+					if(item.SerializeAs == SettingsSerializeAs.String)
+						itemValue.PropertyValue = m_serializationHelper.DeserializeFromBase64((string)databaseResult[item.Name]);
+					
+					else if (item.SerializeAs == SettingsSerializeAs.Xml)
+						itemValue.PropertyValue = m_serializationHelper.DeserializeFromXml((string)databaseResult[item.Name]);
+
+					else if (item.SerializeAs == SettingsSerializeAs.Binary)
+						itemValue.PropertyValue = m_serializationHelper.DeserializeFromBinary((byte[])databaseResult[item.Name]);
+				}
+				itemValue.IsDirty = false;				
+				result.Add(itemValue);
+			}
+
+			UpdateActivityDates(username, isAuthenticated, true);
+
+			return result;
+		}
+
+		public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection collection)
+		{
+			string username = (string)context["UserName"];
+			bool isAuthenticated = (bool)context["IsAuthenticated"];
+
+			if (collection.Count < 1)
+				return;
+
+			if (!ProfileExists(username))
+				CreateProfileForUser(username, isAuthenticated);
+
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				using (SqliteCommand deleteCommand = dbConn.CreateCommand(),
+					insertCommand = dbConn.CreateCommand())
+				{
+					deleteCommand.CommandText = string.Format("DELETE FROM \"{0}\" WHERE \"Name\" = @Name AND \"Profile\" = (SELECT \"pId\" FROM \"{1}\" WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName AND \"IsAnonymous\" = @IsAuthenticated)", m_ProfileDataTableName, m_ProfilesTableName);
+
+					AddParameter (deleteCommand, "@Name");
+					AddParameter (deleteCommand, "@Username", username);
+					AddParameter (deleteCommand, "@ApplicationName", m_ApplicationName);
+					AddParameter (deleteCommand, "@IsAuthenticated", !isAuthenticated);
+
+
+					insertCommand.CommandText = string.Format("INSERT INTO \"{0}\" (\"pId\", \"Profile\", \"Name\", \"ValueString\", \"ValueBinary\") VALUES (@pId, (SELECT \"pId\" FROM \"{1}\" WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName AND \"IsAnonymous\" = @IsAuthenticated), @Name, @ValueString, @ValueBinary)", m_ProfileDataTableName, m_ProfilesTableName);
+
+					AddParameter (insertCommand, "@pId");
+					AddParameter (insertCommand, "@Name");
+					AddParameter (insertCommand, "@ValueString");
+					insertCommand.Parameters["@ValueString"].IsNullable = true;
+					AddParameter (insertCommand, "@ValueBinary");
+					insertCommand.Parameters["@ValueBinary"].IsNullable = true;
+					AddParameter (insertCommand, "@Username", username);
+					AddParameter (insertCommand, "@ApplicationName", m_ApplicationName);
+					AddParameter (insertCommand, "@IsAuthenticated", !isAuthenticated);
+
+					SqliteTransaction dbTrans = null;
+
+					try
+					{
+						dbConn.Open();
+						deleteCommand.Prepare();
+						insertCommand.Prepare();
+
+						using (dbTrans = dbConn.BeginTransaction())
+						{
+
+							foreach (SettingsPropertyValue item in collection)
+							{
+								if (!item.IsDirty)
+									continue;
+
+								deleteCommand.Parameters["@Name"].Value = item.Name;
+
+								insertCommand.Parameters["@pId"].Value = Guid.NewGuid().ToString();
+								insertCommand.Parameters["@Name"].Value = item.Name;
+
+								if (item.Property.SerializeAs == SettingsSerializeAs.String)
+								{
+									insertCommand.Parameters["@ValueString"].Value = m_serializationHelper.SerializeToBase64(item.PropertyValue);
+									insertCommand.Parameters["@ValueBinary"].Value = DBNull.Value; //new byte[0];//DBNull.Value;
+								}
+								else if (item.Property.SerializeAs == SettingsSerializeAs.Xml)
+								{
+									item.SerializedValue = m_serializationHelper.SerializeToXml(item.PropertyValue);
+									insertCommand.Parameters["@ValueString"].Value = item.SerializedValue;
+									insertCommand.Parameters["@ValueBinary"].Value = DBNull.Value; //new byte[0];//DBNull.Value;
+								}
+								else if (item.Property.SerializeAs == SettingsSerializeAs.Binary)
+								{
+									item.SerializedValue = m_serializationHelper.SerializeToBinary(item.PropertyValue);
+									insertCommand.Parameters["@ValueString"].Value = DBNull.Value; //string.Empty;//DBNull.Value;
+									insertCommand.Parameters["@ValueBinary"].Value = item.SerializedValue;
+								}
+
+								deleteCommand.ExecuteNonQuery();
+								insertCommand.ExecuteNonQuery();
+							}
+
+							UpdateActivityDates(username, isAuthenticated, false);
+
+							// Attempt to commit the transaction
+							dbTrans.Commit();
+						}
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+
+						try
+						{
+							// Attempt to roll back the transaction
+							Trace.WriteLine(Properties.Resources.LogRollbackAttempt);
+							dbTrans.Rollback();
+						}
+						catch (SqliteException re)
+						{
+							// Rollback failed
+							Trace.WriteLine(Properties.Resources.ErrRollbackFailed);
+							Trace.WriteLine(re.ToString());
+						}
+
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+		}
+		#endregion
+
+		#region private methods
+		/// <summary>
+		/// Create a empty user profile
+		/// </summary>
+		/// <param name="username"></param>
+		/// <param name="isAuthenticated"></param>
+		private void CreateProfileForUser(string username, bool isAuthenticated)
+		{
+			if (ProfileExists(username))
+			{
+				throw new ProviderException(string.Format(Properties.Resources.ErrProfileAlreadyExist, username));
+			}
+
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("INSERT INTO \"{0}\" (\"pId\", \"Username\", \"ApplicationName\", \"IsAnonymous\", \"LastActivityDate\", \"LastUpdatedDate\") Values (@pId, @Username, @ApplicationName, @IsAuthenticated, @LastActivityDate, @LastUpdatedDate)", m_ProfilesTableName);
+
+					AddParameter (dbCommand, "@pId", Guid.NewGuid().ToString());
+					AddParameter (dbCommand, "@Username", username);
+					AddParameter (dbCommand, "@ApplicationName", m_ApplicationName);
+					AddParameter (dbCommand, "@IsAuthenticated", !isAuthenticated);
+					AddParameter (dbCommand, "@LastActivityDate", DateTime.Now);
+					AddParameter (dbCommand, "@LastUpdatedDate", DateTime.Now);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						dbCommand.ExecuteNonQuery();
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+		}
+
+
+		private bool ProfileExists(string username)
+		{
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("SELECT COUNT(*) FROM \"{0}\" WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_ProfilesTableName);
+
+					AddParameter (dbCommand, "@Username", username);
+					AddParameter (dbCommand, "@ApplicationName", m_ApplicationName);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						int numRecs = 0;
+						Int32.TryParse(dbCommand.ExecuteScalar().ToString(), out numRecs);
+
+						if (numRecs > 0)
+							return true;
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+
+			return false;
+		}
+
+		/// <summary>
+		/// Updates the LastActivityDate and LastUpdatedDate values when profile properties are accessed by the
+		/// GetPropertyValues and SetPropertyValues methods.
+		/// Passing true as the activityOnly parameter will update only the LastActivityDate.
+		/// </summary>
+		/// <param name="username"></param>
+		/// <param name="isAuthenticated"></param>
+		/// <param name="activityOnly"></param>
+		private void UpdateActivityDates(string username, bool isAuthenticated, bool activityOnly)
+		{
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					if (activityOnly)
+					{
+						dbCommand.CommandText = string.Format("UPDATE \"{0}\" SET \"LastActivityDate\" = @LastActivityDate WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName AND \"IsAnonymous\" = @IsAuthenticated", m_ProfilesTableName);
+
+						AddParameter (dbCommand, "@LastActivityDate", DateTime.Now);
+					}
+					else
+					{
+						dbCommand.CommandText = string.Format("UPDATE \"{0}\" SET \"LastActivityDate\" = @LastActivityDate, \"LastUpdatedDate\" = @LastUpdatedDate WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName AND \"IsAnonymous\" = @IsAuthenticated", m_ProfilesTableName);
+
+						AddParameter (dbCommand, "@LastActivityDate", DateTime.Now);
+						AddParameter (dbCommand, "@LastUpdatedDate", DateTime.Now);
+					}
+					
+					AddParameter (dbCommand, "@Username", username);
+					AddParameter (dbCommand, "@ApplicationName", m_ApplicationName);
+					AddParameter (dbCommand, "@IsAuthenticated", !isAuthenticated);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						dbCommand.ExecuteNonQuery();
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+		}
+
+		/// <summary>
+		/// A helper function to retrieve config values from the configuration file.
+		/// </summary>
+		/// <param name="configValue"></param>
+		/// <param name="defaultValue"></param>
+		/// <returns></returns>
+		private string GetConfigValue(string configValue, string defaultValue)
+		{
+			if (string.IsNullOrEmpty(configValue))
+				return defaultValue;
+
+			return configValue;
+		}
+		#endregion
+	}
+}
+#endif

+ 6 - 0
mcs/class/System.Web/System.Web.Properties/ChangeLog

@@ -0,0 +1,6 @@
+2007-12-08  Marek Habersack  <[email protected]>
+
+	* TranslationProperties.Designer.cs: added - contains strongly
+	typed properties referring to string resources used by the Sqlite
+	providers.
+

+ 388 - 0
mcs/class/System.Web/System.Web.Properties/TranslationProperties.Designer.cs

@@ -0,0 +1,388 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:2.0.50727.312
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+#if NET_2_0
+namespace System.Web.Properties {
+    using System;
+    
+    
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Resources {
+        
+        private static global::System.Resources.ResourceManager resourceMan;
+        
+        private static global::System.Globalization.CultureInfo resourceCulture;
+        
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources() {
+        }
+        
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TranslationResources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Argument cannot be null..
+        /// </summary>
+        internal static string ErrArgumentNull {
+            get {
+                return ResourceManager.GetString("ErrArgumentNull", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Argument cannot be null or empty..
+        /// </summary>
+        internal static string ErrArgumentNullOrEmpty {
+            get {
+                return ResourceManager.GetString("ErrArgumentNullOrEmpty", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Hashed or Encrypted passwords are not supported with auto-generated keys..
+        /// </summary>
+        internal static string ErrAutoGeneratedKeyNotSupported {
+            get {
+                return ResourceManager.GetString("ErrAutoGeneratedKeyNotSupported", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Cannot unencode a hashed password..
+        /// </summary>
+        internal static string ErrCantDecodeHashedPw {
+            get {
+                return ResourceManager.GetString("ErrCantDecodeHashedPw", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Cannot delete a populated role..
+        /// </summary>
+        internal static string ErrCantDeletePopulatedRole {
+            get {
+                return ResourceManager.GetString("ErrCantDeletePopulatedRole", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Unable to lock out user &apos;{0}&apos;..
+        /// </summary>
+        internal static string ErrCantLogoutUser {
+            get {
+                return ResourceManager.GetString("ErrCantLogoutUser", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Cannot retrieve hashed passwords..
+        /// </summary>
+        internal static string ErrCantRetrieveHashedPw {
+            get {
+                return ResourceManager.GetString("ErrCantRetrieveHashedPw", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Unable to update failure count..
+        /// </summary>
+        internal static string ErrCantUpdateFailtureCount {
+            get {
+                return ResourceManager.GetString("ErrCantUpdateFailtureCount", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Unable to update failure count and window start..
+        /// </summary>
+        internal static string ErrCantUpdateFailtureCountAndWindowStart {
+            get {
+                return ResourceManager.GetString("ErrCantUpdateFailtureCountAndWindowStart", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Connection string cannot be null or empty..
+        /// </summary>
+        internal static string ErrConnectionStringNullOrEmpty {
+            get {
+                return ResourceManager.GetString("ErrConnectionStringNullOrEmpty", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Incorrect password answer..
+        /// </summary>
+        internal static string ErrIncorrectPasswordAnswer {
+            get {
+                return ResourceManager.GetString("ErrIncorrectPasswordAnswer", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Operation aborted due to an exception (see Trace for details)..
+        /// </summary>
+        internal static string ErrOperationAborted {
+            get {
+                return ResourceManager.GetString("ErrOperationAborted", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Password answer required for password reset..
+        /// </summary>
+        internal static string ErrPasswordAnswerRequired {
+            get {
+                return ResourceManager.GetString("ErrPasswordAnswerRequired", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Change password canceled due to new password validation failure..
+        /// </summary>
+        internal static string ErrPasswordChangeCanceled {
+            get {
+                return ResourceManager.GetString("ErrPasswordChangeCanceled", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to User not found, or user is locked out. Password not Reset..
+        /// </summary>
+        internal static string ErrPasswordResetAborted {
+            get {
+                return ResourceManager.GetString("ErrPasswordResetAborted", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Reset password canceled due to password answer validation failure..
+        /// </summary>
+        internal static string ErrPasswordResetCanceled {
+            get {
+                return ResourceManager.GetString("ErrPasswordResetCanceled", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Password reset is not enabled..
+        /// </summary>
+        internal static string ErrPasswordResetNotEnabled {
+            get {
+                return ResourceManager.GetString("ErrPasswordResetNotEnabled", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Password retrieval not enabled..
+        /// </summary>
+        internal static string ErrPasswordRetrievalNotEnabled {
+            get {
+                return ResourceManager.GetString("ErrPasswordRetrievalNotEnabled", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Profile for user &apos;{0}&apos; already exists..
+        /// </summary>
+        internal static string ErrProfileAlreadyExist {
+            get {
+                return ResourceManager.GetString("ErrProfileAlreadyExist", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Password format not supported..
+        /// </summary>
+        internal static string ErrPwFormatNotSupported {
+            get {
+                return ResourceManager.GetString("ErrPwFormatNotSupported", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Role &apos;{0}&apos; already exists..
+        /// </summary>
+        internal static string ErrRoleAlreadyExist {
+            get {
+                return ResourceManager.GetString("ErrRoleAlreadyExist", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Role &apos;{0}&apos; does not exist..
+        /// </summary>
+        internal static string ErrRoleNotExist {
+            get {
+                return ResourceManager.GetString("ErrRoleNotExist", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Rollback failed..
+        /// </summary>
+        internal static string ErrRollbackFailed {
+            get {
+                return ResourceManager.GetString("ErrRollbackFailed", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to User &apos;{0}&apos; is already in role &apos;{1}&apos;..
+        /// </summary>
+        internal static string ErrUserAlreadyInRole {
+            get {
+                return ResourceManager.GetString("ErrUserAlreadyInRole", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The supplied user is locked out..
+        /// </summary>
+        internal static string ErrUserIsLoggedOut {
+            get {
+                return ResourceManager.GetString("ErrUserIsLoggedOut", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to User &apos;{0}&apos; is not in role &apos;{1}&apos;..
+        /// </summary>
+        internal static string ErrUserIsNotInRole {
+            get {
+                return ResourceManager.GetString("ErrUserIsNotInRole", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The supplied user name is not found..
+        /// </summary>
+        internal static string ErrUserNotFound {
+            get {
+                return ResourceManager.GetString("ErrUserNotFound", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Attempt to roll back the transaction..
+        /// </summary>
+        internal static string LogRollbackAttempt {
+            get {
+                return ResourceManager.GetString("LogRollbackAttempt", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to A PostgreSQL Membership Provider..
+        /// </summary>
+        internal static string MembershipProviderDefaultDescription {
+            get {
+                return ResourceManager.GetString("MembershipProviderDefaultDescription", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to PostgreSQLMembershipProvider.
+        /// </summary>
+        internal static string MembershipProviderDefaultName {
+            get {
+                return ResourceManager.GetString("MembershipProviderDefaultName", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to A PostgreSQL Profile Provider..
+        /// </summary>
+        internal static string ProfileProviderDefaultDescription {
+            get {
+                return ResourceManager.GetString("ProfileProviderDefaultDescription", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to PostgreSQLProfileProvider.
+        /// </summary>
+        internal static string ProfileProviderDefaultName {
+            get {
+                return ResourceManager.GetString("ProfileProviderDefaultName", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to A PostgreSQL Role Provider..
+        /// </summary>
+        internal static string RoleProviderDefaultDescription {
+            get {
+                return ResourceManager.GetString("RoleProviderDefaultDescription", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to PostgreSQLRoleProvider.
+        /// </summary>
+        internal static string RoleProviderDefaultName {
+            get {
+                return ResourceManager.GetString("RoleProviderDefaultName", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to A PostgreSQL Session-State Store Provider.
+        /// </summary>
+        internal static string SessionStoreProviderDefaultDescription {
+            get {
+                return ResourceManager.GetString("SessionStoreProviderDefaultDescription", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to PostgreSQLSessionStateStoreProvider.
+        /// </summary>
+        internal static string SessionStoreProviderDefaultName {
+            get {
+                return ResourceManager.GetString("SessionStoreProviderDefaultName", resourceCulture);
+            }
+        }
+    }
+}
+#endif

+ 10 - 0
mcs/class/System.Web/System.Web.Security/ChangeLog

@@ -1,3 +1,13 @@
+2007-12-08  Marek Habersack  <[email protected]>
+
+	* SqliteRoleProvider.cs: added - a Role Provider for
+	Sqlite, based on PostgreSQL Role Provider code from Daniel
+	Nauck <[email protected]>
+
+	* SqliteMembershipProvider.cs: added - a Membership Provider for
+	Sqlite, based on PostgreSQL Membership Provider code from Daniel
+	Nauck <[email protected]>
+
 2007-11-28  Marek Habersack  <[email protected]>
 
 	* SqlMembershipProvider.cs: handle situation when there is no

+ 1651 - 0
mcs/class/System.Web/System.Web.Security/SqliteMembershipProvider.cs

@@ -0,0 +1,1651 @@
+//
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Copyright © 2006, 2007 Nauck IT KG		http://www.nauck-it.de
+//
+// Author:
+//	Daniel Nauck		<d.nauck(at)nauck-it.de>
+//
+// Adapted to Sqlite by Marek Habersack <[email protected]>
+//
+
+#if NET_2_0
+using System;
+using System.Data;
+using System.Data.Common;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Text;
+using System.Security.Cryptography;
+using System.Web.Hosting;
+using System.Web.Configuration;
+using System.Web.Security;
+using System.Configuration;
+using System.Configuration.Provider;
+using System.Diagnostics;
+
+using Mono.Data.Sqlite;
+
+namespace System.Web.Security
+{
+	internal class SqliteMembershipProvider : MembershipProvider
+	{
+		private const string m_TableName = "Users";
+		private string m_ConnectionString = string.Empty;
+		private const int m_NewPasswordLength = 8;
+		private bool machineKeyIsAutoGenerated;
+		
+		// Used when determining encryption key values.
+		private MachineKeySection m_MachineKey = null;
+
+		DbParameter AddParameter (DbCommand command, string parameterName, object parameterValue)
+                {
+                        return AddParameter (command, parameterName, ParameterDirection.Input, parameterValue);
+                }
+
+                DbParameter AddParameter (DbCommand command, string parameterName, ParameterDirection direction, object parameterValue)
+                {
+                        DbParameter dbp = command.CreateParameter ();
+                        dbp.ParameterName = parameterName;
+                        dbp.Value = parameterValue;
+                        dbp.Direction = direction;
+                        command.Parameters.Add (dbp);
+                        return dbp;
+                }
+
+                DbParameter AddParameter (DbCommand command, string parameterName, ParameterDirection direction, DbType type, object parameterValue)
+                {
+                        DbParameter dbp = command.CreateParameter ();
+                        dbp.ParameterName = parameterName;
+                        dbp.Value = parameterValue;
+                        dbp.Direction = direction;
+                        dbp.DbType = type;
+                        command.Parameters.Add (dbp);
+                        return dbp;
+                }
+		
+		/// <summary>
+		/// System.Configuration.Provider.ProviderBase.Initialize Method.
+		/// </summary>
+		public override void Initialize(string name, NameValueCollection config)
+		{
+			// Initialize values from web.config.
+			if (config == null)
+				throw new ArgumentNullException("Config", Properties.Resources.ErrArgumentNull);
+
+			if (string.IsNullOrEmpty(name))
+				name = Properties.Resources.MembershipProviderDefaultName;
+
+			if (string.IsNullOrEmpty(config["description"]))
+			{
+				config.Remove("description");
+				config.Add("description", Properties.Resources.MembershipProviderDefaultDescription);
+			}
+
+			// Initialize the abstract base class.
+			base.Initialize(name, config);
+
+			m_ApplicationName = GetConfigValue(config["applicationName"], HostingEnvironment.ApplicationVirtualPath);
+			m_MaxInvalidPasswordAttempts = Convert.ToInt32(GetConfigValue(config["maxInvalidPasswordAttempts"], "5"));
+			m_PasswordAttemptWindow = Convert.ToInt32(GetConfigValue(config["passwordAttemptWindow"], "10"));
+			m_MinRequiredNonAlphanumericCharacters = Convert.ToInt32(GetConfigValue(config["minRequiredNonAlphanumericCharacters"], "1"));
+			m_MinRequiredPasswordLength = Convert.ToInt32(GetConfigValue(config["minRequiredPasswordLength"], "7"));
+			m_PasswordStrengthRegularExpression = Convert.ToString(GetConfigValue(config["passwordStrengthRegularExpression"], ""));
+			m_EnablePasswordReset = Convert.ToBoolean(GetConfigValue(config["enablePasswordReset"], "true"));
+			m_EnablePasswordRetrieval = Convert.ToBoolean(GetConfigValue(config["enablePasswordRetrieval"], "true"));
+			m_RequiresQuestionAndAnswer = Convert.ToBoolean(GetConfigValue(config["requiresQuestionAndAnswer"], "false"));
+			m_RequiresUniqueEmail = Convert.ToBoolean(GetConfigValue(config["requiresUniqueEmail"], "true"));
+
+			// Get password encryption type.
+			string pwFormat = GetConfigValue(config["passwordFormat"], "Hashed");
+			switch (pwFormat)
+			{
+				case "Hashed":
+					m_PasswordFormat = MembershipPasswordFormat.Hashed;
+					break;
+				case "Encrypted":
+					m_PasswordFormat = MembershipPasswordFormat.Encrypted;
+					break;
+				case "Clear":
+					m_PasswordFormat = MembershipPasswordFormat.Clear;
+					break;
+				default:
+					throw new ProviderException(Properties.Resources.ErrPwFormatNotSupported);
+			}
+
+			// Get connection string.
+			string connStrName = config["connectionStringName"];
+			
+			if (string.IsNullOrEmpty(connStrName))
+			{
+				throw new ArgumentOutOfRangeException("ConnectionStringName", Properties.Resources.ErrArgumentNullOrEmpty);
+			}
+			else
+			{
+				ConnectionStringSettings ConnectionStringSettings = ConfigurationManager.ConnectionStrings[connStrName];
+
+				if (ConnectionStringSettings == null || string.IsNullOrEmpty(ConnectionStringSettings.ConnectionString.Trim()))
+				{
+					throw new ProviderException(Properties.Resources.ErrConnectionStringNullOrEmpty);
+				}
+
+				m_ConnectionString = ConnectionStringSettings.ConnectionString;
+			}
+
+			// Get encryption and decryption key information from the configuration.
+			System.Configuration.Configuration cfg = WebConfigurationManager.OpenWebConfiguration(HostingEnvironment.ApplicationVirtualPath);
+			m_MachineKey = (MachineKeySection)cfg.GetSection("system.web/machineKey");
+
+			if (!m_PasswordFormat.Equals(MembershipPasswordFormat.Clear))
+			{
+				if (m_MachineKey == null)
+					throw new ArgumentNullException("system.web/machineKey", Properties.Resources.ErrArgumentNull);
+
+				if (m_MachineKey.ValidationKey.Contains("AutoGenerate")) {
+					machineKeyIsAutoGenerated = true;
+					if (m_PasswordFormat.Equals (MembershipPasswordFormat.Encrypted))
+						throw new ProviderException(Properties.Resources.ErrAutoGeneratedKeyNotSupported);
+				}
+			}
+		}
+
+		/// <summary>
+		/// System.Web.Security.MembershipProvider properties.
+		/// </summary>
+		#region System.Web.Security.MembershipProvider properties
+		private string m_ApplicationName = string.Empty;
+		private bool m_EnablePasswordReset = false;
+		private bool m_EnablePasswordRetrieval = false;
+		private bool m_RequiresQuestionAndAnswer = false;
+		private bool m_RequiresUniqueEmail = false;
+		private int m_MaxInvalidPasswordAttempts = 0;
+		private int m_PasswordAttemptWindow = 0;
+		private MembershipPasswordFormat m_PasswordFormat = MembershipPasswordFormat.Clear;
+		private int m_MinRequiredNonAlphanumericCharacters = 0;
+		private int m_MinRequiredPasswordLength = 0;
+		private string m_PasswordStrengthRegularExpression = string.Empty;
+
+		public override string ApplicationName
+		{
+			get { return m_ApplicationName; }
+			set { m_ApplicationName = value; }
+		}
+
+		public override bool EnablePasswordReset
+		{
+			get { return m_EnablePasswordReset; }
+		}
+
+		public override bool EnablePasswordRetrieval
+		{
+			get { return m_EnablePasswordRetrieval; }
+		}
+
+		public override bool RequiresQuestionAndAnswer
+		{
+			get { return m_RequiresQuestionAndAnswer; }
+		}
+
+		public override bool RequiresUniqueEmail
+		{
+			get { return m_RequiresUniqueEmail; }
+		}
+
+		public override int MaxInvalidPasswordAttempts
+		{
+			get { return m_MaxInvalidPasswordAttempts; }
+		}
+
+		public override int PasswordAttemptWindow
+		{
+			get { return m_PasswordAttemptWindow; }
+		}
+
+		public override MembershipPasswordFormat PasswordFormat
+		{
+			get { return m_PasswordFormat; }
+		}
+
+		public override int MinRequiredNonAlphanumericCharacters
+		{
+			get { return m_MinRequiredNonAlphanumericCharacters; }
+		}
+
+		public override int MinRequiredPasswordLength
+		{
+			get { return m_MinRequiredPasswordLength; }
+		}
+
+		public override string PasswordStrengthRegularExpression
+		{
+			get { return m_PasswordStrengthRegularExpression; }
+		}
+		#endregion
+
+		
+		/// <summary>
+		/// System.Web.Security.MembershipProvider methods.
+		/// </summary>
+		#region System.Web.Security.MembershipProvider methods
+
+		/// <summary>
+		/// MembershipProvider.ChangePassword
+		/// </summary>
+		public override bool ChangePassword(string username, string oldPassword, string newPassword)
+		{
+			if (!ValidateUser(username, oldPassword))
+				return false;
+
+			ValidatePasswordEventArgs args = new ValidatePasswordEventArgs(username, newPassword, true);
+
+			OnValidatingPassword(args);
+
+			if (args.Cancel)
+			{
+				if (args.FailureInformation != null)
+					throw args.FailureInformation;
+				else
+					throw new MembershipPasswordException(Properties.Resources.ErrPasswordChangeCanceled);
+			}
+
+			int rowsAffected = 0;
+
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("UPDATE \"{0}\" SET \"Password\" = @Password, \"LastPasswordChangedDate\" = @LastPasswordChangedDate WHERE \"Username\" = @Username AND  \"ApplicationName\" = @ApplicationName", m_TableName);
+
+					AddParameter (dbCommand,"@Password", EncodePassword(newPassword));
+					AddParameter (dbCommand,"@LastPasswordChangedDate", DateTime.Now);
+					AddParameter (dbCommand,"@Username", username);
+					AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						rowsAffected = dbCommand.ExecuteNonQuery();
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+
+			if (rowsAffected > 0)
+				return true;
+			else
+				return false;
+		}
+
+		/// <summary>
+		/// MembershipProvider.ChangePasswordQuestionAndAnswer
+		/// </summary>
+		public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
+		{
+			if (!ValidateUser(username, password))
+				return false;
+
+			int rowsAffected = 0;
+
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("UPDATE \"{0}\" SET \"PasswordQuestion\" = @PasswordQuestion, \"PasswordAnswer\" = @PasswordAnswer WHERE \"Username\" = @Username AND  \"ApplicationName\" = @ApplicationName", m_TableName);
+
+					AddParameter (dbCommand,"@PasswordQuestion", newPasswordQuestion);
+					AddParameter (dbCommand,"@PasswordAnswer", EncodePassword(newPasswordAnswer));
+					AddParameter (dbCommand,"@Username", username);
+					AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						rowsAffected = dbCommand.ExecuteNonQuery();
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+
+			if (rowsAffected > 0)
+				return true;
+			else
+				return false;
+		}
+
+		/// <summary>
+		/// MembershipProvider.CreateUser
+		/// </summary>
+		public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved,
+							  object providerUserKey, out MembershipCreateStatus status)
+		{
+			ValidatePasswordEventArgs args = new ValidatePasswordEventArgs(username, password, true);
+
+			OnValidatingPassword(args);
+
+			if (args.Cancel)
+			{
+				status = MembershipCreateStatus.InvalidPassword;
+				return null;
+			}
+
+			if (RequiresUniqueEmail && string.IsNullOrEmpty(email))
+			{
+				status = MembershipCreateStatus.InvalidEmail;
+				return null;
+			}
+
+			if (RequiresUniqueEmail && !string.IsNullOrEmpty(GetUserNameByEmail(email)))
+			{
+				status = MembershipCreateStatus.DuplicateEmail;
+				return null;
+			}
+
+			if (GetUser(username, false) == null)
+			{
+				DateTime createDate = DateTime.Now;
+
+				if (providerUserKey == null)
+				{
+					providerUserKey = Guid.NewGuid();
+				}
+				else
+				{
+					if (!(providerUserKey is Guid))
+					{
+						status = MembershipCreateStatus.InvalidProviderUserKey;
+						return null;
+					}
+				}
+				
+				// Create user in database
+				using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+				{
+					using (SqliteCommand dbCommand = dbConn.CreateCommand())
+					{
+						dbCommand.CommandText = string.Format("INSERT INTO \"{0}\" (\"pId\", \"Username\", \"Password\", \"Email\", \"PasswordQuestion\", \"PasswordAnswer\", \"IsApproved\", \"CreationDate\", \"LastPasswordChangedDate\", \"LastActivityDate\", \"ApplicationName\", \"IsLockedOut\", \"LastLockedOutDate\", \"FailedPasswordAttemptCount\", \"FailedPasswordAttemptWindowStart\", \"FailedPasswordAnswerAttemptCount\", \"FailedPasswordAnswerAttemptWindowStart\") Values (@pId, @Username, @Password, @Email, @PasswordQuestion, @PasswordAnswer, @IsApproved, @CreationDate, @LastPasswordChangedDate, @LastActivityDate, @ApplicationName, @IsLockedOut, @LastLockedOutDate, @FailedPasswordAttemptCount, @FailedPasswordAttemptWindowStart, @FailedPasswordAnswerAttemptCount, @FailedPasswordAnswerAttemptWindowStart)", m_TableName);
+
+						AddParameter (dbCommand,"@pId", providerUserKey);
+						AddParameter (dbCommand,"@Username", username);
+						AddParameter (dbCommand,"@Password", EncodePassword(password));
+						AddParameter (dbCommand,"@Email", email);
+						AddParameter (dbCommand,"@PasswordQuestion", passwordQuestion);
+						AddParameter (dbCommand,"@PasswordAnswer", EncodePassword(passwordAnswer));
+						AddParameter (dbCommand,"@IsApproved", isApproved);
+						AddParameter (dbCommand,"@CreationDate", createDate);
+						AddParameter (dbCommand,"@LastPasswordChangedDate", createDate);
+						AddParameter (dbCommand,"@LastActivityDate", createDate);
+						AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
+						AddParameter (dbCommand,"@IsLockedOut", false);
+						AddParameter (dbCommand,"@LastLockedOutDate", createDate);
+						AddParameter (dbCommand,"@FailedPasswordAttemptCount", 0);
+						AddParameter (dbCommand,"@FailedPasswordAttemptWindowStart", createDate);
+						AddParameter (dbCommand,"@FailedPasswordAnswerAttemptCount", 0);
+						AddParameter (dbCommand,"@FailedPasswordAnswerAttemptWindowStart", createDate);
+
+						try
+						{
+							dbConn.Open();
+							dbCommand.Prepare();
+
+							if (dbCommand.ExecuteNonQuery() > 0)
+							{
+								status = MembershipCreateStatus.Success;
+							}
+							else
+							{
+								status = MembershipCreateStatus.UserRejected;
+							}
+						}
+						catch (SqliteException e)
+						{
+							status = MembershipCreateStatus.ProviderError;
+							Trace.WriteLine(e.ToString());
+							throw new ProviderException(Properties.Resources.ErrOperationAborted);
+						}
+						finally
+						{
+							if (dbConn != null)
+								dbConn.Close();
+						}
+
+						return GetUser(username, false);
+					}
+				}
+			}
+			else
+			{
+				status = MembershipCreateStatus.DuplicateUserName;
+			}
+			return null;
+		}
+
+		/// <summary>
+		/// MembershipProvider.DeleteUser
+		/// </summary>
+		public override bool DeleteUser(string username, bool deleteAllRelatedData)
+		{
+			int rowsAffected = 0;
+
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("DELETE FROM \"{0}\" WHERE \"Username\" = @Username AND  \"ApplicationName\" = @ApplicationName", m_TableName);
+
+					AddParameter (dbCommand,"@Username", username);
+					AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						rowsAffected = dbCommand.ExecuteNonQuery();
+
+						if (deleteAllRelatedData)
+						{
+							// Process commands to delete all data for the user in the database.
+						}
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+
+			if (rowsAffected > 0)
+				return true;
+			else
+				return false;
+		}
+
+		/// <summary>
+		/// MembershipProvider.FindUsersByEmail
+		/// </summary>
+		public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
+		{
+			totalRecords = 0;
+			MembershipUserCollection users = new MembershipUserCollection();
+
+			// replace permitted wildcard characters 
+			emailToMatch = emailToMatch.Replace('*','%');
+			emailToMatch = emailToMatch.Replace('?', '_');
+
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				// Get user count
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("SELECT Count(*) FROM \"{0}\" WHERE \"Email\" LIKE @Email AND  \"ApplicationName\" = @ApplicationName", m_TableName);
+
+					AddParameter (dbCommand,"@Email", emailToMatch);
+					AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						Int32.TryParse(dbCommand.ExecuteScalar().ToString(), out totalRecords);
+
+						if (totalRecords <= 0) { return users; }
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+
+				// Fetch user from database
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("SELECT \"pId\", \"Username\", \"Email\", \"PasswordQuestion\", \"Comment\", \"IsApproved\", \"IsLockedOut\", \"CreationDate\", \"LastLoginDate\", \"LastActivityDate\", \"LastPasswordChangedDate\", \"LastLockedOutDate\" FROM \"{0}\" WHERE \"Email\" LIKE @Email AND \"ApplicationName\" = @ApplicationName ORDER BY \"Username\" ASC LIMIT @MaxCount OFFSET @StartIndex", m_TableName);
+
+					AddParameter (dbCommand,"@Email", emailToMatch);
+					AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
+					AddParameter (dbCommand,"@MaxCount", pageSize);
+					AddParameter (dbCommand,"@StartIndex", pageSize * pageIndex);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						using (SqliteDataReader reader = dbCommand.ExecuteReader())
+						{
+							while (reader.Read())
+							{
+								MembershipUser u = GetUserFromReader(reader);
+								users.Add(u);
+							}
+						}
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+
+			return users;
+		}
+
+		/// <summary>
+		/// MembershipProvider.FindUsersByName
+		/// </summary>
+		public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
+		{
+			totalRecords = 0;
+			MembershipUserCollection users = new MembershipUserCollection();
+
+			// replace permitted wildcard characters 
+			usernameToMatch = usernameToMatch.Replace('*', '%');
+			usernameToMatch = usernameToMatch.Replace('?', '_');
+
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				// Get user count
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("SELECT Count(*) FROM \"{0}\" WHERE \"Username\" LIKE @Username AND  \"ApplicationName\" = @ApplicationName", m_TableName);
+
+					AddParameter (dbCommand,"@Username", usernameToMatch);
+					AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						Int32.TryParse(dbCommand.ExecuteScalar().ToString(), out totalRecords);
+
+						if (totalRecords <= 0) { return users; }
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+
+				// Fetch user from database
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("SELECT \"pId\", \"Username\", \"Email\", \"PasswordQuestion\", \"Comment\", \"IsApproved\", \"IsLockedOut\", \"CreationDate\", \"LastLoginDate\", \"LastActivityDate\", \"LastPasswordChangedDate\", \"LastLockedOutDate\" FROM \"{0}\" WHERE \"Username\" LIKE @Username AND \"ApplicationName\" = @ApplicationName ORDER BY \"Username\" ASC LIMIT @MaxCount OFFSET @StartIndex", m_TableName);
+
+					AddParameter (dbCommand,"@Username", usernameToMatch);
+					AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
+					AddParameter (dbCommand,"@MaxCount", pageSize);
+					AddParameter (dbCommand,"@StartIndex", pageSize * pageIndex);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						using (SqliteDataReader reader = dbCommand.ExecuteReader())
+						{
+							while (reader.Read())
+							{
+								MembershipUser u = GetUserFromReader(reader);
+								users.Add(u);
+							}
+						}
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+
+			return users;
+		}
+
+		/// <summary>
+		/// MembershipProvider.GetAllUsers
+		/// </summary>
+		public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
+		{
+			totalRecords = 0;
+			MembershipUserCollection users = new MembershipUserCollection();
+
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				// Get user count
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("SELECT Count(*) FROM \"{0}\" WHERE \"ApplicationName\" = @ApplicationName", m_TableName);
+
+					AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						Int32.TryParse(dbCommand.ExecuteScalar().ToString(), out totalRecords);
+
+						if (totalRecords <= 0) { return users; }
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw e;
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+
+				// Fetch user from database
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("SELECT \"pId\", \"Username\", \"Email\", \"PasswordQuestion\", \"Comment\", \"IsApproved\", \"IsLockedOut\", \"CreationDate\", \"LastLoginDate\", \"LastActivityDate\", \"LastPasswordChangedDate\", \"LastLockedOutDate\" FROM \"{0}\" WHERE \"ApplicationName\" = @ApplicationName ORDER BY \"Username\" ASC LIMIT @MaxCount OFFSET @StartIndex", m_TableName);
+					
+					AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
+					AddParameter (dbCommand,"@MaxCount", pageSize);
+					AddParameter (dbCommand,"@StartIndex", pageSize * pageIndex);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						using (SqliteDataReader reader = dbCommand.ExecuteReader())
+						{
+							while (reader.Read())
+							{
+								MembershipUser u = GetUserFromReader(reader);
+								users.Add(u);
+							}
+						}
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+
+			return users;
+		}
+
+		/// <summary>
+		/// MembershipProvider.GetNumberOfUsersOnline
+		/// </summary>
+		public override int GetNumberOfUsersOnline()
+		{
+			int numOnline = 0;
+
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					TimeSpan onlineSpan = new TimeSpan(0, System.Web.Security.Membership.UserIsOnlineTimeWindow, 0);
+					DateTime compareTime = DateTime.Now.Subtract(onlineSpan);
+
+					dbCommand.CommandText = string.Format("SELECT Count(*) FROM \"{0}\" WHERE \"LastActivityDate\" > @CompareTime AND  \"ApplicationName\" = @ApplicationName", m_TableName);
+
+					AddParameter (dbCommand,"@CompareTime", compareTime);
+					AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						numOnline = (int)dbCommand.ExecuteScalar();
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+
+			return numOnline;
+		}
+
+		/// <summary>
+		/// MembershipProvider.GetPassword
+		/// </summary>
+		public override string GetPassword(string username, string answer)
+		{
+			if (!EnablePasswordRetrieval)
+			{
+				throw new ProviderException(Properties.Resources.ErrPasswordRetrievalNotEnabled);
+			}
+
+			if (PasswordFormat == MembershipPasswordFormat.Hashed)
+			{
+				throw new ProviderException(Properties.Resources.ErrCantRetrieveHashedPw);
+			}
+
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("SELECT \"Password\", \"PasswordAnswer\", \"IsLockedOut\" FROM \"{0}\" WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
+
+					AddParameter (dbCommand,"@Username", username);
+					AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						using (SqliteDataReader reader = dbCommand.ExecuteReader())
+						{
+							if (reader.HasRows)
+							{
+								reader.Read();
+
+								string password = reader.GetString(0);
+								string passwordAnswer = reader.GetString(1);
+								bool isLockedOut = reader.GetBoolean(2);
+
+								reader.Close();
+
+								if (isLockedOut)
+									throw new MembershipPasswordException(Properties.Resources.ErrUserIsLoggedOut);
+
+								if (m_RequiresQuestionAndAnswer && !CheckPassword(answer, passwordAnswer))
+								{
+									UpdateFailureCount(username, FailureType.PasswordAnswer);
+
+									throw new MembershipPasswordException(Properties.Resources.ErrIncorrectPasswordAnswer);
+								}
+
+								if (m_PasswordFormat == MembershipPasswordFormat.Encrypted)
+								{
+									password = UnEncodePassword(password);
+								}
+
+								return password;
+							}
+							else
+							{
+								throw new MembershipPasswordException(Properties.Resources.ErrUserNotFound);
+							}
+						}
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+		}
+
+		/// <summary>
+		/// MembershipProvider.GetUser
+		/// </summary>
+		public override MembershipUser GetUser(string username, bool userIsOnline)
+		{
+			MembershipUser u = null;
+
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("SELECT \"pId\", \"Username\", \"Email\", \"PasswordQuestion\", \"Comment\", \"IsApproved\", \"IsLockedOut\", \"CreationDate\", \"LastLoginDate\", \"LastActivityDate\", \"LastPasswordChangedDate\", \"LastLockedOutDate\" FROM \"{0}\" WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
+
+					AddParameter (dbCommand,"@Username", username);
+					AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						using (SqliteDataReader reader = dbCommand.ExecuteReader())
+						{
+							if (reader.HasRows)
+							{
+								reader.Read();
+								u = GetUserFromReader(reader);
+
+								if (userIsOnline)
+								{
+									// Update user online status
+									using (SqliteCommand dbUpdateCommand = dbConn.CreateCommand())
+									{
+										dbUpdateCommand.CommandText = string.Format("UPDATE \"{0}\" SET \"LastActivityDate\" = @LastActivityDate WHERE \"pId\" = @pId", m_TableName);
+
+										AddParameter (dbUpdateCommand, "@LastActivityDate", DateTime.Now);
+										AddParameter (dbUpdateCommand, "@pId", u.ProviderUserKey);
+
+										dbUpdateCommand.Prepare();
+
+										dbUpdateCommand.ExecuteNonQuery();
+									}
+								}
+							}
+						}
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+
+			return u;
+		}
+
+		/// <summary>
+		/// MembershipProvider.GetUser
+		/// </summary>
+		public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
+		{
+			MembershipUser u = null;
+
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("SELECT \"pId\", \"Username\", \"Email\", \"PasswordQuestion\", \"Comment\", \"IsApproved\", \"IsLockedOut\", \"CreationDate\", \"LastLoginDate\", \"LastActivityDate\", \"LastPasswordChangedDate\", \"LastLockedOutDate\" FROM \"{0}\" WHERE \"pId\" = @pId", m_TableName);
+
+					AddParameter (dbCommand,"@pId", providerUserKey);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						using (SqliteDataReader reader = dbCommand.ExecuteReader())
+						{
+							if (reader.HasRows)
+							{
+								reader.Read();
+								u = GetUserFromReader(reader);
+
+								if (userIsOnline)
+								{
+									// Update user online status
+									using (SqliteCommand dbUpdateCommand = dbConn.CreateCommand())
+									{
+										dbUpdateCommand.CommandText = string.Format("UPDATE \"{0}\" SET \"LastActivityDate\" = @LastActivityDate WHERE \"pId\" = @pId", m_TableName);
+
+										AddParameter (dbUpdateCommand, "@LastActivityDate", DateTime.Now);
+										AddParameter (dbUpdateCommand, "@pId", u.ProviderUserKey);
+
+										dbUpdateCommand.Prepare();
+
+										dbUpdateCommand.ExecuteNonQuery();
+									}
+								}
+							}
+						}
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+
+			return u;
+		}
+
+		/// <summary>
+		/// MembershipProvider.GetUserNameByEmail
+		/// </summary>
+		public override string GetUserNameByEmail(string email)
+		{
+			string username = string.Empty;
+
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("SELECT \"Username\" FROM \"{0}\" WHERE \"Email\" = @Email AND \"ApplicationName\" = @ApplicationName", m_TableName);
+
+					AddParameter (dbCommand,"@Email", email);
+					AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						username = (dbCommand.ExecuteScalar() as string) ?? string.Empty;
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+
+			return username;
+		}
+
+		/// <summary>
+		/// MembershipProvider.ResetPassword
+		/// </summary>
+		public override string ResetPassword(string username, string answer)
+		{
+			if (!m_EnablePasswordReset)
+			{
+				throw new NotSupportedException(Properties.Resources.ErrPasswordResetNotEnabled);
+			}
+
+			if (string.IsNullOrEmpty(answer) && m_RequiresQuestionAndAnswer)
+			{
+				UpdateFailureCount(username, FailureType.PasswordAnswer);
+
+				throw new ProviderException(Properties.Resources.ErrPasswordAnswerRequired);
+			}
+
+			string newPassword = Membership.GeneratePassword(m_NewPasswordLength, m_MinRequiredNonAlphanumericCharacters);
+
+
+			ValidatePasswordEventArgs args = new ValidatePasswordEventArgs(username, newPassword, true);
+
+			OnValidatingPassword(args);
+
+			if (args.Cancel)
+			{
+				if (args.FailureInformation != null)
+					throw args.FailureInformation;
+				else
+					throw new MembershipPasswordException(Properties.Resources.ErrPasswordResetCanceled);
+			}
+
+			int rowsAffected = 0;
+
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("SELECT \"PasswordAnswer\", \"IsLockedOut\" FROM \"{0}\" WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
+
+					AddParameter (dbCommand,"@Username", username);
+					AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
+
+					try
+					{
+						string passwordAnswer = string.Empty;
+
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						using (SqliteDataReader reader = dbCommand.ExecuteReader())
+						{
+							if (reader.HasRows)
+							{
+								reader.Read();
+
+								passwordAnswer = reader.GetString(0);
+								bool isLockedOut = reader.GetBoolean(1);
+
+								reader.Close();
+
+								if (isLockedOut)
+									throw new MembershipPasswordException(Properties.Resources.ErrUserIsLoggedOut);
+
+								if (m_RequiresQuestionAndAnswer && !CheckPassword(answer, passwordAnswer))
+								{
+									UpdateFailureCount(username, FailureType.PasswordAnswer);
+
+									throw new MembershipPasswordException(Properties.Resources.ErrIncorrectPasswordAnswer);
+								}
+							}
+							else
+							{
+								throw new MembershipPasswordException(Properties.Resources.ErrUserNotFound);
+							}
+						}
+
+						// Reset Password
+						using (SqliteCommand dbUpdateCommand = dbConn.CreateCommand())
+						{
+							dbUpdateCommand.CommandText = string.Format("UPDATE \"{0}\" SET \"Password\" = @Password, \"LastPasswordChangedDate\" = @LastPasswordChangedDate WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName AND \"IsLockedOut\" = @IsLockedOut", m_TableName);
+
+							AddParameter (dbUpdateCommand, "@Password", EncodePassword(newPassword));
+							AddParameter (dbUpdateCommand, "@LastPasswordChangedDate", DateTime.Now);
+							AddParameter (dbUpdateCommand, "@Username", username);
+							AddParameter (dbUpdateCommand, "@ApplicationName", m_ApplicationName);
+							AddParameter (dbUpdateCommand, "@IsLockedOut", false);
+
+							dbUpdateCommand.Prepare();
+
+							rowsAffected = dbUpdateCommand.ExecuteNonQuery();
+						}
+
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+
+			if (rowsAffected > 0)
+				return newPassword;
+			
+			else
+				throw new MembershipPasswordException(Properties.Resources.ErrPasswordResetAborted);
+		}
+
+		/// <summary>
+		/// MembershipProvider.UnlockUser
+		/// </summary>
+		public override bool UnlockUser(string userName)
+		{
+			int rowsAffected = 0;
+
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("UPDATE  \"{0}\" SET \"IsLockedOut\" = @IsLockedOut, \"LastLockedOutDate\" = @LastLockedOutDate WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
+
+					AddParameter (dbCommand,"@IsLockedOut", false);
+					AddParameter (dbCommand,"@LastLockedOutDate", DateTime.Now);
+					AddParameter (dbCommand,"@Username", userName);
+					AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						rowsAffected = dbCommand.ExecuteNonQuery();
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+
+			if (rowsAffected > 0)
+				return true;
+
+			else
+				return false;
+		}
+
+		/// <summary>
+		/// MembershipProvider.UpdateUser
+		/// </summary>
+		public override void UpdateUser(MembershipUser user)
+		{
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("UPDATE  \"{0}\" SET \"Email\" = @Email, \"Comment\" = @Comment, \"IsApproved\" = @IsApproved WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
+
+					AddParameter (dbCommand,"@Email", user.Email);
+					AddParameter (dbCommand,"@Comment", user.Comment);
+					AddParameter (dbCommand,"@IsApproved", user.IsApproved);
+					AddParameter (dbCommand,"@Username", user.UserName);
+					AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						dbCommand.ExecuteNonQuery();
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+		}
+
+		/// <summary>
+		/// MembershipProvider.ValidateUser
+		/// </summary>
+		public override bool ValidateUser(string username, string password)
+		{
+			string dbPassword = string.Empty;
+			bool dbIsApproved = false;
+
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				// Fetch user data from database
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("SELECT \"Password\", \"IsApproved\" FROM \"{0}\" WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName AND \"IsLockedOut\" = @IsLockedOut", m_TableName);
+
+					AddParameter (dbCommand,"@Username", username);
+					AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
+					AddParameter (dbCommand,"@IsLockedOut", false);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						using (SqliteDataReader reader = dbCommand.ExecuteReader())
+						{
+							if (reader.HasRows)
+							{
+								reader.Read();
+								dbPassword = reader.GetString(0);
+								dbIsApproved = reader.GetBoolean(1);
+							}
+							else
+							{
+								return false;
+							}
+						}
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+
+				if (CheckPassword(password, dbPassword))
+				{
+					if (dbIsApproved)
+					{
+						// Update last login date
+						using (SqliteCommand dbCommand = dbConn.CreateCommand())
+						{
+							dbCommand.CommandText = string.Format("UPDATE \"{0}\" SET \"LastLoginDate\" = @LastLoginDate WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
+
+							AddParameter (dbCommand,"@LastLoginDate", DateTime.Now);
+							AddParameter (dbCommand,"@Username", username);
+							AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
+
+							try
+							{
+								dbConn.Open();
+								dbCommand.Prepare();
+
+								dbCommand.ExecuteNonQuery();
+
+								return true;
+							}
+							catch (SqliteException e)
+							{
+								Trace.WriteLine(e.ToString());
+								throw new ProviderException(Properties.Resources.ErrOperationAborted);
+							}
+							finally
+							{
+								if (dbConn != null)
+									dbConn.Close();
+							}
+						}
+					}
+				}
+
+				return false;
+			}
+		}
+		#endregion
+
+		#region private methods
+		/// <summary>
+		/// A helper function to retrieve config values from the configuration file.
+		/// </summary>
+		/// <param name="configValue"></param>
+		/// <param name="defaultValue"></param>
+		/// <returns></returns>
+		private string GetConfigValue(string configValue, string defaultValue)
+		{
+			if (string.IsNullOrEmpty(configValue))
+				return defaultValue;
+
+			return configValue;
+		}
+
+		/// <summary>
+		/// A helper function that takes the current row from the SqliteDataReader
+		/// and hydrates a MembershipUser from the values. Called by the 
+		/// MembershipUser.GetUser implementation.
+		/// </summary>
+		/// <param name="reader">SqliteDataReader object</param>
+		/// <returns>MembershipUser object</returns>
+		private MembershipUser GetUserFromReader(SqliteDataReader reader)
+		{
+			object providerUserKey = reader.GetValue(0);
+			string username = reader.GetString(1);
+			string email = string.Empty;
+			if (!reader.IsDBNull(2))
+				email = reader.GetString(2);
+
+			string passwordQuestion = string.Empty;
+			if (!reader.IsDBNull(3))
+				passwordQuestion = reader.GetString(3);
+			
+			string comment = string.Empty;
+			if (!reader.IsDBNull(4))
+				comment = reader.GetString(4);
+
+			bool isApproved = reader.GetBoolean(5);
+			bool isLockedOut = reader.GetBoolean(6);
+			DateTime creationDate = reader.GetDateTime(7);
+
+			DateTime lastLoginDate = new DateTime();
+			if (!reader.IsDBNull(8))
+				lastLoginDate = reader.GetDateTime(8);
+
+			DateTime lastActivityDate = reader.GetDateTime(9);
+			DateTime lastPasswordChangedDate = reader.GetDateTime(10);
+
+			DateTime lastLockedOutDate = new DateTime();
+			if (!reader.IsDBNull(11))
+				lastLockedOutDate = reader.GetDateTime(11);
+
+			MembershipUser u = new MembershipUser(this.Name,
+												  username,
+												  providerUserKey,
+												  email,
+												  passwordQuestion,
+												  comment,
+												  isApproved,
+												  isLockedOut,
+												  creationDate,
+												  lastLoginDate,
+												  lastActivityDate,
+												  lastPasswordChangedDate,
+												  lastLockedOutDate);
+			
+			return u;
+		}
+
+		/// <summary>
+		/// Compares password values based on the MembershipPasswordFormat.
+		/// </summary>
+		/// <param name="password"></param>
+		/// <param name="dbpassword"></param>
+		/// <returns></returns>
+		private bool CheckPassword(string password, string dbpassword)
+		{
+			string pass1 = password;
+			string pass2 = dbpassword;
+
+			switch (PasswordFormat)
+			{
+				case MembershipPasswordFormat.Encrypted:
+					pass2 = UnEncodePassword(dbpassword);
+					break;
+
+				case MembershipPasswordFormat.Hashed:
+					pass1 = EncodePassword(password);
+					break;
+
+				default:
+					break;
+			}
+
+			if (pass1.Equals(pass2))
+				return true;
+			else
+				return false;
+		}
+
+		/// <summary>
+		/// Encrypts, Hashes, or leaves the password clear based on the PasswordFormat.
+		/// </summary>
+		/// <param name="password"></param>
+		/// <returns></returns>
+		private string EncodePassword(string password)
+		{
+			if (string.IsNullOrEmpty(password))
+				return password;
+
+			string encodedPassword = password;
+
+			switch (PasswordFormat)
+			{
+				case MembershipPasswordFormat.Clear:
+					break;
+
+				case MembershipPasswordFormat.Encrypted:
+					encodedPassword = Convert.ToBase64String(EncryptPassword(Encoding.Unicode.GetBytes(password)));
+					break;
+
+				case MembershipPasswordFormat.Hashed:
+					HMACSHA1 hash = new HMACSHA1();
+					if (machineKeyIsAutoGenerated)
+						hash.Key = MachineKeySectionUtils.ValidationKeyBytes ();
+					else
+						hash.Key = HexToByte(m_MachineKey.ValidationKey);
+					encodedPassword = Convert.ToBase64String(hash.ComputeHash(Encoding.Unicode.GetBytes(password)));
+					break;
+
+				default:
+					throw new ProviderException(Properties.Resources.ErrPwFormatNotSupported);
+			}
+
+			return encodedPassword;
+		}
+
+		/// <summary>
+		/// Decrypts or leaves the password clear based on the PasswordFormat.
+		/// </summary>
+		/// <param name="encodedPassword"></param>
+		/// <returns></returns>
+		private string UnEncodePassword(string encodedPassword)
+		{
+			string password = encodedPassword;
+
+			switch (PasswordFormat)
+			{
+				case MembershipPasswordFormat.Clear:
+					break;
+
+				case MembershipPasswordFormat.Encrypted:
+					password = Encoding.Unicode.GetString(DecryptPassword(Convert.FromBase64String(password)));
+					break;
+
+				case MembershipPasswordFormat.Hashed:
+					throw new ProviderException(Properties.Resources.ErrCantDecodeHashedPw);
+
+				default:
+					throw new ProviderException(Properties.Resources.ErrPwFormatNotSupported);
+			}
+
+			return password;
+		}
+
+		/// <summary>
+		/// Converts a hexadecimal string to a byte array. Used to convert encryption
+		/// key values from the configuration.
+		/// </summary>
+		/// <param name="hexString"></param>
+		/// <returns></returns>
+		private byte[] HexToByte(string hexString)
+		{
+			byte[] returnBytes = new byte[hexString.Length / 2];
+			for (int i = 0; i < returnBytes.Length; i++)
+				returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
+
+			return returnBytes;
+		}
+
+		/// <summary>
+		/// A helper method that performs the checks and updates associated with
+		/// password failure tracking.
+		/// </summary>
+		/// <param name="username"></param>
+		/// <param name="failType"></param>
+		private void UpdateFailureCount(string username, FailureType failType)
+		{
+			DateTime windowStart = new DateTime();
+			int failureCount = 0;
+
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				// Fetch user data from database
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("SELECT \"FailedPasswordAttemptCount\", \"FailedPasswordAttemptWindowStart\", \"FailedPasswordAnswerAttemptCount\", \"FailedPasswordAnswerAttemptWindowStart\" FROM \"{0}\" WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
+
+					AddParameter (dbCommand,"@Username", username);
+					AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						using (SqliteDataReader reader = dbCommand.ExecuteReader())
+						{
+							if (reader.HasRows)
+							{
+								reader.Read();
+
+								if (failType.Equals(FailureType.Password))
+								{
+									failureCount = reader.GetInt32(0);
+									windowStart = reader.GetDateTime(1);
+								}
+								else if (failType.Equals(FailureType.PasswordAnswer))
+								{
+									failureCount = reader.GetInt32(2);
+									windowStart = reader.GetDateTime(3);
+								}
+							}
+						}
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+
+				// Calculate failture count and update database
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					DateTime windowEnd = windowStart.AddMinutes(m_PasswordAttemptWindow);
+
+					try
+					{
+						if (failureCount == 0 || DateTime.Now > windowEnd)
+						{
+							// First password failure or outside of PasswordAttemptWindow. 
+							// Start a new password failure count from 1 and a new window starting now.
+
+							if (failType.Equals(FailureType.Password))
+							{
+								dbCommand.CommandText = string.Format("UPDATE \"{0}\" SET \"FailedPasswordAttemptCount\" = @Count, \"FailedPasswordAttemptWindowStart\" = @WindowStart WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
+							}
+							else if (failType.Equals(FailureType.PasswordAnswer))
+							{
+								dbCommand.CommandText = string.Format("UPDATE \"{0}\" SET \"FailedPasswordAnswerAttemptCount\" = @Count, \"FailedPasswordAnswerAttemptWindowStart\" = @WindowStart WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
+							}
+
+							AddParameter (dbCommand,"@Count", 1);
+							AddParameter (dbCommand,"@WindowStart", DateTime.Now);
+							AddParameter (dbCommand,"@Username", username);
+							AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
+
+							if (dbCommand.ExecuteNonQuery() < 0)
+								throw new ProviderException(Properties.Resources.ErrCantUpdateFailtureCountAndWindowStart);
+						}
+						else
+						{
+							failureCount++;
+
+							if (failureCount >= m_MaxInvalidPasswordAttempts)
+							{
+								// Password attempts have exceeded the failure threshold. Lock out
+								// the user.
+								dbCommand.CommandText = string.Format("UPDATE \"{0}\" SET \"IsLockedOut\" = @IsLockedOut, \"LastLockedOutDate\" = @LastLockedOutDate WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
+
+								AddParameter (dbCommand,"@IsLockedOut", true);
+								AddParameter (dbCommand,"@LastLockedOutDate", DateTime.Now);
+								AddParameter (dbCommand,"@Username", username);
+								AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
+
+								if (dbCommand.ExecuteNonQuery() < 0)
+									throw new ProviderException(string.Format(Properties.Resources.ErrCantLogoutUser, username));
+							}
+							else
+							{
+								// Password attempts have not exceeded the failure threshold. Update
+								// the failure counts. Leave the window the same.
+								if (failType.Equals(FailureType.Password))
+								{
+									dbCommand.CommandText = string.Format("UPDATE \"{0}\" SET \"FailedPasswordAttemptCount\" = @Count WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
+								}
+								else if (failType.Equals(FailureType.PasswordAnswer))
+								{
+									dbCommand.CommandText = string.Format("UPDATE \"{0}\" SET \"FailedPasswordAnswerAttemptCount\" = @Count WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName", m_TableName);
+								}
+
+								AddParameter (dbCommand,"@Count", failureCount);
+								AddParameter (dbCommand,"@Username", username);
+								AddParameter (dbCommand,"@ApplicationName", m_ApplicationName);
+
+								if (dbCommand.ExecuteNonQuery() < 0)
+									throw new ProviderException(Properties.Resources.ErrCantUpdateFailtureCount);
+							}
+						}
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+		}
+
+		private enum FailureType
+		{
+			Password,
+			PasswordAnswer
+		}
+		#endregion
+	}
+}
+#endif

+ 713 - 0
mcs/class/System.Web/System.Web.Security/SqliteRoleProvider.cs

@@ -0,0 +1,713 @@
+//
+// $Id: PgRoleProvider.cs 12 2007-10-17 17:22:43Z dna $
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Copyright © 2006, 2007 Nauck IT KG		http://www.nauck-it.de
+//
+// Author:
+//	Daniel Nauck		<d.nauck(at)nauck-it.de>
+//
+// Adapted to Sqlite by Marek Habersack <[email protected]>
+//
+
+#if NET_2_0
+using System;
+using System.Data;
+using System.Data.Common;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Diagnostics;
+using System.Text;
+using System.Configuration;
+using System.Configuration.Provider;
+using System.Web.Hosting;
+using System.Web.Security;
+
+using Mono.Data.Sqlite;
+
+namespace System.Web.Security
+{
+	internal class SqliteRoleProvider : RoleProvider
+	{
+		private const string m_RolesTableName = "Roles";
+		private const string m_UserInRolesTableName = "UsersInRoles";
+		private string m_ConnectionString = string.Empty;
+
+		DbParameter AddParameter (DbCommand command, string parameterName)
+		{
+			return AddParameter (command, parameterName, null);
+		}
+		
+		DbParameter AddParameter (DbCommand command, string parameterName, object parameterValue)
+		{
+			return AddParameter (command, parameterName, ParameterDirection.Input, parameterValue);
+                }
+
+                DbParameter AddParameter (DbCommand command, string parameterName, ParameterDirection direction, object parameterValue)
+                {
+                        DbParameter dbp = command.CreateParameter ();
+                        dbp.ParameterName = parameterName;
+                        dbp.Value = parameterValue;
+                        dbp.Direction = direction;
+                        command.Parameters.Add (dbp);
+                        return dbp;
+                }
+
+                DbParameter AddParameter (DbCommand command, string parameterName, ParameterDirection direction, DbType type, object parameterValue)
+                {
+                        DbParameter dbp = command.CreateParameter ();
+                        dbp.ParameterName = parameterName;
+                        dbp.Value = parameterValue;
+                        dbp.Direction = direction;
+                        dbp.DbType = type;
+                        command.Parameters.Add (dbp);
+                        return dbp;
+                }
+		
+		/// <summary>
+		/// System.Configuration.Provider.ProviderBase.Initialize Method
+		/// </summary>
+		public override void Initialize(string name, NameValueCollection config)
+		{
+			// Initialize values from web.config.
+			if (config == null)
+				throw new ArgumentNullException("Config", Properties.Resources.ErrArgumentNull);
+
+			if (string.IsNullOrEmpty(name))
+				name = Properties.Resources.RoleProviderDefaultName;
+
+			if (string.IsNullOrEmpty(config["description"]))
+			{
+				config.Remove("description");
+				config.Add("description", Properties.Resources.RoleProviderDefaultDescription);
+			}
+
+			// Initialize the abstract base class.
+			base.Initialize(name, config);
+
+			m_ApplicationName = GetConfigValue(config["applicationName"], HostingEnvironment.ApplicationVirtualPath);
+
+			// Get connection string.
+			string connStrName = config["connectionStringName"];
+
+			if (string.IsNullOrEmpty(connStrName))
+			{
+				throw new ArgumentOutOfRangeException("ConnectionStringName", Properties.Resources.ErrArgumentNullOrEmpty);
+			}
+			else
+			{
+				ConnectionStringSettings ConnectionStringSettings = ConfigurationManager.ConnectionStrings[connStrName];
+
+				if (ConnectionStringSettings == null || string.IsNullOrEmpty(ConnectionStringSettings.ConnectionString.Trim()))
+				{
+					throw new ProviderException(Properties.Resources.ErrConnectionStringNullOrEmpty);
+				}
+
+				m_ConnectionString = ConnectionStringSettings.ConnectionString;
+			}
+		}
+
+		/// <summary>
+		/// System.Web.Security.RoleProvider properties.
+		/// </summary>
+		#region System.Web.Security.RoleProvider properties
+		private string m_ApplicationName = string.Empty;
+
+		public override string ApplicationName
+		{
+			get { return m_ApplicationName; }
+			set { m_ApplicationName = value; }
+		}
+		#endregion
+
+		/// <summary>
+		/// System.Web.Security.RoleProvider methods.
+		/// </summary>
+		#region System.Web.Security.RoleProvider methods
+
+		/// <summary>
+		/// RoleProvider.AddUsersToRoles
+		/// </summary>
+		public override void AddUsersToRoles(string[] userNames, string[] roleNames)
+		{
+			foreach (string rolename in roleNames)
+			{
+				if (!RoleExists(rolename))
+				{
+					throw new ProviderException(string.Format(Properties.Resources.ErrRoleNotExist, rolename));
+				}
+			}
+
+			foreach (string username in userNames)
+			{
+				foreach (string rolename in roleNames)
+				{
+					if (IsUserInRole(username, rolename))
+					{
+						throw new ProviderException(string.Format(Properties.Resources.ErrUserAlreadyInRole, username, rolename));
+					}
+				}
+			}
+
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("INSERT INTO \"{0}\" (\"Username\", \"Rolename\", \"ApplicationName\") Values (@Username, @Rolename, @ApplicationName)", m_UserInRolesTableName);
+
+					AddParameter (dbCommand, "@Username");
+					AddParameter (dbCommand, "@Rolename");
+					AddParameter (dbCommand, "@ApplicationName", m_ApplicationName);
+
+					SqliteTransaction dbTrans = null;
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						using (dbTrans = dbConn.BeginTransaction())
+						{
+							foreach (string username in userNames)
+							{
+								foreach (string rolename in roleNames)
+								{
+									dbCommand.Parameters["@Username"].Value = username;
+									dbCommand.Parameters["@Rolename"].Value = rolename;
+									dbCommand.ExecuteNonQuery();
+								}
+							}
+							// Attempt to commit the transaction
+							dbTrans.Commit();
+						}
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+
+						try
+						{
+							// Attempt to roll back the transaction
+							Trace.WriteLine(Properties.Resources.LogRollbackAttempt);
+							dbTrans.Rollback();
+						}
+						catch (SqliteException re)
+						{
+							// Rollback failed
+							Trace.WriteLine(Properties.Resources.ErrRollbackFailed);
+							Trace.WriteLine(re.ToString());
+						}
+
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+		}
+
+		/// <summary>
+		/// RoleProvider.CreateRole
+		/// </summary>
+		public override void CreateRole(string roleName)
+		{
+			if (RoleExists(roleName))
+			{
+				throw new ProviderException(string.Format(Properties.Resources.ErrRoleAlreadyExist, roleName));
+			}
+
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("INSERT INTO \"{0}\" (\"Rolename\", \"ApplicationName\") Values (@Rolename, @ApplicationName)", m_RolesTableName);
+
+					AddParameter (dbCommand, "@Rolename", roleName);
+					AddParameter (dbCommand, "@ApplicationName", m_ApplicationName);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						dbCommand.ExecuteNonQuery();
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+		}
+
+		/// <summary>
+		/// RoleProvider.DeleteRole
+		/// </summary>
+		public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
+		{
+			if (!RoleExists(roleName))
+			{
+				throw new ProviderException(string.Format(Properties.Resources.ErrRoleNotExist, roleName));
+			}
+
+			if (throwOnPopulatedRole && GetUsersInRole(roleName).Length > 0)
+			{
+				throw new ProviderException(Properties.Resources.ErrCantDeletePopulatedRole);
+			}
+
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("DELETE FROM \"{0}\" WHERE \"Rolename\" = @Rolename AND \"ApplicationName\" = @ApplicationName", m_RolesTableName);
+
+					AddParameter (dbCommand, "@Rolename", roleName);
+					AddParameter (dbCommand, "@ApplicationName", m_ApplicationName);
+
+					SqliteTransaction dbTrans = null;
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						using (dbTrans = dbConn.BeginTransaction())
+						{
+							dbCommand.ExecuteNonQuery();
+
+							// Attempt to commit the transaction
+							dbTrans.Commit();
+						}
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+
+						try
+						{
+							// Attempt to roll back the transaction
+							Trace.WriteLine(Properties.Resources.LogRollbackAttempt);
+							dbTrans.Rollback();
+						}
+						catch (SqliteException re)
+						{
+							// Rollback failed
+							Trace.WriteLine(Properties.Resources.ErrRollbackFailed);
+							Trace.WriteLine(re.ToString());
+						}
+
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+
+			return true;
+		}
+
+		/// <summary>
+		/// RoleProvider.FindUsersInRole
+		/// </summary>
+		public override string[] FindUsersInRole(string roleName, string usernameToMatch)
+		{
+			List<string> userList = new List<string>();
+
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("SELECT \"Username\" FROM \"{0}\" WHERE \"Username\" LIKE @Username AND \"Rolename\" = @Rolename AND \"ApplicationName\" = @ApplicationName ORDER BY \"Username\" ASC", m_UserInRolesTableName);
+
+					AddParameter (dbCommand, "@Username", usernameToMatch);
+					AddParameter (dbCommand, "@Rolename", roleName);
+					AddParameter (dbCommand, "@ApplicationName", m_ApplicationName);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						using (SqliteDataReader reader = dbCommand.ExecuteReader())
+						{
+							if (reader.HasRows)
+							{
+								while (reader.Read())
+								{
+									userList.Add(reader.GetString(0));
+								}
+							}
+						}
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+
+			return userList.ToArray();
+		}
+
+		/// <summary>
+		/// RoleProvider.GetAllRoles
+		/// </summary>
+		public override string[] GetAllRoles()
+		{
+			List<string> rolesList = new List<string>();
+
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("SELECT \"Rolename\" FROM \"{0}\" WHERE \"ApplicationName\" = @ApplicationName ORDER BY \"Rolename\" ASC", m_RolesTableName);
+
+					AddParameter (dbCommand, "@ApplicationName", m_ApplicationName);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						using (SqliteDataReader reader = dbCommand.ExecuteReader())
+						{
+							while (reader.Read())
+							{
+								rolesList.Add(reader.GetString(0));
+							}
+						}						
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+
+			return rolesList.ToArray();
+		}
+
+		/// <summary>
+		/// RoleProvider.GetRolesForUser
+		/// </summary>
+		public override string[] GetRolesForUser(string username)
+		{
+			List<string> rolesList = new List<string>();
+
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("SELECT \"Rolename\" FROM \"{0}\" WHERE \"Username\" = @Username AND \"ApplicationName\" = @ApplicationName ORDER BY \"Rolename\" ASC", m_UserInRolesTableName);
+
+					AddParameter (dbCommand, "@Username", username);
+					AddParameter (dbCommand, "@ApplicationName", m_ApplicationName);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						using (SqliteDataReader reader = dbCommand.ExecuteReader())
+						{
+							if (reader.HasRows)
+							{
+								while (reader.Read())
+								{
+									rolesList.Add(reader.GetString(0));
+								}
+							}
+						}
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+
+			return rolesList.ToArray();
+		}
+
+		/// <summary>
+		/// RoleProvider.GetUsersInRole
+		/// </summary>
+		public override string[] GetUsersInRole(string roleName)
+		{
+			List<string> userList = new List<string>();
+
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("SELECT \"Username\" FROM \"{0}\" WHERE \"Rolename\" = @Rolename AND \"ApplicationName\" = @ApplicationName ORDER BY \"Username\" ASC", m_UserInRolesTableName);
+
+					AddParameter (dbCommand, "@Rolename", roleName);
+					AddParameter (dbCommand, "@ApplicationName", m_ApplicationName);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						using (SqliteDataReader reader = dbCommand.ExecuteReader())
+						{
+							if (reader.HasRows)
+							{
+								while (reader.Read())
+								{
+									userList.Add(reader.GetString(0));
+								}
+							}
+						}
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+
+			return userList.ToArray();
+		}
+
+		/// <summary>
+		/// RoleProvider.IsUserInRole
+		/// </summary>
+		public override bool IsUserInRole(string userName, string roleName)
+		{
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("SELECT COUNT(*) FROM \"{0}\" WHERE \"Username\" = @Username AND \"Rolename\" = @Rolename AND \"ApplicationName\" = @ApplicationName", m_UserInRolesTableName);
+
+					AddParameter (dbCommand, "@Username", userName);
+					AddParameter (dbCommand, "@Rolename", roleName);
+					AddParameter (dbCommand, "@ApplicationName", m_ApplicationName);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						int numRecs = 0;
+						Int32.TryParse(dbCommand.ExecuteScalar().ToString(), out numRecs);
+
+						if (numRecs > 0)
+							return true;
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+
+			return false;
+		}
+
+		/// <summary>
+		/// RoleProvider.RemoveUsersFromRoles
+		/// </summary>
+		public override void RemoveUsersFromRoles(string[] userNames, string[] roleNames)
+		{
+			foreach (string rolename in roleNames)
+			{
+				if (!RoleExists(rolename))
+				{
+					throw new ProviderException(string.Format(Properties.Resources.ErrRoleNotExist, rolename));
+				}
+			}
+
+			foreach (string username in userNames)
+			{
+				foreach (string rolename in roleNames)
+				{
+					if (!IsUserInRole(username, rolename))
+					{
+						throw new ProviderException(string.Format(Properties.Resources.ErrUserIsNotInRole, username, rolename));
+					}
+				}
+			}
+
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("DELETE FROM \"{0}\" WHERE \"Username\" = @Username AND \"Rolename\" = @Rolename AND \"ApplicationName\" = @ApplicationName", m_UserInRolesTableName);
+
+					AddParameter (dbCommand, "@Username");
+					AddParameter (dbCommand, "@Rolename");
+					AddParameter (dbCommand, "@ApplicationName", m_ApplicationName);
+
+					SqliteTransaction dbTrans = null;
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						using (dbTrans = dbConn.BeginTransaction())
+						{
+							foreach (string username in userNames)
+							{
+								foreach (string rolename in roleNames)
+								{
+									dbCommand.Parameters["@Username"].Value = username;
+									dbCommand.Parameters["@Rolename"].Value = rolename;
+									dbCommand.ExecuteNonQuery();
+								}
+							}
+							// Attempt to commit the transaction
+							dbTrans.Commit();
+						}
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+
+						try
+						{
+							// Attempt to roll back the transaction
+							Trace.WriteLine(Properties.Resources.LogRollbackAttempt);
+							dbTrans.Rollback();
+						}
+						catch (SqliteException re)
+						{
+							// Rollback failed
+							Trace.WriteLine(Properties.Resources.ErrRollbackFailed);
+							Trace.WriteLine(re.ToString());
+						}
+
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+		}
+
+		/// <summary>
+		/// RoleProvider.RoleExists
+		/// </summary>
+		public override bool RoleExists(string roleName)
+		{
+			using (SqliteConnection dbConn = new SqliteConnection(m_ConnectionString))
+			{
+				using (SqliteCommand dbCommand = dbConn.CreateCommand())
+				{
+					dbCommand.CommandText = string.Format("SELECT COUNT(*) FROM \"{0}\" WHERE \"Rolename\" = @Rolename AND \"ApplicationName\" = @ApplicationName", m_RolesTableName);
+
+					AddParameter (dbCommand, "@Rolename", roleName);
+					AddParameter (dbCommand, "@ApplicationName", m_ApplicationName);
+
+					try
+					{
+						dbConn.Open();
+						dbCommand.Prepare();
+
+						int numRecs = 0;
+						Int32.TryParse(dbCommand.ExecuteScalar().ToString(), out numRecs);
+
+						if (numRecs > 0)
+							return true;
+					}
+					catch (SqliteException e)
+					{
+						Trace.WriteLine(e.ToString());
+						throw new ProviderException(Properties.Resources.ErrOperationAborted);
+					}
+					finally
+					{
+						if (dbConn != null)
+							dbConn.Close();
+					}
+				}
+			}
+
+			return false;
+		}
+		#endregion
+
+		#region private methods
+		/// <summary>
+		/// A helper function to retrieve config values from the configuration file.
+		/// </summary>
+		/// <param name="configValue"></param>
+		/// <param name="defaultValue"></param>
+		/// <returns></returns>
+		private string GetConfigValue(string configValue, string defaultValue)
+		{
+			if (string.IsNullOrEmpty(configValue))
+				return defaultValue;
+
+			return configValue;
+		}
+		#endregion	
+	}
+}
+#endif

+ 23 - 0
mcs/class/System.Web/System.Web.Util/ChangeLog

@@ -1,3 +1,26 @@
+2007-12-08  Marek Habersack  <[email protected]>
+
+	* SerializationHelper.cs: added - serialization helper for the
+	Sqlite Profile Provider.
+
+	* RoleManagerSectionMapper.cs: added - section settings mapper for
+	the RoleManager section.
+
+	* MembershipSectionMapper.cs: added - section settings mapper for
+	the Membership section.
+
+	* ISectionSettingsMapper.cs: added - interface definition for
+	section settings mappers.
+
+	* SettingsMappingWhat.cs: added - describes a single 'what' tag
+	instance inside the mapper definition in the settings.map file.
+
+	* SettingsMapping.cs: added - represents a single mapper entry in
+	the settings.map file.
+
+	* SettingsMappingManager.cs: added - manages settings mapping as
+	defined in the settings.map file.
+
 2006-08-19  Vladimir Krasnov  <[email protected]>
 
 	* UrlUtils.cs: optimized string.Replace in RemoveDoubleSlashes

+ 41 - 0
mcs/class/System.Web/System.Web.Util/ISectionSettingsMapper.cs

@@ -0,0 +1,41 @@
+//
+// System.Web.Util.ISectionSettingsMapper
+//
+// Authors:
+//   Marek Habersack ([email protected])
+//
+// (C) 2007 Novell, Inc
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#if NET_2_0
+using System;
+using System.Collections.Generic;
+
+namespace System.Web.Util
+{
+  internal interface ISectionSettingsMapper
+  {
+    object MapSection (object section, List <SettingsMappingWhat> whats);
+  }
+}
+#endif

+ 165 - 0
mcs/class/System.Web/System.Web.Util/MembershipSectionMapper.cs

@@ -0,0 +1,165 @@
+//
+// System.Web.Util.MembershipSectionMapper
+//
+// Authors:
+//   Marek Habersack ([email protected])
+//
+// (C) 2007 Novell, Inc
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#if NET_2_0
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Web.Configuration;
+
+namespace System.Web.Util
+{
+	internal class MembershipSectionMapper : ISectionSettingsMapper
+	{
+		public object MapSection (object _section, List <SettingsMappingWhat> whats)
+		{
+			MembershipSection section = _section as MembershipSection;
+			if (section == null)
+				return _section;
+			
+			List <SettingsMappingWhatContents> contents;
+
+			foreach (SettingsMappingWhat what in whats) {
+				contents = what.Contents;
+				if (contents == null || contents.Count == 0)
+					continue;
+
+				foreach (SettingsMappingWhatContents item in contents) {
+					switch (item.Operation) {
+						case SettingsMappingWhatOperation.Add:
+							ProcessAdd (section, item);
+							break;
+
+						case SettingsMappingWhatOperation.Clear:
+							ProcessClear (section, item);
+							break;
+
+						case SettingsMappingWhatOperation.Replace:
+							ProcessReplace (section, item);
+							break;
+
+						case SettingsMappingWhatOperation.Remove:
+							ProcessRemove (section, item);
+							break;
+					}
+				}
+			}
+				
+			return section;
+		}
+
+		bool GetCommonAttributes (SettingsMappingWhatContents how, out string name, out string type)
+		{
+			name = type = null;
+			
+			Dictionary <string, string> attrs = how.Attributes;
+			
+			if (attrs == null || attrs.Count == 0)
+				return false;
+
+			if (!attrs.TryGetValue ("name", out name))
+				return false;
+
+			if (String.IsNullOrEmpty (name))
+				return false;
+
+			attrs.TryGetValue ("type", out type);
+
+			return true;
+		}
+
+		void SetProviderProperties (SettingsMappingWhatContents how, ProviderSettings prov)
+		{
+			Dictionary <string, string> attrs = how.Attributes;
+			if (attrs == null || attrs.Count == 0)
+				return;
+
+			string key;
+			foreach (KeyValuePair <string, string> kvp in attrs) {
+				key = kvp.Key;
+				if (key == "name")
+					continue;
+				if (key == "type") {
+					prov.Type = kvp.Value;
+					continue;
+				}
+				prov.Parameters [key] = kvp.Value;
+			}
+		}
+		
+		void ProcessAdd (MembershipSection section, SettingsMappingWhatContents how)
+		{
+			string name, type;
+			if (!GetCommonAttributes (how, out name, out type))
+				return;
+
+			ProviderSettingsCollection providers = section.Providers;
+			ProviderSettings provider = providers [name];
+			if (provider != null)
+				return;
+
+			ProviderSettings prov = new ProviderSettings (name, type);
+			SetProviderProperties (how, prov);
+			
+			providers.Add (prov);
+		}
+
+		void ProcessRemove (MembershipSection section, SettingsMappingWhatContents how)
+		{
+			string name, type;
+			if (!GetCommonAttributes (how, out name, out type))
+				return;
+
+			ProviderSettingsCollection providers = section.Providers;
+			ProviderSettings provider = providers [name];
+			if (provider != null) {
+				if (provider.Type != type)
+					return;
+				providers.Remove (name);
+			}
+		}
+		
+		void ProcessClear (MembershipSection section, SettingsMappingWhatContents how)
+		{
+			section.Providers.Clear ();
+		}
+
+		void ProcessReplace (MembershipSection section, SettingsMappingWhatContents how)
+		{
+			string name, type;
+			if (!GetCommonAttributes (how, out name, out type))
+				return;
+
+			ProviderSettings provider = section.Providers [name];
+			if (provider != null)
+				SetProviderProperties (how, provider);
+		}
+	}
+}
+#endif

+ 165 - 0
mcs/class/System.Web/System.Web.Util/RoleManagerSectionMapper.cs

@@ -0,0 +1,165 @@
+//
+// System.Web.Util.RoleManagerSectionMapper
+//
+// Authors:
+//   Marek Habersack ([email protected])
+//
+// (C) 2007 Novell, Inc
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#if NET_2_0
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Web.Configuration;
+
+namespace System.Web.Util
+{
+	internal class RoleManagerSectionMapper : ISectionSettingsMapper
+	{
+		public object MapSection (object _section, List <SettingsMappingWhat> whats)
+		{
+			RoleManagerSection section = _section as RoleManagerSection;
+			if (section == null)
+				return _section;
+			
+			List <SettingsMappingWhatContents> contents;
+
+			foreach (SettingsMappingWhat what in whats) {
+				contents = what.Contents;
+				if (contents == null || contents.Count == 0)
+					continue;
+
+				foreach (SettingsMappingWhatContents item in contents) {
+					switch (item.Operation) {
+						case SettingsMappingWhatOperation.Add:
+							ProcessAdd (section, item);
+							break;
+
+						case SettingsMappingWhatOperation.Clear:
+							ProcessClear (section, item);
+							break;
+
+						case SettingsMappingWhatOperation.Replace:
+							ProcessReplace (section, item);
+							break;
+
+						case SettingsMappingWhatOperation.Remove:
+							ProcessRemove (section, item);
+							break;
+					}
+				}
+			}
+				
+			return section;
+		}
+
+		bool GetCommonAttributes (SettingsMappingWhatContents how, out string name, out string type)
+		{
+			name = type = null;
+			
+			Dictionary <string, string> attrs = how.Attributes;
+			
+			if (attrs == null || attrs.Count == 0)
+				return false;
+
+			if (!attrs.TryGetValue ("name", out name))
+				return false;
+
+			if (String.IsNullOrEmpty (name))
+				return false;
+
+			attrs.TryGetValue ("type", out type);
+
+			return true;
+		}
+
+		void SetProviderProperties (SettingsMappingWhatContents how, ProviderSettings prov)
+		{
+			Dictionary <string, string> attrs = how.Attributes;
+			if (attrs == null || attrs.Count == 0)
+				return;
+
+			string key;
+			foreach (KeyValuePair <string, string> kvp in attrs) {
+				key = kvp.Key;
+				if (key == "name")
+					continue;
+				if (key == "type") {
+					prov.Type = kvp.Value;
+					continue;
+				}
+				prov.Parameters [key] = kvp.Value;
+			}
+		}
+		
+		void ProcessAdd (RoleManagerSection section, SettingsMappingWhatContents how)
+		{
+			string name, type;
+			if (!GetCommonAttributes (how, out name, out type))
+				return;
+
+			ProviderSettingsCollection providers = section.Providers;
+			ProviderSettings provider = providers [name];
+			if (provider != null)
+				return;
+
+			ProviderSettings prov = new ProviderSettings (name, type);
+			SetProviderProperties (how, prov);
+			
+			providers.Add (prov);
+		}
+
+		void ProcessRemove (RoleManagerSection section, SettingsMappingWhatContents how)
+		{
+			string name, type;
+			if (!GetCommonAttributes (how, out name, out type))
+				return;
+
+			ProviderSettingsCollection providers = section.Providers;
+			ProviderSettings provider = providers [name];
+			if (provider != null) {
+				if (provider.Type != type)
+					return;
+				providers.Remove (name);
+			}
+		}
+		
+		void ProcessClear (RoleManagerSection section, SettingsMappingWhatContents how)
+		{
+			section.Providers.Clear ();
+		}
+
+		void ProcessReplace (RoleManagerSection section, SettingsMappingWhatContents how)
+		{
+			string name, type;
+			if (!GetCommonAttributes (how, out name, out type))
+				return;
+
+			ProviderSettings provider = section.Providers [name];
+			if (provider != null)
+				SetProviderProperties (how, provider);
+		}
+	}
+}
+#endif

+ 89 - 0
mcs/class/System.Web/System.Web.Util/SerializationHelper.cs

@@ -0,0 +1,89 @@
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Copyright © 2006, 2007 Nauck IT KG		http://www.nauck-it.de
+//
+// Author:
+//	Daniel Nauck		<d.nauck(at)nauck-it.de>
+
+#if NET_2_0
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Xml;
+using System.Xml.Serialization;
+using System.Runtime.Serialization.Formatters.Binary;
+using System.IO;
+
+namespace System.Web.Util
+{
+	internal class SerializationHelper
+	{
+		internal string SerializeToBase64(object value)
+		{
+			return Convert.ToBase64String(SerializeToBinary(value));
+		}
+
+		internal object DeserializeFromBase64(string value)
+		{
+			return DeserializeFromBinary(Convert.FromBase64String(value));
+		}
+
+		internal string SerializeToXml(object value)
+		{
+			using (MemoryStream mStream = new MemoryStream())
+			{
+				XmlSerializer xmlFormatter = new XmlSerializer(typeof(object), "http://www.nauck-it.de/PostgreSQLProvider");
+				xmlFormatter.Serialize(mStream, value);
+				return Convert.ToBase64String(mStream.ToArray());
+			}
+		}
+
+		internal object DeserializeFromXml(string value)
+		{
+			using (MemoryStream mStream = new MemoryStream(Convert.FromBase64String(value)))
+			{
+				XmlSerializer xmlFormatter = new XmlSerializer(typeof(object), "http://www.nauck-it.de/PostgreSQLProvider");
+				return xmlFormatter.Deserialize(mStream);
+			}
+		}
+
+		internal byte[] SerializeToBinary(object value)
+		{
+			using (MemoryStream mStream = new MemoryStream())
+			{
+				BinaryFormatter binFormatter = new BinaryFormatter();
+				binFormatter.Serialize(mStream, value);
+
+				return mStream.ToArray();
+			}
+		}
+
+		internal object DeserializeFromBinary(byte[] value)
+		{
+			using (MemoryStream mStream = new MemoryStream(value))
+			{
+				BinaryFormatter binFormatter = new BinaryFormatter();
+				return binFormatter.Deserialize(mStream);
+			}
+		}
+	}
+}
+#endif

+ 112 - 0
mcs/class/System.Web/System.Web.Util/SettingsMapping.cs

@@ -0,0 +1,112 @@
+//
+// System.Web.Util.SettingsMapping
+//
+// Authors:
+//   Marek Habersack ([email protected])
+//
+// (C) 2007 Novell, Inc
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#if NET_2_0
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Xml;
+using System.Xml.XPath;
+
+namespace System.Web.Util
+{
+	internal enum SettingsMappingPlatform
+	{
+		Windows,
+		Unix
+	};
+  
+	internal class SettingsMapping
+	{
+		string _sectionTypeName;
+		Type _sectionType;
+		string _mapperTypeName;
+		Type _mapperType;
+		SettingsMappingPlatform _platform;
+		List <SettingsMappingWhat> _whats;
+    
+		public Type SectionType {
+			get {
+				if (_sectionType == null)
+					_sectionType = Type.GetType (_sectionTypeName, false);
+				return _sectionType;
+			}
+		}
+
+		public Type MapperType {
+			get {
+				if (_mapperType == null) {
+					_mapperType = Type.GetType (_mapperTypeName, true);
+					if (!typeof (ISectionSettingsMapper).IsAssignableFrom (_mapperType)) {
+						_mapperType = null;
+						throw new InvalidOperationException ("Mapper type does not implement the ISectionSettingsMapper interface");
+					}
+				}
+	
+				return _mapperType;
+			}
+		}
+
+		public SettingsMappingPlatform Platform {
+			get { return _platform; }
+		}
+    
+		public SettingsMapping (XPathNavigator nav)
+		{
+			_sectionTypeName = nav.GetAttribute ("sectionType", String.Empty);
+			_mapperTypeName = nav.GetAttribute ("mapperType", String.Empty);
+
+			EnumConverter cvt = new EnumConverter (typeof (SettingsMappingPlatform));
+			_platform = (SettingsMappingPlatform) cvt.ConvertFromInvariantString (nav.GetAttribute ("platform", String.Empty));
+
+			LoadContents (nav);
+		}
+
+		public object MapSection (object input, Type type)
+		{
+			if (type != SectionType)
+				throw new ArgumentException ("type", "Invalid section type for this mapper");
+
+			ISectionSettingsMapper mapper = Activator.CreateInstance (MapperType) as ISectionSettingsMapper;
+			if (mapper == null)
+				return input;
+      
+			return mapper.MapSection (input, _whats);
+		}
+    
+		void LoadContents (XPathNavigator nav)
+		{
+			XPathNodeIterator iter = nav.Select ("./what[string-length (@value) > 0]");
+			_whats = new List <SettingsMappingWhat> ();
+			while (iter.MoveNext ())
+				_whats.Add (new SettingsMappingWhat (iter.Current));
+		}
+	}
+}
+#endif

+ 167 - 0
mcs/class/System.Web/System.Web.Util/SettingsMappingManager.cs

@@ -0,0 +1,167 @@
+//
+// System.Web.Util.SettingsMappingManager
+//
+// Authors:
+//   Marek Habersack ([email protected])
+//
+// (C) 2007 Novell, Inc
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#if NET_2_0
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Web;
+using System.Web.Configuration;
+using System.Xml;
+using System.Xml.XPath;
+
+namespace System.Web.Util
+{
+	internal class SettingsMappingManager
+	{
+		const string settingsMapFileName = "settings.map";
+		
+		static SettingsMappingManager _instance;
+		static string _mappingFile;
+		Dictionary <Type, SettingsMapping> _mappers;
+		static Dictionary <object, object> _mappedSections;
+		PlatformID _platform = Environment.OSVersion.Platform;
+
+		public bool HasMappings {
+			get { return (_mappers != null && _mappers.Count > 0); }
+		}
+		
+		static SettingsMappingManager ()
+		{
+			_mappingFile = Path.Combine (Path.GetDirectoryName (RuntimeEnvironment.SystemConfigurationFile), settingsMapFileName);
+		}
+
+		static public void Init ()
+		{
+			if (_instance != null)
+				return;
+			
+			if (Environment.GetEnvironmentVariable ("MONO_ASPNET_INHIBIT_SETTINGSMAP") != null)
+				return;
+
+			NameValueCollection appSettings = WebConfigurationManager.AppSettings;
+			if (appSettings != null) {
+				string inhibit = appSettings ["MonoAspnetInhibitSettingsMap"];
+				if (String.Compare (inhibit, "true", StringComparison.OrdinalIgnoreCase) == 0)
+					return;
+			}
+
+			SettingsMappingManager mapper = new SettingsMappingManager ();
+			mapper.LoadMappings ();
+
+			if (mapper.HasMappings) {
+				_instance = mapper;
+				_mappedSections = new Dictionary <object, object> ();
+			}
+		}
+		
+		public void LoadMappings ()
+		{
+			if (File.Exists (_mappingFile))
+				LoadMappings (_mappingFile);
+
+			AppDomainSetup domain = AppDomain.CurrentDomain.SetupInformation;
+			string appMappingFile = Path.Combine (domain.ApplicationBase, settingsMapFileName);
+			if (File.Exists (appMappingFile))
+				LoadMappings (appMappingFile);
+		}
+		
+		void LoadMappings (string mappingFilePath)
+		{
+			XPathNavigator top;
+			XPathDocument doc;
+			try {
+				doc = new XPathDocument (mappingFilePath);
+				top = doc.CreateNavigator ();
+			} catch (Exception ex) {
+				throw new ApplicationException ("Error loading mapping settings", ex);
+			}
+			
+			XPathNodeIterator iter;
+			if (_mappers == null)
+				_mappers = new Dictionary <Type, SettingsMapping> ();
+			else {
+				iter = top.Select ("//settingsMap/clear");
+				if (iter.MoveNext ())
+					_mappers.Clear ();
+			}
+
+			iter = top.Select ("//settingsMap/map[string-length (@sectionType) > 0 and string-length (@mapperType) > 0 and string-length (@platform) > 0]");
+			SettingsMapping map;
+      
+			while (iter.MoveNext ()) {
+				map = new SettingsMapping (iter.Current);
+				if (!_mappers.ContainsKey (map.SectionType))
+					_mappers.Add (map.SectionType, map);
+				else
+					_mappers [map.SectionType] = map;
+			}      
+		}
+		
+		public static object MapSection (object input)
+		{
+			if (_instance == null || input == null)
+				return input;
+
+			object mappedSection;
+			if (_mappedSections.TryGetValue (input, out mappedSection))
+				return mappedSection;
+			
+			object ret = _instance.MapSection (input, input.GetType ());
+			if (ret != null)
+				_mappedSections.Add (ret, ret);
+
+			return ret;
+		}
+
+		object MapSection (object input, Type type)
+		{
+			if (_mappers == null || _mappers.Count == 0 || !_mappers.ContainsKey (type))
+				return input;
+      
+			SettingsMapping map;
+			if (!_mappers.TryGetValue (type, out map))
+				return input;
+			
+			if (map == null)
+				return input;
+
+			if ((int) _platform != 128 && (int) _platform != 4) {
+				if (map.Platform != SettingsMappingPlatform.Windows)
+					return input;
+			} else if (map.Platform != SettingsMappingPlatform.Unix)
+				return input;
+      
+			return map.MapSection (input, type);
+		}
+	}
+}
+#endif

+ 119 - 0
mcs/class/System.Web/System.Web.Util/SettingsMappingWhat.cs

@@ -0,0 +1,119 @@
+//
+// System.Web.Util.SettingsMappingWhat
+//
+// Authors:
+//   Marek Habersack ([email protected])
+//
+// (C) 2007 Novell, Inc
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#if NET_2_0
+using System;
+using System.Collections.Generic;
+using System.Xml;
+using System.Xml.XPath;
+
+namespace System.Web.Util
+{
+	internal enum SettingsMappingWhatOperation
+	{
+		Add,
+		Clear,
+		Replace,
+		Remove
+	}
+
+	internal class SettingsMappingWhatContents
+	{
+		SettingsMappingWhatOperation _operation;
+		Dictionary <string, string> _attributes;
+
+		public SettingsMappingWhatOperation Operation {
+			get { return _operation; }
+		}
+
+		public Dictionary <string, string> Attributes {
+			get { return _attributes; }
+		}
+    
+		public SettingsMappingWhatContents (XPathNavigator nav, SettingsMappingWhatOperation operation)
+		{
+			_operation = operation;
+      
+			if (nav.HasAttributes) {
+				_attributes = new Dictionary <string, string> ();
+	
+				nav.MoveToFirstAttribute ();
+				_attributes.Add (nav.Name, nav.Value);
+	
+				while (nav.MoveToNextAttribute ())
+					_attributes.Add (nav.Name, nav.Value);
+			}
+		}
+	}
+  
+	internal class SettingsMappingWhat
+	{    
+		string _value;
+		List <SettingsMappingWhatContents> _contents;
+    
+		public string Value {
+			get { return _value; }
+		}
+
+		public List <SettingsMappingWhatContents> Contents {
+			get { return _contents; }
+		}
+    
+		public SettingsMappingWhat (XPathNavigator nav)
+		{
+			_value = nav.GetAttribute ("value", String.Empty);
+
+			XPathNodeIterator iter = nav.Select ("./*");
+			XPathNavigator cur;
+
+			_contents = new List <SettingsMappingWhatContents> ();
+			while (iter.MoveNext ()) {
+				cur = iter.Current;
+				switch (cur.LocalName) {
+					case "replace":
+						_contents.Add (new SettingsMappingWhatContents (cur, SettingsMappingWhatOperation.Replace));
+						break;
+
+					case "add":
+						_contents.Add (new SettingsMappingWhatContents (cur, SettingsMappingWhatOperation.Add));
+						break;
+
+					case "clear":
+						_contents.Add (new SettingsMappingWhatContents (cur, SettingsMappingWhatOperation.Clear));
+						break;
+
+					case "remove":
+						_contents.Add (new SettingsMappingWhatContents (cur, SettingsMappingWhatOperation.Remove));
+						break;
+				}
+			}
+		}
+	}
+}
+#endif

+ 11 - 0
mcs/class/System.Web/System.Web.dll.sources

@@ -372,7 +372,9 @@ System.Web.Profile/ProfileProviderAttribute.cs
 System.Web.Profile/ProfileProviderCollection.cs
 System.Web.Profile/ProfileProvider.cs
 System.Web.Profile/SettingsAllowAnonymousAttribute.cs
+System.Web.Profile/SqliteProfileProvider.cs
 System.Web.Profile/SqlProfileProvider.cs
+System.Web.Properties/TranslationProperties.Designer.cs
 System.Web/QueueManager.cs
 System.Web.Security/ActiveDirectoryConnectionProtection.cs
 System.Web.Security/ActiveDirectoryMembershipProvider.cs
@@ -411,6 +413,8 @@ System.Web.Security/RolePrincipal.cs
 System.Web.Security/RoleProviderCollection.cs
 System.Web.Security/RoleProvider.cs
 System.Web.Security/Roles.cs
+System.Web.Security/SqliteMembershipProvider.cs
+System.Web.Security/SqliteRoleProvider.cs
 System.Web.Security/SqlMembershipProvider.cs
 System.Web.Security/SqlRoleProvider.cs
 System.Web.Security/UrlAuthorizationModule.cs
@@ -1126,8 +1130,15 @@ System.Web.Util/DataSourceHelper.cs
 System.Web.Util/DataSourceResolver.cs
 System.Web.Util/FileUtils.cs
 System.Web.Util/ICalls.cs
+System.Web.Util/ISectionSettingsMapper.cs
 System.Web.Util/IWebObjectFactory.cs
 System.Web.Util/IWebPropertyAccessor.cs
+System.Web.Util/MembershipSectionMapper.cs
+System.Web.Util/RoleManagerSectionMapper.cs
+System.Web.Util/SerializationHelper.cs
+System.Web.Util/SettingsMapping.cs
+System.Web.Util/SettingsMappingManager.cs
+System.Web.Util/SettingsMappingWhat.cs
 System.Web.Util/StrUtils.cs
 System.Web.Util/TimeUtil.cs
 System.Web.Util/TransactedCallback.cs

+ 5 - 0
mcs/class/System.Web/System.Web/ChangeLog

@@ -1,3 +1,8 @@
+2007-12-08  Marek Habersack  <[email protected]>
+
+	* HttpRuntime.cs: initialize the Settings Mapping Manager once per
+	application, just after initalizing the WebConfigurationManager.
+
 2007-11-28  Marek Habersack  <[email protected]>
 
 	* HttpApplication.cs: peform the check of whether we're running on

+ 1 - 1
mcs/class/System.Web/System.Web/HttpRuntime.cs

@@ -125,10 +125,10 @@ namespace System.Web {
 #if NET_2_0
 			try {
 				WebConfigurationManager.Init ();
+				SettingsMappingManager.Init ();
 			} catch (Exception ex) {
 				initialException = ex;
 			}
-			
 #endif
 
 			// The classes in whose constructors exceptions may be thrown, should be handled the same way QueueManager

+ 5 - 0
mcs/class/System.Web/resources/ChangeLog

@@ -1,3 +1,8 @@
+2007-12-08  Marek Habersack  <[email protected]>
+
+	* TranslationResources.resx: added - string resources for the
+	Sqlite providers.
+
 2007-11-20  Marek Habersack  <[email protected]>
 
 	* WebUIValidation.js: fix regular expression validator. Fixes bug

+ 228 - 0
mcs/class/System.Web/resources/TranslationResources.resx

@@ -0,0 +1,228 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <data name="ErrArgumentNull" xml:space="preserve">
+    <value>Argument cannot be null.</value>
+  </data>
+  <data name="ErrArgumentNullOrEmpty" xml:space="preserve">
+    <value>Argument cannot be null or empty.</value>
+  </data>
+  <data name="ErrAutoGeneratedKeyNotSupported" xml:space="preserve">
+    <value>Hashed or Encrypted passwords are not supported with auto-generated keys.</value>
+  </data>
+  <data name="ErrCantDecodeHashedPw" xml:space="preserve">
+    <value>Cannot unencode a hashed password.</value>
+  </data>
+  <data name="ErrCantDeletePopulatedRole" xml:space="preserve">
+    <value>Cannot delete a populated role.</value>
+  </data>
+  <data name="ErrCantLogoutUser" xml:space="preserve">
+    <value>Unable to lock out user '{0}'.</value>
+  </data>
+  <data name="ErrCantRetrieveHashedPw" xml:space="preserve">
+    <value>Cannot retrieve hashed passwords.</value>
+  </data>
+  <data name="ErrCantUpdateFailtureCount" xml:space="preserve">
+    <value>Unable to update failure count.</value>
+  </data>
+  <data name="ErrCantUpdateFailtureCountAndWindowStart" xml:space="preserve">
+    <value>Unable to update failure count and window start.</value>
+  </data>
+  <data name="ErrConnectionStringNullOrEmpty" xml:space="preserve">
+    <value>Connection string cannot be null or empty.</value>
+  </data>
+  <data name="ErrIncorrectPasswordAnswer" xml:space="preserve">
+    <value>Incorrect password answer.</value>
+  </data>
+  <data name="ErrOperationAborted" xml:space="preserve">
+    <value>Operation aborted due to an exception (see Trace for details).</value>
+  </data>
+  <data name="ErrPasswordAnswerRequired" xml:space="preserve">
+    <value>Password answer required for password reset.</value>
+  </data>
+  <data name="ErrPasswordChangeCanceled" xml:space="preserve">
+    <value>Change password canceled due to new password validation failure.</value>
+  </data>
+  <data name="ErrPasswordResetAborted" xml:space="preserve">
+    <value>User not found, or user is locked out. Password not Reset.</value>
+  </data>
+  <data name="ErrPasswordResetCanceled" xml:space="preserve">
+    <value>Reset password canceled due to password answer validation failure.</value>
+  </data>
+  <data name="ErrPasswordResetNotEnabled" xml:space="preserve">
+    <value>Password reset is not enabled.</value>
+  </data>
+  <data name="ErrPasswordRetrievalNotEnabled" xml:space="preserve">
+    <value>Password retrieval not enabled.</value>
+  </data>
+  <data name="ErrProfileAlreadyExist" xml:space="preserve">
+    <value>Profile for user '{0}' already exists.</value>
+  </data>
+  <data name="ErrPwFormatNotSupported" xml:space="preserve">
+    <value>Password format not supported.</value>
+  </data>
+  <data name="ErrRoleAlreadyExist" xml:space="preserve">
+    <value>Role '{0}' already exists.</value>
+  </data>
+  <data name="ErrRoleNotExist" xml:space="preserve">
+    <value>Role '{0}' does not exist.</value>
+  </data>
+  <data name="ErrRollbackFailed" xml:space="preserve">
+    <value>Rollback failed.</value>
+  </data>
+  <data name="ErrUserAlreadyInRole" xml:space="preserve">
+    <value>User '{0}' is already in role '{1}'.</value>
+  </data>
+  <data name="ErrUserIsLoggedOut" xml:space="preserve">
+    <value>The supplied user is locked out.</value>
+  </data>
+  <data name="ErrUserIsNotInRole" xml:space="preserve">
+    <value>User '{0}' is not in role '{1}'.</value>
+  </data>
+  <data name="ErrUserNotFound" xml:space="preserve">
+    <value>The supplied user name is not found.</value>
+  </data>
+  <data name="LogRollbackAttempt" xml:space="preserve">
+    <value>Attempt to roll back the transaction.</value>
+  </data>
+  <data name="MembershipProviderDefaultDescription" xml:space="preserve">
+    <value>A PostgreSQL Membership Provider.</value>
+  </data>
+  <data name="MembershipProviderDefaultName" xml:space="preserve">
+    <value>PostgreSQLMembershipProvider</value>
+  </data>
+  <data name="ProfileProviderDefaultDescription" xml:space="preserve">
+    <value>A PostgreSQL Profile Provider.</value>
+  </data>
+  <data name="ProfileProviderDefaultName" xml:space="preserve">
+    <value>PostgreSQLProfileProvider</value>
+  </data>
+  <data name="RoleProviderDefaultDescription" xml:space="preserve">
+    <value>A PostgreSQL Role Provider.</value>
+  </data>
+  <data name="RoleProviderDefaultName" xml:space="preserve">
+    <value>PostgreSQLRoleProvider</value>
+  </data>
+  <data name="SessionStoreProviderDefaultDescription" xml:space="preserve">
+    <value>A PostgreSQL Session-State Store Provider</value>
+  </data>
+  <data name="SessionStoreProviderDefaultName" xml:space="preserve">
+    <value>PostgreSQLSessionStateStoreProvider</value>
+  </data>
+</root>