using System;
using System.Data;
using System.Configuration;
using System.Diagnostics;
using System.Web;
using System.Web.Configuration;
using System.Linq;
using System.Threading;
using System.Globalization;
using System.Web.Profile;
using System.Configuration.Provider;
using System.Collections.Specialized;
using System.Collections.Generic;
#if DynamicFileSys
using CryptoGateway.RDB.Data.DynamicFileSystem;
#elif MembershipPlus
using CryptoGateway.RDB.Data.MembershipPlus;
#else
using CryptoGateway.RDB.Data.AspNetMember;
#endif
//using log4net;
namespace Archymeta.Web.Security
{
/// <summary>
/// Provider for Asp.Net user profile management using the Membership Data Service.
/// </summary>
public sealed class AspNetProfileProvider : ProfileProvider
{
#if TEST
public CallContext cntx
{
get
{
return _cctx;
}
}
public Application_ App
{
get { return app; }
}
public Action<SettingsProperty> Del_PropName = null;
#endif
//private static ILog log = LogManager.GetLogger(typeof(AspNetMembershipProvider));
private string exceptionMessage = "An exception occurred. Please check the event log.";
#if DynamicFileSys
private DynamicFileSystemServiceProxy svc = new DynamicFileSystemServiceProxy();
#elif MembershipPlus
private MembershipPlusServiceProxy svc = new MembershipPlusServiceProxy();
#else
private AspNetMemberServiceProxy svc = new AspNetMemberServiceProxy();
#endif
private Application_ app
{
get { return AspNetMembershipProvider.app; }
set { AspNetMembershipProvider.app = value; }
}
private CallContext _cctx
{
get
{
return AspNetMembershipProvider._cctx;
}
set
{
AspNetMembershipProvider._cctx = value;
}
}
/// <summary>
/// The name of the current application
/// </summary>
public override string ApplicationName
{
get { return pApplicationName; }
set { pApplicationName = value; }
}
private string pApplicationName;
/// <summary>
///
/// </summary>
public bool WriteExceptionsToEventLog
{
get { return pWriteExceptionsToEventLog; }
set { pWriteExceptionsToEventLog = value; }
}
private bool pWriteExceptionsToEventLog;
/// <summary>
/// Initialize the Profile Provider.
/// </summary>
/// <param name="name">Name of the provider.</param>
/// <param name="config">The configuraton values</param>
/// <remarks>
/// <para>
/// In a multi-thread application, like a Asp.Net one, more than one of the providers (membership, role and profile)
/// may try to enter the initialization procedure from different threads at the same time, so the calls to service API has to be synchronized
/// with a lock.
/// </para>
/// </remarks>
public override void Initialize(string name, NameValueCollection config)
{
//
// Initialize values from web.config.
//
if (config == null)
throw new ArgumentNullException("config");
if (name == null || name.Length == 0)
name = "AspNetProfileServiceProvider";
if (String.IsNullOrEmpty(config["description"]))
{
config.Remove("description");
config.Add("description", "Asp.Net Profile Service Provider");
}
// Initialize the abstract base class.
base.Initialize(name, config);
if (config["applicationName"] == null || config["applicationName"].Trim() == "")
{
pApplicationName = System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath;
}
else
{
pApplicationName = config["applicationName"];
}
if (config["writeExceptionsToEventLog"] != null)
{
if (config["writeExceptionsToEventLog"].ToUpper() == "TRUE")
{
pWriteExceptionsToEventLog = true;
}
}
CallContext cctx;
lock (AspNetMembershipProvider.syncRoot)
{
if (_cctx == null)
_cctx = svc.SignInService(new CallContext(), null);
cctx = _cctx.CreateCopy();
// set this for profiles since machine tends to do repeatative works and this will ensure no exception been thrown..
cctx.OverrideExisting = true;
// must use direct access since all three providers is trying to create the app at the same time.
cctx.DirectDataAccess = true;
Application_ServiceProxy apprepo = new Application_ServiceProxy();
List<Application_> apps = apprepo.LoadEntityByNature(cctx, ApplicationName);
if (apps == null || apps.Count == 0)
{
//
// when the application is registerred the first time, membership, role, and profile provider could try to add the application at the same time,
// setting cctx.OverrideExisting = true will prevent concurrent add exception for new items.
// set it back if you do not want to accidentally overwriting an existing items by a new one
//
var tuple = apprepo.AddOrUpdateEntities(cctx, new Application_Set(), new Application_[] { new Application_ { Name = ApplicationName } });
app = tuple.ChangedEntities.Length == 1 && AspNetMembershipProvider.IsValidUpdate(tuple.ChangedEntities[0].OpStatus) ?
tuple.ChangedEntities[0].UpdatedItem : null;
}
else
app = apps[0];
}
if (app == null)
throw new Exception("User Profile provider initialization failed.");
#if TEST
ProfileSection profile = ConfigurationManager.GetSection("system.web/profile") as ProfileSection;
#else
Configuration cfg = WebConfigurationManager.OpenWebConfiguration(System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath);
ProfileSection profile = cfg.GetSection("system.web/profile") as ProfileSection;
#endif
RootProfilePropertySettingsCollection rootsettings = profile.PropertySettings;
List<UserProfileType> l = new List<UserProfileType>();
foreach (ProfilePropertySettings props in rootsettings)
{
UserProfileType upt = new UserProfileType();
upt.ClrType = GetTypeFromSimpleName(props.Type).FullName;
if (props.SerializeAs == SerializationMode.ProviderSpecific)
upt.SerializeType = SerializationMode.String.ToString();
else
upt.SerializeType = props.SerializeAs.ToString();
if (l.Count == 0 || !(from d in l where d.SerializeType == upt.SerializeType && d.ClrType == upt.ClrType select d).Any())
l.Add(upt);
#if TEST
if (Del_PropName != null)
{
SettingsProperty sprp = new SettingsProperty(props.Name);
sprp.PropertyType = Type.GetType(upt.ClrType);
sprp.SerializeAs = (SettingsSerializeAs)Enum.Parse(typeof(SettingsSerializeAs), upt.SerializeType);
Del_PropName(sprp);
}
#endif
}
foreach (ProfileGroupSettings propgrp in rootsettings.GroupSettings)
{
foreach (ProfilePropertySettings props in propgrp.PropertySettings)
{
UserProfileType upt = new UserProfileType();
upt.ClrType = GetTypeFromSimpleName(props.Type).FullName;
if (props.SerializeAs == SerializationMode.ProviderSpecific)
upt.SerializeType = SerializationMode.String.ToString();
else
upt.SerializeType = props.SerializeAs.ToString();
if (l.Count == 0 || !(from d in l where d.SerializeType == upt.SerializeType && d.ClrType == upt.ClrType select d).Any())
l.Add(upt);
#if TEST
if (Del_PropName != null)
{
SettingsProperty sprp = new SettingsProperty(propgrp.Name + "." + props.Name);
sprp.PropertyType = Type.GetType(upt.ClrType);
sprp.SerializeAs = (SettingsSerializeAs)Enum.Parse(typeof(SettingsSerializeAs), upt.SerializeType);
Del_PropName(sprp);
}
#endif
}
}
if (l.Count > 0)
{
UserProfileTypeServiceProxy uptsvc = new UserProfileTypeServiceProxy();
int cnt = l.Count;
int ptr = 0;
for (int i = 0; i < cnt; i++)
{
var _lt = uptsvc.LoadEntityByNature(cctx, l[ptr].ClrType, null, l[ptr].SerializeType);
if (_lt != null && _lt.Count > 0)
l.RemoveAt(ptr);
else
ptr++;
}
if (l.Count > 0)
{
uptsvc.AddOrUpdateEntities(cctx, new UserProfileTypeSet(), l.ToArray());
}
}
}
/// <summary>
/// Returns the collection of settings property values and settings property group for the specified application instance.
/// </summary>
/// <param name="context">
/// A <see cref="SettingsContext"/> describing the current application use.
/// </param>
/// <param name="ppc">
/// A <see cref="SettingsPropertyCollection"/> containing the settings property group whose values are to be retrieved.
/// </param>
/// <returns>
/// A <see cref="SettingsPropertyValueCollection"/> containing the values for the specified settings property group.
/// </returns>
public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection ppc)
{
string username = (string)context["UserName"];
bool isAuthenticated = (bool)context["IsAuthenticated"];
// The serializeAs attribute is ignored in this provider implementation.
SettingsPropertyValueCollection svc = new SettingsPropertyValueCollection();
CallContext cctx = _cctx.CreateCopy();
cctx.OverrideExisting = true;
try
{
User u = isAuthenticated ? findUser(username) : null;
UserProfileTypeServiceProxy uptsvc = new UserProfileTypeServiceProxy();
UserProfileServiceProxy upsvc = new UserProfileServiceProxy();
List<UserProfile> update = new List<UserProfile>();
List<UserProfile> added = new List<UserProfile>();
UserProfileSetConstraints cond = new UserProfileSetConstraints
{
ApplicationIDWrap = new ForeignKeyData<string> { KeyValue = app.ID },
TypeIDWrap = null,
UserIDWrap = new ForeignKeyData<string> { KeyValue = u != null ? u.ID : null }
};
var profs = upsvc.ConstraintQuery(cctx, new UserProfileSet(), cond, null);
foreach (SettingsProperty prop in ppc)
{
bool found = false;
if (profs != null)
{
foreach (UserProfile p in profs)
{
if (prop.Name == p.PropName)
{
SettingsPropertyValue pv = new SettingsPropertyValue(prop);
switch (prop.SerializeAs)
{
case SettingsSerializeAs.String:
case SettingsSerializeAs.Xml:
if (!p.IsStringValueLoaded)
{
p.StringValue = upsvc.LoadEntityStringValue(cctx, p.ID);
p.IsStringValueLoaded = true;
}
pv.SerializedValue = p.StringValue;
break;
case SettingsSerializeAs.Binary:
if (!p.IsBinaryValueLoaded)
{
p.BinaryValue = upsvc.LoadEntityBinaryValue(cctx, p.ID);
p.IsBinaryValueLoaded = true;
}
pv.SerializedValue = p.BinaryValue;
break;
default:
break;
}
svc.Add(pv);
update.Add(p);
p.LastAccessTime = DateTime.UtcNow;
p.IsLastAccessTimeModified = true;
found = true;
break;
}
}
}
if (!found)
{
// do not support provider in this version ...
string seras = prop.SerializeAs == SettingsSerializeAs.ProviderSpecific? SerializationMode.String.ToString() : prop.SerializeAs.ToString();
var upts = uptsvc.LoadEntityByNature(cctx, prop.PropertyType.FullName, null, seras);
UserProfileType upt;
if (upts != null && upts.Count > 0)
upt = upts[0];
else
{
upt = new UserProfileType();
upt.ClrType = prop.PropertyType.FullName;
upt.SerializeType = seras;
upt.SerializationProvider = null; // not handled now
}
UserProfile p = new UserProfile();
p.PropName = prop.Name;
p.ApplicationID = app.ID;
p.UserID = u == null ? null : u.ID;
p.TypeID = upt.ID;
p.UserProfileTypeRef = upt;
p.LastAccessTime = DateTime.UtcNow;
p.LastUpdateTime = p.LastAccessTime;
added.Add(p);
SettingsPropertyValue pv = new SettingsPropertyValue(prop);
switch (prop.SerializeAs)
{
case SettingsSerializeAs.String:
case SettingsSerializeAs.Xml:
pv.SerializedValue = p.StringValue;
break;
case SettingsSerializeAs.Binary:
pv.SerializedValue = p.BinaryValue;
break;
default:
pv.SerializedValue = p.StringValue;
break;
}
svc.Add(pv);
}
}
if (added.Count > 0)
upsvc.AddOrUpdateEntities(cctx, new UserProfileSet(), added.ToArray());
if (update.Count > 0)
upsvc.EnqueueNewOrUpdateEntities(cctx, new UserProfileSet(), update.ToArray());
return svc;
}
catch (Exception e)
{
throw e;
}
finally
{
}
}
/// <summary>
/// Sets the values of the specified group of property settings.
/// </summary>
/// <param name="context">
/// A <see cref="SettingsContext"/> describing the current application usage.
/// </param>
/// <param name="ppvc">
/// A <see cref="SettingsPropertyValueCollection"/> representing the group of property settings to set.
/// </param>
public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection ppvc)
{
string username = (string)context["UserName"];
bool isAuthenticated = (bool)context["IsAuthenticated"];
// The serializeAs attribute is ignored in this provider implementation.
CallContext cctx = _cctx.CreateCopy();
cctx.OverrideExisting = true;
try
{
User u = isAuthenticated ? findUser(username) : null;
UserProfileTypeServiceProxy uptsvc = new UserProfileTypeServiceProxy();
UserProfileServiceProxy upsvc = new UserProfileServiceProxy();
UserProfileSetConstraints cond = new UserProfileSetConstraints
{
ApplicationIDWrap = new ForeignKeyData<string> { KeyValue = app.ID },
TypeIDWrap = null,
UserIDWrap = new ForeignKeyData<string> { KeyValue = u != null ? u.ID : null }
};
var profs = upsvc.ConstraintQuery(cctx, new UserProfileSet(), cond, null);
List<UserProfile> update = new List<UserProfile>();
List<SettingsPropertyValue> added = new List<SettingsPropertyValue>();
List<UserProfile> newitems = new List<UserProfile>();
foreach (SettingsPropertyValue prop in ppvc)
{
if (prop.IsDirty)
added.Add(prop);
}
if (profs != null)
{
foreach (SettingsPropertyValue prop in ppvc)
{
if (!prop.IsDirty)
continue;
foreach (UserProfile p in from d in profs where d.PropName == prop.Property.Name select d)
{
if (prop.Property.SerializeAs == SettingsSerializeAs.Binary)
{
p.StringValue = null;
p.IsStringValueModified = true;
p.IsStringValueLoaded = true;
p.BinaryValue = prop.SerializedValue == null ? null : (byte[])prop.SerializedValue;
p.IsBinaryValueModified = true;
p.IsBinaryValueLoaded = true;
}
else if (prop.Property.SerializeAs == SettingsSerializeAs.String || prop.Property.SerializeAs == SettingsSerializeAs.Xml)
{
p.StringValue = prop.SerializedValue == null ? null : prop.SerializedValue as string;
p.IsStringValueModified = true;
p.IsStringValueLoaded = true;
p.BinaryValue = null;
p.IsBinaryValueModified = true;
p.IsBinaryValueLoaded = true;
}
else
{
//??
}
update.Add(p);
p.LastAccessTime = DateTime.UtcNow;
p.IsLastAccessTimeModified = true;
p.LastUpdateTime = p.LastAccessTime;
p.IsLastUpdateTimeModified = true;
added.Remove(prop);
break;
}
}
}
foreach (SettingsPropertyValue prop in added)
{
UserProfile p = new UserProfile();
// do not support provider in this version ...
string seras = prop.Property.SerializeAs == SettingsSerializeAs.ProviderSpecific ? SerializationMode.String.ToString() : prop.Property.SerializeAs.ToString();
var pts = uptsvc.LoadEntityByNature(cctx, prop.Property.PropertyType.FullName, null, seras);
UserProfileType pt = pts != null && pts.Count > 0 ? pts[0] : null;
if (pt == null)
{
pt = new UserProfileType();
pt.SerializeType = seras;
pt.ClrType = prop.Property.PropertyType.FullName;
p.UserProfileTypeRef = pt;
}
else
p.TypeID = pt.ID;
p.ApplicationID = app.ID;
p.UserID = u.ID;
p.PropName = prop.Property.Name;
if (prop.Property.SerializeAs == SettingsSerializeAs.Binary)
{
p.StringValue = null;
p.IsStringValueModified = true;
p.IsStringValueLoaded = true;
p.BinaryValue = prop.SerializedValue == null ? null : (byte[])prop.SerializedValue;
p.IsBinaryValueModified = true;
p.IsBinaryValueLoaded = true;
}
else if (prop.Property.SerializeAs == SettingsSerializeAs.String || prop.Property.SerializeAs == SettingsSerializeAs.Xml || prop.Property.SerializeAs == SettingsSerializeAs.ProviderSpecific)
{
p.StringValue = prop.SerializedValue == null ? null : prop.SerializedValue as string;
p.IsStringValueModified = true;
p.IsStringValueLoaded = true;
p.BinaryValue = null;
p.IsBinaryValueModified = true;
p.IsBinaryValueLoaded = true;
}
else
{
//??
}
p.LastAccessTime = DateTime.UtcNow;
p.IsLastAccessTimeModified = true;
p.LastUpdateTime = p.LastAccessTime;
p.IsLastUpdateTimeModified = true;
newitems.Add(p);
}
UserProfileSet ups = new UserProfileSet();
if (newitems.Count > 0)
upsvc.AddOrUpdateEntities(cctx, ups, newitems.ToArray());
if (update.Count > 0)
upsvc.EnqueueNewOrUpdateEntities(cctx, ups, update.ToArray());
}
catch (Exception e)
{
throw e;
}
finally
{
}
}
/// <summary>
/// Delete profile properties and information for the supplied list of profiles.
/// </summary>
/// <param name="profiles">
/// A <see cref="ProfileInfoCollection"/> of information about profiles that are to be deleted.
/// </param>
/// <returns>
/// The number of profiles deleted from the data source.
/// </returns>
public override int DeleteProfiles(ProfileInfoCollection profiles)
{
List<string> ln = new List<string>();
foreach (ProfileInfo p in profiles)
ln.Add(p.UserName);
return DeleteProfiles(ln.ToArray());
}
/// <summary>
/// Delete profile properties and information for profiles that match the supplied list of user names.
/// </summary>
/// <param name="usernames">A string array of user names for profiles to be deleted.</param>
/// <returns>
/// The number of profiles deleted from the data source.
/// </returns>
public override int DeleteProfiles(string[] usernames)
{
CallContext cctx = _cctx.CreateCopy();
int deleteCount = 0;
try
{
UserServiceProxy usvc = new UserServiceProxy();
UserProfileServiceProxy upsvc = new UserProfileServiceProxy();
List<UserProfile> l = new List<UserProfile>();
UserProfileSet upset = new UserProfileSet();
bool banonymous = false;
Dictionary<string, bool> dic = new Dictionary<string, bool>();
foreach (string n in usernames)
{
if (n != null && !dic.ContainsKey(n))
continue;
User u = findUser(n);
if (u != null)
{
UserProfileSetConstraints cond = new UserProfileSetConstraints
{
ApplicationIDWrap = new ForeignKeyData<string> { KeyValue = app.ID },
TypeIDWrap = null,
UserIDWrap = new ForeignKeyData<string> { KeyValue = u.ID }
};
var ups = upsvc.ConstraintQuery(cctx, upset, cond, null);
foreach (UserProfile up in ups)
{
l.Add(up);
}
deleteCount++;
dic.Add(n, true);
}
else if (n == null && !banonymous)
{
UserProfileSetConstraints cond = new UserProfileSetConstraints
{
ApplicationIDWrap = new ForeignKeyData<string> { KeyValue = app.ID },
TypeIDWrap = null,
UserIDWrap = new ForeignKeyData<string> { KeyValue = u.ID }
};
var ups = upsvc.ConstraintQuery(cctx, upset, cond, null);
foreach (UserProfile up in ups)
{
l.Add(up);
}
deleteCount++;
banonymous = true;
}
}
if (l.Count > 0)
{
upsvc.DeleteEntities(cctx, upset, l.ToArray());
}
return deleteCount;
}
catch (Exception e)
{
if (WriteExceptionsToEventLog)
{
WriteToEventLog(e, "DeleteProfiles(ProfileInfoCollection)");
throw new ProviderException(exceptionMessage);
}
else
{
throw e;
}
}
finally
{
}
}
/// <summary>
/// Delete all user-profile data for profiles in which the last activity date occurred before the specified date.
/// </summary>
/// <param name="authenticationOption">
/// One of the <see cref="ProfileAuthenticationOption"/> values, specifying whether anonymous, authenticated, or both types of profiles are deleted.
/// </param>
/// <param name="userInactiveSinceDate">
/// A <see cref="DateTime"/> that identifies which user profiles are considered inactive. If the LastActivityDate value of a user profile occurs on
/// or before this date and time, the profile is considered inactive.
/// </param>
/// <returns>
/// The number of profiles deleted from the data source.
/// </returns>
public override int DeleteInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate)
{
CallContext cctx = _cctx.CreateCopy();
try
{
UserProfileServiceProxy upsvc = new UserProfileServiceProxy();
List<UserProfile> l = new List<UserProfile>();
UserProfileSet upset = new UserProfileSet();
QueryExpresion qexpr = new QueryExpresion();
qexpr.OrderTks = new List<QToken>(new QToken[] { new QToken { TkName = "PropName" } });
qexpr.FilterTks = new List<QToken>(new QToken[]{
new QToken { TkName = "ApplicationID" },
new QToken { TkName = "==" },
new QToken { TkName = "\"" + app.ID + "\"" }
});
if (authenticationOption == ProfileAuthenticationOption.Anonymous)
{
qexpr.FilterTks.AddRange(new QToken[]{
new QToken { TkName = "&&" },
new QToken { TkName = "UserID" },
new QToken { TkName = "is null" }
});
}
else if (authenticationOption == ProfileAuthenticationOption.Authenticated)
{
qexpr.FilterTks.AddRange(new QToken[]{
new QToken { TkName = "&&" },
new QToken { TkName = "UserID" },
new QToken { TkName = "is not null" }
});
}
qexpr.FilterTks.AddRange(new QToken[]{
new QToken { TkName = "&&" },
new QToken { TkName = "LastAccessTime" },
new QToken { TkName = "<=" },
new QToken { TkName = svc.FormatRepoDateTime(userInactiveSinceDate) },
});
var profs = upsvc.QueryDatabase(cctx, upset, qexpr);
foreach (UserProfile up in profs)
l.Add(up);
if (l.Count > 0)
{
upsvc.DeleteEntities(cctx, upset, l.ToArray());
}
return l.Count;
}
catch (Exception e)
{
if (WriteExceptionsToEventLog)
{
WriteToEventLog(e, "DeleteInactiveProfiles");
throw new ProviderException(exceptionMessage);
}
else
{
throw e;
}
}
finally
{
}
}
/// <summary>
/// Retrieve profile information for profiles in which the user name matches the specified user names.
/// </summary>
/// <param name="authenticationOption">
/// One of the <see cref="ProfileAuthenticationOption"/> values, specifying whether anonymous, authenticated, or both types of profiles are returned.
/// </param>
/// <param name="usernameToMatch">
/// The user name to search for.
/// </param>
/// <param name="pageIndex">
/// The index of the page of results to return.
/// </param>
/// <param name="pageSize">
/// The size of the page of results to return.
/// </param>
/// <param name="totalRecords">
/// When this method returns, contains the total number of profiles.
/// </param>
/// <returns>
/// A <see cref="ProfileInfoCollection"/> containing user-profile information for all profiles in the data source.
/// </returns>
public override ProfileInfoCollection FindProfilesByUserName(ProfileAuthenticationOption authenticationOption, string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
{
CheckParameters(pageIndex, pageSize);
return GetProfileInfo(authenticationOption, usernameToMatch,
null, pageIndex, pageSize, out totalRecords);
}
/// <summary>
/// Retrieve profile information for profiles in which the last activity date occurred on or before the specified date and the user name matches the
/// specified user name.
/// </summary>
/// <param name="authenticationOption">
/// One of the <see cref="ProfileAuthenticationOption"/> values, specifying whether anonymous, authenticated, or both types of profiles are returned.
/// </param>
/// <param name="usernameToMatch">
/// The user name to search for.
/// </param>
/// <param name="userInactiveSinceDate">
/// A <see cref="DateTime"/> that identifies which user profiles are considered inactive. If the LastActivityDate value of a user profile occurs on or before this date and time, the profile is considered inactive.
/// </param>
/// <param name="pageIndex">
/// The index of the page of results to return.
/// </param>
/// <param name="pageSize">
/// The size of the page of results to return.
/// </param>
/// <param name="totalRecords">
/// When this method returns, contains the total number of profiles.
/// </param>
/// <returns>
/// A <see cref="ProfileInfoCollection"/> containing user profile information for inactive profiles where the user name matches the supplied usernameToMatch parameter.
/// </returns>
public override ProfileInfoCollection FindInactiveProfilesByUserName(ProfileAuthenticationOption authenticationOption, string usernameToMatch, DateTime userInactiveSinceDate, int pageIndex, int pageSize, out int totalRecords)
{
CheckParameters(pageIndex, pageSize);
return GetProfileInfo(authenticationOption, usernameToMatch, userInactiveSinceDate,
pageIndex, pageSize, out totalRecords);
}
/// <summary>
/// Retrieve user profile data for all profiles in the data source.
/// </summary>
/// <param name="authenticationOption">
/// One of the <see cref="ProfileAuthenticationOption"/> values, specifying whether anonymous, authenticated, or both types of profiles are returned.
/// </param>
/// <param name="pageIndex">
/// The index of the page of results to return.
/// </param>
/// <param name="pageSize">
/// The size of the page of results to return.
/// </param>
/// <param name="totalRecords">
/// When this method returns, contains the total number of profiles.
/// </param>
/// <returns>
/// A <see cref="ProfileInfoCollection"/> containing user-profile information for profiles where the user name matches the supplied usernameToMatch parameter.
/// </returns>
public override ProfileInfoCollection GetAllProfiles(
ProfileAuthenticationOption authenticationOption,
int pageIndex,
int pageSize,
out int totalRecords)
{
CheckParameters(pageIndex, pageSize);
return GetProfileInfo(authenticationOption, null, null,
pageIndex, pageSize, out totalRecords);
}
/// <summary>
/// Retrieve user-profile data from the data source for profiles in which the last activity date occurred on or before the specified date.
/// </summary>
/// <param name="authenticationOption">
/// One of the <see cref="ProfileAuthenticationOption"/> values, specifying whether anonymous, authenticated, or both types of profiles are returned.
/// </param>
/// <param name="userInactiveSinceDate">
/// A <see cref="DateTime"/> that identifies which user profiles are considered inactive. If the LastActivityDate of a user profile occurs on or before this date and time,
/// the profile is considered inactive.
/// </param>
/// <param name="pageIndex">
/// The index of the page of results to return.
/// </param>
/// <param name="pageSize">
/// The size of the page of results to return.
/// </param>
/// <param name="totalRecords">
/// When this method returns, contains the total number of profiles.
/// </param>
/// <returns>
/// A <see cref="ProfileInfoCollection"/> containing user-profile information about the inactive profiles.
/// </returns>
public override ProfileInfoCollection GetAllInactiveProfiles(
ProfileAuthenticationOption authenticationOption,
DateTime userInactiveSinceDate,
int pageIndex,
int pageSize,
out int totalRecords)
{
CheckParameters(pageIndex, pageSize);
return GetProfileInfo(authenticationOption, null, userInactiveSinceDate,
pageIndex, pageSize, out totalRecords);
}
/// <summary>
/// Return the number of profiles in which the last activity date occurred on or before the specified date.
/// </summary>
/// <param name="authenticationOption">
/// One of the <see cref="ProfileAuthenticationOption"/> values, specifying whether anonymous, authenticated, or both types of profiles are returned.
/// </param>
/// <param name="userInactiveSinceDate">
/// A <see cref="DateTime"/> that identifies which user profiles are considered inactive. If the LastActivityDate of a user profile occurs on or before this date and time,
/// the profile is considered inactive.
/// </param>
/// <returns>The number of profiles in which the last activity date occurred on or before the specified date.</returns>
public override int GetNumberOfInactiveProfiles(
ProfileAuthenticationOption authenticationOption,
DateTime userInactiveSinceDate)
{
int inactiveProfiles = 0;
ProfileInfoCollection profiles =
GetProfileInfo(authenticationOption, null, userInactiveSinceDate,
0, 0, out inactiveProfiles);
return inactiveProfiles;
}
private void CheckParameters(int pageIndex, int pageSize)
{
if (pageIndex < 0)
throw new ArgumentException("Page index must 0 or greater.");
if (pageSize < 1)
throw new ArgumentException("Page size must be greater than 0.");
}
private ProfileInfoCollection GetProfileInfo(
ProfileAuthenticationOption authenticationOption,
string usernameToMatch,
object userInactiveSinceDate,
int pageIndex,
int pageSize,
out int totalRecords)
{
CallContext cctx = _cctx.CreateCopy();
try
{
UserProfileServiceProxy upsvc = new UserProfileServiceProxy();
UserProfileSet upset = new UserProfileSet();
QueryExpresion qexpr = new QueryExpresion();
qexpr.OrderTks = new List<QToken>(new QToken[] { new QToken { TkName = "PropName" } });
qexpr.FilterTks = new List<QToken>(new QToken[]{
new QToken { TkName = "ApplicationID" },
new QToken { TkName = "==" },
new QToken { TkName = "\"" + app.ID + "\"" }
});
if (authenticationOption == ProfileAuthenticationOption.Anonymous)
{
qexpr.FilterTks.AddRange(new QToken[]{
new QToken { TkName = "&&" },
new QToken { TkName = "UserID" },
new QToken { TkName = "is null" }
});
}
else if (authenticationOption == ProfileAuthenticationOption.Authenticated)
{
qexpr.FilterTks.AddRange(new QToken[]{
new QToken { TkName = "&&" },
new QToken { TkName = "UserID" },
new QToken { TkName = "is not null" }
});
}
if (usernameToMatch != null)
{
qexpr.FilterTks.AddRange(new QToken[]{
new QToken { TkName = "&&" },
new QToken { TkName = "UserRef." },
new QToken { TkName = "Username" },
new QToken { TkName = "contains" },
new QToken { TkName = "\"" + usernameToMatch + "\"" }
});
}
if (userInactiveSinceDate != null)
{
qexpr.FilterTks.AddRange(new QToken[]{
new QToken { TkName = "&&" },
new QToken { TkName = "LastAccessTime" },
new QToken { TkName = "<=" },
new QToken { TkName = svc.FormatRepoDateTime((DateTime)userInactiveSinceDate) },
});
}
totalRecords = (int)upsvc.QueryEntityCount(cctx, upset, qexpr);
UserProfile last = null;
int npages = 0;
UserProfilePageBlock pb = null;
UserProfilePageBlock prevpb = null;
int ipage = pageIndex;
bool failed = false;
while (npages <= pageIndex)
{
prevpb = pb;
pb = upsvc.NextPageBlock(cctx, upset, qexpr, last);
if (pb.BlockCount == 0)
{
failed = true;
break;
}
last = pb.Pages[pb.Pages.Length - 1].LastItem;
ipage -= npages;
npages += pb.BlockCount;
}
ProfileInfoCollection profiles = new ProfileInfoCollection();
if (failed)
return profiles;
UserProfilePage page = pb.Pages[ipage];
if (ipage > 0)
last = pb.Pages[ipage - 1].LastItem;
else
last = prevpb == null || prevpb.Pages.Length == 0 ? null : prevpb.Pages[prevpb.Pages.Length - 1].LastItem;
IEnumerable<UserProfile> l = upsvc.GetPageItems(cctx, upset, qexpr, last);
foreach (var up in l)
{
up.LoadUserRef();
ProfileInfo pi = new ProfileInfo(up.UserRef == null ? "anonymous" : up.UserRef.Username, up.UserRef == null, up.LastAccessTime.HasValue ? up.LastAccessTime.Value : DateTime.MinValue, up.LastUpdateTime.HasValue ? up.LastUpdateTime.Value : DateTime.MinValue, -1);
profiles.Add(pi);
}
return profiles;
}
catch (Exception e)
{
if (WriteExceptionsToEventLog)
{
WriteToEventLog(e, "DeleteInactiveProfiles");
throw new ProviderException(exceptionMessage);
}
else
{
throw e;
}
}
finally
{
}
}
private User findUser(string name)
{
UserServiceProxy usvc = new UserServiceProxy();
var usrs = usvc.LoadEntityByNature(_cctx.CreateCopy(), name);
if (usrs == null || usrs.Count == 0)
return null;
return usrs[0];
}
private void WriteToEventLog(Exception e, string action)
{
string message = "An exception occurred communicating with the data source.\n\n";
message += "Action: " + action;
Trace.Write(message);
Debug.Write(message);
/*
CallContext cctx = _cctx.CreateCopy();
if (log.IsErrorEnabled)
log.Error("[" + cctx.InVokePath + "]: " + message, e);
*/
}
private Type GetTypeFromSimpleName(string typeName)
{
if (typeName == null)
throw new ArgumentNullException("typeName");
bool isArray = false, isNullable = false;
if (typeName.IndexOf("[]") != -1)
{
isArray = true;
typeName = typeName.Remove(typeName.IndexOf("[]"), 2);
}
if (typeName.IndexOf("?") != -1)
{
isNullable = true;
typeName = typeName.Remove(typeName.IndexOf("?"), 1);
}
typeName = typeName.ToLower();
string parsedTypeName = null;
switch (typeName)
{
case "bool":
case "boolean":
parsedTypeName = "System.Boolean";
break;
case "byte":
parsedTypeName = "System.Byte";
break;
case "char":
parsedTypeName = "System.Char";
break;
case "datetime":
parsedTypeName = "System.DateTime";
break;
case "datetimeoffset":
parsedTypeName = "System.DateTimeOffset";
break;
case "decimal":
parsedTypeName = "System.Decimal";
break;
case "double":
parsedTypeName = "System.Double";
break;
case "float":
parsedTypeName = "System.Single";
break;
case "int16":
case "short":
parsedTypeName = "System.Int16";
break;
case "int32":
case "int":
parsedTypeName = "System.Int32";
break;
case "int64":
case "long":
parsedTypeName = "System.Int64";
break;
case "object":
parsedTypeName = "System.Object";
break;
case "sbyte":
parsedTypeName = "System.SByte";
break;
case "string":
parsedTypeName = "System.String";
break;
case "timespan":
parsedTypeName = "System.TimeSpan";
break;
case "uint16":
case "ushort":
parsedTypeName = "System.UInt16";
break;
case "uint32":
case "uint":
parsedTypeName = "System.UInt32";
break;
case "uint64":
case "ulong":
parsedTypeName = "System.UInt64";
break;
}
if (parsedTypeName != null)
{
if (isArray)
parsedTypeName = parsedTypeName + "[]";
if (isNullable)
parsedTypeName = String.Concat("System.Nullable`1[", parsedTypeName, "]");
}
else
parsedTypeName = typeName;
// Expected to throw an exception in case the type has not been recognized.
return Type.GetType(parsedTypeName);
}
}
}