Click here to Skip to main content
15,892,737 members
Articles / Web Development

Service Based Membership Providers for ASP.NET

Rate me:
Please Sign up or sign in to vote.
4.93/5 (45 votes)
4 May 2014CPOL29 min read 132K   8.2K   173  
Service based, multi-application ASP.NET custom membership, role and profile providers with a hierarchical role system.
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);
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Founder CryptoGateway Software Inc.
Canada Canada


His interests in software research and development include security, domain specific meta-language development technologies and tools, meta-language driven code generation, generation of non-invasive and virtual SQL database for "un-structured" data (sqlization), automated relational data service production technologies, file system sqlization technologies and products, structured multi-lingual documentation tools and technologies, sqlization of user's personal data, like emails, etc..


He was a physicist before year 2000. He studied theoretical physics (the hidden symmetry between the past and future, quantum field theories, mirror universe, cosmological dark energies etc.) in which he think to had made fundamental breakthroughs[^] but the community is either not ready for it or is actively rejecting/ignoring it Smile | :) .



It struck me on Apr. 11, 2023 that the said theory above can even generate General Relativity naturally after a recent discussion in the Insider News group that triggers a rethinking of the subject on my side. The first stage of the work is completed in Sept. 2023, it is and will be continue to be published online

  • On Vacuum
  • Quantum and Gravity







    Most recent software system to share:



    • V-NET[^] - Full stack virtualization management system including networking, storage, virtual machines and containers, with an emphasis on networking ... to be released.

Comments and Discussions