Follow

Advanced Integrations - Handling Multiple Organizations With One Installation

Avatar

Some of our more advanced integrations are setup to use multiple tenants or organizations on the same installation with each one having their own database connection string and course storage directories. This sample code will show you how to setup this functionality in your integration code.

 

 

ClientExternalConfiguration.cs

public const DEFAULT__ORGANIZATION = string.Empty;

public string Organization = DEFAULT_ORGANIZATION;

 

ClientIntegration.cs

        #region Application Utilities

        /// <summary>

        /// See <see cref="IntegrationInterface.GetConnectionString"/> for a full description. This implementation uses the <see cref="GetConfigurationSetting"/> method to read the

        /// connection string from the web.config using the parameter name stored in <see cref="Constants.CONFIG_DB_CONNECTION_INFO"/>.

        /// </summary>

        /// <param name="externalConfig">External configuration information.</param>

        /// <returns>The database connection string.</returns>

        public override string GetConnectionString(ExternalConfiguration externalConfig)

        {

            ClientExternalConfiguration myExternalConfig = externalConfig as ClientExternalConfiguration;

 

            if (myExternalConfig == null)

            {

                throw new ScormContentPlayerApplicationException("The external configuration argument was not a valid ClientExternalConfiguration object.");

            }

 

            if (String.IsNullOrEmpty(myExternalConfig.Organization))

            {

                return base.GetConnectionString(externalConfig);

            }

 

            string connString = GetConfigurationSetting("OrganizationDatabaseConnectionString");

 

            if (String.IsNullOrEmpty(connString))

            {

                throw new ScormContentPlayerApplicationException("Missing configuration parameter for \"OrganizationDatabaseConnectionString\" in the SCP web.config");

            }

 

            connString = connString.Replace("@Organization@", myExternalConfig.Organization);

 

            return connString;

        }

 

        #endregion

 

        #region OPTIONAL: Import Functions:  Implement when using the SCP-provided Import Web Controls

 

        /// <summary>

        /// See <see cref="IntegrationInterface.GetFilePathToUploadedZippedPackage"/> for a full description.

        /// </summary>

        /// <param name="externalConfig">External configuration information.</param>

        /// <returns>The URL listed in the configuration repository under the <see cref="Constants.CONFIG_FILE_PATH_TO_UPLOADED_ZIPPED_PACKAGE"/> setting</returns>

        public override string GetFilePathToUploadedZippedPackage(ExternalConfiguration externalConfig)

        {

            ClientExternalConfiguration myExternalConfig = externalConfig as ClientExternalConfiguration;

 

            if (myExternalConfig == null)

            {

                throw new ScormContentPlayerApplicationException("The external configuration argument was not a valid ClientExternalConfiguration object.");

            }

 

            if (String.IsNullOrEmpty(myExternalConfig.Organization))

            {

                return base.GetFilePathToUploadedZippedPackage(externalConfig);

            }

 

            string uploadDir = this.GetConfigurationSetting("OrganizationFilePathToUploadedZippedPackage");

 

            if (uploadDir == null || uploadDir.Length == 0)

            {

                throw new ScormContentPlayerApplicationException("Missing configuration parameter for \"OrganizationFilePathToUploadedZippedPackage\" in the SCP Central web.config");

            }

 

            uploadDir = uploadDir.Replace("@Organization@", myExternalConfig.Organization);

 

            // Make sure the file path we return includes a trailing backslash

            if (!uploadDir.EndsWith(@"\"))

            {

                uploadDir += @"\";

            }

 

            return uploadDir;

        }

 

        /// <summary>

        /// See <see cref="IntegrationInterface.GetFilePathToContent"/> for a full description.

        /// </summary>

        /// <param name="courseName">Used to name the directory in which the uploaded course is placed.</param>

        /// <param name="externalConfig">External configuration information.</param>

        /// <returns>The file path listed in the configuration repository under the <see cref="Constants.CONFIG_FILE_PATH_TO_UPLOADED_ZIPPED_PACKAGE"/> setting

        /// with the course name appended to the end.</returns>

        public override String GetFilePathToContent(string courseName, ExternalConfiguration externalConfig)

        {

            ClientExternalConfiguration myExternalConfig = externalConfig as ClientExternalConfiguration;

 

            if (myExternalConfig == null)

            {

                throw new ScormContentPlayerApplicationException(

                    "The external configuration argument was not a valid ClientExternalConfiguration object.");

            }

 

            if (String.IsNullOrEmpty(myExternalConfig.Organization))

            {

                return base.GetFilePathToContent(courseName, externalConfig);

            }

 

            //string courseDir = ConfigurationSettings.AppSettings.Get("FilePathToContentRoot");

            string courseDir = this.GetConfigurationSetting("OrganizationFilePathToContentRoot");

 

            if (courseDir == null || courseDir.Length == 0)

            {

                throw new ScormContentPlayerApplicationException("Missing configuration parameter for \"OrganizationFilePathToContentRoot\" in the SCP Central web.config");

            }

            courseDir = courseDir.Replace("@Organization@", myExternalConfig.Organization);

 

            // Make sure the course dir has a trailing backslash, regardless of whether

            // the web.config entry had one

            if (!courseDir.EndsWith(@"\"))

            {

                courseDir += @"\";

            }

 

            string contentLocation = courseDir + courseName;

 

            // Append a timestamp for uniqueness.  This is good for any system because the zip filename certainly can't be guaranteed

            // to be unique, but especially necessary for systems that utilize versionings.  We could do a simple guid for the content

            // directory, but by using the zip name and this timestamp it provides a simpler means of identifying course files on

            // the filesystem

            if (Directory.Exists(contentLocation))

            {

                contentLocation += DateTime.Now.ToString("-yyyyMMddHHmmss");

            }

 

            // Make sure the file path we return includes a trailing backslash

            if (!contentLocation.EndsWith(@"\"))

            {

                contentLocation += @"\";

            }

 

            return contentLocation;

        }

 

        /// <summary>

        /// See <see cref="IntegrationInterface.GetWebPathToContent"/> for a full description.

        /// </summary>

        /// <param name="filePathToContent">The filesystem path to the root of the content.</param>

        /// <param name="externalConfig">External configuration information.</param>

        /// <returns>The value saved in the <see cref="Constants.CONFIG_WEB_PATH_TO_CONTENT_ROOT"/> configuration setting

        /// with the relative directory of the content appended.</returns>

        public override string GetWebPathToContent(string filePathToContent, ExternalConfiguration externalConfig)

        {

            ClientExternalConfiguration myExternalConfig = externalConfig as ClientExternalConfiguration;

 

            if (myExternalConfig == null)

            {

                throw new ScormContentPlayerApplicationException(

                    "The external configuration argument was not a valid ClientExternalConfiguration object.");

            }

 

            if (String.IsNullOrEmpty(myExternalConfig.Organization))

            {

                return base.GetWebPathToContent(filePathToContent, externalConfig);

            }

 

            filePathToContent = filePathToContent.ToLower();

 

            string webPathRoot = this.GetConfigurationSetting("OrganizationWebPathToContentRoot");

 

            if (webPathRoot == null || webPathRoot.Length == 0)

            {

                throw new ScormContentPlayerApplicationException("Missing configuration parameter for \"OrganizationWebPathToContentRoot\" in the SCP Central web.config");

            }

 

            webPathRoot = webPathRoot.Replace("@Organization@", myExternalConfig.Organization).ToLower(); ;

 

            // Make sure the web path we return includes a trailing forward slash

            if (!webPathRoot.EndsWith(@"/"))

            {

                webPathRoot += @"/";

            }

 

            string filePathRoot = this.GetConfigurationSetting("OrganizationFilePathToContentRoot");

            filePathRoot = filePathRoot.Replace("@Organization@", myExternalConfig.Organization).ToLower();

 

            // Make sure the web path we return includes a trailing forward slash

            if (!filePathRoot.EndsWith(@"\"))

            {

                filePathRoot += @"\";

            }

 

            string relativeCourseDir = filePathToContent.Replace(filePathRoot, "");

            relativeCourseDir = relativeCourseDir.Replace('\\', '/');

            string webPathToContent = webPathRoot + relativeCourseDir;

 

            return webPathToContent;

        }

 

        #endregion

 

Was this article helpful?
1 out of 1 found this helpful
Have more questions? Submit a request
Powered by Zendesk