/// <summary>
        /// Contact the license server and activate the license. Applies only to commercial versions.
        /// </summary>
        /// <param name="appUrl">The URL to the root of the gallery application.</param>
        private void ActivateLicenseKey(string appUrl)
        {
            if (string.IsNullOrWhiteSpace(LicenseEmail))
            {
                IsValid          = false;
                KeyInvalidReason = "Missing e-mail address. Enter the e-mail address used when you purchased the license.";
                return;
            }

            // Call license activation web service
            // API info: https://docs.woothemes.com/document/software-add-on/
            //http://dev.galleryserverpro.com/woocommerce/?wc-api=software-api&request=activation&[email protected]&licence_key=GS-9659000f-f127-45a5-93ac-8d70d99b6adf&product_id=Gallery Server Enterprise&platform=http://localhost/dev/gs/default.aspx
            var url = $"{GlobalConstants.LicenseServerUrl}?wc-api=software-api&request=activation&email={Uri.EscapeDataString(LicenseEmail)}&licence_key={Uri.EscapeDataString(LicenseKey)}&product_id={Uri.EscapeDataString(LicenseType.GetDescription())}&platform={Uri.EscapeDataString(appUrl)}";

            LicenseServerResult licenseServerResult = null;
            string response = null;

            using (var client = new WebClient())
            {
                try
                {
                    response = client.DownloadString(url);
                }
                catch (WebException ex)
                {
                    // A web error occurred (most likely the web site is down). We don't want activation to be a hassle, so just go ahead and authorize.
                    // We'll store a hard-coded instance ID and then detect that if the user later attempts to deactivate to skip going to the server.
                    var msg = $"An error occurred communicating with the license server. {ex.GetType()}: {ex.Message}";
                    EventController.RecordEvent(msg, EventType.Error, null, Factory.LoadGallerySettings());;

                    licenseServerResult = new LicenseServerResult()
                    {
                        Activated = true, InstanceId = GlobalConstants.LicenseActivationFailedInstanceId
                    };
                }
            }

            if (licenseServerResult == null)
            {
                if (!string.IsNullOrWhiteSpace(response))
                {
                    try
                    {
                        // We got a string from the server. It should be JSON and convertable to a LicenseServerResult instance.
                        licenseServerResult = JsonConvert.DeserializeObject <LicenseServerResult>(response);
                    }
                    catch (ArgumentException ex)
                    {
                        var msg = $"An error occurred communicating with the license server. {ex.GetType()}: {ex.Message} HTTP response: {response}";

                        licenseServerResult = new LicenseServerResult()
                        {
                            Reset = false, Error = msg, Code = "801"
                        };
                    }
                    catch (InvalidCastException ex)
                    {
                        var msg = $"An error occurred communicating with the license server. {ex.GetType()}: {ex.Message} HTTP response: {response}";

                        licenseServerResult = new LicenseServerResult()
                        {
                            Reset = false, Error = msg, Code = "802"
                        };
                    }
                    catch (JsonReaderException ex)
                    {
                        var msg = $"An error occurred trying to deserialize a string that was expected to be JSON. {ex.GetType()}: {ex.Message} HTTP response: {response}";

                        licenseServerResult = new LicenseServerResult()
                        {
                            Reset = false, Error = msg, Code = "903"
                        };
                    }
                }
                else
                {
                    // If we get here the server call succeeded but we got an empty string.
                    licenseServerResult = new LicenseServerResult()
                    {
                        Activated = false, Error = "Server returned an empty response", Code = "803"
                    };
                }
            }

            if (licenseServerResult.Activated)
            {
                InstanceId = licenseServerResult.InstanceId;

                EventController.RecordEvent($"License {LicenseKey} activated.", EventType.Info, null, Factory.LoadGallerySettings());;
            }

            IsValid = licenseServerResult.Activated;

            if (!IsValid)
            {
                if (licenseServerResult.Code == "103")
                {
                    // User exceeded maximum number of activations.
                    KeyInvalidReason = $"The license could not be validated. {licenseServerResult.Message} {licenseServerResult.Error} (Code {licenseServerResult.Code}). Deactivate an existing gallery installation by navigating to the site settings page in that gallery and clicking the deactivate link, then return here and try again. If you need any help, feel free to <a href='https://galleryserverpro.com/get-support/#cntctfrm_contact_form'>contact us</a>.";
                }
                else
                {
                    KeyInvalidReason = $"The license could not be validated. {licenseServerResult.Message} {licenseServerResult.Error} (Code {licenseServerResult.Code}). You must enter a license key for {LicenseType.GetDescription()}. If your license key is for another edition, download the version_key.txt file from your <a href='https://galleryserverpro.com/my-account/'>subscriptions</a> page and copy it to the App_Data directory of the web application.";
                }

                var eventMsg = string.Concat(KeyInvalidReason, $" LicenseEmail={LicenseEmail}; LicenseKey={LicenseKey}; ProductId={LicenseType.GetDescription()}; URL={url}; Server response={response}");
                EventController.RecordEvent(eventMsg, EventType.Error, null, Factory.LoadGallerySettings());;
            }
        }
        /// <summary>
        /// Deactivates a license that was previously activated.
        /// </summary>
        /// <returns><c>true</c> if deactivation successful, <c>false</c> otherwise.</returns>
        public bool Deactivate()
        {
            // Call web service to deactivate key, then clear out LicenseKey, LicenseEmail, and InstanceId
            // API info: https://docs.woothemes.com/document/software-add-on/
            //http://dev.galleryserverpro.com/woocommerce/?wc-api=software-api&request=deactivation&[email protected]&licence_key=GS-9659000f-f127-45a5-93ac-8d70d99b6adf&product_id=Gallery Server Enterprise&platform=http://localhost/dev/gs/default.aspx&instance=1456851984
            var url = $"{GlobalConstants.LicenseServerUrl}?wc-api=software-api&request=deactivation&email={Uri.EscapeDataString(LicenseEmail)}&licence_key={Uri.EscapeDataString(LicenseKey)}&instance={Uri.EscapeDataString(InstanceId)}&product_id={Uri.EscapeDataString(LicenseType.GetDescription())}";
            // For debug purposes - causes error: var url = $"{LicenseServerUrl}?wc-api=software-api&request=deactivation&email={Uri.EscapeDataString(LicenseEmail)}&licence_key={Uri.EscapeDataString(LicenseKey)}&instance={Uri.EscapeDataString(InstanceId)}";

            LicenseServerResult licenseServerResult = null;

            string response = null;

            if (InstanceId != GlobalConstants.LicenseActivationFailedInstanceId)
            {
                using (var client = new WebClient())
                {
                    try
                    {
                        response = client.DownloadString(url);
                    }
                    catch (WebException ex)
                    {
                        // A web error occurred (most likely the web site is down).
                        var msg = $"An error occurred communicating with the license server. {ex.GetType()}: {ex.Message}";

                        if (ex.InnerException != null)
                        {
                            msg += $" {ex.InnerException.GetType()}: {ex.InnerException.Message}";
                        }

                        licenseServerResult = new LicenseServerResult()
                        {
                            Reset = false, Error = msg, Code = "901"
                        };
                    }
                }

                if (licenseServerResult == null)
                {
                    try
                    {
                        licenseServerResult = JsonConvert.DeserializeObject <LicenseServerResult>(response);
                    }
                    catch (ArgumentException ex)
                    {
                        var msg = $"An error occurred communicating with the license server. {ex.GetType()}: {ex.Message} HTTP response: {response}";

                        licenseServerResult = new LicenseServerResult()
                        {
                            Reset = false, Error = msg, Code = "902"
                        };
                    }
                    catch (InvalidCastException ex)
                    {
                        var msg = $"An error occurred communicating with the license server. {ex.GetType()}: {ex.Message} HTTP response: {response}";

                        licenseServerResult = new LicenseServerResult()
                        {
                            Reset = false, Error = msg, Code = "903"
                        };
                    }
                    catch (JsonReaderException ex)
                    {
                        var msg = $"An error occurred trying to deserialize a string that was expected to be JSON. {ex.GetType()}: {ex.Message} HTTP response: {response}";

                        licenseServerResult = new LicenseServerResult()
                        {
                            Reset = false, Error = msg, Code = "903"
                        };
                    }
                }
            }
            else
            {
                // When user originally activated the license, we couldn't reach the license server, but we treated it as a successful activation
                // to minimize user disruption. Since there's nothing to deactivate on the server, just mark it as deactivated and move on.
                licenseServerResult = new LicenseServerResult()
                {
                    Reset = true
                };
            }

            if (licenseServerResult.Reset)
            {
                LicenseEmail = string.Empty;
                LicenseKey   = string.Empty;
                InstanceId   = string.Empty;

                EventController.RecordEvent($"License {LicenseKey} deactivated.", EventType.Info, null, Factory.LoadGallerySettings());;
            }
            else
            {
                KeyInvalidReason = $"The license could not be deactivated. {licenseServerResult.Message} {licenseServerResult.Error} (Code {licenseServerResult.Code})";

                var eventMsg = string.Concat(KeyInvalidReason, $". LicenseEmail={LicenseEmail}; LicenseKey={LicenseKey}; InstanceId={InstanceId}; ProductId={LicenseType.GetDescription()}; URL={url}; Server response={response}");
                EventController.RecordEvent(eventMsg, EventType.Error, null, Factory.LoadGallerySettings());;
            }

            return(licenseServerResult.Reset);
        }