a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
567 lines
20 KiB
C#
567 lines
20 KiB
C#
//
|
|
// System.Web.UI.WebControls.SqlProfileProvider.cs
|
|
//
|
|
// Authors:
|
|
// Chris Toshok (toshok@ximian.com)
|
|
// Vladimir Krasnov (vladimirk@mainsoft.com)
|
|
//
|
|
// (C) 2006 Novell, Inc (http://www.novell.com)
|
|
//
|
|
// 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.Data;
|
|
using System.Data.Common;
|
|
using System.Collections;
|
|
using System.Globalization;
|
|
using System.Configuration;
|
|
using System.Configuration.Provider;
|
|
using System.Web.Configuration;
|
|
using System.Collections.Specialized;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Web.Security;
|
|
using System.Web.Util;
|
|
|
|
namespace System.Web.Profile
|
|
{
|
|
public class SqlProfileProvider : ProfileProvider
|
|
{
|
|
ConnectionStringSettings connectionString;
|
|
DbProviderFactory factory;
|
|
|
|
string applicationName;
|
|
bool schemaIsOk = false;
|
|
|
|
public override int DeleteInactiveProfiles (ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate)
|
|
{
|
|
using (DbConnection connection = CreateConnection ()) {
|
|
DbCommand command = factory.CreateCommand ();
|
|
command.Connection = connection;
|
|
command.CommandType = CommandType.StoredProcedure;
|
|
command.CommandText = @"aspnet_Profile_DeleteInactiveProfiles";
|
|
|
|
AddParameter (command, "ApplicationName", ApplicationName);
|
|
AddParameter (command, "ProfileAuthOptions", authenticationOption);
|
|
AddParameter (command, "InactiveSinceDate", userInactiveSinceDate);
|
|
DbParameter returnValue = AddParameter (command, null, ParameterDirection.ReturnValue, null);
|
|
|
|
command.ExecuteNonQuery ();
|
|
int retVal = GetReturnValue (returnValue);
|
|
return retVal;
|
|
}
|
|
}
|
|
|
|
public override int DeleteProfiles (ProfileInfoCollection profiles)
|
|
{
|
|
if (profiles == null)
|
|
throw new ArgumentNullException ("prfoles");
|
|
if (profiles.Count == 0)
|
|
throw new ArgumentException ("prfoles");
|
|
|
|
string [] usernames = new string [profiles.Count];
|
|
|
|
int i = 0;
|
|
foreach (ProfileInfo pi in profiles) {
|
|
if (pi.UserName == null)
|
|
throw new ArgumentNullException ("element in profiles collection is null");
|
|
|
|
if (pi.UserName.Length == 0 || pi.UserName.Length > 256 || pi.UserName.IndexOf (',') != -1)
|
|
throw new ArgumentException ("element in profiles collection in illegal format");
|
|
|
|
usernames [i++] = pi.UserName;
|
|
}
|
|
|
|
return DeleteProfilesInternal (usernames);
|
|
}
|
|
|
|
public override int DeleteProfiles (string [] usernames)
|
|
{
|
|
if (usernames == null)
|
|
throw new ArgumentNullException ("usernames");
|
|
|
|
Hashtable users = new Hashtable ();
|
|
foreach (string username in usernames) {
|
|
if (username == null)
|
|
throw new ArgumentNullException ("element in usernames array is null");
|
|
|
|
if (username.Length == 0 || username.Length > 256 || username.IndexOf (',') != -1)
|
|
throw new ArgumentException ("element in usernames array in illegal format");
|
|
|
|
if (users.ContainsKey(username))
|
|
throw new ArgumentException ("duplicate element in usernames array");
|
|
|
|
users.Add (username, username);
|
|
}
|
|
|
|
return DeleteProfilesInternal (usernames);
|
|
}
|
|
|
|
int DeleteProfilesInternal (string [] usernames)
|
|
{
|
|
using (DbConnection connection = CreateConnection ()) {
|
|
DbCommand command = factory.CreateCommand ();
|
|
command.Connection = connection;
|
|
command.CommandType = CommandType.StoredProcedure;
|
|
command.CommandText = @"aspnet_Profile_DeleteProfiles";
|
|
|
|
AddParameter (command, "ApplicationName", ApplicationName);
|
|
AddParameter (command, "UserNames", string.Join (",", usernames));
|
|
DbParameter returnValue = AddParameter (command, null, ParameterDirection.ReturnValue, null);
|
|
|
|
command.ExecuteNonQuery ();
|
|
int retVal = GetReturnValue (returnValue);
|
|
return retVal;
|
|
}
|
|
}
|
|
|
|
public override ProfileInfoCollection FindInactiveProfilesByUserName (ProfileAuthenticationOption authenticationOption,
|
|
string usernameToMatch,
|
|
DateTime userInactiveSinceDate,
|
|
int pageIndex,
|
|
int pageSize,
|
|
out int totalRecords)
|
|
{
|
|
CheckParam ("usernameToMatch", usernameToMatch, 256);
|
|
if (pageIndex < 0)
|
|
throw new ArgumentException("pageIndex is less than zero");
|
|
if (pageSize < 1)
|
|
throw new ArgumentException ("pageIndex is less than one");
|
|
if (pageIndex * pageSize + pageSize - 1 > Int32.MaxValue)
|
|
throw new ArgumentException ("pageIndex and pageSize are too large");
|
|
|
|
using (DbConnection connection = CreateConnection ()) {
|
|
DbCommand command = factory.CreateCommand ();
|
|
command.Connection = connection;
|
|
command.CommandType = CommandType.StoredProcedure;
|
|
command.CommandText = @"aspnet_Profile_GetProfiles";
|
|
|
|
AddParameter (command, "ApplicationName", ApplicationName);
|
|
AddParameter (command, "ProfileAuthOptions", authenticationOption);
|
|
AddParameter (command, "PageIndex", pageIndex);
|
|
AddParameter (command, "PageSize", pageSize);
|
|
AddParameter (command, "UserNameToMatch", usernameToMatch);
|
|
AddParameter (command, "InactiveSinceDate", userInactiveSinceDate);
|
|
|
|
using (DbDataReader reader = command.ExecuteReader ()) {
|
|
return BuildProfileInfoCollection (reader, out totalRecords);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override ProfileInfoCollection FindProfilesByUserName (ProfileAuthenticationOption authenticationOption,
|
|
string usernameToMatch,
|
|
int pageIndex,
|
|
int pageSize,
|
|
out int totalRecords)
|
|
{
|
|
CheckParam ("usernameToMatch", usernameToMatch, 256);
|
|
if (pageIndex < 0)
|
|
throw new ArgumentException ("pageIndex is less than zero");
|
|
if (pageSize < 1)
|
|
throw new ArgumentException ("pageIndex is less than one");
|
|
if (pageIndex * pageSize + pageSize - 1 > Int32.MaxValue)
|
|
throw new ArgumentException ("pageIndex and pageSize are too large");
|
|
|
|
using (DbConnection connection = CreateConnection ()) {
|
|
DbCommand command = factory.CreateCommand ();
|
|
command.Connection = connection;
|
|
command.CommandType = CommandType.StoredProcedure;
|
|
command.CommandText = @"aspnet_Profile_GetProfiles";
|
|
|
|
AddParameter (command, "ApplicationName", ApplicationName);
|
|
AddParameter (command, "ProfileAuthOptions", authenticationOption);
|
|
AddParameter (command, "PageIndex", pageIndex);
|
|
AddParameter (command, "PageSize", pageSize);
|
|
AddParameter (command, "UserNameToMatch", usernameToMatch);
|
|
AddParameter (command, "InactiveSinceDate", null);
|
|
|
|
using (DbDataReader reader = command.ExecuteReader ()) {
|
|
return BuildProfileInfoCollection (reader, out totalRecords);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override ProfileInfoCollection GetAllInactiveProfiles (ProfileAuthenticationOption authenticationOption,
|
|
DateTime userInactiveSinceDate,
|
|
int pageIndex,
|
|
int pageSize,
|
|
out int totalRecords)
|
|
{
|
|
if (pageIndex < 0)
|
|
throw new ArgumentException ("pageIndex is less than zero");
|
|
if (pageSize < 1)
|
|
throw new ArgumentException ("pageIndex is less than one");
|
|
if (pageIndex * pageSize + pageSize - 1 > Int32.MaxValue)
|
|
throw new ArgumentException ("pageIndex and pageSize are too large");
|
|
|
|
using (DbConnection connection = CreateConnection ()) {
|
|
DbCommand command = factory.CreateCommand ();
|
|
command.Connection = connection;
|
|
command.CommandType = CommandType.StoredProcedure;
|
|
command.CommandText = @"aspnet_Profile_GetProfiles";
|
|
|
|
AddParameter (command, "ApplicationName", ApplicationName);
|
|
AddParameter (command, "ProfileAuthOptions", authenticationOption);
|
|
AddParameter (command, "PageIndex", pageIndex);
|
|
AddParameter (command, "PageSize", pageSize);
|
|
AddParameter (command, "UserNameToMatch", null);
|
|
AddParameter (command, "InactiveSinceDate", null);
|
|
|
|
using (DbDataReader reader = command.ExecuteReader ()) {
|
|
return BuildProfileInfoCollection (reader, out totalRecords);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override ProfileInfoCollection GetAllProfiles (ProfileAuthenticationOption authenticationOption,
|
|
int pageIndex,
|
|
int pageSize,
|
|
out int totalRecords)
|
|
{
|
|
if (pageIndex < 0)
|
|
throw new ArgumentException ("pageIndex is less than zero");
|
|
if (pageSize < 1)
|
|
throw new ArgumentException ("pageIndex is less than one");
|
|
if (pageIndex * pageSize + pageSize - 1 > Int32.MaxValue)
|
|
throw new ArgumentException ("pageIndex and pageSize are too large");
|
|
|
|
using (DbConnection connection = CreateConnection ()) {
|
|
DbCommand command = factory.CreateCommand ();
|
|
command.Connection = connection;
|
|
command.CommandType = CommandType.StoredProcedure;
|
|
command.CommandText = @"aspnet_Profile_GetProfiles";
|
|
|
|
AddParameter (command, "ApplicationName", ApplicationName);
|
|
AddParameter (command, "ProfileAuthOptions", authenticationOption);
|
|
AddParameter (command, "PageIndex", pageIndex);
|
|
AddParameter (command, "PageSize", pageSize);
|
|
AddParameter (command, "UserNameToMatch", null);
|
|
AddParameter (command, "InactiveSinceDate", null);
|
|
|
|
using (DbDataReader reader = command.ExecuteReader ()) {
|
|
return BuildProfileInfoCollection (reader, out totalRecords);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override int GetNumberOfInactiveProfiles (ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate)
|
|
{
|
|
using (DbConnection connection = CreateConnection ()) {
|
|
|
|
DbCommand command = factory.CreateCommand ();
|
|
command.Connection = connection;
|
|
command.CommandType = CommandType.StoredProcedure;
|
|
command.CommandText = @"aspnet_Profile_GetNumberOfInactiveProfiles";
|
|
|
|
AddParameter (command, "ApplicationName", ApplicationName);
|
|
AddParameter (command, "ProfileAuthOptions", authenticationOption);
|
|
AddParameter (command, "InactiveSinceDate", userInactiveSinceDate);
|
|
|
|
int returnValue = 0;
|
|
using (DbDataReader reader = command.ExecuteReader ()) {
|
|
if (reader.Read ())
|
|
returnValue = reader.GetInt32 (0);
|
|
}
|
|
return returnValue;
|
|
}
|
|
}
|
|
|
|
public override SettingsPropertyValueCollection GetPropertyValues (SettingsContext sc, SettingsPropertyCollection properties)
|
|
{
|
|
SettingsPropertyValueCollection settings = new SettingsPropertyValueCollection ();
|
|
|
|
if (properties.Count == 0)
|
|
return settings;
|
|
|
|
foreach (SettingsProperty property in properties) {
|
|
if (property.SerializeAs == SettingsSerializeAs.ProviderSpecific)
|
|
if (property.PropertyType.IsPrimitive || property.PropertyType == typeof (String))
|
|
property.SerializeAs = SettingsSerializeAs.String;
|
|
else
|
|
property.SerializeAs = SettingsSerializeAs.Xml;
|
|
|
|
settings.Add (new SettingsPropertyValue (property));
|
|
}
|
|
|
|
string username = (string) sc ["UserName"];
|
|
using (DbConnection connection = CreateConnection ()) {
|
|
DbCommand command = factory.CreateCommand ();
|
|
command.Connection = connection;
|
|
command.CommandType = CommandType.StoredProcedure;
|
|
command.CommandText = @"aspnet_Profile_GetProperties";
|
|
|
|
AddParameter (command, "ApplicationName", ApplicationName);
|
|
AddParameter (command, "UserName", username);
|
|
AddParameter (command, "CurrentTimeUtc", DateTime.UtcNow);
|
|
|
|
using (DbDataReader reader = command.ExecuteReader ()) {
|
|
if (reader.Read ()) {
|
|
string allnames = reader.GetString (0);
|
|
string allvalues = reader.GetString (1);
|
|
int binaryLen = (int) reader.GetBytes (2, 0, null, 0, 0);
|
|
byte [] binaryvalues = new byte [binaryLen];
|
|
reader.GetBytes (2, 0, binaryvalues, 0, binaryLen);
|
|
|
|
DecodeProfileData (allnames, allvalues, binaryvalues, settings);
|
|
}
|
|
}
|
|
}
|
|
|
|
return settings;
|
|
}
|
|
|
|
public override void SetPropertyValues (SettingsContext sc, SettingsPropertyValueCollection properties)
|
|
{
|
|
string username = (string) sc ["UserName"];
|
|
bool isAnonymous = !(bool) sc ["IsAuthenticated"];
|
|
|
|
string names = String.Empty;
|
|
string values = String.Empty;
|
|
byte [] buf = null;
|
|
|
|
EncodeProfileData (ref names, ref values, ref buf, properties, !isAnonymous);
|
|
|
|
using (DbConnection connection = CreateConnection ()) {
|
|
DbCommand command = factory.CreateCommand ();
|
|
command.Connection = connection;
|
|
command.CommandType = CommandType.StoredProcedure;
|
|
command.CommandText = @"aspnet_Profile_SetProperties";
|
|
|
|
AddParameter (command, "ApplicationName", ApplicationName);
|
|
AddParameter (command, "PropertyNames", names);
|
|
AddParameter (command, "PropertyValuesString", values);
|
|
AddParameter (command, "PropertyValuesBinary", buf);
|
|
AddParameter (command, "UserName", username);
|
|
AddParameter (command, "IsUserAnonymous", isAnonymous);
|
|
AddParameter (command, "CurrentTimeUtc", DateTime.UtcNow);
|
|
|
|
// Return value
|
|
AddParameter (command, null, ParameterDirection.ReturnValue, null);
|
|
|
|
command.ExecuteNonQuery ();
|
|
return;
|
|
}
|
|
}
|
|
|
|
public override void Initialize (string name, NameValueCollection config)
|
|
{
|
|
if (config == null)
|
|
throw new ArgumentNullException ("config");
|
|
|
|
base.Initialize (name, config);
|
|
|
|
applicationName = GetStringConfigValue (config, "applicationName", "/");
|
|
|
|
string connectionStringName = config ["connectionStringName"];
|
|
|
|
if (applicationName.Length > 256)
|
|
throw new ProviderException ("The ApplicationName attribute must be 256 characters long or less.");
|
|
if (connectionStringName == null || connectionStringName.Length == 0)
|
|
throw new ProviderException ("The ConnectionStringName attribute must be present and non-zero length.");
|
|
|
|
connectionString = WebConfigurationManager.ConnectionStrings [connectionStringName];
|
|
factory = connectionString == null || String.IsNullOrEmpty (connectionString.ProviderName) ?
|
|
System.Data.SqlClient.SqlClientFactory.Instance :
|
|
ProvidersHelper.GetDbProviderFactory (connectionString.ProviderName);
|
|
}
|
|
|
|
public override string ApplicationName {
|
|
get { return applicationName; }
|
|
set { applicationName = value; }
|
|
}
|
|
|
|
DbConnection CreateConnection ()
|
|
{
|
|
if (!schemaIsOk && !(schemaIsOk = AspNetDBSchemaChecker.CheckMembershipSchemaVersion (factory, connectionString.ConnectionString, "profile", "1")))
|
|
throw new ProviderException ("Incorrect ASP.NET DB Schema Version.");
|
|
|
|
DbConnection connection = factory.CreateConnection ();
|
|
connection.ConnectionString = connectionString.ConnectionString;
|
|
|
|
connection.Open ();
|
|
return connection;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
void CheckParam (string pName, string p, int length)
|
|
{
|
|
if (p == null)
|
|
throw new ArgumentNullException (pName);
|
|
if (p.Length == 0 || p.Length > length || p.IndexOf (',') != -1)
|
|
throw new ArgumentException (String.Concat ("invalid format for ", pName));
|
|
}
|
|
|
|
static int GetReturnValue (DbParameter returnValue)
|
|
{
|
|
object value = returnValue.Value;
|
|
return value is int ? (int) value : -1;
|
|
}
|
|
|
|
ProfileInfo ReadProfileInfo (DbDataReader reader)
|
|
{
|
|
ProfileInfo pi = null;
|
|
try {
|
|
string username = reader.GetString (0);
|
|
bool anonymous = reader.GetBoolean (1);
|
|
DateTime lastUpdate = reader.GetDateTime (2);
|
|
DateTime lastActivity = reader.GetDateTime (3);
|
|
int size = reader.GetInt32 (4);
|
|
|
|
pi = new ProfileInfo (username, anonymous, lastActivity, lastUpdate, size);
|
|
}
|
|
catch {
|
|
}
|
|
|
|
return pi;
|
|
}
|
|
|
|
ProfileInfoCollection BuildProfileInfoCollection (DbDataReader reader, out int totalRecords)
|
|
{
|
|
ProfileInfoCollection pic = new ProfileInfoCollection ();
|
|
while (reader.Read ()) {
|
|
ProfileInfo pi = ReadProfileInfo (reader);
|
|
if (pi != null)
|
|
pic.Add (pi);
|
|
}
|
|
totalRecords = 0;
|
|
if (reader.NextResult ()) {
|
|
if (reader.Read ())
|
|
totalRecords = reader.GetInt32 (0);
|
|
}
|
|
return pic;
|
|
}
|
|
|
|
string GetStringConfigValue (NameValueCollection config, string name, string def)
|
|
{
|
|
string retVal = def;
|
|
string val = config [name];
|
|
if (val != null)
|
|
retVal = val;
|
|
return retVal;
|
|
}
|
|
|
|
// Helper methods
|
|
void DecodeProfileData (string allnames, string values, byte [] buf, SettingsPropertyValueCollection properties)
|
|
{
|
|
if (allnames == null || values == null || buf == null || properties == null)
|
|
return;
|
|
|
|
string [] names = allnames.Split (':');
|
|
for (int i = 0; i < names.Length; i += 4) {
|
|
string name = names [i];
|
|
SettingsPropertyValue pp = properties [name];
|
|
|
|
if (pp == null)
|
|
continue;
|
|
|
|
int pos = Int32.Parse (names [i + 2], Helpers.InvariantCulture);
|
|
int len = Int32.Parse (names [i + 3], Helpers.InvariantCulture);
|
|
|
|
if (len == -1 && !pp.Property.PropertyType.IsValueType) {
|
|
pp.PropertyValue = null;
|
|
pp.IsDirty = false;
|
|
pp.Deserialized = true;
|
|
}
|
|
else if (names [i + 1] == "S" && pos >= 0 && len > 0 && values.Length >= pos + len) {
|
|
pp.SerializedValue = values.Substring (pos, len);
|
|
}
|
|
else if (names [i + 1] == "B" && pos >= 0 && len > 0 && buf.Length >= pos + len) {
|
|
byte [] buf2 = new byte [len];
|
|
Buffer.BlockCopy (buf, pos, buf2, 0, len);
|
|
pp.SerializedValue = buf2;
|
|
}
|
|
}
|
|
}
|
|
|
|
void EncodeProfileData (ref string allNames, ref string allValues, ref byte [] buf, SettingsPropertyValueCollection properties, bool userIsAuthenticated)
|
|
{
|
|
StringBuilder names = new StringBuilder ();
|
|
StringBuilder values = new StringBuilder ();
|
|
MemoryStream stream = new MemoryStream ();
|
|
|
|
try {
|
|
foreach (SettingsPropertyValue pp in properties) {
|
|
if (!userIsAuthenticated && !(bool) pp.Property.Attributes ["AllowAnonymous"])
|
|
continue;
|
|
|
|
if (!pp.IsDirty && pp.UsingDefaultValue)
|
|
continue;
|
|
|
|
int len = 0, pos = 0;
|
|
string propValue = null;
|
|
|
|
if (pp.Deserialized && pp.PropertyValue == null)
|
|
len = -1;
|
|
else {
|
|
object sVal = pp.SerializedValue;
|
|
|
|
if (sVal == null)
|
|
len = -1;
|
|
else if (sVal is string) {
|
|
propValue = (string) sVal;
|
|
len = propValue.Length;
|
|
pos = values.Length;
|
|
}
|
|
else {
|
|
byte [] b2 = (byte []) sVal;
|
|
pos = (int) stream.Position;
|
|
stream.Write (b2, 0, b2.Length);
|
|
stream.Position = pos + b2.Length;
|
|
len = b2.Length;
|
|
}
|
|
}
|
|
|
|
names.Append (pp.Name + ":" + ((propValue != null) ? "S" : "B") + ":" + pos.ToString (Helpers.InvariantCulture) + ":" + len.ToString (Helpers.InvariantCulture) + ":");
|
|
|
|
if (propValue != null)
|
|
values.Append (propValue);
|
|
}
|
|
buf = stream.ToArray ();
|
|
}
|
|
finally {
|
|
if (stream != null)
|
|
stream.Close ();
|
|
}
|
|
|
|
allNames = names.ToString ();
|
|
allValues = values.ToString ();
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|