/// <summary>
        /// Initializes the class. This includes loading application settings from the configuration file. The application name should be scoped within the system.
        /// For non web applications, this method must be called directly from the main executable assembly and not from a supporting library.
        ///
        /// To debug this method, create a folder called C:\AnyoneFullControl and give Everyone full control. A file will appear in that folder explaining how far
        /// it got in init.
        /// </summary>
        /// <param name="appName"></param>
        /// <param name="isClientSideProgram"></param>
        /// <param name="systemLogic"></param>
        /// <param name="mainDataAccessStateGetter">A method that returns the current main data-access state whenever it is requested, including during this
        /// AppTools.Init call. Do not allow multiple threads to use the same state at the same time. If you pass null, the data-access subsystem will not be
        /// available in the application.</param>
        public static void Init(string appName, bool isClientSideProgram, SystemLogic systemLogic, Func <DataAccessState> mainDataAccessStateGetter = null)
        {
            var initializationLog = "Starting init";

            try {
                if (initialized)
                {
                    throw new ApplicationException("This class can only be initialized once.");
                }

                if (systemLogic == null)
                {
                    throw new ApplicationException("The system must have a global logic class and you must pass an instance of it to AppTools.Init.");
                }

                // Initialize ConfigurationStatics, including the general provider, before the exception handling block below because it's reasonable for the exception
                // handling to depend on this.
                ConfigurationStatics.Init(systemLogic.GetType(), appName, isClientSideProgram, ref initializationLog);

                // Setting the initialized flag to true must be done before executing the secondary init block below so that exception handling works.
                initialized        = true;
                initializationLog += Environment.NewLine + "Succeeded in primary init.";
            }
            catch (Exception e) {
                initializationLog += Environment.NewLine + e;
                StandardLibraryMethods.EmergencyLog("Initialization log", initializationLog);
                throw;
            }

            try {
                var asposeLicense = ConfigurationStatics.SystemGeneralProvider.AsposeLicenseName;
                if (asposeLicense.Any())
                {
                    new Aspose.Pdf.License().SetLicense(asposeLicense);
                    new Aspose.Words.License().SetLicense(asposeLicense);
                }

                // This initialization could be performed using reflection. There is no need for AppTools to have a dependency on these classes.
                AppMemoryCache.Init();
                BlobFileOps.Init();
                DataAccessStatics.Init();
                DataAccessState.Init(mainDataAccessStateGetter);
                EncryptionOps.Init();
                HtmlBlockStatics.Init();
                InstallationSupportUtility.ConfigurationLogic.Init1();
                UserManagementStatics.Init();

                systemLogic.InitSystem();
            }
            catch (Exception e) {
                secondaryInitFailed = true;

                // Suppress all exceptions since they would prevent apps from knowing that primary initialization succeeded. EWF apps need to know this in order to
                // automatically restart themselves. Other apps could find this knowledge useful as well.
                try {
                    EmailAndLogError("An exception occurred during application initialization:", e);
                }
                catch {}
            }
        }
        internal AppRequestState( string url )
        {
            beginTime = DateTime.Now;
            MiniProfiler.Start();
            this.url = url;

            dataAccessState = new DataAccessState( databaseConnectionInitializer: initDatabaseConnection );
            dataAccessState.ResetCache();

            TransferRequestPath = "";

            // We cache the browser capabilities so we can determine the actual browser making the request even after modifying the capabilities, which we do later in
            // the life cycle from EwfPage.
            Browser = HttpContext.Current.Request.Browser;
        }
示例#3
0
        internal AppRequestState(string url)
        {
            beginInstant = SystemClock.Instance.GetCurrentInstant();
            MiniProfiler.Start();
            this.url = url;

            dataAccessState = new DataAccessState(databaseConnectionInitializer: initDatabaseConnection);
            dataAccessState.ResetCache();

            TransferRequestPath = "";

            // We cache the browser capabilities so we can determine the actual browser making the request even after modifying the capabilities, which we do later in
            // the life cycle from EwfPage.
            Browser = HttpContext.Current.Request.Browser;
        }
示例#4
0
        /// <summary>
        /// Initializes the system. This includes loading application settings from the configuration file. The application name should be scoped within the system.
        /// For non web applications, this method must be called directly from the main executable assembly and not from a supporting library.
        ///
        /// To debug this method, create a folder called C:\AnyoneFullControl and give Everyone full control. A file will appear in that folder explaining how far
        /// it got in init.
        /// </summary>
        /// <param name="globalInitializer">The system's global initializer. Do not pass null.</param>
        /// <param name="appName"></param>
        /// <param name="isClientSideApp"></param>
        /// <param name="assemblyFolderPath">Pass a nonempty string to override the assembly folder path, which is used to locate the installation folder. Use with
        /// caution.</param>
        /// <param name="mainDataAccessStateGetter">A method that returns the current main data-access state whenever it is requested, including during this
        /// InitStatics call. Do not allow multiple threads to use the same state at the same time. If you pass null, the data-access subsystem will not be
        /// available in the application.</param>
        /// <param name="useLongDatabaseTimeouts">Pass true if the application is a background process that can tolerate slow database access.</param>
        public static void InitStatics(
            SystemInitializer globalInitializer, string appName, bool isClientSideApp, string assemblyFolderPath = "",
            Func <DataAccessState> mainDataAccessStateGetter = null, bool useLongDatabaseTimeouts = false)
        {
            var initializationLog = "Starting init";

            try {
                if (initialized)
                {
                    throw new ApplicationException("This class can only be initialized once.");
                }

                if (globalInitializer == null)
                {
                    throw new ApplicationException("The system must have a global initializer.");
                }

                // Initialize these before the exception handling block below because it's reasonable for the exception handling to depend on them.
                ConfigurationStatics.Init(assemblyFolderPath, globalInitializer.GetType(), appName, isClientSideApp, ref initializationLog);
                EmailStatics.Init();
                TelemetryStatics.Init();

                // Setting the initialized flag to true must be done before executing the secondary init block below so that exception handling works.
                initialized        = true;
                initializationLog += Environment.NewLine + "Succeeded in primary init.";
            }
            catch (Exception e) {
                initializationLog += Environment.NewLine + e;
                EwlStatics.EmergencyLog("Initialization log", initializationLog);
                throw;
            }

            try {
                CultureInfo.DefaultThreadCurrentCulture = Cultures.EnglishUnitedStates;

                var asposePdfLicensePath = EwlStatics.CombinePaths(ConfigurationStatics.InstallationConfiguration.AsposeLicenseFolderPath, "Aspose.PDF.lic");
                if (File.Exists(asposePdfLicensePath))
                {
                    new Aspose.Pdf.License().SetLicense(asposePdfLicensePath);
                }
                var asposeWordsLicensePath = EwlStatics.CombinePaths(ConfigurationStatics.InstallationConfiguration.AsposeLicenseFolderPath, "Aspose.Words.lic");
                if (File.Exists(asposeWordsLicensePath))
                {
                    new Aspose.Words.License().SetLicense(asposeWordsLicensePath);
                }

                AppMemoryCache.Init();
                BlobStorageStatics.Init();
                DataAccessStatics.Init();
                DataAccessState.Init(mainDataAccessStateGetter, useLongDatabaseTimeouts);
                EncryptionOps.Init();
                HtmlBlockStatics.Init();
                UserManagementStatics.Init();

                GlobalInitializationOps.globalInitializer = globalInitializer;
                globalInitializer.InitStatics();
            }
            catch (Exception e) {
                secondaryInitFailed = true;

                // Suppress all exceptions since they would prevent apps from knowing that primary initialization succeeded. EWF apps need to know this in order to
                // automatically restart themselves. Other apps could find this knowledge useful as well.
                try {
                    TelemetryStatics.ReportError("An exception occurred during application initialization:", e);
                }
                catch {}
            }
        }
        /// <summary>
        /// It's important to call this from EwfPage instead of EwfApp because requests for some pages, with their associated images, CSS files, etc., can easily
        /// cause 20-30 server requests, and we only want to update the time stamp once for all of these.
        /// </summary>
        private void updateLastPageRequestTimeForUser( User user )
        {
            // Only update the request time if it's been more than a minute since we did it last. This can dramatically reduce concurrency issues caused by people
            // rapidly assigning tasks to one another in the System Manager or similar situations.
            if( ( DateTime.Now - user.LastRequestDateTime ) < TimeSpan.FromMinutes( 1 ) )
                return;

            // Now we want to do a timestamp-based concurrency check so we don't update the last login date if we know another transaction already did.
            // It is not perfect, but it reduces errors caused by one user doing a long-running request and then doing smaller requests
            // in another browser window while the first one is still running.
            // We have to query in a separate transaction because otherwise snapshot isolation will result in us always getting the original LastRequestDatetime, even if
            // another transaction has modified its value during this transaction.
            var newlyQueriedUser = new DataAccessState().ExecuteWithThis(
                () => {
                    Func<User> userGetter = () => UserManagementStatics.GetUser( user.UserId, false );
                    return ConfigurationStatics.DatabaseExists ? DataAccessState.Current.PrimaryDatabaseConnection.ExecuteWithConnectionOpen( userGetter ) : userGetter();
                } );
            if( newlyQueriedUser == null || newlyQueriedUser.LastRequestDateTime > user.LastRequestDateTime )
                return;

            Action userUpdater = () => {
                var externalAuthProvider = UserManagementStatics.SystemProvider as ExternalAuthUserManagementProvider;
                if( FormsAuthStatics.FormsAuthEnabled ) {
                    var formsAuthCapableUser = (FormsAuthCapableUser)user;
                    FormsAuthStatics.SystemProvider.InsertOrUpdateUser(
                        user.UserId,
                        user.Email,
                        user.Role.RoleId,
                        DateTime.Now,
                        formsAuthCapableUser.Salt,
                        formsAuthCapableUser.SaltedPassword,
                        formsAuthCapableUser.MustChangePassword );
                }
                else if( externalAuthProvider != null )
                    externalAuthProvider.InsertOrUpdateUser( user.UserId, user.Email, user.Role.RoleId, DateTime.Now );
            };
            if( ConfigurationStatics.DatabaseExists ) {
                DataAccessState.Current.PrimaryDatabaseConnection.ExecuteInTransaction(
                    () => {
                        try {
                            userUpdater();
                        }
                        catch( DbConcurrencyException ) {
                            // Since this method is called on every page request, concurrency errors are common. They are caused when an authenticated user makes one request
                            // and then makes another before ASP.NET has finished processing the first. Since we are only updating the last request date and time, we don't
                            // need to get an error email if the update fails.
                            throw new DoNotCommitException();
                        }
                    } );
            }
            else
                userUpdater();
        }