From d94c94d30e16a10cd8f267c2f4ad8c3b0bf89ff4 Mon Sep 17 00:00:00 2001 From: Ahmed Elsawalhy Date: Thu, 29 Apr 2021 15:32:44 +0200 Subject: [PATCH] Improved: connection readiness performance. --- .../AssemblyRegistration.cs | 8 +- .../CrmPluginRegExt.VSPackage.csproj | 23 +- .../Dialogs/Login.xaml.cs | 2 +- .../Helpers/CrmDataHelper.cs | 3 +- .../MessageEventArgs.cs | 13 - .../Properties/AssemblyInfo.cs | 4 +- .../ProviderSolutionProps.cs | 1 - CrmCodeGenerator.VSPackage/QuickConnection.cs | 117 --- CrmCodeGenerator.VSPackage/deviceidmanager.cs | 799 ------------------ CrmCodeGenerator.VSPackage/packages.config | 12 +- .../source.extension.vsixmanifest | 2 +- README.md | 4 +- 12 files changed, 30 insertions(+), 958 deletions(-) delete mode 100644 CrmCodeGenerator.VSPackage/MessageEventArgs.cs delete mode 100644 CrmCodeGenerator.VSPackage/ProviderSolutionProps.cs delete mode 100644 CrmCodeGenerator.VSPackage/QuickConnection.cs delete mode 100644 CrmCodeGenerator.VSPackage/deviceidmanager.cs diff --git a/CrmCodeGenerator.VSPackage/AssemblyRegistration.cs b/CrmCodeGenerator.VSPackage/AssemblyRegistration.cs index 152db6b..48cf6b1 100644 --- a/CrmCodeGenerator.VSPackage/AssemblyRegistration.cs +++ b/CrmCodeGenerator.VSPackage/AssemblyRegistration.cs @@ -429,8 +429,10 @@ private void RefreshTypes(List existingTypeNames) UpdateStatus($"Refreshing '{className}' ... "); Guid? typeId; - - using (var context = new XrmServiceContext(GetConnection(ConnectionString)) { MergeOption = MergeOption.NoTracking }) + + var service = GetConnection(ConnectionString); + + using (var context = new XrmServiceContext(service) { MergeOption = MergeOption.NoTracking }) { typeId = (from typeQ in context.PluginTypeSet @@ -457,7 +459,7 @@ private void RefreshTypes(List existingTypeNames) UpdateStatus($"Refreshing type '{updatedType.Id}' ... "); - GetConnection(ConnectionString).Update(updatedType); + service.Update(updatedType); UpdateStatus($"Finished refreshing '{className}'."); }); diff --git a/CrmCodeGenerator.VSPackage/CrmPluginRegExt.VSPackage.csproj b/CrmCodeGenerator.VSPackage/CrmPluginRegExt.VSPackage.csproj index e59cf0b..6653605 100644 --- a/CrmCodeGenerator.VSPackage/CrmPluginRegExt.VSPackage.csproj +++ b/CrmCodeGenerator.VSPackage/CrmPluginRegExt.VSPackage.csproj @@ -88,7 +88,7 @@ True - ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.26\lib\net462\Microsoft.Crm.Sdk.Proxy.dll + ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.25\lib\net462\Microsoft.Crm.Sdk.Proxy.dll @@ -98,7 +98,7 @@ ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.19.8\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll - ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.1.0.49\lib\net462\Microsoft.Rest.ClientRuntime.dll + ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.1.0.68\lib\net462\Microsoft.Rest.ClientRuntime.dll ..\packages\WindowsAzure.ServiceBus.2.5.1.0\lib\net40-full\Microsoft.ServiceBus.dll @@ -321,19 +321,20 @@ True - ..\packages\Yagasoft.Libraries.EnhancedOrgService.5.1.3\lib\net462\Microsoft.Xrm.Client.dll + ..\packages\Yagasoft.Libraries.EnhancedOrgService.5.3.2\lib\net462\Microsoft.Xrm.Client.dll - ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.26\lib\net462\Microsoft.Xrm.Sdk.dll + ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.25\lib\net462\Microsoft.Xrm.Sdk.dll - ..\packages\Microsoft.CrmSdk.Deployment.9.0.2.26\lib\net462\Microsoft.Xrm.Sdk.Deployment.dll + ..\packages\Microsoft.CrmSdk.Deployment.9.0.2.25\lib\net462\Microsoft.Xrm.Sdk.Deployment.dll - ..\packages\Microsoft.CrmSdk.Workflow.9.0.2.26\lib\net462\Microsoft.Xrm.Sdk.Workflow.dll + ..\packages\Microsoft.CrmSdk.Workflow.9.0.2.25\lib\net462\Microsoft.Xrm.Sdk.Workflow.dll - ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.1.0.49\lib\net462\Microsoft.Xrm.Tooling.Connector.dll + ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.1.0.68\lib\net462\Microsoft.Xrm.Tooling.Connector.dll + True ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll @@ -409,10 +410,10 @@ True - ..\packages\Yagasoft.Libraries.Common.2.4.3\lib\net462\Yagasoft.Libraries.Common.dll + ..\packages\Yagasoft.Libraries.Common.2.4.5\lib\net462\Yagasoft.Libraries.Common.dll - ..\packages\Yagasoft.Libraries.EnhancedOrgService.5.1.3\lib\net462\Yagasoft.Libraries.EnhancedOrgService.dll + ..\packages\Yagasoft.Libraries.EnhancedOrgService.5.3.2\lib\net462\Yagasoft.Libraries.EnhancedOrgService.dll @@ -438,7 +439,6 @@ - Login.xaml @@ -465,7 +465,6 @@ - @@ -476,8 +475,6 @@ - - True True diff --git a/CrmCodeGenerator.VSPackage/Dialogs/Login.xaml.cs b/CrmCodeGenerator.VSPackage/Dialogs/Login.xaml.cs index 568f577..f60bdc3 100644 --- a/CrmCodeGenerator.VSPackage/Dialogs/Login.xaml.cs +++ b/CrmCodeGenerator.VSPackage/Dialogs/Login.xaml.cs @@ -39,7 +39,7 @@ public partial class Login : INotifyPropertyChanged { #region Properties - private const string WindowTitle = "Plugin Registration Extension v2.2.3"; + private const string WindowTitle = "Plugin Registration Extension v2.2.4"; private Settings settings; private readonly SettingsArray settingsArray; diff --git a/CrmCodeGenerator.VSPackage/Helpers/CrmDataHelper.cs b/CrmCodeGenerator.VSPackage/Helpers/CrmDataHelper.cs index 64552c8..5ef6067 100644 --- a/CrmCodeGenerator.VSPackage/Helpers/CrmDataHelper.cs +++ b/CrmCodeGenerator.VSPackage/Helpers/CrmDataHelper.cs @@ -1,6 +1,7 @@ #region Imports using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using CrmPluginEntities; @@ -37,7 +38,7 @@ internal static class CrmDataHelper { public static List MessageList = new List(); public static List UserList = new List(); - public static Dictionary> AttributeList = new Dictionary>(); + public static IDictionary> AttributeList = new ConcurrentDictionary>(); internal static List GetEntityNames(string connectionString, bool cached = true) { diff --git a/CrmCodeGenerator.VSPackage/MessageEventArgs.cs b/CrmCodeGenerator.VSPackage/MessageEventArgs.cs deleted file mode 100644 index 7aa3a5e..0000000 --- a/CrmCodeGenerator.VSPackage/MessageEventArgs.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace CrmPluginRegExt.VSPackage -{ - public class MessageEventArgs : EventArgs - { - public string Message { get; set; } - public string MessageExtended { get; set; } - } -} diff --git a/CrmCodeGenerator.VSPackage/Properties/AssemblyInfo.cs b/CrmCodeGenerator.VSPackage/Properties/AssemblyInfo.cs index 7f0a35a..1959e82 100644 --- a/CrmCodeGenerator.VSPackage/Properties/AssemblyInfo.cs +++ b/CrmCodeGenerator.VSPackage/Properties/AssemblyInfo.cs @@ -30,8 +30,8 @@ // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("2.2.3.0")] -[assembly: AssemblyFileVersion("2.2.3.0")] +[assembly: AssemblyVersion("2.2.4.0")] +[assembly: AssemblyFileVersion("2.2.4.0")] [assembly: ProvideBindingRedirection(AssemblyName = "Microsoft.Xrm.Sdk", diff --git a/CrmCodeGenerator.VSPackage/ProviderSolutionProps.cs b/CrmCodeGenerator.VSPackage/ProviderSolutionProps.cs deleted file mode 100644 index 5f28270..0000000 --- a/CrmCodeGenerator.VSPackage/ProviderSolutionProps.cs +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/CrmCodeGenerator.VSPackage/QuickConnection.cs b/CrmCodeGenerator.VSPackage/QuickConnection.cs deleted file mode 100644 index 63597a6..0000000 --- a/CrmCodeGenerator.VSPackage/QuickConnection.cs +++ /dev/null @@ -1,117 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Microsoft.Xrm.Sdk; -using Microsoft.Xrm.Sdk.Client; -using Microsoft.Xrm.Sdk.Discovery; -using System.ServiceModel.Description; - -namespace CrmPluginRegExt.VSPackage -{ - public class QuickConnection - { - public static IOrganizationService Connect(string url, string domain, string username, string password, string organization) - { - //var connectionString = @"Url=" + url + "; Username=" + username + "; password=" + password + ";"; - //var connection = new Microsoft.Xrm.Client.CrmConnection(connectionString); - //var test = new Microsoft.Xrm.Client.Services.OrganizationService(connection); - //return test; - - var credentials = GetCredentials(url, domain, username, password); - ClientCredentials deviceCredentials = null; - if (url.IndexOf("dynamics.com", StringComparison.InvariantCultureIgnoreCase) > -1) - { - deviceCredentials = DeviceIdManager.LoadOrRegisterDevice(new Guid()); - } - - Uri orgUri = null; - OrganizationServiceProxy sdk = null; - - using (DiscoveryServiceProxy disco = new DiscoveryServiceProxy(new Uri(url), null, credentials, deviceCredentials)) - { - if (disco != null) - { - OrganizationDetailCollection orgs = DiscoverOrganizations(disco); - if (orgs.Count > 0) - { - var found = orgs.ToList() - .Where(a => a.UniqueName.Equals(organization, StringComparison.InvariantCultureIgnoreCase)) - .Take(1).SingleOrDefault(); - - if (found != null) - { - orgUri = new Uri(found.Endpoints[EndpointType.OrganizationService]); - } - } - } - } - - if (orgUri != null) - { - sdk = new OrganizationServiceProxy(orgUri, null, credentials, deviceCredentials); - } - - return sdk; - } - - public static List GetOrganizations(string url, string domain, string username, string password) - { - var results = new List() { }; - var credentials = GetCredentials(url, domain, username, password); - ClientCredentials deviceCredentials = null; - if (url.IndexOf("dynamics.com", StringComparison.InvariantCultureIgnoreCase) > -1) - { - deviceCredentials = DeviceIdManager.LoadOrRegisterDevice(new Guid()); // TODO this was failing with some online connections - } - - using (DiscoveryServiceProxy disco = new DiscoveryServiceProxy(new Uri(url), null, credentials, deviceCredentials)) - { - if (disco != null) - { - OrganizationDetailCollection orgs = DiscoverOrganizations(disco); - if (orgs.Count > 0) - { - results = orgs.Select(o => o.FriendlyName).ToList(); - } - } - } - - return results; - } - - - - private static OrganizationDetailCollection DiscoverOrganizations(DiscoveryServiceProxy service) - { - RetrieveOrganizationsRequest request = new RetrieveOrganizationsRequest(); - RetrieveOrganizationsResponse response = (RetrieveOrganizationsResponse)service.Execute(request); - - return response.Details; - } - - private static ClientCredentials GetCredentials(string url, string domain, string username, string password) - { - ClientCredentials credentials = new ClientCredentials(); - - var config = ServiceConfigurationFactory.CreateConfiguration(new Uri(url)); - - if (config.AuthenticationType == AuthenticationProviderType.ActiveDirectory) - { - credentials.Windows.ClientCredential = new System.Net.NetworkCredential(username, password, domain); - } - else if (config.AuthenticationType == AuthenticationProviderType.Federation - || config.AuthenticationType == AuthenticationProviderType.LiveId - || config.AuthenticationType == AuthenticationProviderType.OnlineFederation) - { - credentials.UserName.UserName = username; - credentials.UserName.Password = password; - } - else if (config.AuthenticationType == AuthenticationProviderType.None) - { - } - - return credentials; - } - } -} diff --git a/CrmCodeGenerator.VSPackage/deviceidmanager.cs b/CrmCodeGenerator.VSPackage/deviceidmanager.cs deleted file mode 100644 index 24966b3..0000000 --- a/CrmCodeGenerator.VSPackage/deviceidmanager.cs +++ /dev/null @@ -1,799 +0,0 @@ -using System; -using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.IO; -using System.Net; -using System.Runtime.Serialization; -using System.Security.Cryptography; -using System.ServiceModel.Description; -using System.Text; -using System.Windows.Forms; -using System.Xml; -using System.Xml.Serialization; - - - - -// TODO this was taken from XrmToolBox, but will it work with the standard DeviceIdManager from Microsoft??? I think it will - - -/// -/// Management utility for the Device Id -/// -public static class DeviceIdManager -{ - #region Fields - private static readonly Random RandomInstance = new Random(); - #endregion - - #region Methods - /// - /// Loads the device credentials (if they exist). If they don't - /// - /// - public static ClientCredentials LoadOrRegisterDevice(Guid applicationId) - { - return LoadOrRegisterDevice(null, applicationId); - } - - /// - /// Loads the device credentials (if they exist). If they don't - /// - /// URL for the current token issuer - /// - /// The issuerUri can be retrieved from the IServiceConfiguration interface's CurrentIssuer property. - /// - public static ClientCredentials LoadOrRegisterDevice(Uri issuerUri, Guid applicationId) - { - ClientCredentials credentials = LoadDeviceCredentials(issuerUri); - if (null == credentials) - { - credentials = RegisterDevice(applicationId, issuerUri); - } - - return credentials; - } - - /// - /// Registers the given device with Live ID with a random application ID - /// - /// ClientCredentials that were registered - public static ClientCredentials RegisterDevice() - { - return RegisterDevice(Guid.NewGuid()); - } - - /// - /// Registers the given device with Live ID - /// - /// ID for the application - /// ClientCredentials that were registered - public static ClientCredentials RegisterDevice(Guid applicationId) - { - return RegisterDevice(applicationId, (Uri)null); - } - - /// - /// Registers the given device with Live ID - /// - /// ID for the application - /// URL for the current token issuer - /// ClientCredentials that were registered - /// - /// The issuerUri can be retrieved from the IServiceConfiguration interface's CurrentIssuer property. - /// - public static ClientCredentials RegisterDevice(Guid applicationId, Uri issuerUri) - { - return RegisterDevice(applicationId, issuerUri, null, null); - } - - /// - /// Registers the given device with Live ID - /// - /// ID for the application - /// Device name that should be registered - /// Device password that should be registered - /// ClientCredentials that were registered - public static ClientCredentials RegisterDevice(Guid applicationId, string deviceName, string devicePassword) - { - return RegisterDevice(applicationId, (Uri)null, deviceName, devicePassword); - } - - /// - /// Registers the given device with Live ID - /// - /// ID for the application - /// URL for the current token issuer - /// Device name that should be registered - /// Device password that should be registered - /// ClientCredentials that were registered - /// - /// The issuerUri can be retrieved from the IServiceConfiguration interface's CurrentIssuer property. - /// - public static ClientCredentials RegisterDevice(Guid applicationId, Uri issuerUri, string deviceName, string devicePassword) - { - if (string.IsNullOrWhiteSpace(deviceName) != string.IsNullOrWhiteSpace(devicePassword)) - { - throw new ArgumentNullException("deviceName", "Either deviceName/devicePassword should both be specified or they should be null."); - } - - DeviceUserName userNameCredentials; - if (string.IsNullOrWhiteSpace(deviceName)) - { - userNameCredentials = GenerateDeviceUserName(); - } - else - { - userNameCredentials = new DeviceUserName() { DeviceName = deviceName, DecryptedPassword = devicePassword }; - } - - return RegisterDevice(applicationId, issuerUri, userNameCredentials); - } - - /// - /// Loads the device's credentials from the file system - /// - /// Device Credentials (if set) or null - public static ClientCredentials LoadDeviceCredentials() - { - return LoadDeviceCredentials(null); - } - - /// - /// Loads the device's credentials from the file system - /// - /// URL for the current token issuer - /// Device Credentials (if set) or null - /// - /// The issuerUri can be retrieved from the IServiceConfiguration interface's CurrentIssuer property. - /// - public static ClientCredentials LoadDeviceCredentials(Uri issuerUri) - { - string environment = DiscoverEnvironment(issuerUri); - - LiveDevice device = ReadExistingDevice(environment); - if (null == device || null == device.User) - { - return null; - } - - return device.User.ToClientCredentials(); - } - #endregion - - #region Private Methods - private static void Serialize(Stream stream, T value) - { - XmlSerializer serializer = new XmlSerializer(typeof(T), string.Empty); - - XmlSerializerNamespaces xmlNamespaces = new XmlSerializerNamespaces(); - xmlNamespaces.Add(string.Empty, string.Empty); - - serializer.Serialize(stream, value, xmlNamespaces); - } - - private static T Deserialize(Stream stream) - { - XmlSerializer serializer = new XmlSerializer(typeof(T), string.Empty); - return (T)serializer.Deserialize(stream); - } - - private static FileInfo GetDeviceFile(string environment) - { - return new FileInfo(string.Format(CultureInfo.InvariantCulture, LiveIdConstants.LiveDeviceFileNameFormat, - string.IsNullOrWhiteSpace(environment) ? null : "-" + environment.ToUpperInvariant())); - } - - private static ClientCredentials RegisterDevice(Guid applicationId, Uri issuerUri, DeviceUserName userName) - { - bool doContinue = true; - int attempt = 1; - - while (doContinue) - { - string environment = DiscoverEnvironment(issuerUri); - - LiveDevice device = new LiveDevice() { User = userName, Version = 1 }; - - DeviceRegistrationRequest request = new DeviceRegistrationRequest(applicationId, device); - - string url = string.Format(CultureInfo.InvariantCulture, LiveIdConstants.RegistrationEndpointUriFormat, - string.IsNullOrWhiteSpace(environment) ? null : "-" + environment); - - - try - { - DeviceRegistrationResponse response = ExecuteRegistrationRequest(url, request); - if (!response.IsSuccess) - { - throw new DeviceRegistrationFailedException(response.RegistrationErrorCode.GetValueOrDefault(), response.ErrorSubCode); - } - - WriteDevice(environment, device); - } - catch (Exception error) - { - if (error.Message.ToLower().Contains("unknown")) - { - if (attempt > 3) - { - if (MessageBox.Show("Failed to connect 3 times.\r\n\r\nDo you want to retry?", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No) - { - doContinue = false; - } - } - - attempt++; - } - else - { - throw error; - } - } - - return device.User.ToClientCredentials(); - } - - return null; - } - - private static LiveDevice ReadExistingDevice(string environment) - { - //Retrieve the file info - FileInfo file = GetDeviceFile(environment); - if (!file.Exists) - { - return null; - } - - // Ajout Tanguy - file.Delete(); - return null; - - //using (FileStream stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.Read)) - //{ - // return Deserialize(stream); - //} - } - - private static void WriteDevice(string environment, LiveDevice device) - { - FileInfo file = GetDeviceFile(environment); - if (!file.Directory.Exists) - { - file.Directory.Create(); - } - - using (FileStream stream = file.Open(FileMode.Create, FileAccess.Write, FileShare.None)) - { - Serialize(stream, device); - } - } - - private static DeviceRegistrationResponse ExecuteRegistrationRequest(string url, DeviceRegistrationRequest registrationRequest) - { - //Create the request that will submit the request to the server - WebRequest request = WebRequest.Create(url); - request.ContentType = "application/soap+xml; charset=UTF-8"; - request.Method = "POST"; - request.Timeout = 180000; - request.Proxy.Credentials = System.Net.CredentialCache.DefaultCredentials; - - //Write the envelope to the RequestStream - using (Stream stream = request.GetRequestStream()) - { - Serialize(stream, registrationRequest); - } - - // Read the response into an XmlDocument and return that doc - try - { - using (WebResponse response = request.GetResponse()) - { - using (Stream stream = response.GetResponseStream()) - { - return Deserialize(stream); - } - } - } - catch (WebException ex) - { - if (null != ex.Response) - { - using (Stream stream = ex.Response.GetResponseStream()) - { - return Deserialize(stream); - } - } - - throw; - } - } - - private static DeviceUserName GenerateDeviceUserName() - { - DeviceUserName userName = new DeviceUserName(); - userName.DeviceName = GenerateRandomString(LiveIdConstants.ValidDeviceNameCharacters, LiveIdConstants.DeviceNameLength); - userName.DecryptedPassword = GenerateRandomString(LiveIdConstants.ValidDevicePasswordCharacters, LiveIdConstants.DevicePasswordLength); - - return userName; - } - - private static string GenerateRandomString(string characterSet, int count) - { - //Create an array of the characters that will hold the final list of random characters - char[] value = new char[count]; - - //Convert the character set to an array that can be randomly accessed - char[] set = characterSet.ToCharArray(); - - //Loop the set of characters and locate the space character. - int spaceCharacterIndex = -1; - for (int i = 0; i < set.Length; i++) - { - if (' ' == set[i]) - { - spaceCharacterIndex = i; - } - } - - lock (RandomInstance) - { - //Populate the array with random characters from the character set - for (int i = 0; i < count; i++) - { - //If this is the first or the last character, exclude the space (to avoid trimming and encryption issues) - //The main reason for this restriction is the EncryptPassword/DecryptPassword methods will pad the string - //with spaces (' ') if the string needs to be longer. - int characterCount = set.Length; - if (-1 != spaceCharacterIndex && (0 == i || count == i + 1)) - { - characterCount--; - } - - //Select an index that's within the set - int index = RandomInstance.Next(0, characterCount); - - //If this character is at or past the space character (and it is supposed to be excluded), - //increment the index by 1. The effect of this operation is that the space character will never be included - //in the random set since the possible values for index are: - //<0, spaceCharacterIndex - 1> and (according to the value of characterCount). - //By incrementing the index by 1, the range will be: - //<0, spaceCharacterIndex - 1> and - if (characterCount != set.Length && index >= spaceCharacterIndex) - { - index++; - } - - //Select the character from the set and store it in the return value - value[i] = set[index]; - } - } - - return new string(value); - } - - private static string DiscoverEnvironment(Uri issuerUri) - { - if (null == issuerUri) - { - return null; - } - - const string HostSearchString = "login.live"; - if (issuerUri.Host.Length > HostSearchString.Length && - issuerUri.Host.StartsWith(HostSearchString, StringComparison.OrdinalIgnoreCase)) - { - string environment = issuerUri.Host.Substring(HostSearchString.Length); - - if ('-' == environment[0]) - { - int separatorIndex = environment.IndexOf('.', 1); - if (-1 != separatorIndex) - { - return environment.Substring(1, separatorIndex - 1); - } - } - } - - //In all other cases the environment is either not applicable or it is a production system - return null; - } - #endregion - - #region Private Classes - private static class LiveIdConstants - { - public const string RegistrationEndpointUriFormat = @"https://login.live{0}.com/ppsecure/DeviceAddCredential.srf"; - - public const string DevicePrefix = "11"; - public static readonly string LiveDeviceFileNameFormat = Path.Combine(Path.Combine( - Environment.ExpandEnvironmentVariables("%USERPROFILE%"), "LiveDeviceID"), "LiveDevice{0}.xml"); - - public const string ValidDeviceNameCharacters = "0123456789abcdefghijklmnopqrstuvqxyz"; - public const int DeviceNameLength = 24; - - //Consists of the list of characters specified in the documentation - public const string ValidDevicePasswordCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^*()-_=+; ,./?`~"; - public const int DevicePasswordLength = 24; - } - #endregion -} - -#region Public Classes & Enums -/// -/// Indicates an error during registration -/// -public enum DeviceRegistrationErrorCode -{ - /// - /// Unspecified or Unknown Error occurred - /// - Unknown = 0, - - /// - /// Interface Disabled - /// - InterfaceDisabled = 1, - - /// - /// Invalid Request Format - /// - InvalidRequestFormat = 3, - - /// - /// Unknown Client Version - /// - UnknownClientVersion = 4, - - /// - /// Blank Password - /// - BlankPassword = 6, - - /// - /// Missing Device User Name or Password - /// - MissingDeviceUserNameOrPassword = 7, - - /// - /// Invalid Parameter Syntax - /// - InvalidParameterSyntax = 8, - - /// - /// Internal Error - /// - InternalError = 11, - - /// - /// Device Already Exists - /// - DeviceAlreadyExists = 13 -} - -/// -/// Indicates that Device Registration failed -/// -[Serializable] -public sealed class DeviceRegistrationFailedException : Exception -{ - /// - /// Construct an instance of the DeviceRegistrationFailedException class - /// - public DeviceRegistrationFailedException() - : base() - { - } - - /// - /// Construct an instance of the DeviceRegistrationFailedException class - /// - /// Message to pass - public DeviceRegistrationFailedException(string message) - : base(message) - { - } - - /// - /// Construct an instance of the DeviceRegistrationFailedException class - /// - /// Message to pass - /// Exception to include - public DeviceRegistrationFailedException(string message, Exception innerException) - : base(message, innerException) - { - } - - /// - /// Construct an instance of the DeviceRegistrationFailedException class - /// - /// Error code that occurred - /// Subcode that occurred - public DeviceRegistrationFailedException(DeviceRegistrationErrorCode code, string subCode) - : this(code, subCode, null) - { - } - - /// - /// Construct an instance of the DeviceRegistrationFailedException class - /// - /// Error code that occurred - /// Subcode that occurred - /// Inner exception - public DeviceRegistrationFailedException(DeviceRegistrationErrorCode code, string subCode, Exception innerException) - : base(string.Concat(code.ToString(), ": ", subCode), innerException) - { - } - - /// - /// Construct an instance of the DeviceRegistrationFailedException class - /// - /// - /// - private DeviceRegistrationFailedException(SerializationInfo si, StreamingContext sc) - : base(si, sc) - { - } -} - -#region Serialization Classes -#region DeviceRegistrationRequest Class -[EditorBrowsable(EditorBrowsableState.Never)] -[XmlRoot("DeviceAddRequest")] -public sealed class DeviceRegistrationRequest -{ - #region Constructors - public DeviceRegistrationRequest() - { - } - - public DeviceRegistrationRequest(Guid applicationId, LiveDevice device) - : this() - { - if (null == device) - { - throw new ArgumentNullException("device"); - } - - this.ClientInfo = new DeviceRegistrationClientInfo() { ApplicationId = applicationId, Version = "1.0" }; - this.Authentication = new DeviceRegistrationAuthentication() - { - MemberName = device.User.DeviceId, - Password = device.User.DecryptedPassword - }; - } - #endregion - - #region Properties - [XmlElement("ClientInfo")] - public DeviceRegistrationClientInfo ClientInfo { get; set; } - - [XmlElement("Authentication")] - public DeviceRegistrationAuthentication Authentication { get; set; } - #endregion -} -#endregion - -#region DeviceRegistrationClientInfo Class -[EditorBrowsable(EditorBrowsableState.Never)] -[XmlRoot("ClientInfo")] -public sealed class DeviceRegistrationClientInfo -{ - #region Properties - [XmlAttribute("name")] - public Guid ApplicationId { get; set; } - - [XmlAttribute("version")] - public string Version { get; set; } - #endregion -} -#endregion - -#region DeviceRegistrationAuthentication Class -[EditorBrowsable(EditorBrowsableState.Never)] -[XmlRoot("Authentication")] -public sealed class DeviceRegistrationAuthentication -{ - #region Properties - [XmlElement("Membername")] - public string MemberName { get; set; } - - [XmlElement("Password")] - public string Password { get; set; } - #endregion -} -#endregion - -#region DeviceRegistrationResponse Class -[EditorBrowsable(EditorBrowsableState.Never)] -[XmlRoot("DeviceAddResponse")] -public sealed class DeviceRegistrationResponse -{ - private string _errorSubCode; - - #region Properties - [XmlElement("success")] - public bool IsSuccess { get; set; } - - [XmlElement("puid")] - public string Puid { get; set; } - - [XmlElement("Error Code")] - public string ErrorCode { get; set; } - - [XmlElement("ErrorSubcode")] - public string ErrorSubCode - { - get - { - return this._errorSubCode; - } - - set - { - this._errorSubCode = value; - - //Parse the error code - if (string.IsNullOrWhiteSpace(value)) - { - this.RegistrationErrorCode = null; - } - else - { - this.RegistrationErrorCode = DeviceRegistrationErrorCode.Unknown; - - //Parse the error code - if (value.StartsWith("dc", StringComparison.Ordinal)) - { - int code; - if (int.TryParse(value.Substring(2), NumberStyles.Integer, - CultureInfo.InvariantCulture, out code) && - Enum.IsDefined(typeof(DeviceRegistrationErrorCode), code)) - { - this.RegistrationErrorCode = (DeviceRegistrationErrorCode)Enum.ToObject( - typeof(DeviceRegistrationErrorCode), code); - } - } - } - } - } - - [XmlIgnore] - public DeviceRegistrationErrorCode? RegistrationErrorCode { get; private set; } - #endregion -} -#endregion - -#region LiveDevice Class -[EditorBrowsable(EditorBrowsableState.Never)] -[XmlRoot("Data")] -public sealed class LiveDevice -{ - #region Properties - [XmlAttribute("version")] - public int Version { get; set; } - - [XmlElement("User")] - public DeviceUserName User { get; set; } - - [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes", MessageId = "System.Xml.XmlNode", Justification = "This is required for proper XML Serialization")] - [XmlElement("Token")] - public XmlNode Token { get; set; } - - [XmlElement("Expiry")] - public string Expiry { get; set; } - - [XmlElement("ClockSkew")] - public string ClockSkew { get; set; } - #endregion -} -#endregion - -#region DeviceUserName Class -[EditorBrowsable(EditorBrowsableState.Never)] -public sealed class DeviceUserName -{ - #region Constants - private const string UserNamePrefix = "11"; - #endregion - - #region Constructors - public DeviceUserName() - { - this.UserNameType = "Logical"; - } - #endregion - - #region Properties - [XmlAttribute("username")] - public string DeviceName { get; set; } - - [XmlAttribute("type")] - public string UserNameType { get; set; } - - [XmlElement("Pwd")] - public string EncryptedPassword { get; set; } - - public string DeviceId - { - get - { - return UserNamePrefix + DeviceName; - } - } - - [XmlIgnore] - public string DecryptedPassword - { - get - { - if (string.IsNullOrWhiteSpace(this.EncryptedPassword)) - { - return this.EncryptedPassword; - } - - byte[] decryptedBytes = Convert.FromBase64String(this.EncryptedPassword); - ProtectedMemory.Unprotect(decryptedBytes, MemoryProtectionScope.SameLogon); - - //The array will have been padded with null characters for the memory protection to work. - //See the setter for this property for more details - int count = decryptedBytes.Length; - for (int i = count - 1; i >= 0; i--) - { - if ('\0' == decryptedBytes[i]) - { - count--; - } - else - { - break; - } - } - if (count <= 0) - { - return null; - } - - return Encoding.UTF8.GetString(decryptedBytes, 0, count); - } - - set - { - if (string.IsNullOrWhiteSpace(value)) - { - this.EncryptedPassword = value; - return; - } - - byte[] encryptedBytes = Encoding.UTF8.GetBytes(value); - - //The length of the bytes needs to be a multiple of 16, or a CryptographicException will be thrown. - //For more information, see http://msdn.microsoft.com/en-us/library/system.security.cryptography.protectedmemory.protect.aspx - int missingCharacterCount = 16 - (encryptedBytes.Length % 16); - if (missingCharacterCount > 0) - { - Array.Resize(ref encryptedBytes, encryptedBytes.Length + missingCharacterCount); - } - - ProtectedMemory.Protect(encryptedBytes, MemoryProtectionScope.SameLogon); - this.EncryptedPassword = Convert.ToBase64String(encryptedBytes); - } - } - #endregion - - #region Methods - public ClientCredentials ToClientCredentials() - { - ClientCredentials credentials = new ClientCredentials(); - credentials.UserName.UserName = this.DeviceId; - credentials.UserName.Password = this.DecryptedPassword; - - return credentials; - } - #endregion -} -#endregion -#endregion -#endregion \ No newline at end of file diff --git a/CrmCodeGenerator.VSPackage/packages.config b/CrmCodeGenerator.VSPackage/packages.config index 01651af..87ded73 100644 --- a/CrmCodeGenerator.VSPackage/packages.config +++ b/CrmCodeGenerator.VSPackage/packages.config @@ -3,10 +3,10 @@ - - - - + + + + @@ -38,6 +38,6 @@ - - + + \ No newline at end of file diff --git a/CrmCodeGenerator.VSPackage/source.extension.vsixmanifest b/CrmCodeGenerator.VSPackage/source.extension.vsixmanifest index fca9a2c..16b145f 100644 --- a/CrmCodeGenerator.VSPackage/source.extension.vsixmanifest +++ b/CrmCodeGenerator.VSPackage/source.extension.vsixmanifest @@ -1,7 +1,7 @@  - + Dynamics CRM - Plugin Registration Extension Visual Studio extension that reduces the hassle of using the official plugin tool, so it is much easier and faster to update plugins. https://marketplace.visualstudio.com/items?itemName=Yagasoft.CrmPluginRegExt diff --git a/README.md b/README.md index 030f303..8eacc3f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Join the chat at https://gitter.im/yagasoft/DynamicsCrm-PluginRegExtension](https://badges.gitter.im/yagasoft/DynamicsCrm-PluginRegExtension.svg)](https://gitter.im/yagasoft/DynamicsCrm-PluginRegExtension?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -### Version: 2.2.3 +### Version: 2.2.4 --- A Visual Studio extension that reduces the hassle of using the official plugin tool, so it is much easier and faster to update plugins. @@ -23,6 +23,8 @@ A Visual Studio extension that reduces the hassle of using the official plugin t ## Changes +#### _v2.2.4 (2021-04-29)_ ++ Improved: connection readiness performance #### _v2.2.3 (2020-12-08)_ + Fixed: clear cache #### _v2.2.2 (2020-11-22)_