diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/AddConnectionFileDialog.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/AddConnectionFileDialog.cs new file mode 100644 index 0000000..3ca1ef8 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/AddConnectionFileDialog.cs @@ -0,0 +1,90 @@ +using System; +using System.Linq; +using System.Windows.Forms; + +namespace McTools.Xrm.Connection.WinForms +{ + public partial class AddConnectionFileDialog : Form + { + public AddConnectionFileDialog() + { + InitializeComponent(); + } + + public ConnectionFile OpenedFile { get; private set; } + public string OpenedFilePath { get; private set; } + + private void btnBrowse_Click(object sender, EventArgs e) + { + var ofd = new OpenFileDialog + { + Filter = "XML file|*.xml|CONFIG file|*.config", + }; + + if (ofd.ShowDialog(this) == DialogResult.OK) + { + txtFilePath.Text = ofd.FileName; + } + } + + private void btnCancel_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.Cancel; + Close(); + } + + private void btnOk_Click(object sender, EventArgs e) + { + try + { + var newCc = CrmConnections.LoadFromFile(txtFilePath.Text); + OpenedFile = new ConnectionFile(newCc) + { + Path = txtFilePath.Text, + Name = newCc.Name, + LastUsed = DateTime.Now + }; + + if (ConnectionsList.Instance.Files.Any(f => f.Name == OpenedFile.Name)) + { + int cloneId = 1; + string newName = OpenedFile.Name ?? "New File"; + + while (ConnectionsList.Instance.Files.FirstOrDefault(f => f.Name == newName) != null) + { + var rule = new System.Text.RegularExpressions.Regex(".* \\(" + cloneId + "\\)$"); + if (rule.IsMatch(newName)) + { + cloneId++; + newName = $"{OpenedFile.Name.Replace($" ({cloneId - 1})", "")} ({cloneId})"; + } + else + { + newName = $"{newName} ({cloneId})"; + } + } + + OpenedFile.Name = newName; + + MessageBox.Show(this, $"A connection file with this name already exists!\n\nIt has been renamed to '{newName}'", "Warning", + MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + + ConnectionManager.ConfigurationFile = txtFilePath.Text; + ConnectionsList.Instance.Files.First(f => f.Path == txtFilePath.Text).Name = OpenedFile.Name; + ConnectionManager.Instance.LoadConnectionsList(); + ConnectionsList.Instance.Save(); + + OpenedFilePath = txtFilePath.Text; + + DialogResult = DialogResult.OK; + Close(); + } + catch (Exception error) + { + MessageBox.Show(this, "It seems something went wrong when loading your file: " + error, + "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/AddConnectionFileDialog.designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/AddConnectionFileDialog.designer.cs new file mode 100644 index 0000000..11910e5 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/AddConnectionFileDialog.designer.cs @@ -0,0 +1,158 @@ +namespace McTools.Xrm.Connection.WinForms +{ + partial class AddConnectionFileDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label2 = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.btnOk = new System.Windows.Forms.Button(); + this.txtFilePath = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.btnBrowse = new System.Windows.Forms.Button(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnCancel.Location = new System.Drawing.Point(477, 179); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(75, 23); + this.btnCancel.TabIndex = 1; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); + // + // panel1 + // + this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel1.BackColor = System.Drawing.Color.White; + this.panel1.Controls.Add(this.label2); + this.panel1.Controls.Add(this.label1); + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(572, 60); + this.panel1.TabIndex = 11; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label2.Location = new System.Drawing.Point(13, 38); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(297, 13); + this.label2.TabIndex = 13; + this.label2.Text = "Please define the location of the existing connection file"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Segoe UI", 14F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(246, 25); + this.label1.TabIndex = 12; + this.label1.Text = "Add existing connection file"; + // + // btnOk + // + this.btnOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnOk.Location = new System.Drawing.Point(396, 179); + this.btnOk.Name = "btnOk"; + this.btnOk.Size = new System.Drawing.Size(75, 23); + this.btnOk.TabIndex = 13; + this.btnOk.Text = "OK"; + this.btnOk.UseVisualStyleBackColor = true; + this.btnOk.Click += new System.EventHandler(this.btnOk_Click); + // + // txtFilePath + // + this.txtFilePath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtFilePath.Location = new System.Drawing.Point(127, 68); + this.txtFilePath.Name = "txtFilePath"; + this.txtFilePath.Size = new System.Drawing.Size(364, 20); + this.txtFilePath.TabIndex = 16; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(12, 71); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(29, 13); + this.label4.TabIndex = 17; + this.label4.Text = "Path"; + // + // btnBrowse + // + this.btnBrowse.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnBrowse.Location = new System.Drawing.Point(497, 66); + this.btnBrowse.Name = "btnBrowse"; + this.btnBrowse.Size = new System.Drawing.Size(55, 23); + this.btnBrowse.TabIndex = 18; + this.btnBrowse.Text = "..."; + this.btnBrowse.UseVisualStyleBackColor = true; + this.btnBrowse.Click += new System.EventHandler(this.btnBrowse_Click); + // + // AddConnectionFileDialog + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(564, 214); + this.Controls.Add(this.btnBrowse); + this.Controls.Add(this.label4); + this.Controls.Add(this.txtFilePath); + this.Controls.Add(this.btnOk); + this.Controls.Add(this.panel1); + this.Controls.Add(this.btnCancel); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; + this.Name = "AddConnectionFileDialog"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button btnCancel; + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Button btnOk; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox txtFilePath; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Button btnBrowse; + } +} \ No newline at end of file diff --git a/CrmWebResourcesUpdater.Froms/CreateWebResourceForm.resx b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/AddConnectionFileDialog.resx similarity index 100% rename from CrmWebResourcesUpdater.Froms/CreateWebResourceForm.resx rename to CrmConnectionProjects/McTools.Xrm.Connection.WinForms/AddConnectionFileDialog.resx diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CRMLoginForm1.xaml b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CRMLoginForm1.xaml new file mode 100644 index 0000000..a24ee08 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CRMLoginForm1.xaml @@ -0,0 +1,24 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CRMLoginForm1.xaml.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CRMLoginForm1.xaml.cs new file mode 100644 index 0000000..8ba1901 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CRMLoginForm1.xaml.cs @@ -0,0 +1,360 @@ +using Microsoft.Xrm.Tooling.Connector; +using Microsoft.Xrm.Tooling.CrmConnectControl; +using System; +using System.Windows; +using System.Windows.Threading; + +namespace McTools.Xrm.Connection.WinForms +{ + /// + /// Interaction logic for CRMLoginForm1.xaml + /// + public partial class CRMLoginForm1 : Window + { + #region Vars + + private readonly Guid connectionDetailId; + + private readonly bool isUpdate; + + /// + /// Bool flag to determine if there is a connection + /// + private bool bIsConnectedComplete = false; + + /// + /// CRM Connection Manager component. + /// + private CrmConnectionManager mgr = null; + + /// + /// This is used to allow the UI to reset w/out closing + /// + private bool resetUiFlag = false; + + #endregion Vars + + #region Properties + + public string AppId { get; set; } + + /// + /// CRM Connection Manager + /// + public CrmConnectionManager CrmConnectionMgr { get { return mgr; } } + + /// + /// Microsoft.Xrm.Tooling.Connector services + /// + public CrmServiceClient CrmSvc { get; private set; } + + public Uri RedirectUri { get; set; } + + #endregion Properties + + #region Event + + /// + /// Raised when a connection to CRM has completed. + /// + public event EventHandler ConnectionToCrmCompleted; + + #endregion Event + + public CRMLoginForm1(Guid connectionDetailId, bool isUpdate = false) + { + this.connectionDetailId = connectionDetailId; + this.isUpdate = isUpdate; + + InitializeComponent(); + //// Should be used for testing only. + //ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => + //{ + // MessageBox.Show("CertError"); + // return true; + //}; + } + + /// + /// This raises and processes Success + /// + private void ProcessSuccess() + { + resetUiFlag = true; + bIsConnectedComplete = true; + CrmSvc = mgr.CrmSvc; + CrmLoginCtrl.GoBackToLogin(); + Dispatcher.Invoke(DispatcherPriority.Normal, + new System.Action(() => + { + this.Title = "Notification from Parent"; + CrmLoginCtrl.IsEnabled = true; + } + )); + + // Notify Caller that we are done with success. + ConnectionToCrmCompleted?.Invoke(this, null); + + resetUiFlag = false; + Close(); + } + + /// + /// Raised when the window loads for the first time. + /// + /// + /// + private void Window_Loaded(object sender, RoutedEventArgs e) + { + /* + This is the setup process for the login control, + The login control uses a class called CrmConnectionManager to manage the interaction with CRM, this class and also be queried as later points for information about the current connection. + In this case, the login control is referred to as CrmLoginCtrl + */ + + // Set off flag. + bIsConnectedComplete = false; + + // Init the CRM Connection manager.. + mgr = new CrmConnectionManager(); + + mgr.UseUserLocalDirectoryForConfigStore = true; + mgr.ProfileName = connectionDetailId.ToString("B"); + mgr.ClientId = AppId; + mgr.RedirectUri = RedirectUri; + + // Pass a reference to the current UI or container control, this is used to synchronize UI threads In the login control + mgr.ParentControl = CrmLoginCtrl; + // if you are using an unmanaged client, excel for example, and need to store the config in the users local directory + // set this option to true. + mgr.UseUserLocalDirectoryForConfigStore = true; + // if you are using an unmanaged client, you need to provide the name of an exe to use to create app config key's for. + //mgr.HostApplicatioNameOveride = "MyExecName.exe"; + // CrmLoginCtrl is the Login control, this sets the CrmConnection Manager into it. + CrmLoginCtrl.SetGlobalStoreAccess(mgr); + // There are several modes to the login control UI + CrmLoginCtrl.SetControlMode(ServerLoginConfigCtrlMode.FullLoginPanel); + // this wires an event that is raised when the login button is pressed. + CrmLoginCtrl.ConnectionCheckBegining += new EventHandler(CrmLoginCtrl_ConnectionCheckBegining); + // this wires an event that is raised when an error in the connect process occurs. + CrmLoginCtrl.ConnectErrorEvent += new EventHandler(CrmLoginCtrl_ConnectErrorEvent); + // this wires an event that is raised when a status event is returned. + CrmLoginCtrl.ConnectionStatusEvent += new EventHandler(CrmLoginCtrl_ConnectionStatusEvent); + // this wires an event that is raised when the user clicks the cancel button. + CrmLoginCtrl.UserCancelClicked += new EventHandler(CrmLoginCtrl_UserCancelClicked); + // Check to see if its possible to do an Auto Login + if (!mgr.RequireUserLogin() && !isUpdate) + { + //if (MessageBox.Show("Credentials already saved in configuration\nChoose Yes to Auto Login or No to Reset Credentials", "Auto Login", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) + //{ + // If RequireUserLogin is false, it means that there has been a successful login here before and the credentials are cached. + CrmLoginCtrl.IsEnabled = false; + // When running an auto login, you need to wire and listen to the events from the connection manager. + // Run Auto User Login process, Wire events. + mgr.ServerConnectionStatusUpdate += new EventHandler(mgr_ServerConnectionStatusUpdate); + mgr.ConnectionCheckComplete += new EventHandler(mgr_ConnectionCheckComplete); + // Start the connection process. + mgr.ConnectToServerCheck(); + + // Show the message grid. + CrmLoginCtrl.ShowMessageGrid(); + //} + } + } + + #region Events + + /// + /// Login control Error event. + /// + /// + /// + private void CrmLoginCtrl_ConnectErrorEvent(object sender, ConnectErrorEventArgs e) + { + MessageBox.Show(this, e.ErrorMessage, "Connection failed", MessageBoxButton.OK, MessageBoxImage.Error); + } + + /// + /// Login control connect check starting. + /// + /// + /// + private void CrmLoginCtrl_ConnectionCheckBegining(object sender, EventArgs e) + { + bIsConnectedComplete = false; + Dispatcher.Invoke(DispatcherPriority.Normal, + new System.Action(() => + { + this.Title = "Starting Login Process. "; + CrmLoginCtrl.IsEnabled = true; + } + )); + } + + /// + /// Login control connect check status event. + /// + /// + /// + private void CrmLoginCtrl_ConnectionStatusEvent(object sender, ConnectStatusEventArgs e) + { + //Here we are using the bIsConnectedComplete bool to check to make sure we only process this call once. + if (e.ConnectSucceeded && !bIsConnectedComplete) + ProcessSuccess(); + } + + /// + /// Login Control Cancel event raised. + /// + /// + /// + private void CrmLoginCtrl_UserCancelClicked(object sender, EventArgs e) + { + if (!resetUiFlag) + this.Close(); + } + + /// + /// Complete Event from the Auto Login process + /// + /// + /// + private void mgr_ConnectionCheckComplete(object sender, ServerConnectStatusEventArgs e) + { + // The Status event will contain information about the current login process, if Connected is false, then there is not yet a connection. + // Unwire events that we are not using anymore, this prevents issues if the user uses the control after a failed login. + ((CrmConnectionManager)sender).ConnectionCheckComplete -= mgr_ConnectionCheckComplete; + ((CrmConnectionManager)sender).ServerConnectionStatusUpdate -= mgr_ServerConnectionStatusUpdate; + + if (!e.Connected) + { + // if its not connected pop the login screen here. + if (e.MultiOrgsFound) + MessageBox.Show("Unable to Login to CRM using cached credentials. Org Not found", "Login Failure"); + else + MessageBox.Show("Unable to Login to CRM using cached credentials", "Login Failure"); + + resetUiFlag = true; + CrmLoginCtrl.GoBackToLogin(); + // Bad Login Get back on the UI. + Dispatcher.Invoke(DispatcherPriority.Normal, + new System.Action(() => + { + this.Title = "Failed to Login with cached credentials."; + MessageBox.Show(this.Title, "Notification from ConnectionManager", MessageBoxButton.OK, MessageBoxImage.Error); + CrmLoginCtrl.IsEnabled = true; + } + )); + resetUiFlag = false; + } + else + { + // Good Login Get back on the UI + if (e.Connected && !bIsConnectedComplete) + ProcessSuccess(); + } + } + + /// + /// Updates from the Auto Login process. + /// + /// + /// + private void mgr_ServerConnectionStatusUpdate(object sender, ServerConnectStatusEventArgs e) + { + // The Status event will contain information about the current login process, if Connected is false, then there is not yet a connection. + // Set the updated status of the loading process. + Dispatcher.Invoke(DispatcherPriority.Normal, + new System.Action(() => + { + this.Title = string.IsNullOrWhiteSpace(e.StatusMessage) ? e.ErrorMessage : e.StatusMessage; + } + )); + } + + #endregion Events + } + + #region system.diagnostics settings for this control + + // Add or merge this section to your app to enable diagnostics on the use of the CRM login control and connection + /* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +*/ + + #endregion system.diagnostics settings for this control +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ConnectionSelector.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ConnectionSelector.cs index 3a20729..3b251f1 100644 --- a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ConnectionSelector.cs +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ConnectionSelector.cs @@ -1,11 +1,10 @@ -using System; +using Microsoft.Xrm.Sdk.Discovery; +using System; using System.Collections.Generic; +using System.Drawing; using System.Linq; -using System.Text.RegularExpressions; using System.Windows.Forms; -using Microsoft.Xrm.Sdk.Client; -using EnvDTE; -using System.IO; +using System.Xml; namespace McTools.Xrm.Connection.WinForms { @@ -17,36 +16,36 @@ public partial class ConnectionSelector : Form { #region Variables - /// - /// Connexion sélectionnée - /// - List selectedConnections; + private readonly bool isConnectionSelection; + //private int currentIndex; + private bool hadCreatedNewConnection; /// /// Obtient la connexion sélectionnée /// - public List SelectedConnections - { - get { return selectedConnections; } - } - - private bool hadCreatedNewConnection; - - public CrmConnections ConnectionList { get; set; } + public List SelectedConnections { get; private set; } - private readonly ConnectionManager connectionManager; - - #endregion + #endregion Variables #region Constructeur /// /// Créé une nouvelle instance de la classe ConnectionSelector /// - /// Liste des connexions disponibles - /// Gestionnaire des connexions + public ConnectionSelector(bool isConnectionSelection = true) + { + InitializeComponent(); + + this.isConnectionSelection = isConnectionSelection; + + if (isConnectionSelection) + { + bValidate.Text = @"Connect"; + } + + } - public ConnectionSelector(CrmConnections connections, ConnectionManager cManager, ConnectionDetail selectedConnection = null, bool allowMultipleSelection = false, bool showPublisButton = false) + public ConnectionSelector(CrmConnections connections, ConnectionDetail selectedConnection = null, bool allowMultipleSelection = false, bool showPublisButton = false) { InitializeComponent(); @@ -56,11 +55,10 @@ public ConnectionSelector(CrmConnections connections, ConnectionManager cManager bValidate.Visible = true; bPublish.Visible = showPublisButton; - - connectionManager = cManager; - connections.Connections.Sort(); + connections.Connections.Sort(); + ConnectionManager.Instance.ConnectionsList = connections; ConnectionList = connections; cbAutoPublish.Checked = connections.PublishAfterUpload; cbIgnoreExtensions.Checked = connections.IgnoreExtensions; @@ -70,82 +68,125 @@ public ConnectionSelector(CrmConnections connections, ConnectionManager cManager lvConnections.MultiSelect = allowMultipleSelection; - LoadImages(); + DisplayConnections(); + RefreshComboBoxSelectedConnection(); + } - foreach (ConnectionDetail detail in connections.Connections) + private void DisplayConnections() + { + lvConnections.Items.Clear(); + lvConnections.Groups.Clear(); + try { - var item = new ListViewItem(detail.ConnectionName); - item.SubItems.Add(detail.ServerName); - item.SubItems.Add(detail.OrganizationFriendlyName); - item.SubItems.Add(detail.OrganizationVersion); - item.SubItems.Add(detail.SolutionFriendlyName); - item.Tag = detail; - item.Group = GetGroup(detail.AuthType); - item.ImageIndex = GetImageIndex(detail); - - lvConnections.Items.Add(item); + LoadImages(); - } + var details = ConnectionManager.Instance.ConnectionsList.Connections; + if (ConnectionManager.Instance.ConnectionsList.UseMruDisplay) + { + details = ConnectionManager.Instance.ConnectionsList.Connections.OrderByDescending(c => c.LastUsedOn).ThenBy(c => c.ConnectionName).ToList(); + } - RefreshComboBoxSelectedConnection(); + foreach (ConnectionDetail detail in details) + { + var item = new ListViewItem(detail.ConnectionName); + item.SubItems.Add(detail.ServerName); + item.SubItems.Add(detail.Organization); + item.SubItems.Add(string.IsNullOrEmpty(detail.UserDomain) ? detail.UserName : $"{detail.UserDomain}\\{detail.UserName}"); + item.SubItems.Add(detail.OrganizationVersion); + item.SubItems.Add(detail.SolutionName); + item.Tag = detail; + item.ImageIndex = GetImageIndex(detail); + + if (!ConnectionManager.Instance.ConnectionsList.UseMruDisplay) + { + item.Group = GetGroup(detail); + } + + lvConnections.Items.Add(item); + } - var groups = new ListViewGroup[lvConnections.Groups.Count]; + if (!ConnectionManager.Instance.ConnectionsList.UseMruDisplay) + { + var groups = new ListViewGroup[lvConnections.Groups.Count]; - lvConnections.Groups.CopyTo(groups, 0); + lvConnections.Groups.CopyTo(groups, 0); - Array.Sort(groups, new GroupComparer()); + Array.Sort(groups, new GroupComparer()); - lvConnections.BeginUpdate(); - lvConnections.Groups.Clear(); - lvConnections.Groups.AddRange(groups); - lvConnections.EndUpdate(); + lvConnections.BeginUpdate(); + lvConnections.Groups.Clear(); + lvConnections.Groups.AddRange(groups); + lvConnections.EndUpdate(); + } + tsbNewConnection.Enabled = !ConnectionManager.Instance.ConnectionsList.IsReadOnly; + tsbUpdateConnection.Enabled = !ConnectionManager.Instance.ConnectionsList.IsReadOnly; + //tsbCloneConnection.Enabled = !ConnectionManager.Instance.ConnectionsList.IsReadOnly; + tsbDeleteConnection.Enabled = !ConnectionManager.Instance.ConnectionsList.IsReadOnly; + //tsbUpdatePassword.Enabled = !ConnectionManager.Instance.ConnectionsList.IsReadOnly; + //tsb_UseMru.Enabled = !ConnectionManager.Instance.ConnectionsList.IsReadOnly; + } + catch(Exception ex) + { + MessageBox.Show($"Failed to display connections: {ex.Message}\r\n{ex.StackTrace}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } } - private void RefreshComboBoxSelectedConnection() + private void LoadConnectionFile() { - comboBoxSelectedConnection.Items.Clear(); - comboBoxSelectedConnection.SelectedText = ""; - comboBoxSelectedConnection.Text = ""; - if (ConnectionList == null || ConnectionList.Connections == null) + //tsb_UseMru.Checked = ConnectionManager.Instance.ConnectionsList.UseMruDisplay; + //tsb_UseMru.CheckedChanged += tsb_UseMru_CheckedChanged; + + if (isConnectionSelection) { - return; + Text = @"Select a connection"; + tsbDeleteConnection.Visible = false; + tsbUpdateConnection.Visible = false; + //tsbCloneConnection.Visible = false; + //tsbRemoveConnectionList.Visible = false; + tsbUpdateSolution.Visible = false; + bCancel.Text = @"Cancel"; + bValidate.Visible = true; } - - foreach (ConnectionDetail detail in ConnectionList.Connections) + else { - comboBoxSelectedConnection.Items.Add(detail); + Text = @"Connections Manager"; + tsbDeleteConnection.Visible = true; + tsbUpdateConnection.Visible = true; + //tsbCloneConnection.Visible = true; + tsbUpdateSolution.Visible = true; + //tsbRemoveConnectionList.Visible = true; + bCancel.Text = @"Close"; + bValidate.Visible = false; } - if (SelectedConnection != null) { - comboBoxSelectedConnection.SelectedIndex = ConnectionList.Connections.FindIndex(x => x.ConnectionId == SelectedConnection.ConnectionId); - }; + + DisplayConnections(); } private void LoadImages() { lvConnections.SmallImageList = new ImageList(); - lvConnections.SmallImageList.Images.Add(RessourceManager.GetImage("McTools.Xrm.Connection.WinForms.Resources.server.png")); - lvConnections.SmallImageList.Images.Add(RessourceManager.GetImage("McTools.Xrm.Connection.WinForms.Resources.server_key.png")); lvConnections.SmallImageList.Images.Add(RessourceManager.GetImage("McTools.Xrm.Connection.WinForms.Resources.CRMOnlineLive_16.png")); + lvConnections.SmallImageList.Images.Add(RessourceManager.GetImage("McTools.Xrm.Connection.WinForms.Resources.server_key.png")); + lvConnections.SmallImageList.Images.Add(RessourceManager.GetImage("McTools.Xrm.Connection.WinForms.Resources.powerapps16.png")); } - #endregion + #endregion Constructeur #region Properties - public bool HadCreatedNewConnection - { - get { return hadCreatedNewConnection; } - } + public bool HadCreatedNewConnection => hadCreatedNewConnection; public ConnectionDetail SelectedConnection { get; set; } - #endregion + #endregion Properties #region Méthodes - private void LvConnectionsMouseDoubleClick(object sender, MouseEventArgs e) + private void BCancelClick(object sender, EventArgs e) { + DialogResult = DialogResult.Cancel; + Close(); } private void BValidateClick(object sender, EventArgs e) @@ -155,7 +196,6 @@ private void BValidateClick(object sender, EventArgs e) ConnectionList.IgnoreExtensions = cbIgnoreExtensions.Checked; ConnectionList.ExtendedLog = cbExtendedLog.Checked; DialogResult = DialogResult.OK; - Close(); } private void bPublishClick(object sender, EventArgs e) @@ -168,25 +208,348 @@ private void bPublishClick(object sender, EventArgs e) Close(); } - private void BCancelClick(object sender, EventArgs e) - { - DialogResult = DialogResult.Cancel; - Close(); - } - private void LvConnectionsColumnClick(object sender, ColumnClickEventArgs e) { lvConnections.Sorting = lvConnections.Sorting == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending; lvConnections.ListViewItemSorter = new ListViewItemComparer(e.Column, lvConnections.Sorting); } - #endregion + private void LvConnectionsMouseDoubleClick(object sender, MouseEventArgs e) + { + if (isConnectionSelection) + { + BValidateClick(sender, e); + } + else if (!ConnectionManager.Instance.ConnectionsList.IsReadOnly) + { + tsbUpdateConnection_Click(sender, null); + } + } + + #endregion Méthodes + + private void ConnectionSelector_KeyDown(object sender, KeyEventArgs e) + { + if (e.Control && e.KeyCode == Keys.N) + { + tsbNewConnection_Click(null, null); + } + + if (e.Control && e.KeyCode == Keys.U) + { + tsbUpdateConnection_Click(null, null); + } + + if (e.Control && e.KeyCode == Keys.D) + { + tsbDeleteConnection_Click(null, null); + } + } + + private void RefreshComboBoxSelectedConnection() + { + comboBoxSelectedConnection.Items.Clear(); + comboBoxSelectedConnection.SelectedText = ""; + comboBoxSelectedConnection.Text = ""; + if (ConnectionList == null || ConnectionList.Connections == null) + { + return; + } + + foreach (ConnectionDetail detail in ConnectionList.Connections) + { + comboBoxSelectedConnection.Items.Add(detail); + } + if (SelectedConnection != null) + { + comboBoxSelectedConnection.SelectedIndex = ConnectionList.Connections.FindIndex(x => x.ConnectionId == SelectedConnection.ConnectionId); + }; + } + + private void ConnectionSelector_Load(object sender, EventArgs e) + { + //var mostRecentFile = ConnectionsList.Instance.Files.OrderByDescending(f => f.LastUsed).FirstOrDefault(); + //var index = 0; + //var indexToSelect = 0; + + //tsbRemoveConnectionList.Enabled = false; + //currentIndex = 0; + + //if (mostRecentFile != null) + //{ + // foreach (var file in ConnectionsList.Instance.Files.OrderBy(k => k.Name)) + // { + // if (file.Name == mostRecentFile.Name) + // { + // indexToSelect = index; + // } + // else if (!Uri.IsWellFormedUriString(file.Path, UriKind.Absolute)) + // { + // tsbMoveToExistingFile.DropDownItems.Add(new ToolStripButton + // { + // Text = file.Name, + // Tag = file, + // Size = new Size(155, 22), + // AutoSize = true + // }); + // } + + // tscbbConnectionsFile.Items.Add(file); + // index++; + // } + //} + + //tscbbConnectionsFile.Items.Add(""); + //tscbbConnectionsFile.Items.Add(""); + //tscbbConnectionsFile.SelectedIndexChanged -= tscbbConnectionsFile_SelectedIndexChanged; + //tscbbConnectionsFile.SelectedIndex = indexToSelect; + //tscbbConnectionsFile.SelectedIndexChanged += tscbbConnectionsFile_SelectedIndexChanged; + + //if (tscbbConnectionsFile.SelectedItem != null && !ConnectionManager.FileExists(((ConnectionFile)tscbbConnectionsFile.SelectedItem).Path)) + //{ + // CleanFileList((ConnectionFile)tscbbConnectionsFile.SelectedItem); + // return; + //} + + //tsbMoveToExistingFile.Enabled = tscbbConnectionsFile.Items.Count > 3; + //tsbRemoveConnectionList.Enabled = tscbbConnectionsFile.Items.Count > 3; + + // Display connections + //LoadConnectionFile(); + + //lvConnections_SelectedIndexChanged(this, new EventArgs()); + } + + private ListViewGroup GetGroup(ConnectionDetail detail) + { + string groupName; + + if (detail.UseOnline) + { + groupName = "Online"; + } + else if (detail.UseIfd) + { + groupName = "Claims authentication - Internet Facing Deployment"; + } + else + { + groupName = "OnPremise"; + } + + var group = lvConnections.Groups.Cast().FirstOrDefault(g => g.Name == groupName); + if (group == null) + { + group = new ListViewGroup(groupName, groupName); + lvConnections.Groups.Add(group); + } + + return group; + } + + private int GetImageIndex(ConnectionDetail detail) + { + if (detail.UseOnline) + { + return 2; + } + + if (detail.UseIfd) + { + return 1; + } + + return 0; + } + + private void lvConnections_KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode != Keys.Enter || lvConnections.SelectedItems.Count == 0) + return; + + BValidateClick(null, null); + } + + private void lvConnections_SelectedIndexChanged(object sender, EventArgs e) + { + bValidate.Enabled = lvConnections.SelectedItems.Count > 0; + //tsbShowConnectionString.Visible = lvConnections.SelectedItems.Count == 1; + //toolStripSeparator4.Visible = lvConnections.SelectedItems.Count == 1; + + tsbUpdateConnection.Visible = lvConnections.SelectedItems.Count == 1; + + //tsbCloneConnection.Visible = lvConnections.SelectedItems.Count > 0; + //tsbDeleteConnection.Visible = lvConnections.SelectedItems.Count > 0; + //tsbUpdatePassword.Visible = lvConnections.SelectedItems.Count > 0; + //toolStripSeparator3.Visible = lvConnections.SelectedItems.Count > 0; + + //tsbMoveToExistingFile.Visible = lvConnections.SelectedItems.Count > 0; + //tsbMoveToNewFile.Visible = lvConnections.SelectedItems.Count > 0; + + tsbUpdateSolution.Visible = lvConnections.SelectedItems.Count == 1; + } + + private void tsb_UseMru_CheckedChanged(object sender, EventArgs e) + { + var tsb = (ToolStripButton)sender; + ConnectionManager.Instance.ConnectionsList.UseMruDisplay = tsb.Checked; + + DisplayConnections(); + } + + private void tscbbConnectionsFile_SelectedIndexChanged(object sender, EventArgs e) + { + //var cbbValue = tscbbConnectionsFile.SelectedItem; + //var connectionFile = cbbValue as ConnectionFile; + //bool loadConnections = true; + + //// If null, then we selected an action rather than a connection file + //if (connectionFile == null) + //{ + // tscbbConnectionsFile.SelectedIndexChanged -= tscbbConnectionsFile_SelectedIndexChanged; + // tscbbConnectionsFile.SelectedIndex = currentIndex; + // tscbbConnectionsFile.SelectedIndexChanged += tscbbConnectionsFile_SelectedIndexChanged; + + // // It can be a new file + // if (cbbValue.ToString() == "") + // { + // var nfd = new NewConnectionFileDialog(); + // if (nfd.ShowDialog(this) == DialogResult.OK) + // { + // ConnectionManager.ConfigurationFile = nfd.CreatedFilePath; + + // var newIndex = tscbbConnectionsFile.Items.Count - 2; + + // tscbbConnectionsFile.Items.Insert(newIndex, + // ConnectionsList.Instance.Files.First(f => f.Path == nfd.CreatedFilePath)); + // tscbbConnectionsFile.SelectedIndex = newIndex; + // tsbRemoveConnectionList.Enabled = true; + + // tsbMoveToExistingFile.Enabled = tscbbConnectionsFile.Items.Count > 3; + // } + // else + // { + // loadConnections = false; + // } + // } + // // Or an existing file + // else + // { + // var afd = new AddConnectionFileDialog(); + // if (afd.ShowDialog(this) == DialogResult.OK) + // { + // var newIndex = tscbbConnectionsFile.Items.Count - 2; + + // tscbbConnectionsFile.Items.Insert(newIndex, afd.OpenedFile); + // tscbbConnectionsFile.SelectedIndex = newIndex; + // tsbRemoveConnectionList.Enabled = true; + // } + // else + // { + // loadConnections = false; + // } + // } + //} + //else + //{ + // if (!ConnectionManager.FileExists(connectionFile.Path)) + // { + // CleanFileList(connectionFile); + // return; + // } + + // currentIndex = tscbbConnectionsFile.SelectedIndex; + + // // Or it is a connection file so we load it for the connection manager + // ConnectionManager.ConfigurationFile = connectionFile.Path; + + // tsbRemoveConnectionList.Enabled = tscbbConnectionsFile.Items.Count > 3; + + // connectionFile.LastUsed = DateTime.Now; + + // tsbMoveToExistingFile.DropDownItems.Clear(); + // foreach (var file in ConnectionsList.Instance.Files.OrderBy(k => k.Name)) + // { + // if (connectionFile.Path == file.Path || Uri.IsWellFormedUriString(file.Path, UriKind.Absolute)) + // { + // continue; + // } + + // tsbMoveToExistingFile.DropDownItems.Add(new ToolStripButton + // { + // Text = file.Name, + // Tag = file, + // Size = new Size(155, 22), + // AutoSize = true + // }); + // } + //} + + //if (loadConnections) + //{ + // LoadConnectionFile(); + //} + + //ConnectionsList.Instance.Save(); + } + + #region Connection actions + + private void LvConnections_AfterLabelEdit(object sender, LabelEditEventArgs e) + { + if (!e.CancelEdit) + { + var detail = (ConnectionDetail)lvConnections.Items[e.Item].Tag; + detail.ConnectionName = e.Label; + + } + } + + private void tsbCloneConnection_Click(object sender, EventArgs e) + { + var newItems = new List(); + + foreach (ListViewItem item in lvConnections.SelectedItems) + { + var detail = (ConnectionDetail)item.Tag; + + var newDetail = ConnectionManager.Instance.ConnectionsList.CloneConnection(detail); + + var newItem = new ListViewItem(newDetail.ConnectionName); + newItem.SubItems.Add(newDetail.ServerName); + newItem.SubItems.Add(newDetail.Organization); + newItem.SubItems.Add(newDetail.OrganizationVersion); + newItem.Tag = newDetail; + newItem.Group = GetGroup(newDetail); + newItem.ImageIndex = GetImageIndex(newDetail); + + newItems.Add(newItem); + } + + lvConnections.Items.AddRange(newItems.ToArray()); + } + + private void tsbDeleteConnection_Click(object sender, EventArgs e) + { + if (lvConnections.SelectedItems.Count > 0 && + MessageBox.Show(this, @"Are you sure you want to delete selected connection(s)?", @"Question", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No) + return; + + foreach (ListViewItem connectionItem in lvConnections.SelectedItems) + { + var detailToRemove = (ConnectionDetail)connectionItem.Tag; + + lvConnections.Items.Remove(lvConnections.SelectedItems[0]); + + ConnectionManager.Instance.ConnectionsList.Connections.RemoveAll(d => d.ConnectionId == detailToRemove.ConnectionId); + } + + } private void tsbNewConnection_Click(object sender, EventArgs e) { - var cForm = new ConnectionForm(true, false) + var cForm = new ConnectionWizard2 { - ConnectionList = ConnectionList, StartPosition = FormStartPosition.CenterParent }; @@ -198,21 +561,45 @@ private void tsbNewConnection_Click(object sender, EventArgs e) var item = new ListViewItem(newConnection.ConnectionName); item.SubItems.Add(newConnection.ServerName); item.SubItems.Add(newConnection.Organization); + item.SubItems.Add(newConnection.UserName); item.SubItems.Add(newConnection.OrganizationVersion); - item.SubItems.Add(newConnection.SolutionFriendlyName); + item.SubItems.Add(newConnection.SolutionName); item.Tag = newConnection; - item.Group = GetGroup(newConnection.AuthType); + item.Group = GetGroup(newConnection); item.ImageIndex = GetImageIndex(newConnection); lvConnections.Items.Add(item); lvConnections.SelectedItems.Clear(); item.Selected = true; - if (!connectionManager.ConnectionsList.Connections.Contains(newConnection)) - connectionManager.ConnectionsList.Connections.Add(newConnection); + lvConnections.Sort(); - RefreshComboBoxSelectedConnection(); + if (isConnectionSelection) + { + BValidateClick(sender, e); + } + // If the connection id is not found and the user want to save + // the connection (ie. he provided a name for the connection) + if (ConnectionManager.Instance.ConnectionsList.Connections.FirstOrDefault(d => d.ConnectionId == newConnection.ConnectionId) == null + && !string.IsNullOrEmpty(newConnection.ConnectionName)) + { + ConnectionManager.Instance.ConnectionsList.Connections.Add(newConnection); + RefreshComboBoxSelectedConnection(); + } + } + } + + private void tsbShowConnectionString_Click(object sender, EventArgs e) + { + var connections = lvConnections.SelectedItems + .Cast().Select(lvi => (ConnectionDetail)lvi.Tag) + .ToList(); + + if (connections.Count == 1) + { + var csd = new ConnectionStringDialog(connections.First()); + csd.ShowDialog(this); } } @@ -222,110 +609,272 @@ private void tsbUpdateConnection_Click(object sender, EventArgs e) { ListViewItem item = lvConnections.SelectedItems[0]; - var cForm = new ConnectionForm(false, false) + var cd = (ConnectionDetail)item.Tag; + + if (cd.IsFromSdkLoginCtrl) + { + var ctrl = new CRMLoginForm1(cd.ConnectionId.Value, true); + ctrl.ShowDialog(); + + if (ctrl.CrmConnectionMgr.CrmSvc?.IsReady ?? false) + { + cd.Organization = ctrl.CrmConnectionMgr.ConnectedOrgUniqueName; + cd.OrganizationFriendlyName = ctrl.CrmConnectionMgr.ConnectedOrgFriendlyName; + cd.OrganizationDataServiceUrl = + ctrl.CrmConnectionMgr.ConnectedOrgPublishedEndpoints[EndpointType.OrganizationDataService]; + cd.OrganizationServiceUrl = + ctrl.CrmConnectionMgr.ConnectedOrgPublishedEndpoints[EndpointType.OrganizationService]; + cd.WebApplicationUrl = + ctrl.CrmConnectionMgr.ConnectedOrgPublishedEndpoints[EndpointType.WebApplication]; + cd.ServerName = new Uri(cd.WebApplicationUrl).Host; + cd.OrganizationVersion = ctrl.CrmConnectionMgr.CrmSvc.ConnectedOrgVersion.ToString(); + + + item.Tag = cd; + lvConnections.Items.Remove(item); + lvConnections.Items.Add(item); + lvConnections.Refresh();//RedrawItems(0, lvConnections.Items.Count - 1, false); + + var updatedConnectionDetail = ConnectionManager.Instance.ConnectionsList.Connections.FirstOrDefault( + c => c.ConnectionId == cd.ConnectionId); + + ConnectionManager.Instance.ConnectionsList.Connections.Remove(updatedConnectionDetail); + ConnectionManager.Instance.ConnectionsList.Connections.Add(cd); + + RefreshComboBoxSelectedConnection(); + } + + return; + } + + var cForm = new ConnectionWizard2(cd) { - CrmConnectionDetail = (ConnectionDetail)item.Tag, - ConnectionList = ConnectionList, StartPosition = FormStartPosition.CenterParent }; if (cForm.ShowDialog(this) == DialogResult.OK) { + item.Tag = cForm.CrmConnectionDetail; item.SubItems[0].Text = cForm.CrmConnectionDetail.ConnectionName; item.SubItems[1].Text = cForm.CrmConnectionDetail.ServerName; - item.SubItems[2].Text = cForm.CrmConnectionDetail.OrganizationFriendlyName; - item.SubItems[3].Text = cForm.CrmConnectionDetail.OrganizationVersion; - item.SubItems[4].Text = cForm.CrmConnectionDetail.SolutionFriendlyName; - - item.Group = GetGroup(cForm.CrmConnectionDetail.AuthType); + item.SubItems[2].Text = cForm.CrmConnectionDetail.Organization; + if (item.SubItems.Count == 4) + { + item.SubItems[3].Text = cForm.CrmConnectionDetail.OrganizationVersion; + } + else + { + item.SubItems.Add(cForm.CrmConnectionDetail.OrganizationVersion); + } + item.Group = GetGroup(cForm.CrmConnectionDetail); + item.SubItems[5].Text = cForm.CrmConnectionDetail.SolutionName; lvConnections.Refresh(); + var updatedConnectionDetail = ConnectionManager.Instance.ConnectionsList.Connections.FirstOrDefault( + c => c.ConnectionId == cForm.CrmConnectionDetail.ConnectionId); + + ConnectionManager.Instance.ConnectionsList.Connections.Remove(updatedConnectionDetail); + ConnectionManager.Instance.ConnectionsList.Connections.Add(cForm.CrmConnectionDetail); + RefreshComboBoxSelectedConnection(); } - } } - private void tsbDeleteConnection_Click(object sender, EventArgs e) + private void tsbUpdatePassword_Click(object sender, EventArgs e) { - if (lvConnections.SelectedItems.Count > 0) + var connections = lvConnections.SelectedItems + .Cast().Select(lvi => (ConnectionDetail)lvi.Tag) + .ToList(); + + if (!connections.Any()) { - var connectionToDelete = lvConnections.SelectedItems[0].Tag as ConnectionDetail; - if (SelectedConnection != null && SelectedConnection.ConnectionId == connectionToDelete.ConnectionId) - { - SelectedConnection = null; - } + return; + } - lvConnections.Items.Remove(lvConnections.SelectedItems[0]); + var upDialog = new UpdatePasswordForm(connections); + var result = upDialog.ShowDialog(); + if (result == DialogResult.OK) + { + MessageBox.Show(this, @"Connections have been updated!", @"Information", MessageBoxButtons.OK, + MessageBoxIcon.Information); + } + else if (result == DialogResult.Ignore) + { + MessageBox.Show(this, @"No connection were updated!", @"Warning", MessageBoxButtons.OK, + MessageBoxIcon.Warning); + } + } + #endregion Connection actions - ConnectionList.Connections = lvConnections.Items.Cast().Select(i => (ConnectionDetail)i.Tag).ToList(); + #region Connection file actions - RefreshComboBoxSelectedConnection(); - } + private void CleanFileList(ConnectionFile connectionFile) + { + //var message = $"The file '{connectionFile.Path}' does not exist and will be removed from the list!"; + //MessageBox.Show(this, message, @"Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + //var index = tscbbConnectionsFile.SelectedIndex != 0 ? tscbbConnectionsFile.SelectedIndex - 1 : 0; + //ConnectionsList.Instance.Files.Remove(connectionFile); + //tscbbConnectionsFile.Items.Remove(tscbbConnectionsFile.SelectedItem); + //tscbbConnectionsFile.SelectedIndex = index; } - private ListViewGroup GetGroup(AuthenticationProviderType type) + private void tsbMoveToExistingFile_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e) { - string groupName = string.Empty; + var connectionsIds = + lvConnections.SelectedItems.Cast().Select(i => ((ConnectionDetail)i.Tag).ConnectionId); - switch (type) - { - case AuthenticationProviderType.ActiveDirectory: - groupName = "OnPremise"; - break; - case AuthenticationProviderType.OnlineFederation: - groupName = "CRM Online - Office 365"; - break; - case AuthenticationProviderType.LiveId: - groupName = "CRM Online - CTP"; - break; - case AuthenticationProviderType.Federation: - groupName = "Claims authentication - Internet Facing Deployment"; - break; - } + var currentFilePath = ConnectionManager.ConfigurationFile; + var newFilePath = ((ConnectionFile)e.ClickedItem.Tag).Path; - var group = lvConnections.Groups.Cast().FirstOrDefault(g => g.Name == groupName); - if (group == null) + var currentDoc = new XmlDocument(); + currentDoc.Load(currentFilePath); + var newDoc = new XmlDocument(); + newDoc.Load(newFilePath); + + foreach (var connectionId in connectionsIds) { - group = new ListViewGroup(groupName, groupName); - lvConnections.Groups.Add(group); + var nodeToMove = currentDoc.SelectSingleNode("//ConnectionDetail[ConnectionId/text()='" + connectionId + "']"); + if (nodeToMove == null) continue; + + newDoc.SelectSingleNode("//Connections")?.AppendChild(newDoc.ImportNode(nodeToMove, true)); + currentDoc.SelectSingleNode("//Connections")?.RemoveChild(nodeToMove); } - return group; + currentDoc.Save(currentFilePath); + newDoc.Save(newFilePath); + LoadConnectionFile(); } - private int GetImageIndex(ConnectionDetail detail) + private void tsbMoveToNewFile_Click(object sender, EventArgs e) { - if (detail.UseOnline) - { - return 2; - } + //bool loadConnections = true; - if (detail.UseOsdp) - { - return 2; - } + //var nfd = new NewConnectionFileDialog(); + //if (nfd.ShowDialog(this) == DialogResult.OK) + //{ + // var scs = lvConnections.SelectedItems.Cast().Select(i => (ConnectionDetail)i.Tag).ToList(); + // foreach (var sc in scs) + // { + // ConnectionManager.Instance.ConnectionsList.Connections.Remove(sc); + // } - if (detail.UseIfd) + // ConnectionManager.Instance.SaveConnectionsFile(); + + // ConnectionManager.ConfigurationFile = nfd.CreatedFilePath; + + // var newIndex = tscbbConnectionsFile.Items.Count - 2; + + // tscbbConnectionsFile.Items.Insert(newIndex, ConnectionsList.Instance.Files.First(f => f.Path == nfd.CreatedFilePath)); + // tscbbConnectionsFile.SelectedIndex = newIndex; + // tsbRemoveConnectionList.Enabled = true; + + // ConnectionManager.Instance.ConnectionsList.Connections = scs; + // ConnectionManager.Instance.SaveConnectionsFile(); + //} + //else + //{ + // loadConnections = false; + //} + + //if (loadConnections) + //{ + // LoadConnectionFile(); + //} + + //ConnectionsList.Instance.Save(); + + //tsbMoveToExistingFile.Enabled = tscbbConnectionsFile.Items.Count > 3; + } + + private void tsbRemoveConnectionList_Click(object sender, EventArgs e) + { + //var message = "Are you sure you want to remove this connections list file?\n\nThe file is not deleted physically but just removed from connections files list"; + //if (MessageBox.Show(this, message, @"Question", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == + // DialogResult.No) + // return; + + //var item = (ConnectionFile)tscbbConnectionsFile.SelectedItem; + //tscbbConnectionsFile.Items.RemoveAt(tscbbConnectionsFile.SelectedIndex); + //ConnectionsList.Instance.Files.Remove(item); + //ConnectionsList.Instance.Save(); + //tscbbConnectionsFile.SelectedIndex = tscbbConnectionsFile.Items.Count - 3; + + //tsbMoveToExistingFile.Enabled = tscbbConnectionsFile.Items.Count > 3; + } + + private void tsbRenameFile_Click(object sender, EventArgs e) + { + //var index = tscbbConnectionsFile.SelectedIndex; + //var item = (ConnectionFile)tscbbConnectionsFile.SelectedItem; + //var dialog = new RenameConnectionFileDialog(item.Name ?? "N/A"); + //if (dialog.ShowDialog() == DialogResult.OK) + //{ + // item.Name = dialog.NewName; + // ConnectionsList.Instance.Save(); + + // tscbbConnectionsFile.Items.Remove(item); + // tscbbConnectionsFile.Items.Insert(index, item); + // tscbbConnectionsFile.SelectedIndex = index; + //} + } + + #endregion Connection file actions + + private void tsbUpdateSolution_Click(object sender, EventArgs e) + { + if (lvConnections.SelectedItems.Count == 1) { - return 1; - } + ListViewItem item = lvConnections.SelectedItems[0]; + var cd = (ConnectionDetail)item.Tag; - return 0; + var upDialog = new UpdateSolutionForm(cd); + var result = upDialog.ShowDialog(); + if (result == DialogResult.OK) + { + + item.Tag = cd; + item.SubItems[0].Text = cd.ConnectionName; + item.SubItems[1].Text = cd.ServerName; + item.SubItems[2].Text = cd.Organization; + if (item.SubItems.Count == 4) + { + item.SubItems[3].Text = cd.OrganizationVersion; + } + else + { + item.SubItems.Add(cd.OrganizationVersion); + } + item.SubItems[5].Text = cd.SolutionName; + + item.Group = GetGroup(cd); + lvConnections.Refresh(); + + MessageBox.Show(this, @"Connection have been updated!", @"Information", MessageBoxButtons.OK, + MessageBoxIcon.Information); + } + else if (result == DialogResult.Ignore) + { + MessageBox.Show(this, @"No connection were updated!", @"Warning", MessageBoxButtons.OK, + MessageBoxIcon.Warning); + } + + } } private void ComboBoxSelectedConnectionSelectedIndexChanged(object sender, EventArgs e) { SelectedConnection = comboBoxSelectedConnection.SelectedItem as ConnectionDetail; } - public Action OnCreateMappingFile { get; set; } private void bCreateMappingClick(object sender, EventArgs e) { OnCreateMappingFile(); } + + public CrmConnections ConnectionList { get; set; } } } \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ConnectionSelector.designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ConnectionSelector.designer.cs index 622e4eb..d4ceadc 100644 --- a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ConnectionSelector.designer.cs +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ConnectionSelector.designer.cs @@ -32,32 +32,39 @@ private void InitializeComponent() this.bValidate = new System.Windows.Forms.Button(); this.bCancel = new System.Windows.Forms.Button(); this.lvConnections = new System.Windows.Forms.ListView(); - this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.columnHeader4 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.columnHeader5 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chServer = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chOrganization = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chUser = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chVersion = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chSolution = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.menu = new System.Windows.Forms.ToolStrip(); this.tsbNewConnection = new System.Windows.Forms.ToolStripButton(); this.tsbUpdateConnection = new System.Windows.Forms.ToolStripButton(); this.tsbDeleteConnection = new System.Windows.Forms.ToolStripButton(); - this.labelSelectedConnection = new System.Windows.Forms.Label(); - this.comboBoxSelectedConnection = new System.Windows.Forms.ComboBox(); - this.cbAutoPublish = new System.Windows.Forms.CheckBox(); - this.bPublish = new System.Windows.Forms.Button(); + this.tsbUpdateSolution = new System.Windows.Forms.ToolStripButton(); + this.pnlFooter = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.cbExtendedLog = new System.Windows.Forms.CheckBox(); this.cbIgnoreExtensions = new System.Windows.Forms.CheckBox(); + this.cbAutoPublish = new System.Windows.Forms.CheckBox(); this.bCreateMapping = new System.Windows.Forms.Button(); - this.cbExtendedLog = new System.Windows.Forms.CheckBox(); + this.comboBoxSelectedConnection = new System.Windows.Forms.ComboBox(); + this.bPublish = new System.Windows.Forms.Button(); + this.pnlMain = new System.Windows.Forms.Panel(); this.menu.SuspendLayout(); + this.pnlFooter.SuspendLayout(); + this.pnlMain.SuspendLayout(); this.SuspendLayout(); // // bValidate // this.bValidate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.bValidate.Location = new System.Drawing.Point(501, 335); + this.bValidate.Location = new System.Drawing.Point(580, 105); + this.bValidate.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3); this.bValidate.Name = "bValidate"; - this.bValidate.Size = new System.Drawing.Size(75, 23); - this.bValidate.TabIndex = 6; + this.bValidate.Size = new System.Drawing.Size(74, 23); + this.bValidate.TabIndex = 3; this.bValidate.Text = "Save"; this.bValidate.UseVisualStyleBackColor = true; this.bValidate.Click += new System.EventHandler(this.BValidateClick); @@ -65,60 +72,72 @@ private void InitializeComponent() // bCancel // this.bCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.bCancel.Location = new System.Drawing.Point(581, 335); + this.bCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.bCancel.Location = new System.Drawing.Point(662, 105); + this.bCancel.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3); this.bCancel.Name = "bCancel"; - this.bCancel.Size = new System.Drawing.Size(75, 23); - this.bCancel.TabIndex = 5; + this.bCancel.Size = new System.Drawing.Size(74, 23); + this.bCancel.TabIndex = 4; this.bCancel.Text = "Cancel"; this.bCancel.UseVisualStyleBackColor = true; this.bCancel.Click += new System.EventHandler(this.BCancelClick); // // lvConnections // - this.lvConnections.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); this.lvConnections.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.columnHeader1, - this.columnHeader3, - this.columnHeader2, - this.columnHeader4, - this.columnHeader5}); + this.chName, + this.chServer, + this.chOrganization, + this.chUser, + this.chVersion, + this.chSolution}); + this.lvConnections.Dock = System.Windows.Forms.DockStyle.Fill; this.lvConnections.FullRowSelect = true; this.lvConnections.GridLines = true; - this.lvConnections.Location = new System.Drawing.Point(12, 28); + this.lvConnections.HideSelection = false; + this.lvConnections.LabelEdit = true; + this.lvConnections.Location = new System.Drawing.Point(4, 4); + this.lvConnections.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3); this.lvConnections.Name = "lvConnections"; - this.lvConnections.Size = new System.Drawing.Size(644, 204); - this.lvConnections.TabIndex = 9; + this.lvConnections.Size = new System.Drawing.Size(736, 243); + this.lvConnections.TabIndex = 2; this.lvConnections.UseCompatibleStateImageBehavior = false; this.lvConnections.View = System.Windows.Forms.View.Details; + this.lvConnections.AfterLabelEdit += new System.Windows.Forms.LabelEditEventHandler(this.LvConnections_AfterLabelEdit); this.lvConnections.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.LvConnectionsColumnClick); + this.lvConnections.SelectedIndexChanged += new System.EventHandler(this.lvConnections_SelectedIndexChanged); + this.lvConnections.KeyDown += new System.Windows.Forms.KeyEventHandler(this.lvConnections_KeyDown); this.lvConnections.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.LvConnectionsMouseDoubleClick); // - // columnHeader1 + // chName + // + this.chName.Text = "Name"; + this.chName.Width = 180; // - this.columnHeader1.Text = "Name"; - this.columnHeader1.Width = 150; + // chServer // - // columnHeader3 + this.chServer.Text = "Server"; + this.chServer.Width = 120; // - this.columnHeader3.Text = "Server"; - this.columnHeader3.Width = 150; + // chOrganization // - // columnHeader2 + this.chOrganization.Text = "Organization"; + this.chOrganization.Width = 120; // - this.columnHeader2.Text = "Organization"; - this.columnHeader2.Width = 120; + // chUser // - // columnHeader4 + this.chUser.Text = "User"; + this.chUser.Width = 86; // - this.columnHeader4.Text = "Version"; - this.columnHeader4.Width = 100; + // chVersion // - // columnHeader5 + this.chVersion.Text = "Version"; + this.chVersion.Width = 90; // - this.columnHeader5.Text = "Solution"; - this.columnHeader5.Width = 120; + // chSolution + // + this.chSolution.Text = "Solution"; + this.chSolution.Width = 132; // // menu // @@ -126,21 +145,21 @@ private void InitializeComponent() this.menu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.tsbNewConnection, this.tsbUpdateConnection, - this.tsbDeleteConnection}); - this.menu.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.HorizontalStackWithOverflow; + this.tsbDeleteConnection, + this.tsbUpdateSolution}); this.menu.Location = new System.Drawing.Point(0, 0); this.menu.Name = "menu"; - this.menu.Padding = new System.Windows.Forms.Padding(10, 2, 12, 0); - this.menu.Size = new System.Drawing.Size(668, 25); - this.menu.TabIndex = 11; - this.menu.Text = "toolStrip1"; + this.menu.Padding = new System.Windows.Forms.Padding(0); + this.menu.Size = new System.Drawing.Size(744, 25); + this.menu.TabIndex = 1; + this.menu.Text = "tsMain"; // // tsbNewConnection // this.tsbNewConnection.Image = ((System.Drawing.Image)(resources.GetObject("tsbNewConnection.Image"))); this.tsbNewConnection.ImageTransparentColor = System.Drawing.Color.Magenta; this.tsbNewConnection.Name = "tsbNewConnection"; - this.tsbNewConnection.Size = new System.Drawing.Size(114, 20); + this.tsbNewConnection.Size = new System.Drawing.Size(114, 22); this.tsbNewConnection.Text = "New connection"; this.tsbNewConnection.Click += new System.EventHandler(this.tsbNewConnection_Click); // @@ -149,7 +168,7 @@ private void InitializeComponent() this.tsbUpdateConnection.Image = ((System.Drawing.Image)(resources.GetObject("tsbUpdateConnection.Image"))); this.tsbUpdateConnection.ImageTransparentColor = System.Drawing.Color.Magenta; this.tsbUpdateConnection.Name = "tsbUpdateConnection"; - this.tsbUpdateConnection.Size = new System.Drawing.Size(128, 20); + this.tsbUpdateConnection.Size = new System.Drawing.Size(128, 22); this.tsbUpdateConnection.Text = "Update connection"; this.tsbUpdateConnection.Click += new System.EventHandler(this.tsbUpdateConnection_Click); // @@ -158,131 +177,170 @@ private void InitializeComponent() this.tsbDeleteConnection.Image = ((System.Drawing.Image)(resources.GetObject("tsbDeleteConnection.Image"))); this.tsbDeleteConnection.ImageTransparentColor = System.Drawing.Color.Magenta; this.tsbDeleteConnection.Name = "tsbDeleteConnection"; - this.tsbDeleteConnection.Size = new System.Drawing.Size(123, 20); + this.tsbDeleteConnection.Size = new System.Drawing.Size(123, 22); this.tsbDeleteConnection.Text = "Delete connection"; this.tsbDeleteConnection.Click += new System.EventHandler(this.tsbDeleteConnection_Click); // - // labelSelectedConnection + // tsbUpdateSolution + // + this.tsbUpdateSolution.Image = global::McTools.Xrm.Connection.WinForms.Properties.Resources.ico_16_7100; + this.tsbUpdateSolution.ImageTransparentColor = System.Drawing.Color.Magenta; + this.tsbUpdateSolution.Name = "tsbUpdateSolution"; + this.tsbUpdateSolution.Size = new System.Drawing.Size(112, 22); + this.tsbUpdateSolution.Text = "Update Solution"; + this.tsbUpdateSolution.ToolTipText = "Update solution for selected connection"; + this.tsbUpdateSolution.Click += new System.EventHandler(this.tsbUpdateSolution_Click); + // + // pnlFooter + // + this.pnlFooter.Controls.Add(this.label1); + this.pnlFooter.Controls.Add(this.cbExtendedLog); + this.pnlFooter.Controls.Add(this.cbIgnoreExtensions); + this.pnlFooter.Controls.Add(this.cbAutoPublish); + this.pnlFooter.Controls.Add(this.bCreateMapping); + this.pnlFooter.Controls.Add(this.comboBoxSelectedConnection); + this.pnlFooter.Controls.Add(this.bCancel); + this.pnlFooter.Controls.Add(this.bPublish); + this.pnlFooter.Controls.Add(this.bValidate); + this.pnlFooter.Dock = System.Windows.Forms.DockStyle.Bottom; + this.pnlFooter.Location = new System.Drawing.Point(0, 276); + this.pnlFooter.Margin = new System.Windows.Forms.Padding(2); + this.pnlFooter.Name = "pnlFooter"; + this.pnlFooter.Size = new System.Drawing.Size(744, 134); + this.pnlFooter.TabIndex = 5; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(10, 83); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(105, 13); + this.label1.TabIndex = 10; + this.label1.Text = "Selected connection"; // - this.labelSelectedConnection.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.labelSelectedConnection.AutoSize = true; - this.labelSelectedConnection.Location = new System.Drawing.Point(9, 319); - this.labelSelectedConnection.Name = "labelSelectedConnection"; - this.labelSelectedConnection.Size = new System.Drawing.Size(105, 13); - this.labelSelectedConnection.TabIndex = 12; - this.labelSelectedConnection.Text = "Selected connection"; + // cbExtendedLog // - // comboBoxSelectedConnection + this.cbExtendedLog.AutoSize = true; + this.cbExtendedLog.Location = new System.Drawing.Point(12, 53); + this.cbExtendedLog.Name = "cbExtendedLog"; + this.cbExtendedLog.Size = new System.Drawing.Size(88, 17); + this.cbExtendedLog.TabIndex = 9; + this.cbExtendedLog.Text = "Extended log"; + this.cbExtendedLog.UseVisualStyleBackColor = true; // - this.comboBoxSelectedConnection.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.comboBoxSelectedConnection.FormattingEnabled = true; - this.comboBoxSelectedConnection.Location = new System.Drawing.Point(12, 335); - this.comboBoxSelectedConnection.Name = "comboBoxSelectedConnection"; - this.comboBoxSelectedConnection.Size = new System.Drawing.Size(244, 21); - this.comboBoxSelectedConnection.TabIndex = 13; - this.comboBoxSelectedConnection.SelectedIndexChanged += new System.EventHandler(this.ComboBoxSelectedConnectionSelectedIndexChanged); + // cbIgnoreExtensions + // + this.cbIgnoreExtensions.AutoSize = true; + this.cbIgnoreExtensions.Location = new System.Drawing.Point(12, 29); + this.cbIgnoreExtensions.Name = "cbIgnoreExtensions"; + this.cbIgnoreExtensions.Size = new System.Drawing.Size(193, 17); + this.cbIgnoreExtensions.TabIndex = 8; + this.cbIgnoreExtensions.Text = "Search with and without extensions"; + this.cbIgnoreExtensions.UseVisualStyleBackColor = true; // // cbAutoPublish // this.cbAutoPublish.AutoSize = true; - this.cbAutoPublish.Checked = true; - this.cbAutoPublish.CheckState = System.Windows.Forms.CheckState.Checked; - this.cbAutoPublish.Location = new System.Drawing.Point(12, 246); + this.cbAutoPublish.Location = new System.Drawing.Point(12, 5); this.cbAutoPublish.Name = "cbAutoPublish"; this.cbAutoPublish.Size = new System.Drawing.Size(119, 17); - this.cbAutoPublish.TabIndex = 14; + this.cbAutoPublish.TabIndex = 7; this.cbAutoPublish.Text = "Publish after upload"; this.cbAutoPublish.UseVisualStyleBackColor = true; // - // bPublish - // - this.bPublish.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.bPublish.Location = new System.Drawing.Point(387, 335); - this.bPublish.Name = "bPublish"; - this.bPublish.Size = new System.Drawing.Size(108, 23); - this.bPublish.TabIndex = 15; - this.bPublish.Text = "Save and Update"; - this.bPublish.UseVisualStyleBackColor = true; - this.bPublish.Click += new System.EventHandler(this.bPublishClick); - // - // cbIgnoreExtensions - // - this.cbIgnoreExtensions.AutoSize = true; - this.cbIgnoreExtensions.Location = new System.Drawing.Point(12, 269); - this.cbIgnoreExtensions.Name = "cbIgnoreExtensions"; - this.cbIgnoreExtensions.Size = new System.Drawing.Size(193, 17); - this.cbIgnoreExtensions.TabIndex = 16; - this.cbIgnoreExtensions.Text = "Search with and without extensions"; - this.cbIgnoreExtensions.UseVisualStyleBackColor = true; - // // bCreateMapping // - this.bCreateMapping.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.bCreateMapping.Location = new System.Drawing.Point(500, 246); + this.bCreateMapping.Location = new System.Drawing.Point(580, 5); this.bCreateMapping.Name = "bCreateMapping"; this.bCreateMapping.Size = new System.Drawing.Size(156, 23); - this.bCreateMapping.TabIndex = 17; + this.bCreateMapping.TabIndex = 6; this.bCreateMapping.Text = "Create Mapping File"; this.bCreateMapping.UseVisualStyleBackColor = true; this.bCreateMapping.Click += new System.EventHandler(this.bCreateMappingClick); // - // cbExtendedLog + // comboBoxSelectedConnection // - this.cbExtendedLog.AutoSize = true; - this.cbExtendedLog.Location = new System.Drawing.Point(12, 292); - this.cbExtendedLog.Name = "cbExtendedLog"; - this.cbExtendedLog.Size = new System.Drawing.Size(88, 17); - this.cbExtendedLog.TabIndex = 18; - this.cbExtendedLog.Text = "Extended log"; - this.cbExtendedLog.UseVisualStyleBackColor = true; + this.comboBoxSelectedConnection.FormattingEnabled = true; + this.comboBoxSelectedConnection.Location = new System.Drawing.Point(12, 102); + this.comboBoxSelectedConnection.Name = "comboBoxSelectedConnection"; + this.comboBoxSelectedConnection.Size = new System.Drawing.Size(297, 21); + this.comboBoxSelectedConnection.TabIndex = 5; + this.comboBoxSelectedConnection.SelectedIndexChanged += new System.EventHandler(this.ComboBoxSelectedConnectionSelectedIndexChanged); + // + // bPublish + // + this.bPublish.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.bPublish.Location = new System.Drawing.Point(498, 105); + this.bPublish.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3); + this.bPublish.Name = "bPublish"; + this.bPublish.Size = new System.Drawing.Size(74, 23); + this.bPublish.TabIndex = 3; + this.bPublish.Text = "Publish"; + this.bPublish.UseVisualStyleBackColor = true; + this.bPublish.Click += new System.EventHandler(this.bPublishClick); + // + // pnlMain + // + this.pnlMain.Controls.Add(this.lvConnections); + this.pnlMain.Dock = System.Windows.Forms.DockStyle.Fill; + this.pnlMain.Location = new System.Drawing.Point(0, 25); + this.pnlMain.Margin = new System.Windows.Forms.Padding(2); + this.pnlMain.Name = "pnlMain"; + this.pnlMain.Padding = new System.Windows.Forms.Padding(4); + this.pnlMain.Size = new System.Drawing.Size(744, 251); + this.pnlMain.TabIndex = 6; // // ConnectionSelector // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(668, 370); - this.Controls.Add(this.bPublish); - this.Controls.Add(this.cbExtendedLog); - this.Controls.Add(this.comboBoxSelectedConnection); - this.Controls.Add(this.cbIgnoreExtensions); - this.Controls.Add(this.cbAutoPublish); - this.Controls.Add(this.labelSelectedConnection); - this.Controls.Add(this.bCreateMapping); + this.CancelButton = this.bCancel; + this.ClientSize = new System.Drawing.Size(744, 410); + this.Controls.Add(this.pnlMain); + this.Controls.Add(this.pnlFooter); this.Controls.Add(this.menu); - this.Controls.Add(this.bValidate); - this.Controls.Add(this.bCancel); - this.Controls.Add(this.lvConnections); + this.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3); this.Name = "ConnectionSelector"; this.ShowIcon = false; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "Microsoft Dynamics CRM Web Resources Updater Options"; + this.Text = "Connection Manager"; + this.Load += new System.EventHandler(this.ConnectionSelector_Load); + this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ConnectionSelector_KeyDown); this.menu.ResumeLayout(false); this.menu.PerformLayout(); + this.pnlFooter.ResumeLayout(false); + this.pnlFooter.PerformLayout(); + this.pnlMain.ResumeLayout(false); this.ResumeLayout(false); this.PerformLayout(); } + + #endregion private System.Windows.Forms.Button bValidate; private System.Windows.Forms.Button bCancel; private System.Windows.Forms.ListView lvConnections; - private System.Windows.Forms.ColumnHeader columnHeader1; - private System.Windows.Forms.ColumnHeader columnHeader2; - private System.Windows.Forms.ColumnHeader columnHeader3; - private System.Windows.Forms.ColumnHeader columnHeader4; + private System.Windows.Forms.ColumnHeader chName; + private System.Windows.Forms.ColumnHeader chOrganization; + private System.Windows.Forms.ColumnHeader chServer; + private System.Windows.Forms.ColumnHeader chVersion; private System.Windows.Forms.ToolStrip menu; private System.Windows.Forms.ToolStripButton tsbNewConnection; private System.Windows.Forms.ToolStripButton tsbUpdateConnection; private System.Windows.Forms.ToolStripButton tsbDeleteConnection; - private System.Windows.Forms.ColumnHeader columnHeader5; - private System.Windows.Forms.Label labelSelectedConnection; + private System.Windows.Forms.Panel pnlFooter; + private System.Windows.Forms.Panel pnlMain; + private System.Windows.Forms.ColumnHeader chUser; + private System.Windows.Forms.ColumnHeader chSolution; + private System.Windows.Forms.ToolStripButton tsbUpdateSolution; private System.Windows.Forms.ComboBox comboBoxSelectedConnection; - private System.Windows.Forms.CheckBox cbAutoPublish; - private System.Windows.Forms.Button bPublish; + private System.Windows.Forms.CheckBox cbExtendedLog; private System.Windows.Forms.CheckBox cbIgnoreExtensions; + private System.Windows.Forms.CheckBox cbAutoPublish; private System.Windows.Forms.Button bCreateMapping; - private System.Windows.Forms.CheckBox cbExtendedLog; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Button bPublish; } } \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ConnectionStringDialog.Designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ConnectionStringDialog.Designer.cs new file mode 100644 index 0000000..c2730d2 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ConnectionStringDialog.Designer.cs @@ -0,0 +1,104 @@ +namespace McTools.Xrm.Connection.WinForms +{ + partial class ConnectionStringDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.pnlTop = new System.Windows.Forms.Panel(); + this.pnlMain = new System.Windows.Forms.Panel(); + this.lblTitle = new System.Windows.Forms.Label(); + this.txtConnectionString = new System.Windows.Forms.TextBox(); + this.pnlTop.SuspendLayout(); + this.pnlMain.SuspendLayout(); + this.SuspendLayout(); + // + // pnlTop + // + this.pnlTop.BackColor = System.Drawing.Color.White; + this.pnlTop.Controls.Add(this.lblTitle); + this.pnlTop.Dock = System.Windows.Forms.DockStyle.Top; + this.pnlTop.Location = new System.Drawing.Point(0, 0); + this.pnlTop.Name = "pnlTop"; + this.pnlTop.Size = new System.Drawing.Size(800, 100); + this.pnlTop.TabIndex = 0; + // + // pnlMain + // + this.pnlMain.Controls.Add(this.txtConnectionString); + this.pnlMain.Dock = System.Windows.Forms.DockStyle.Fill; + this.pnlMain.Location = new System.Drawing.Point(0, 100); + this.pnlMain.Name = "pnlMain"; + this.pnlMain.Padding = new System.Windows.Forms.Padding(10); + this.pnlMain.Size = new System.Drawing.Size(800, 174); + this.pnlMain.TabIndex = 2; + // + // lblTitle + // + this.lblTitle.AutoSize = true; + this.lblTitle.Font = new System.Drawing.Font("Segoe UI Light", 14F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblTitle.Location = new System.Drawing.Point(13, 13); + this.lblTitle.Name = "lblTitle"; + this.lblTitle.Size = new System.Drawing.Size(359, 45); + this.lblTitle.TabIndex = 0; + this.lblTitle.Text = "Connection string for {0}"; + // + // txtConnectionString + // + this.txtConnectionString.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtConnectionString.Font = new System.Drawing.Font("Consolas", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtConnectionString.Location = new System.Drawing.Point(10, 10); + this.txtConnectionString.Multiline = true; + this.txtConnectionString.Name = "txtConnectionString"; + this.txtConnectionString.Size = new System.Drawing.Size(780, 154); + this.txtConnectionString.TabIndex = 0; + // + // ConnectionStringDialog + // + this.AutoScaleDimensions = new System.Drawing.SizeF(11F, 24F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(800, 274); + this.Controls.Add(this.pnlMain); + this.Controls.Add(this.pnlTop); + this.Name = "ConnectionStringDialog"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.pnlTop.ResumeLayout(false); + this.pnlTop.PerformLayout(); + this.pnlMain.ResumeLayout(false); + this.pnlMain.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Panel pnlTop; + private System.Windows.Forms.Panel pnlMain; + private System.Windows.Forms.Label lblTitle; + private System.Windows.Forms.TextBox txtConnectionString; + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ConnectionStringDialog.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ConnectionStringDialog.cs new file mode 100644 index 0000000..cce6252 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ConnectionStringDialog.cs @@ -0,0 +1,15 @@ +using System.Windows.Forms; + +namespace McTools.Xrm.Connection.WinForms +{ + public partial class ConnectionStringDialog : Form + { + public ConnectionStringDialog(ConnectionDetail detail) + { + InitializeComponent(); + + txtConnectionString.Text = detail.GetConnectionString(); + lblTitle.Text = string.Format(lblTitle.Text, detail.ConnectionName); + } + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ConnectionStringDialog.resx b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ConnectionStringDialog.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ConnectionStringDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ConnectionWizard2.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ConnectionWizard2.cs new file mode 100644 index 0000000..45f0685 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ConnectionWizard2.cs @@ -0,0 +1,860 @@ +using McTools.Xrm.Connection.WinForms.CustomControls; +using Microsoft.Xrm.Sdk.Client; +using Microsoft.Xrm.Sdk.Discovery; +using Microsoft.Xrm.Sdk.Query; +using Microsoft.Xrm.Tooling.Connector; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Net; +using System.Security.Cryptography.X509Certificates; +using System.Windows.Forms; + +namespace McTools.Xrm.Connection.WinForms +{ + public partial class ConnectionWizard2 : Form + { + private readonly bool isNew; + private readonly List navigationHistory = new List(); + private IConnectionWizardControl ctrl; + private string lastError; + private ConnectionDetail originalDetail; + private ConnectionType type; + + public ConnectionWizard2(ConnectionDetail detail = null) + { + InitializeComponent(); + + isNew = detail == null; + originalDetail = (ConnectionDetail)detail?.Clone(); + CrmConnectionDetail = detail ?? new ConnectionDetail(true); + + Text = originalDetail == null ? "New connection" : "Update connection"; + + btnBack.Visible = false; + btnReset.Visible = false; + } + + public ConnectionDetail CrmConnectionDetail { get; private set; } + + public sealed override string Text + { + get => base.Text; + set => base.Text = value; + } + + #region Buttons events + + private void btnBack_Click(object sender, EventArgs e) + { + navigationHistory.RemoveAt(navigationHistory.Count - 1); + var type = navigationHistory.Last(); + navigationHistory.RemoveAt(navigationHistory.Count - 1); + + if (type == typeof(ConnectionFirstStepControl)) + DisplayControl(); + else if (type == typeof(ConnectionCredentialsControl)) + DisplayControl(); + else if (type == typeof(ConnectionFailedControl)) + DisplayControl(); + else if (type == typeof(ConnectionIfdControl)) + DisplayControl(); + else if (type == typeof(ConnectionLoadingControl)) + DisplayControl(); + else if (type == typeof(ConnectionOauthControl)) + DisplayControl(); + else if (type == typeof(ConnectionStringControl)) + DisplayControl(); + else if (type == typeof(ConnectionSucceededControl)) + DisplayControl(); + else if (type == typeof(SdkLoginControlControl)) + DisplayControl(); + else if (type == typeof(StartPageControl)) + DisplayControl(); + else if (type == typeof(ConnectionCertificateControl)) + DisplayControl(); + else if (type == typeof(ConnectionUrlControl)) + DisplayControl(); + else if (type == typeof(ConnectionClientSecretControl)) + DisplayControl(); + else if (type == typeof(ConnectionAppIdControl)) + DisplayControl(); + else if (type == typeof(ConnectionMfaControl)) + DisplayControl(); + } + + private void btnNext_Click(object sender, EventArgs e) + { + if (ctrl is ConnectionFirstStepControl cfsc) + { + CrmConnectionDetail.OriginalUrl = cfsc.Url; + CrmConnectionDetail.IsCustomAuth = !cfsc.UseIntegratedAuth; + CrmConnectionDetail.UseMfa = cfsc.UseMfa; + CrmConnectionDetail.ServerName = cfsc.HostName; + CrmConnectionDetail.ServerPort = cfsc.HostPort; + CrmConnectionDetail.OrganizationUrlName = cfsc.OrganizationUrlName; + CrmConnectionDetail.Timeout = cfsc.Timeout; + + if (CrmConnectionDetail.Timeout.Ticks == 0 || CrmConnectionDetail.ServerName == null) + { + return; + } + + if (CrmConnectionDetail.OrganizationUrlName == null) + { + if (!IPAddress.TryParse(CrmConnectionDetail.ServerName, out _)) + { + if (CrmConnectionDetail.ServerName.Split('.').Length > 1) + CrmConnectionDetail.OrganizationUrlName = CrmConnectionDetail.ServerName.Split('.')[0]; + } + + if (CrmConnectionDetail.UseOnline) + { + if (!cfsc.UseIntegratedAuth) + { + if (CrmConnectionDetail.UseMfa) + { + DisplayControl(); + } + else if (!CrmConnectionDetail.UseOnline && CrmConnectionDetail.OriginalUrl.Split('.').Length > 1) + { + DisplayControl(); + } + else + { + DisplayControl(); + } + } + else + { + DisplayControl(); + Connect(); + } + } + else + { + DisplayControl(); + } + } + else + { + if (CrmConnectionDetail.IsCustomAuth) + { + if (CrmConnectionDetail.UseMfa) + { + DisplayControl(); + } + else if (!CrmConnectionDetail.UseOnline && CrmConnectionDetail.OriginalUrl.Split('.').Length > 1) + { + DisplayControl(); + } + else + { + DisplayControl(); + } + } + else + { + DisplayControl(); + Connect(); + } + } + } + else if (ctrl is ConnectionCredentialsControl ccc) + { + CrmConnectionDetail.UserDomain = ccc.Domain; + CrmConnectionDetail.UserName = ccc.Username; + CrmConnectionDetail.SavePassword = ccc.SavePassword; + + if (ccc.PasswordChanged) + { + CrmConnectionDetail.SetPassword(ccc.Password); + } + + if (string.IsNullOrEmpty(CrmConnectionDetail.UserName) + || CrmConnectionDetail.PasswordIsEmpty) + { + MessageBox.Show(this, + @"Please enter your credentials before trying to connect", + @"Warning", + MessageBoxButtons.OK, + MessageBoxIcon.Warning); + + return; + } + + if (originalDetail == null) + { + DisplayControl(); + Connect(); + } + else if (CrmConnectionDetail.IsConnectionBrokenWithUpdatedData(originalDetail)) + { + if (DialogResult.Yes == MessageBox.Show(this, @"You changed some values that require to test the connection. Would you like to test it now? + + Note that this is required to validate this wizard", + @"Question", MessageBoxButtons.YesNo, MessageBoxIcon.Question)) + { + DisplayControl(); + Connect(); + } + } + else + { + CrmConnectionDetail.Solutions = CrmConnectionDetail.GetSolutionsList(); + DisplayControl(); + } + } + else if (ctrl is ConnectionIfdControl cic) + { + CrmConnectionDetail.UseIfd = cic.IsIfd; + CrmConnectionDetail.HomeRealmUrl = cic.HomeRealmUrl; + + if (CrmConnectionDetail.OrganizationUrlName == null) + { + if (!CrmConnectionDetail.UseIfd) + { + MessageBox.Show(this, + @"We were unable to determine the organization name based on the information you specified. Please complete the url to add the organization name inside", + @"Warning", + MessageBoxButtons.OK, + MessageBoxIcon.Warning); + + DisplayControl(); + return; + } + + CrmConnectionDetail.OrganizationUrlName = CrmConnectionDetail.ServerName.Split('.')[0]; + + if (CrmConnectionDetail.OrganizationUrlName == CrmConnectionDetail.ServerName) + { + MessageBox.Show(this, + @"The url you specified does not look like a valid url for an IFD deployment. Please correct the url", + @"Warning", + MessageBoxButtons.OK, + MessageBoxIcon.Warning); + + DisplayControl(); + return; + } + } + + CrmConnectionDetail.NewAuthType = cic.IsIfd ? AuthenticationType.IFD : AuthenticationType.AD; + + if (CrmConnectionDetail.IsCustomAuth) + { + DisplayControl(); + } + else if (originalDetail == null) + { + DisplayControl(); + Connect(); + } + else + { + if (CrmConnectionDetail.IsConnectionBrokenWithUpdatedData(originalDetail)) + { + if (DialogResult.Yes == MessageBox.Show(this, @"You changed some values that require to test the connection. Would you like to test it now? + + Note that this is required to validate this wizard", + @"Question", MessageBoxButtons.YesNo, MessageBoxIcon.Question)) + { + DisplayControl(); + Connect(); + } + } + else + { + CrmConnectionDetail.Solutions = CrmConnectionDetail.GetSolutionsList(); + DisplayControl(); + } + } + } + else if (ctrl is ConnectionOauthControl coc) + { + CrmConnectionDetail.AzureAdAppId = coc.AzureAdAppId; + CrmConnectionDetail.ReplyUrl = coc.ReplyUrl; + + if (coc.ClientSecretChanged) + { + CrmConnectionDetail.SetClientSecret(coc.ClientSecret); + } + + if (CrmConnectionDetail.AzureAdAppId == Guid.Empty + || string.IsNullOrEmpty(CrmConnectionDetail.ReplyUrl)) + { + MessageBox.Show(this, + @"Please provide all information for OAuth authentication", + @"Warning", + MessageBoxButtons.OK, + MessageBoxIcon.Warning); + + return; + } + + if (!CrmConnectionDetail.ClientSecretIsEmpty) + { + DisplayControl(); + Connect(); + } + else + { + DisplayControl(); + } + } + else if (ctrl is ConnectionStringControl csc) + { + CrmConnectionDetail.SetConnectionString(csc.ConnectionString); + + DisplayControl(); + Connect(); + } + else if (ctrl is ConnectionSucceededControl cokc) + { + CrmConnectionDetail.ConnectionName = cokc.ConnectionName; + CrmConnectionDetail.SelectedSolution = cokc.SelectedSolution; + + DialogResult = DialogResult.OK; + Close(); + } + else if (ctrl is SdkLoginControlControl slcc) + { + CrmConnectionDetail.IsFromSdkLoginCtrl = true; + CrmConnectionDetail.AuthType = slcc.AuthType; + CrmConnectionDetail.UseIfd = slcc.AuthType == AuthenticationProviderType.Federation; + CrmConnectionDetail.Organization = slcc.ConnectionManager.ConnectedOrgUniqueName; + CrmConnectionDetail.OrganizationFriendlyName = slcc.ConnectionManager.ConnectedOrgFriendlyName; + CrmConnectionDetail.OrganizationDataServiceUrl = + slcc.ConnectionManager.ConnectedOrgPublishedEndpoints[EndpointType.OrganizationDataService]; + CrmConnectionDetail.OrganizationServiceUrl = + slcc.ConnectionManager.ConnectedOrgPublishedEndpoints[EndpointType.OrganizationService]; + CrmConnectionDetail.WebApplicationUrl = + slcc.ConnectionManager.ConnectedOrgPublishedEndpoints[EndpointType.WebApplication]; + CrmConnectionDetail.OriginalUrl = CrmConnectionDetail.WebApplicationUrl; + CrmConnectionDetail.ServerName = new Uri(CrmConnectionDetail.WebApplicationUrl).Host; + CrmConnectionDetail.OrganizationVersion = slcc.ConnectionManager.CrmSvc.ConnectedOrgVersion.ToString(); + CrmConnectionDetail.ServiceClient = slcc.ConnectionManager.CrmSvc; + if (!string.IsNullOrEmpty(slcc.ConnectionManager.ClientId)) + { + CrmConnectionDetail.AzureAdAppId = new Guid(slcc.ConnectionManager.ClientId); + CrmConnectionDetail.ReplyUrl = slcc.ConnectionManager.RedirectUri.AbsoluteUri; + } + + CrmConnectionDetail.UserName = CrmConnectionDetail.ServiceClient.OAuthUserId; + + CrmConnectionDetail.Solutions = CrmConnectionDetail.GetSolutionsList(); + + DisplayControl(); + } + else if (ctrl is ConnectionUrlControl cuc) + { + if (string.IsNullOrEmpty(cuc.Url) || !Uri.TryCreate(cuc.Url, UriKind.Absolute, out _)) + { + MessageBox.Show(this, @"Please provide a valid url", @"Warning", MessageBoxButtons.OK, + MessageBoxIcon.Warning); + return; + } + + CrmConnectionDetail.OriginalUrl = cuc.Url; + CrmConnectionDetail.Timeout = cuc.Timeout; + + if (type == ConnectionType.Certificate) + { + DisplayControl(); + } + else if (type == ConnectionType.ClientSecret) + { + DisplayControl(); + } + else if (type == ConnectionType.Mfa) + { + DisplayControl(); + } + } + else if (ctrl is ConnectionClientSecretControl ccsc) + { + CrmConnectionDetail.AzureAdAppId = ccsc.AzureAdAppId; + CrmConnectionDetail.NewAuthType = AuthenticationType.ClientSecret; + + if (ccsc.ClientSecretChanged) + { + CrmConnectionDetail.SetClientSecret(ccsc.ClientSecret); + } + + if (CrmConnectionDetail.AzureAdAppId == Guid.Empty + || CrmConnectionDetail.ClientSecretIsEmpty) + { + MessageBox.Show(this, + @"Please provide all information for Client Id/Secret authentication", + @"Warning", + MessageBoxButtons.OK, + MessageBoxIcon.Warning); + + return; + } + + if (!CrmConnectionDetail.ClientSecretIsEmpty) + { + DisplayControl(); + Connect(); + } + } + else if (ctrl is ConnectionMfaControl cmfac) + { + CrmConnectionDetail.AzureAdAppId = cmfac.AzureAdAppId; + CrmConnectionDetail.ReplyUrl = cmfac.ReplyUrl; + CrmConnectionDetail.UserName = cmfac.Username; + CrmConnectionDetail.AzureAdAppId = cmfac.AzureAdAppId; + CrmConnectionDetail.NewAuthType = AuthenticationType.OAuth; + CrmConnectionDetail.UseMfa = true; + + if (CrmConnectionDetail.AzureAdAppId == Guid.Empty + || string.IsNullOrEmpty(CrmConnectionDetail.ReplyUrl)) + { + MessageBox.Show(this, + @"Please provide at least Application Id and Reply Url for multi factor authentication", + @"Warning", + MessageBoxButtons.OK, + MessageBoxIcon.Warning); + + return; + } + + DisplayControl(); + Connect(); + } + else if (ctrl is ConnectionCertificateControl ccertc) + { + CrmConnectionDetail.Certificate = new CertificateInfo + { + Thumbprint = ccertc.Certificate.Thumbprint, + Issuer = ccertc.Certificate.Issuer, + Name = ccertc.Certificate.GetNameInfo(X509NameType.SimpleName, false) + }; + + CrmConnectionDetail.NewAuthType = AuthenticationType.Certificate; + + DisplayControl(); + } + else if (ctrl is ConnectionAppIdControl cac) + { + if (Guid.TryParse(cac.AppId, out Guid appId)) + { + CrmConnectionDetail.AzureAdAppId = appId; + + DisplayControl(); + Connect(); + } + else + { + MessageBox.Show(this, @"Invalid Application Id", @"Error", MessageBoxButtons.OK, + MessageBoxIcon.Error); + } + } + } + + private void btnReset_Click(object sender, EventArgs e) + { + CrmConnectionDetail = new ConnectionDetail(true); + navigationHistory.Clear(); + DisplayControl(); + } + + #endregion Buttons events + + private void Connect() + { + var bw = new BackgroundWorker(); + bw.DoWork += (bwSender, evt) => + { + var currentDetail = (ConnectionDetail)evt.Argument; + var client = currentDetail.GetCrmServiceClient(true); + + var connectionResult = new ConnectionResult(); + + connectionResult.CrmServiceClient = client; + connectionResult.Solutions = currentDetail.GetSolutionsList(); + + evt.Result = connectionResult; + }; + bw.RunWorkerCompleted += (bwSender, evt) => + { + if (evt.Error != null) + { + lastError = evt.Error.Message; + DisplayControl(); + + return; + } + + ConnectionResult connectionResult = (ConnectionResult)evt.Result; + var crmSvc = connectionResult.CrmServiceClient; + + if (!crmSvc.IsReady) + { + lastError = crmSvc.LastCrmError; + DisplayControl(); + + return; + } + + CrmConnectionDetail.Solutions = connectionResult.Solutions; + CrmConnectionDetail.Organization = crmSvc.ConnectedOrgUniqueName; + CrmConnectionDetail.OrganizationFriendlyName = crmSvc.ConnectedOrgFriendlyName; + CrmConnectionDetail.OrganizationUrlName = CrmConnectionDetail.OrganizationUrlName; + CrmConnectionDetail.OrganizationVersion = crmSvc.ConnectedOrgVersion.ToString(); + CrmConnectionDetail.OrganizationDataServiceUrl = crmSvc.ConnectedOrgPublishedEndpoints[EndpointType.OrganizationDataService]; + CrmConnectionDetail.OrganizationServiceUrl = crmSvc.ConnectedOrgPublishedEndpoints[EndpointType.OrganizationService]; + CrmConnectionDetail.ServiceClient = crmSvc; + CrmConnectionDetail.UserName = CrmConnectionDetail.UserName?.Length > 0 + ? CrmConnectionDetail.UserName + : crmSvc.OAuthUserId?.Length > 0 + ? crmSvc.OAuthUserId + : CrmConnectionDetail.AzureAdAppId != Guid.Empty + ? CrmConnectionDetail.AzureAdAppId.ToString("B") + : null; + + DisplayControl(); + }; + bw.RunWorkerAsync(CrmConnectionDetail); + } + + private void ConnectionWizard2_Load(object sender, EventArgs e) + { + if (!isNew) + { + if (CrmConnectionDetail.UseConnectionString) + { + DisplayControl(); + } + else if (CrmConnectionDetail.IsFromSdkLoginCtrl) + { + // Should not be possible as updating a + // connection from the SDK login control + // is handled in ConnectionSelector class + DisplayControl(); + } + else if (CrmConnectionDetail.Certificate != null) + { + type = ConnectionType.Certificate; + DisplayControl(); + } + else if (CrmConnectionDetail.NewAuthType == AuthenticationType.ClientSecret) + { + type = ConnectionType.ClientSecret; + DisplayControl(); + } + else if (CrmConnectionDetail.UseMfa) + { + type = ConnectionType.Mfa; + DisplayControl(); + } + else + { + DisplayControl(); + } + } + else + { + DisplayControl(); + } + } + + private void DisplayControl() where T : IConnectionWizardControl + { + btnBack.Visible = navigationHistory.Count > 0; + + if (typeof(T) != typeof(ConnectionLoadingControl)) + navigationHistory.Add(typeof(T)); + + if (typeof(T) == typeof(StartPageControl)) + { + pnlFooter.Visible = false; + lblHeader.Text = @"Choose a connection method"; + + ctrl = new StartPageControl(); + ((StartPageControl)ctrl).TypeSelected += (sender, e) => + { + type = ((StartPageControl)ctrl).Type; + + switch (((StartPageControl)ctrl).Type) + { + case ConnectionType.Wizard: + DisplayControl(); + break; + + case ConnectionType.Sdk: + DisplayControl(); + break; + + case ConnectionType.ConnectionString: + DisplayControl(); + break; + + case ConnectionType.Certificate: + DisplayControl(); + break; + + case ConnectionType.ClientSecret: + DisplayControl(); + break; + + case ConnectionType.Mfa: + DisplayControl(); + break; + } + }; + + btnReset.Visible = false; + btnNext.Visible = false; + } + else if (typeof(T) == typeof(ConnectionFirstStepControl)) + { + pnlFooter.Visible = true; + lblHeader.Text = @"General information and options"; + + var timespan = CrmConnectionDetail?.Timeout; + if (!timespan.HasValue || timespan.Value.Ticks == 0) + { + timespan = new TimeSpan(0, 2, 0); + } + ctrl = new ConnectionFirstStepControl + { + // Connection Properties + Url = CrmConnectionDetail?.OriginalUrl, + UseIntegratedAuth = !isNew && !(CrmConnectionDetail?.IsCustomAuth ?? true), + UseMfa = CrmConnectionDetail?.UseMfa ?? false, + Timeout = timespan.Value + }; + + btnReset.Visible = true; + btnNext.Visible = true; + btnNext.Text = @"Next"; + } + else if (typeof(T) == typeof(ConnectionCredentialsControl)) + { + pnlFooter.Visible = true; + lblHeader.Text = @"User credentials"; + + ctrl = new ConnectionCredentialsControl + { + // Connection Properties + Domain = CrmConnectionDetail?.UserDomain, + Username = CrmConnectionDetail?.UserName, + IsOnline = CrmConnectionDetail?.UseOnline ?? false, + PasswordIsSet = !CrmConnectionDetail?.PasswordIsEmpty ?? false, + SavePassword = CrmConnectionDetail?.SavePassword ?? false + }; + + btnReset.Visible = true; + btnNext.Visible = true; + btnNext.Text = @"Next"; + } + else if (typeof(T) == typeof(ConnectionIfdControl)) + { + pnlFooter.Visible = true; + lblHeader.Text = @"Internet Facing Deployment settings"; + + ctrl = new ConnectionIfdControl + { + // Connection Properties + IsIfd = CrmConnectionDetail?.UseIfd ?? false, + HomeRealmUrl = CrmConnectionDetail?.HomeRealmUrl + }; + + btnReset.Visible = true; + btnNext.Visible = true; + btnNext.Text = @"Next"; + } + else if (typeof(T) == typeof(ConnectionLoadingControl)) + { + pnlFooter.Visible = true; + lblHeader.Text = @"Connecting..."; + + ctrl = new ConnectionLoadingControl(); + + btnBack.Visible = false; + btnReset.Visible = false; + btnNext.Visible = false; + btnNext.Text = @"Next"; + } + else if (typeof(T) == typeof(ConnectionSucceededControl)) + { + pnlFooter.Visible = true; + lblHeader.Text = @"Connection validated!"; + + ctrl = new ConnectionSucceededControl + { + ConnectionName = CrmConnectionDetail.ConnectionName, + ConnectionDetail = CrmConnectionDetail + }; + + btnBack.Visible = true; + btnReset.Visible = false; + btnNext.Visible = true; + btnNext.Text = @"Finish"; + } + else if (typeof(T) == typeof(ConnectionFailedControl)) + { + pnlFooter.Visible = true; + lblHeader.Text = @"Connection failed!"; + + ctrl = new ConnectionFailedControl + { + ErrorMEssage = lastError + }; + + btnBack.Visible = true; + btnReset.Visible = true; + btnNext.Visible = false; + btnNext.Text = @"Finish"; + } + else if (typeof(T) == typeof(ConnectionStringControl)) + { + pnlFooter.Visible = true; + lblHeader.Text = @"Connectionstring settings"; + + ctrl = new ConnectionStringControl + { + ConnectionString = CrmConnectionDetail.ConnectionString + }; + + btnReset.Visible = true; + btnNext.Visible = true; + btnNext.Text = @"Next"; + } + else if (typeof(T) == typeof(ConnectionOauthControl)) + { + pnlFooter.Visible = true; + lblHeader.Text = @"OAuth protocol settings"; + + ctrl = new ConnectionOauthControl + { + AzureAdAppId = CrmConnectionDetail.AzureAdAppId, + ReplyUrl = CrmConnectionDetail.ReplyUrl, + HasClientSecret = !CrmConnectionDetail.ClientSecretIsEmpty + }; + + btnReset.Visible = true; + btnNext.Visible = true; + btnNext.Text = @"Next"; + } + else if (typeof(T) == typeof(SdkLoginControlControl)) + { + pnlFooter.Visible = true; + lblHeader.Text = @"SDK Login control (Preview)"; + + if (!CrmConnectionDetail.ConnectionId.HasValue) + { + CrmConnectionDetail.ConnectionId = Guid.NewGuid(); + } + + ctrl = new SdkLoginControlControl(CrmConnectionDetail.ConnectionId.Value, isNew); + ((SdkLoginControlControl)ctrl).ConnectionSucceeded += (sender, evt) => { btnNext_Click(btnNext, null); }; + + btnReset.Visible = true; + btnNext.Visible = false; + } + else if (typeof(T) == typeof(ConnectionUrlControl)) + { + pnlFooter.Visible = true; + lblHeader.Text = @"Provide environment information"; + + if (!CrmConnectionDetail.ConnectionId.HasValue) + { + CrmConnectionDetail.ConnectionId = Guid.NewGuid(); + } + + ctrl = new ConnectionUrlControl(CrmConnectionDetail); + + btnReset.Visible = true; + btnNext.Visible = true; + btnNext.Text = @"Next"; + } + else if (typeof(T) == typeof(ConnectionCertificateControl)) + { + pnlFooter.Visible = true; + lblHeader.Text = @"Connection with certificate"; + + if (!CrmConnectionDetail.ConnectionId.HasValue) + { + CrmConnectionDetail.ConnectionId = Guid.NewGuid(); + } + + ctrl = new ConnectionCertificateControl(CrmConnectionDetail); + + btnReset.Visible = true; + btnNext.Visible = true; + btnNext.Text = @"Next"; + } + else if (typeof(T) == typeof(ConnectionAppIdControl)) + { + pnlFooter.Visible = true; + lblHeader.Text = @"Application user Application ID"; + + if (!CrmConnectionDetail.ConnectionId.HasValue) + { + CrmConnectionDetail.ConnectionId = Guid.NewGuid(); + } + + ctrl = new ConnectionAppIdControl(); + if (CrmConnectionDetail.AzureAdAppId != Guid.Empty) + { + ((ConnectionAppIdControl)ctrl).AppId = CrmConnectionDetail.AzureAdAppId.ToString("B"); + } + + btnReset.Visible = true; + btnNext.Visible = true; + btnNext.Text = @"Next"; + } + else if (typeof(T) == typeof(ConnectionClientSecretControl)) + { + pnlFooter.Visible = true; + lblHeader.Text = @"Client Id / Secret"; + + if (!CrmConnectionDetail.ConnectionId.HasValue) + { + CrmConnectionDetail.ConnectionId = Guid.NewGuid(); + } + + ctrl = new ConnectionClientSecretControl(); + ((ConnectionClientSecretControl)ctrl).HasClientSecret = !CrmConnectionDetail.ClientSecretIsEmpty; + if (CrmConnectionDetail.AzureAdAppId != Guid.Empty) + { + ((ConnectionClientSecretControl)ctrl).AzureAdAppId = CrmConnectionDetail.AzureAdAppId; + } + + btnReset.Visible = true; + btnNext.Visible = true; + btnNext.Text = @"Next"; + } + else if (typeof(T) == typeof(ConnectionMfaControl)) + { + pnlFooter.Visible = true; + lblHeader.Text = @"Mutli Factor Authentication"; + + if (!CrmConnectionDetail.ConnectionId.HasValue) + { + CrmConnectionDetail.ConnectionId = Guid.NewGuid(); + } + + ctrl = new ConnectionMfaControl(); + ((ConnectionMfaControl)ctrl).Username = CrmConnectionDetail.UserName; + ((ConnectionMfaControl)ctrl).ReplyUrl = CrmConnectionDetail.ReplyUrl; + if (CrmConnectionDetail.AzureAdAppId != Guid.Empty) + { + ((ConnectionMfaControl)ctrl).AzureAdAppId = CrmConnectionDetail.AzureAdAppId; + } + + btnReset.Visible = true; + btnNext.Visible = true; + btnNext.Text = @"Next"; + } + + ((UserControl)ctrl).Dock = DockStyle.Fill; + pnlMain.Controls.Clear(); + pnlMain.Controls.Add((UserControl)ctrl); + } + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ConnectionWizard2.designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ConnectionWizard2.designer.cs new file mode 100644 index 0000000..d7cb6f1 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ConnectionWizard2.designer.cs @@ -0,0 +1,153 @@ +namespace McTools.Xrm.Connection.WinForms +{ + partial class ConnectionWizard2 + { + /// + /// Variable nécessaire au concepteur. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Nettoyage des ressources utilisées. + /// + /// true si les ressources managées doivent être supprimées ; sinon, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Code généré par le Concepteur Windows Form + + /// + /// Méthode requise pour la prise en charge du concepteur - ne modifiez pas + /// le contenu de cette méthode avec l'éditeur de code. + /// + private void InitializeComponent() + { + this.pnlHeader = new System.Windows.Forms.Panel(); + this.lblHeader = new System.Windows.Forms.Label(); + this.pnlFooter = new System.Windows.Forms.Panel(); + this.btnReset = new System.Windows.Forms.Button(); + this.btnBack = new System.Windows.Forms.Button(); + this.btnNext = new System.Windows.Forms.Button(); + this.pnlMain = new System.Windows.Forms.Panel(); + this.pnlHeader.SuspendLayout(); + this.pnlFooter.SuspendLayout(); + this.SuspendLayout(); + // + // pnlHeader + // + this.pnlHeader.BackColor = System.Drawing.Color.White; + this.pnlHeader.Controls.Add(this.lblHeader); + this.pnlHeader.Dock = System.Windows.Forms.DockStyle.Top; + this.pnlHeader.Location = new System.Drawing.Point(0, 0); + this.pnlHeader.Margin = new System.Windows.Forms.Padding(4); + this.pnlHeader.Name = "pnlHeader"; + this.pnlHeader.Size = new System.Drawing.Size(985, 74); + this.pnlHeader.TabIndex = 9; + // + // lblHeader + // + this.lblHeader.AutoSize = true; + this.lblHeader.Font = new System.Drawing.Font("Segoe UI", 14F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblHeader.Location = new System.Drawing.Point(14, 10); + this.lblHeader.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblHeader.Name = "lblHeader"; + this.lblHeader.Size = new System.Drawing.Size(256, 45); + this.lblHeader.TabIndex = 0; + this.lblHeader.Text = "New connection"; + // + // pnlFooter + // + this.pnlFooter.Controls.Add(this.btnReset); + this.pnlFooter.Controls.Add(this.btnBack); + this.pnlFooter.Controls.Add(this.btnNext); + this.pnlFooter.Dock = System.Windows.Forms.DockStyle.Bottom; + this.pnlFooter.Location = new System.Drawing.Point(0, 321); + this.pnlFooter.Name = "pnlFooter"; + this.pnlFooter.Padding = new System.Windows.Forms.Padding(4); + this.pnlFooter.Size = new System.Drawing.Size(985, 50); + this.pnlFooter.TabIndex = 10; + // + // btnReset + // + this.btnReset.Dock = System.Windows.Forms.DockStyle.Right; + this.btnReset.Location = new System.Drawing.Point(615, 4); + this.btnReset.Margin = new System.Windows.Forms.Padding(4); + this.btnReset.Name = "btnReset"; + this.btnReset.Size = new System.Drawing.Size(122, 42); + this.btnReset.TabIndex = 8; + this.btnReset.Text = "Reset"; + this.btnReset.UseVisualStyleBackColor = true; + this.btnReset.Click += new System.EventHandler(this.btnReset_Click); + // + // btnBack + // + this.btnBack.Dock = System.Windows.Forms.DockStyle.Right; + this.btnBack.Location = new System.Drawing.Point(737, 4); + this.btnBack.Margin = new System.Windows.Forms.Padding(4); + this.btnBack.Name = "btnBack"; + this.btnBack.Size = new System.Drawing.Size(122, 42); + this.btnBack.TabIndex = 7; + this.btnBack.Text = "Back"; + this.btnBack.UseVisualStyleBackColor = true; + this.btnBack.Click += new System.EventHandler(this.btnBack_Click); + // + // btnNext + // + this.btnNext.Dock = System.Windows.Forms.DockStyle.Right; + this.btnNext.Location = new System.Drawing.Point(859, 4); + this.btnNext.Margin = new System.Windows.Forms.Padding(4); + this.btnNext.Name = "btnNext"; + this.btnNext.Size = new System.Drawing.Size(122, 42); + this.btnNext.TabIndex = 6; + this.btnNext.Text = "Next"; + this.btnNext.UseVisualStyleBackColor = true; + this.btnNext.Click += new System.EventHandler(this.btnNext_Click); + // + // pnlMain + // + this.pnlMain.Dock = System.Windows.Forms.DockStyle.Fill; + this.pnlMain.Location = new System.Drawing.Point(0, 74); + this.pnlMain.Name = "pnlMain"; + this.pnlMain.Size = new System.Drawing.Size(985, 247); + this.pnlMain.TabIndex = 11; + // + // ConnectionWizard2 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(168F, 168F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.ClientSize = new System.Drawing.Size(985, 371); + this.Controls.Add(this.pnlMain); + this.Controls.Add(this.pnlFooter); + this.Controls.Add(this.pnlHeader); + this.Font = new System.Drawing.Font("Segoe UI", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.Margin = new System.Windows.Forms.Padding(4); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ConnectionWizard2"; + this.ShowIcon = false; + this.Load += new System.EventHandler(this.ConnectionWizard2_Load); + this.pnlHeader.ResumeLayout(false); + this.pnlHeader.PerformLayout(); + this.pnlFooter.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + private System.Windows.Forms.Panel pnlHeader; + private System.Windows.Forms.Label lblHeader; + private System.Windows.Forms.Panel pnlFooter; + private System.Windows.Forms.Panel pnlMain; + private System.Windows.Forms.Button btnReset; + private System.Windows.Forms.Button btnBack; + private System.Windows.Forms.Button btnNext; + } +} + diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ConnectionWizard2.resx b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ConnectionWizard2.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ConnectionWizard2.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CrmConnectionStatusBar.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CrmConnectionStatusBar.cs index f9f504a..e5733bd 100644 --- a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CrmConnectionStatusBar.cs +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CrmConnectionStatusBar.cs @@ -1,4 +1,7 @@ using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; using System.Windows.Forms; namespace McTools.Xrm.Connection.WinForms @@ -11,121 +14,82 @@ public partial class CrmConnectionStatusBar : StatusStrip { #region Variables - /// - /// Crm connection manager - /// - ConnectionManager cManager; - - private FormHelper _formHelper; + private readonly FormHelper _formHelper; /// /// Resources manager /// - System.ComponentModel.ComponentResourceManager resources; + private readonly System.ComponentModel.ComponentResourceManager resources; + + private bool mergeConnectionFiles; - #endregion + #endregion Variables #region Constructor /// /// Initializes a new instance of class CrmConnectionStatusBar /// - /// Connection manager to use - public CrmConnectionStatusBar(ConnectionManager connectionManager, FormHelper formHelper) + public CrmConnectionStatusBar(FormHelper formHelper, bool mergeConnectionFiles = false) { + this.mergeConnectionFiles = mergeConnectionFiles; resources = new System.ComponentModel.ComponentResourceManager(typeof(CrmConnectionStatusBar)); - - this.cManager = connectionManager; + ConnectionManager.Instance.ConnectionListUpdated += cManager_ConnectionListUpdated; _formHelper = formHelper; // Build connection control - this.BuildConnectionControl(); + BuildConnectionControl(); // Add label that will display information about connection - ToolStripLabel informationLabel = new ToolStripLabel(); - this.Items.Add(informationLabel); - base.RenderMode = ToolStripRenderMode.Professional; - } - - #endregion + ToolStripStatusLabel informationLabel = new ToolStripStatusLabel + { + Spring = true, + TextAlign = ContentAlignment.MiddleRight + }; - #region Methods + Items.Add(informationLabel); - /// - /// Builds the ToolStripDropDownButton that will manage connections - /// - private void BuildConnectionControl() - { - ToolStripDropDownButton connexionManager = new ToolStripDropDownButton(); - connexionManager.Text = "Not connected"; - connexionManager.Image = ((System.Drawing.Image)(resources.GetObject("server"))); - //connexionManager.Click += new EventHandler(connexionManager_Click); - - this.AddActionsList(connexionManager); + ToolStripProgressBar progress = new ToolStripProgressBar + { + Minimum = 0, + Maximum = 100, + Visible = false + }; + Items.Add(progress); - this.Items.Add(connexionManager); + RenderMode = ToolStripRenderMode.Professional; } - public void RebuildConnectionList() + private void cManager_ConnectionListUpdated(object sender, EventArgs e) { - AddActionsList((ToolStripDropDownButton)Items[0]); + RebuildConnectionList(); } - /// - /// Adds the ToolStripMenuItems representing connections to the - /// ToolStripDropDownButton - /// - /// ToolStripDropDownButton where to add connections - private void AddActionsList(ToolStripDropDownButton btn) - { - // Clearing existing connections - btn.DropDownItems.Clear(); - - if (this.cManager != null && this.cManager.ConnectionsList != null && this.cManager.ConnectionsList.Connections.Count > 0) - { - this.cManager.ConnectionsList.Connections.Sort(); - - foreach (ConnectionDetail cDetail in this.cManager.ConnectionsList.Connections) - { - ToolStripMenuItem item = new ToolStripMenuItem(); - item.Text = cDetail.ConnectionName; - item.Tag = cDetail; - - if (cDetail.UseOnline) - { - item.Image = RessourceManager.GetImage("McTools.Xrm.Connection.WinForms.Resources.CRMOnlineLive_16.png"); - } - else if (cDetail.UseOsdp) - { - item.Image = RessourceManager.GetImage("McTools.Xrm.Connection.WinForms.Resources.CRMOnlineLive_16.png"); - } - else if (cDetail.UseIfd) - { - item.Image = RessourceManager.GetImage("McTools.Xrm.Connection.WinForms.Resources.server_key.png"); - } - else - { - item.Image = RessourceManager.GetImage("McTools.Xrm.Connection.WinForms.Resources.server.png"); - } + #endregion Constructor - this.BuildActionItems(item); + #region Properties - btn.DropDownItems.Add(item); - } - - if (this.cManager.ConnectionsList.Connections.Count > 0) + public bool MergeConnectionsFiles + { + get { return mergeConnectionFiles; } + set + { + if (value != mergeConnectionFiles) { - ToolStripSeparator separator = new ToolStripSeparator(); - btn.DropDownItems.Add(separator); + mergeConnectionFiles = value; + RebuildConnectionList(); } } + } + + #endregion Properties - ToolStripMenuItem newConnectionItem = new ToolStripMenuItem(); - newConnectionItem.Text = "Create new connection"; - newConnectionItem.Image = ((System.Drawing.Image)(resources.GetObject("server_add"))); - newConnectionItem.Click += new EventHandler(newConnectionItem_Click); - btn.DropDownItems.Add(newConnectionItem); + #region Methods + + public void RebuildConnectionList() + { + AddActionsList((ToolStripDropDownButton)Items[0]); } /// @@ -135,20 +99,18 @@ private void AddActionsList(ToolStripDropDownButton btn) /// Connection details public void SetConnectionStatus(bool isConnected, ConnectionDetail detail) { - ToolStripDropDownButton btn = (ToolStripDropDownButton)this.Items[0]; + ToolStripDropDownButton btn = (ToolStripDropDownButton)Items[0]; if (isConnected) { - this.SetMessage("Connected!"); - btn.Text = string.Format("Connected to '{0} ({1})'", - detail.ServerName, - detail.OrganizationFriendlyName); - btn.Image = (System.Drawing.Image)(resources.GetObject("server_lightning")); + SetMessage("Connected!"); + btn.Text = $"Connected to '{detail.ServerName} ({detail.OrganizationFriendlyName})'"; + btn.Image = (Image)resources.GetObject("server_lightning"); } else { btn.Text = "Not connected"; - btn.Image = (System.Drawing.Image)(resources.GetObject("server")); + btn.Image = (Image)resources.GetObject("server"); } } @@ -158,16 +120,16 @@ public void SetConnectionStatus(bool isConnected, ConnectionDetail detail) /// Message to display public void SetMessage(string message) { - ToolStripLabel label = (ToolStripLabel)this.Items[1]; + ToolStripStatusLabel label = (ToolStripStatusLabel)Items[1]; MethodInvoker mi = delegate { label.Text = message; }; - if (this.InvokeRequired) + if (InvokeRequired) { - this.Invoke(mi); + Invoke(mi); } else { @@ -175,82 +137,243 @@ public void SetMessage(string message) } } - /// - /// Creates the three action menus for a connection - /// - /// Menu where to add the actions - private void BuildActionItems(ToolStripMenuItem item) + public void SetProgress(int? percent) { - ToolStripMenuItem cItem = new ToolStripMenuItem(); - cItem.Click += new EventHandler(actionItem_Click); - cItem.Text = "Connect"; - cItem.Image = ((System.Drawing.Image)(resources.GetObject("server_connect"))); - item.DropDownItems.Add(cItem); + ToolStripProgressBar progress = (ToolStripProgressBar)Items[2]; + + MethodInvoker mi = delegate + { + if (percent.HasValue) + { + progress.Value = percent.Value; + progress.Visible = true; + } + else + { + progress.Value = 0; + progress.Visible = false; + } + }; - ToolStripMenuItem eItem = new ToolStripMenuItem(); - eItem.Click += new EventHandler(actionItem_Click); - eItem.Text = "Edit"; - eItem.Image = ((System.Drawing.Image)(resources.GetObject("server_edit"))); - item.DropDownItems.Add(eItem); - - ToolStripMenuItem dItem = new ToolStripMenuItem(); - dItem.Click += new EventHandler(actionItem_Click); - dItem.Text = "Delete"; - dItem.Image = ((System.Drawing.Image)(resources.GetObject("server_delete"))); - item.DropDownItems.Add(dItem); + if (InvokeRequired) + { + Invoke(mi); + } + else + { + mi(); + } } - #endregion + /// + /// Adds the ToolStripMenuItems representing connections to the + /// ToolStripDropDownButton + /// + /// ToolStripDropDownButton where to add connections + private void AddActionsList(ToolStripDropDownButton btn) + { + var list = new List(); + int filesCount = ConnectionsList.Instance.Files.Count; - #region Events + if (filesCount == 0) + { + var defaultFilePath = Path.Combine(new FileInfo(ConnectionsList.ConnectionsListFilePath).DirectoryName, "ConnectionsList.Default.xml"); - void connexionManager_Click(object sender, EventArgs e) - { - // On main ToolStripDropDownButton button click, we rebuild the list - // of crm connections - this.AddActionsList((ToolStripDropDownButton)sender); - } + CrmConnections cc = new CrmConnections("Default"); + cc.SerializeToFile(defaultFilePath); - void newConnectionItem_Click(object sender, EventArgs e) - { - ConnectionDetail detail = _formHelper.EditConnection(true, null); + ConnectionsList.Instance.Files.Add(new ConnectionFile(cc) { Path = defaultFilePath, LastUsed = DateTime.Now }); + ConnectionsList.Instance.Save(); + } - if (detail != null) + foreach (var file in ConnectionsList.Instance.Files) { - ToolStripMenuItem item = new ToolStripMenuItem(); - item.Text = detail.ConnectionName; - item.Tag = detail; + var connections = CrmConnections.LoadFromFile(file.Path); + connections.Connections.Sort(); + + var fileItem = new ToolStripMenuItem(file.Name); + fileItem.Tag = file; + if (!mergeConnectionFiles && filesCount > 1) + { + list.Add(fileItem); + } + + foreach (var cDetail in connections.Connections) + { + ToolStripMenuItem item = new ToolStripMenuItem(); + item.Text = cDetail.ConnectionName; + item.Tag = cDetail; - BuildActionItems(item); + if (cDetail.UseOnline) + { + item.Image = + RessourceManager.GetImage( + "McTools.Xrm.Connection.WinForms.Resources.CRMOnlineLive_16.png"); + } + else if (cDetail.UseIfd) + { + item.Image = + RessourceManager.GetImage( + "McTools.Xrm.Connection.WinForms.Resources.server_key.png"); + } + else + { + item.Image = + RessourceManager.GetImage( + "McTools.Xrm.Connection.WinForms.Resources.server.png"); + } - ToolStripDropDownButton connexionManager = (ToolStripDropDownButton)this.Items[0]; + BuildActionItems(item, connections.IsReadOnly); + if (!mergeConnectionFiles && filesCount > 1) + { + fileItem.DropDownItems.Add(item); + } + else + { + list.Add(item); + } + } - if (connexionManager.DropDownItems.Count == 1) + if (!mergeConnectionFiles && filesCount > 1) { - connexionManager.DropDownItems.Insert(0, new ToolStripSeparator()); - connexionManager.DropDownItems.Insert(0, item); + if (fileItem.DropDownItems.Count > 0) + { + fileItem.DropDownItems.Add(new ToolStripSeparator()); + } } - else + + if (!connections.IsReadOnly) { - connexionManager.DropDownItems.Insert(connexionManager.DropDownItems.Count - 2, item); + var newConnectionItem = new ToolStripMenuItem(); + newConnectionItem.Text = "Create new connection"; + newConnectionItem.Image = (Image)resources.GetObject("server_add"); + newConnectionItem.Click += newConnectionItem_Click; + + if (!mergeConnectionFiles && filesCount > 1) + { + fileItem.DropDownItems.Add(newConnectionItem); + } } + } - MessageBox.Show(this, "Connection Created Successfully!", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information); + if (mergeConnectionFiles || filesCount == 1) + { + if (list.Count > 0) + { + list.Add(new ToolStripSeparator()); + } + + var newConnectionItem = new ToolStripMenuItem(); + newConnectionItem.Text = "Create new connection"; + newConnectionItem.Image = (Image)resources.GetObject("server_add"); + newConnectionItem.Click += newConnectionItem_Click; + + list.Add(newConnectionItem); + } + + if (InvokeRequired) + { + Invoke(new Action(() => + { + btn.DropDownItems.Clear(); + btn.DropDownItems.AddRange(list.ToArray()); + })); + } + else + { + btn.DropDownItems.Clear(); + btn.DropDownItems.AddRange(list.ToArray()); } } - void actionItem_Click(object sender, EventArgs e) + /// + /// Creates the three action menus for a connection + /// + /// Menu where to add the actions + /// Indicates if the connection is from a read-only list + private void BuildActionItems(ToolStripMenuItem item, bool readOnly) + { + ToolStripMenuItem cItem = new ToolStripMenuItem(); + cItem.Click += actionItem_Click; + cItem.Text = "Connect"; + cItem.Image = (Image)resources.GetObject("server_connect"); + item.DropDownItems.Add(cItem); + + if (!readOnly) + { + ToolStripMenuItem eItem = new ToolStripMenuItem(); + eItem.Click += actionItem_Click; + eItem.Text = "Edit"; + eItem.Image = (Image)resources.GetObject("server_edit"); + item.DropDownItems.Add(eItem); + + ToolStripMenuItem dItem = new ToolStripMenuItem(); + dItem.Click += actionItem_Click; + dItem.Text = "Delete"; + dItem.Image = (Image)resources.GetObject("server_delete"); + item.DropDownItems.Add(dItem); + } + } + + /// + /// Builds the ToolStripDropDownButton that will manage connections + /// + private void BuildConnectionControl() + { + ToolStripDropDownButton connexionManager = new ToolStripDropDownButton(); + connexionManager.Text = "Not connected"; + connexionManager.Image = (Image)resources.GetObject("server"); + connexionManager.Click += connexionManager_Click; + AddActionsList(connexionManager); + + Items.Add(connexionManager); + } + + #endregion Methods + + #region Events + + private void actionItem_Click(object sender, EventArgs e) { ToolStripMenuItem clickedItem = (ToolStripMenuItem)sender; - ToolStripMenuItem parentItem = (ToolStripMenuItem)clickedItem.OwnerItem; + ToolStripDropDownItem parentItem = (ToolStripDropDownItem)clickedItem.OwnerItem; ConnectionDetail currentConnection = (ConnectionDetail)parentItem.Tag; - ToolStripDropDownButton connexionManager = (ToolStripDropDownButton)parentItem.OwnerItem; + ToolStripDropDownItem connexionManager = (ToolStripDropDownItem)parentItem.OwnerItem; switch (clickedItem.Text) { case "Connect": - this.cManager.ConnectToServer(currentConnection); + + if (currentConnection.IsCustomAuth) + { + if (_formHelper.RequestPassword(currentConnection)) + { + ConnectionManager.Instance.ConnectToServer(new List { currentConnection }); + } + } + else + { + if (currentConnection.IsFromSdkLoginCtrl) + { + var ctrl = new CRMLoginForm1(currentConnection.ConnectionId.Value); + if (currentConnection.AzureAdAppId != Guid.Empty) + { + ctrl.AppId = currentConnection.AzureAdAppId.ToString(); + ctrl.RedirectUri = new Uri(currentConnection.ReplyUrl); + } + + ctrl.ShowDialog(); + + ConnectionManager.Instance.ConnectToServerWithSdkLoginCtrl(currentConnection, ctrl.CrmConnectionMgr.CrmSvc, + null); + } + else + { + ConnectionManager.Instance.ConnectToServer(new List { currentConnection }); + } + } break; + case "Edit": currentConnection = _formHelper.EditConnection(false, currentConnection); @@ -261,7 +384,11 @@ void actionItem_Click(object sender, EventArgs e) } break; + case "Delete": + if (MessageBox.Show(this, "Are you sure you want to delete selected connection(s)?", "Question", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No) + return; + connexionManager.DropDownItems.Remove(parentItem); if (connexionManager.DropDownItems.Count == 2) @@ -269,12 +396,68 @@ void actionItem_Click(object sender, EventArgs e) connexionManager.DropDownItems.RemoveAt(0); } - _formHelper.DeleteConnection(currentConnection); + _formHelper.DeleteConnection(currentConnection.ConnectionId); break; } } - #endregion + private void connexionManager_Click(object sender, EventArgs e) + { + // On main ToolStripDropDownButton button click, we rebuild the list + // of crm connections + AddActionsList((ToolStripDropDownButton)sender); + } + + private void newConnectionItem_Click(object sender, EventArgs e) + { + var actionMenu = (ToolStripMenuItem)sender; + ToolStripDropDownItem parentItem = (ToolStripDropDownItem)actionMenu.OwnerItem; + var connectionFile = (ConnectionFile)parentItem.Tag; + + ConnectionDetail detail = _formHelper.EditConnection(true, null, connectionFile); + + if (detail != null) + { + ToolStripMenuItem item = new ToolStripMenuItem(); + item.Text = detail.ConnectionName; + item.Tag = detail; + + if (detail.UseOnline) + { + item.Image = + RessourceManager.GetImage( + "McTools.Xrm.Connection.WinForms.Resources.CRMOnlineLive_16.png"); + } + else if (detail.UseIfd) + { + item.Image = + RessourceManager.GetImage( + "McTools.Xrm.Connection.WinForms.Resources.server_key.png"); + } + else + { + item.Image = + RessourceManager.GetImage( + "McTools.Xrm.Connection.WinForms.Resources.server.png"); + } + + BuildActionItems(item, false); + + if (parentItem.DropDownItems.Count == 1) + { + parentItem.DropDownItems.Insert(0, new ToolStripSeparator()); + parentItem.DropDownItems.Insert(0, item); + } + else + { + parentItem.DropDownItems.Insert(parentItem.DropDownItems.Count - 2, item); + } + + MessageBox.Show(this, "Connection Created Successfully!", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + } + + #endregion Events } } \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionAppIdControl.Designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionAppIdControl.Designer.cs new file mode 100644 index 0000000..cb39578 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionAppIdControl.Designer.cs @@ -0,0 +1,73 @@ +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + partial class ConnectionAppIdControl + { + /// + /// Variable nécessaire au concepteur. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Nettoyage des ressources utilisées. + /// + /// true si les ressources managées doivent être supprimées ; sinon, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Code généré par le Concepteur de composants + + /// + /// Méthode requise pour la prise en charge du concepteur - ne modifiez pas + /// le contenu de cette méthode avec l'éditeur de code. + /// + private void InitializeComponent() + { + this.lblHomeRealmQuestion = new System.Windows.Forms.Label(); + this.txtAppId = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // lblHomeRealmQuestion + // + this.lblHomeRealmQuestion.AutoSize = true; + this.lblHomeRealmQuestion.Location = new System.Drawing.Point(4, 0); + this.lblHomeRealmQuestion.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblHomeRealmQuestion.Name = "lblHomeRealmQuestion"; + this.lblHomeRealmQuestion.Size = new System.Drawing.Size(238, 25); + this.lblHomeRealmQuestion.TabIndex = 11; + this.lblHomeRealmQuestion.Text = "Azure AD Application Id"; + // + // txtAppId + // + this.txtAppId.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtAppId.Location = new System.Drawing.Point(9, 39); + this.txtAppId.Margin = new System.Windows.Forms.Padding(4); + this.txtAppId.Name = "txtAppId"; + this.txtAppId.Size = new System.Drawing.Size(956, 31); + this.txtAppId.TabIndex = 3; + // + // ConnectionAppIdControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.lblHomeRealmQuestion); + this.Controls.Add(this.txtAppId); + this.Name = "ConnectionAppIdControl"; + this.Size = new System.Drawing.Size(982, 285); + this.Load += new System.EventHandler(this.ConnectionIfdControl_Load); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + private System.Windows.Forms.Label lblHomeRealmQuestion; + private System.Windows.Forms.TextBox txtAppId; + } +} diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionAppIdControl.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionAppIdControl.cs new file mode 100644 index 0000000..0d97d0a --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionAppIdControl.cs @@ -0,0 +1,22 @@ +using System.Windows.Forms; + +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + public partial class ConnectionAppIdControl : UserControl, IConnectionWizardControl + { + public ConnectionAppIdControl() + { + InitializeComponent(); + } + + public string AppId + { + get => txtAppId.Text; + set => txtAppId.Text = value; + } + + private void ConnectionIfdControl_Load(object sender, System.EventArgs e) + { + } + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionAppIdControl.resx b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionAppIdControl.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionAppIdControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionCertificateControl.Designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionCertificateControl.Designer.cs new file mode 100644 index 0000000..96f0c55 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionCertificateControl.Designer.cs @@ -0,0 +1,130 @@ +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + partial class ConnectionCertificateControl + { + /// + /// Variable nécessaire au concepteur. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Nettoyage des ressources utilisées. + /// + /// true si les ressources managées doivent être supprimées ; sinon, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Code généré par le Concepteur de composants + + /// + /// Méthode requise pour la prise en charge du concepteur - ne modifiez pas + /// le contenu de cette méthode avec l'éditeur de code. + /// + private void InitializeComponent() + { + this.btnBrowseCert = new System.Windows.Forms.Button(); + this.pnlMain = new System.Windows.Forms.Panel(); + this.lblTitle = new System.Windows.Forms.Label(); + this.lblName = new System.Windows.Forms.Label(); + this.lblIssuer = new System.Windows.Forms.Label(); + this.lblThumbprint = new System.Windows.Forms.Label(); + this.pnlMain.SuspendLayout(); + this.SuspendLayout(); + // + // btnBrowseCert + // + this.btnBrowseCert.Dock = System.Windows.Forms.DockStyle.Bottom; + this.btnBrowseCert.Location = new System.Drawing.Point(10, 209); + this.btnBrowseCert.Name = "btnBrowseCert"; + this.btnBrowseCert.Size = new System.Drawing.Size(962, 66); + this.btnBrowseCert.TabIndex = 0; + this.btnBrowseCert.Text = "Select certificate"; + this.btnBrowseCert.UseVisualStyleBackColor = true; + this.btnBrowseCert.Click += new System.EventHandler(this.btnBrowseCert_Click); + // + // pnlMain + // + this.pnlMain.Controls.Add(this.lblThumbprint); + this.pnlMain.Controls.Add(this.lblIssuer); + this.pnlMain.Controls.Add(this.lblName); + this.pnlMain.Controls.Add(this.lblTitle); + this.pnlMain.Dock = System.Windows.Forms.DockStyle.Fill; + this.pnlMain.Location = new System.Drawing.Point(10, 10); + this.pnlMain.Name = "pnlMain"; + this.pnlMain.Size = new System.Drawing.Size(962, 199); + this.pnlMain.TabIndex = 1; + // + // lblTitle + // + this.lblTitle.Dock = System.Windows.Forms.DockStyle.Top; + this.lblTitle.Font = new System.Drawing.Font("Microsoft Sans Serif", 7.875F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblTitle.Location = new System.Drawing.Point(0, 0); + this.lblTitle.Name = "lblTitle"; + this.lblTitle.Size = new System.Drawing.Size(962, 40); + this.lblTitle.TabIndex = 0; + this.lblTitle.Text = "Current selected certificate"; + // + // lblName + // + this.lblName.Dock = System.Windows.Forms.DockStyle.Top; + this.lblName.Font = new System.Drawing.Font("Microsoft Sans Serif", 7.875F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblName.Location = new System.Drawing.Point(0, 40); + this.lblName.Name = "lblName"; + this.lblName.Size = new System.Drawing.Size(962, 40); + this.lblName.TabIndex = 1; + this.lblName.Tag = "Name : {0}"; + this.lblName.Text = "Name :"; + // + // lblIssuer + // + this.lblIssuer.Dock = System.Windows.Forms.DockStyle.Top; + this.lblIssuer.Font = new System.Drawing.Font("Microsoft Sans Serif", 7.875F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblIssuer.Location = new System.Drawing.Point(0, 80); + this.lblIssuer.Name = "lblIssuer"; + this.lblIssuer.Size = new System.Drawing.Size(962, 40); + this.lblIssuer.TabIndex = 2; + this.lblIssuer.Tag = "Issuer : {0}"; + this.lblIssuer.Text = "Issuer :"; + // + // lblThumbprint + // + this.lblThumbprint.Dock = System.Windows.Forms.DockStyle.Top; + this.lblThumbprint.Font = new System.Drawing.Font("Microsoft Sans Serif", 7.875F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblThumbprint.Location = new System.Drawing.Point(0, 120); + this.lblThumbprint.Name = "lblThumbprint"; + this.lblThumbprint.Size = new System.Drawing.Size(962, 40); + this.lblThumbprint.TabIndex = 3; + this.lblThumbprint.Tag = "Thumbprint : {0}"; + this.lblThumbprint.Text = "Thumbprint :"; + // + // ConnectionCertificateControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.pnlMain); + this.Controls.Add(this.btnBrowseCert); + this.Name = "ConnectionCertificateControl"; + this.Padding = new System.Windows.Forms.Padding(10); + this.Size = new System.Drawing.Size(982, 285); + this.Load += new System.EventHandler(this.ConnectionStringControl_Load); + this.pnlMain.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Button btnBrowseCert; + private System.Windows.Forms.Panel pnlMain; + private System.Windows.Forms.Label lblThumbprint; + private System.Windows.Forms.Label lblIssuer; + private System.Windows.Forms.Label lblName; + private System.Windows.Forms.Label lblTitle; + } +} diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionCertificateControl.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionCertificateControl.cs new file mode 100644 index 0000000..ae249df --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionCertificateControl.cs @@ -0,0 +1,71 @@ +using System; +using System.Security.Cryptography.X509Certificates; +using System.Windows.Forms; + +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + public partial class ConnectionCertificateControl : UserControl, IConnectionWizardControl + { + private readonly ConnectionDetail _detail; + private readonly X509Store _store; + + public ConnectionCertificateControl(ConnectionDetail detail = null) + { + _store = new X509Store("MY", StoreLocation.CurrentUser); + InitializeComponent(); + + _detail = detail; + } + + public X509Certificate2 Certificate { get; private set; } + + private void btnBrowseCert_Click(object sender, System.EventArgs e) + { + _store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); + X509Certificate2Collection collection = _store.Certificates; + X509Certificate2Collection fcollection = collection.Find(X509FindType.FindByTimeValid, DateTime.Now, false); + + X509Certificate2Collection scollection = X509Certificate2UI.SelectFromCollection(fcollection, + "Certificate selection", + "Select a certificate from the following list to use as connection credentials", + X509SelectionFlag.SingleSelection); + + if (scollection.Count == 0) return; + + Certificate = scollection[0]; + + DisplayCertInfo(); + + _store.Close(); + } + + private void ConnectionStringControl_Load(object sender, System.EventArgs e) + { + if (_detail != null) + { + _store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); + X509Certificate2Collection collection = _store.Certificates; + + foreach (var c in collection) + { + if (c.GetNameInfo(X509NameType.SimpleName, false) == _detail.Certificate?.Name + && c.Issuer == _detail.Certificate?.Issuer + && c.Thumbprint == _detail.Certificate?.Thumbprint) + { + Certificate = c; + DisplayCertInfo(); + } + } + + _store.Close(); + } + } + + private void DisplayCertInfo() + { + lblName.Text = string.Format(lblName.Tag.ToString(), Certificate.GetNameInfo(X509NameType.SimpleName, false)); + lblIssuer.Text = string.Format(lblIssuer.Tag.ToString(), Certificate.Issuer); + lblThumbprint.Text = string.Format(lblThumbprint.Tag.ToString(), Certificate.Thumbprint); + } + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionCertificateControl.resx b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionCertificateControl.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionCertificateControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionClientSecretControl.Designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionClientSecretControl.Designer.cs new file mode 100644 index 0000000..d07f9fb --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionClientSecretControl.Designer.cs @@ -0,0 +1,151 @@ +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + partial class ConnectionClientSecretControl + { + /// + /// Variable nécessaire au concepteur. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Nettoyage des ressources utilisées. + /// + /// true si les ressources managées doivent être supprimées ; sinon, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Code généré par le Concepteur de composants + + /// + /// Méthode requise pour la prise en charge du concepteur - ne modifiez pas + /// le contenu de cette méthode avec l'éditeur de code. + /// + private void InitializeComponent() + { + this.lblOauthDesc = new System.Windows.Forms.Label(); + this.llMoreInfo = new System.Windows.Forms.LinkLabel(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.txtClientSecret = new System.Windows.Forms.TextBox(); + this.lblClientId = new System.Windows.Forms.Label(); + this.txtAzureAdAppId = new System.Windows.Forms.TextBox(); + this.lblClientSecret = new System.Windows.Forms.Label(); + this.tableLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // lblOauthDesc + // + this.lblOauthDesc.AutoSize = true; + this.lblOauthDesc.Dock = System.Windows.Forms.DockStyle.Top; + this.lblOauthDesc.Location = new System.Drawing.Point(0, 0); + this.lblOauthDesc.Name = "lblOauthDesc"; + this.lblOauthDesc.Padding = new System.Windows.Forms.Padding(0, 10, 0, 10); + this.lblOauthDesc.Size = new System.Drawing.Size(984, 45); + this.lblOauthDesc.TabIndex = 7; + this.lblOauthDesc.Text = "To connect to Microsoft Dynamics 365 with Oauth, it is required to connect to an " + + "Azure AD application"; + // + // llMoreInfo + // + this.llMoreInfo.Dock = System.Windows.Forms.DockStyle.Bottom; + this.llMoreInfo.Location = new System.Drawing.Point(0, 251); + this.llMoreInfo.Name = "llMoreInfo"; + this.llMoreInfo.Padding = new System.Windows.Forms.Padding(0, 0, 0, 10); + this.llMoreInfo.Size = new System.Drawing.Size(982, 34); + this.llMoreInfo.TabIndex = 3; + this.llMoreInfo.TabStop = true; + this.llMoreInfo.Text = "Show me how to create an Azure AD application"; + this.llMoreInfo.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.llMoreInfo_LinkClicked); + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 2; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 327F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.Controls.Add(this.txtClientSecret, 1, 1); + this.tableLayoutPanel1.Controls.Add(this.lblClientId, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.txtAzureAdAppId, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.lblClientSecret, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 45); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 3; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 47F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 47F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 47F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(982, 206); + this.tableLayoutPanel1.TabIndex = 15; + // + // txtClientSecret + // + this.txtClientSecret.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtClientSecret.Location = new System.Drawing.Point(330, 54); + this.txtClientSecret.Margin = new System.Windows.Forms.Padding(3, 7, 3, 3); + this.txtClientSecret.Name = "txtClientSecret"; + this.txtClientSecret.PasswordChar = '*'; + this.txtClientSecret.Size = new System.Drawing.Size(649, 31); + this.txtClientSecret.TabIndex = 16; + this.txtClientSecret.TextChanged += new System.EventHandler(this.txtClientSecret_TextChanged); + // + // lblClientId + // + this.lblClientId.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblClientId.Location = new System.Drawing.Point(4, 0); + this.lblClientId.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblClientId.Name = "lblClientId"; + this.lblClientId.Size = new System.Drawing.Size(319, 47); + this.lblClientId.TabIndex = 11; + this.lblClientId.Text = "Client Id"; + this.lblClientId.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // txtAzureAdAppId + // + this.txtAzureAdAppId.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtAzureAdAppId.Location = new System.Drawing.Point(331, 10); + this.txtAzureAdAppId.Margin = new System.Windows.Forms.Padding(4, 10, 4, 4); + this.txtAzureAdAppId.Name = "txtAzureAdAppId"; + this.txtAzureAdAppId.Size = new System.Drawing.Size(647, 31); + this.txtAzureAdAppId.TabIndex = 1; + // + // lblClientSecret + // + this.lblClientSecret.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblClientSecret.Location = new System.Drawing.Point(3, 47); + this.lblClientSecret.Name = "lblClientSecret"; + this.lblClientSecret.Size = new System.Drawing.Size(321, 47); + this.lblClientSecret.TabIndex = 15; + this.lblClientSecret.Text = "Client Secret"; + this.lblClientSecret.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // ConnectionClientSecretControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.tableLayoutPanel1); + this.Controls.Add(this.llMoreInfo); + this.Controls.Add(this.lblOauthDesc); + this.Name = "ConnectionClientSecretControl"; + this.Size = new System.Drawing.Size(982, 285); + this.Load += new System.EventHandler(this.ConnectionOauthControl_Load); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + private System.Windows.Forms.Label lblOauthDesc; + private System.Windows.Forms.LinkLabel llMoreInfo; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.Label lblClientId; + private System.Windows.Forms.TextBox txtAzureAdAppId; + private System.Windows.Forms.TextBox txtClientSecret; + private System.Windows.Forms.Label lblClientSecret; + } +} diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionClientSecretControl.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionClientSecretControl.cs new file mode 100644 index 0000000..25b9bda --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionClientSecretControl.cs @@ -0,0 +1,58 @@ +using System; +using System.Diagnostics; +using System.Globalization; +using System.Windows.Forms; + +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + public partial class ConnectionClientSecretControl : UserControl, IConnectionWizardControl + { + private string clientSecretTemp = "********************************************************"; + + public ConnectionClientSecretControl() + { + InitializeComponent(); + } + + public Guid AzureAdAppId + { + get + { + if (!Guid.TryParse(txtAzureAdAppId.Text, out Guid id)) + { + MessageBox.Show(this, @"The Azure AD Application Id is not a valid GUID!", @"Error", + MessageBoxButtons.OK, MessageBoxIcon.Error); + + return Guid.Empty; + } + + return id; + } + set => txtAzureAdAppId.Text = value.ToString(); + } + + public string ClientSecret => txtClientSecret.Text == clientSecretTemp ? null : txtClientSecret.Text; + + public bool ClientSecretChanged { get; private set; } + + public bool HasClientSecret { get; set; } + + private void ConnectionOauthControl_Load(object sender, EventArgs e) + { + txtAzureAdAppId.Focus(); + + if (HasClientSecret) + txtClientSecret.Text = clientSecretTemp; + } + + private void llMoreInfo_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Process.Start($"https://docs.microsoft.com/{CultureInfo.CurrentUICulture.Name}/dynamics365/customer-engagement/developer/walkthrough-register-dynamics-365-app-azure-active-directory"); + } + + private void txtClientSecret_TextChanged(object sender, EventArgs e) + { + ClientSecretChanged = true; + } + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionClientSecretControl.resx b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionClientSecretControl.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionClientSecretControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionCredentialsControl.Designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionCredentialsControl.Designer.cs new file mode 100644 index 0000000..a16ffcd --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionCredentialsControl.Designer.cs @@ -0,0 +1,175 @@ +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + partial class ConnectionCredentialsControl + { + /// + /// Variable nécessaire au concepteur. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Nettoyage des ressources utilisées. + /// + /// true si les ressources managées doivent être supprimées ; sinon, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Code généré par le Concepteur de composants + + /// + /// Méthode requise pour la prise en charge du concepteur - ne modifiez pas + /// le contenu de cette méthode avec l'éditeur de code. + /// + private void InitializeComponent() + { + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.lblDomain = new System.Windows.Forms.Label(); + this.txtDomain = new System.Windows.Forms.TextBox(); + this.lblUsername = new System.Windows.Forms.Label(); + this.lblPassword = new System.Windows.Forms.Label(); + this.txtUsername = new System.Windows.Forms.TextBox(); + this.txtPassword = new System.Windows.Forms.TextBox(); + this.chkSavePassword = new System.Windows.Forms.CheckBox(); + this.tableLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 2; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 300F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.Controls.Add(this.lblDomain, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.txtDomain, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.lblUsername, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.lblPassword, 0, 2); + this.tableLayoutPanel1.Controls.Add(this.txtUsername, 1, 1); + this.tableLayoutPanel1.Controls.Add(this.txtPassword, 1, 2); + this.tableLayoutPanel1.Controls.Add(this.chkSavePassword, 1, 3); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 5; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 50F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 50F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 50F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 50F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.Size = new System.Drawing.Size(900, 274); + this.tableLayoutPanel1.TabIndex = 0; + // + // lblDomain + // + this.lblDomain.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblDomain.Location = new System.Drawing.Point(4, 0); + this.lblDomain.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblDomain.Name = "lblDomain"; + this.lblDomain.Size = new System.Drawing.Size(292, 50); + this.lblDomain.TabIndex = 11; + this.lblDomain.Text = "Domain"; + this.lblDomain.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // txtDomain + // + this.txtDomain.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtDomain.Location = new System.Drawing.Point(304, 10); + this.txtDomain.Margin = new System.Windows.Forms.Padding(4, 10, 4, 4); + this.txtDomain.Name = "txtDomain"; + this.txtDomain.Size = new System.Drawing.Size(592, 29); + this.txtDomain.TabIndex = 1; + this.txtDomain.TextChanged += new System.EventHandler(this.txt_TextChanged); + this.txtDomain.Enter += new System.EventHandler(this.txt_Enter); + this.txtDomain.Leave += new System.EventHandler(this.txt_Leave); + // + // lblUsername + // + this.lblUsername.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblUsername.Location = new System.Drawing.Point(4, 50); + this.lblUsername.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblUsername.Name = "lblUsername"; + this.lblUsername.Size = new System.Drawing.Size(292, 50); + this.lblUsername.TabIndex = 14; + this.lblUsername.Text = "Username"; + this.lblUsername.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // lblPassword + // + this.lblPassword.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblPassword.Location = new System.Drawing.Point(4, 100); + this.lblPassword.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblPassword.Name = "lblPassword"; + this.lblPassword.Size = new System.Drawing.Size(292, 50); + this.lblPassword.TabIndex = 16; + this.lblPassword.Text = "Password"; + this.lblPassword.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // txtUsername + // + this.txtUsername.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtUsername.Location = new System.Drawing.Point(304, 60); + this.txtUsername.Margin = new System.Windows.Forms.Padding(4, 10, 4, 4); + this.txtUsername.Name = "txtUsername"; + this.txtUsername.Size = new System.Drawing.Size(592, 29); + this.txtUsername.TabIndex = 2; + this.txtUsername.TextChanged += new System.EventHandler(this.txt_TextChanged); + this.txtUsername.Enter += new System.EventHandler(this.txt_Enter); + this.txtUsername.Leave += new System.EventHandler(this.txt_Leave); + // + // txtPassword + // + this.txtPassword.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtPassword.Location = new System.Drawing.Point(304, 110); + this.txtPassword.Margin = new System.Windows.Forms.Padding(4, 10, 4, 4); + this.txtPassword.Name = "txtPassword"; + this.txtPassword.Size = new System.Drawing.Size(592, 29); + this.txtPassword.TabIndex = 3; + this.txtPassword.UseSystemPasswordChar = true; + this.txtPassword.TextChanged += new System.EventHandler(this.txt_TextChanged); + this.txtPassword.Enter += new System.EventHandler(this.txt_Enter); + this.txtPassword.Leave += new System.EventHandler(this.txt_Leave); + // + // chkSavePassword + // + this.chkSavePassword.AutoSize = true; + this.chkSavePassword.CheckAlign = System.Drawing.ContentAlignment.MiddleRight; + this.chkSavePassword.Dock = System.Windows.Forms.DockStyle.Fill; + this.chkSavePassword.Location = new System.Drawing.Point(305, 155); + this.chkSavePassword.Margin = new System.Windows.Forms.Padding(5); + this.chkSavePassword.Name = "chkSavePassword"; + this.chkSavePassword.Size = new System.Drawing.Size(590, 40); + this.chkSavePassword.TabIndex = 4; + this.chkSavePassword.Text = "Save password as encrypted string in connections file"; + this.chkSavePassword.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + this.chkSavePassword.UseVisualStyleBackColor = true; + // + // ConnectionCredentialsControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(11F, 24F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.tableLayoutPanel1); + this.Name = "ConnectionCredentialsControl"; + this.Size = new System.Drawing.Size(900, 274); + this.Load += new System.EventHandler(this.ConnectionCredentialsControl_Load); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.Label lblDomain; + private System.Windows.Forms.TextBox txtDomain; + private System.Windows.Forms.Label lblUsername; + private System.Windows.Forms.Label lblPassword; + private System.Windows.Forms.TextBox txtUsername; + private System.Windows.Forms.TextBox txtPassword; + private System.Windows.Forms.CheckBox chkSavePassword; + } +} diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionCredentialsControl.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionCredentialsControl.cs new file mode 100644 index 0000000..9eae1d4 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionCredentialsControl.cs @@ -0,0 +1,162 @@ +using System.Drawing; +using System.Windows.Forms; + +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + public partial class ConnectionCredentialsControl : UserControl, IConnectionWizardControl + { + private const string DomainTip = "Provide domain name, possibly not mandatory for IFD connection"; + private const string PasswordTemp = "@@PASSWORD@@"; + private const string PasswordTip = "Please specify the password"; + private const string UserTip = "Provide user name. For IFD connections, try domain\\username"; + + public ConnectionCredentialsControl() + { + InitializeComponent(); + + txtUsername.Text = UserTip; + txtDomain.Text = DomainTip; + txtPassword.TextChanged -= txt_TextChanged; + txtPassword.Text = PasswordTip; + txtPassword.TextChanged += txt_TextChanged; + } + + public string Domain + { + get => txtDomain.Text == DomainTip ? "" : txtDomain.Text; + set + { + if (value?.Length > 0) + txtDomain.Text = value; + } + } + + public bool IsOnline { private get; set; } + + public string Password => txtPassword.Text == PasswordTip ? null : txtPassword.Text; + + public bool PasswordChanged { get; private set; } + + public bool PasswordIsSet + { + set + { + if (value) + { + txtPassword.TextChanged -= txt_TextChanged; + txtPassword.Text = PasswordTemp; + txtPassword.ForeColor = DefaultForeColor; + txtPassword.UseSystemPasswordChar = true; + txtPassword.TextChanged += txt_TextChanged; + } + else + { + txtPassword.TextChanged -= txt_TextChanged; + txtPassword.Text = PasswordTip; + txtPassword.ForeColor = Color.DarkGray; + txtPassword.UseSystemPasswordChar = false; + txtPassword.TextChanged += txt_TextChanged; + } + } + } + + public bool SavePassword + { + get => chkSavePassword.Checked; + set => chkSavePassword.Checked = value; + } + + public string Username + { + get => txtUsername.Text == UserTip ? null : txtUsername.Text; + set + { + if (value?.Length > 0) + txtUsername.Text = value; + } + } + + private void ConnectionCredentialsControl_Load(object sender, System.EventArgs e) + { + txtDomain.Enabled = !IsOnline; + + txtDomain.ForeColor = txtDomain.Text == DomainTip ? Color.DarkGray : DefaultForeColor; + txtUsername.ForeColor = txtUsername.Text == UserTip ? Color.DarkGray : DefaultForeColor; + txtPassword.ForeColor = txtPassword.Text == PasswordTip ? Color.DarkGray : DefaultForeColor; + + if (txtPassword.Text == PasswordTip) + { + txtPassword.UseSystemPasswordChar = false; + } + + txtDomain.Focus(); + } + + private void txt_Enter(object sender, System.EventArgs e) + { + var textbox = (TextBox)sender; + + if (textbox == txtDomain && textbox.Text == DomainTip + || textbox == txtUsername && textbox.Text == UserTip) + { + textbox.Text = string.Empty; + textbox.ForeColor = DefaultForeColor; + } + else if (textbox.Text == PasswordTip) + { + textbox.TextChanged -= txt_TextChanged; + + textbox.UseSystemPasswordChar = true; + textbox.Text = string.Empty; + textbox.ForeColor = DefaultForeColor; + + textbox.TextChanged += txt_TextChanged; + } + else if (textbox.Text == PasswordTemp) + { + textbox.TextChanged -= txt_TextChanged; + + textbox.Text = string.Empty; + + textbox.TextChanged += txt_TextChanged; + } + } + + private void txt_Leave(object sender, System.EventArgs e) + { + var textbox = (TextBox)sender; + + if (textbox == txtDomain && textbox.Text.Length == 0) + { + textbox.Text = DomainTip; + textbox.ForeColor = Color.DarkGray; + } + + if (textbox == txtUsername && textbox.Text.Length == 0) + { + textbox.Text = UserTip; + textbox.ForeColor = Color.DarkGray; + } + + if (textbox == txtPassword && textbox.Text.Length == 0) + { + textbox.TextChanged -= txt_TextChanged; + + textbox.Text = PasswordTip; + textbox.ForeColor = Color.DarkGray; + textbox.UseSystemPasswordChar = false; + + textbox.TextChanged += txt_TextChanged; + } + } + + private void txt_TextChanged(object sender, System.EventArgs e) + { + var textbox = (TextBox)sender; + if (textbox == txtPassword) + { + PasswordChanged = true; + } + } + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionCredentialsControl.resx b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionCredentialsControl.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionCredentialsControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionFailedControl.Designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionFailedControl.Designer.cs new file mode 100644 index 0000000..5505572 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionFailedControl.Designer.cs @@ -0,0 +1,79 @@ +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + partial class ConnectionFailedControl + { + /// + /// Variable nécessaire au concepteur. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Nettoyage des ressources utilisées. + /// + /// true si les ressources managées doivent être supprimées ; sinon, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Code généré par le Concepteur de composants + + /// + /// Méthode requise pour la prise en charge du concepteur - ne modifiez pas + /// le contenu de cette méthode avec l'éditeur de code. + /// + private void InitializeComponent() + { + this.llOpenConnectionLog = new System.Windows.Forms.LinkLabel(); + this.lblError = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // llOpenConnectionLog + // + this.llOpenConnectionLog.AutoSize = true; + this.llOpenConnectionLog.Dock = System.Windows.Forms.DockStyle.Bottom; + this.llOpenConnectionLog.Location = new System.Drawing.Point(0, 249); + this.llOpenConnectionLog.Margin = new System.Windows.Forms.Padding(5, 0, 5, 0); + this.llOpenConnectionLog.Name = "llOpenConnectionLog"; + this.llOpenConnectionLog.Size = new System.Drawing.Size(162, 25); + this.llOpenConnectionLog.TabIndex = 20; + this.llOpenConnectionLog.TabStop = true; + this.llOpenConnectionLog.Text = "Open Logs folder"; + this.llOpenConnectionLog.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.llOpenConnectionLog_LinkClicked); + // + // lblError + // + this.lblError.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblError.ForeColor = System.Drawing.Color.Red; + this.lblError.Location = new System.Drawing.Point(0, 0); + this.lblError.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblError.Name = "lblError"; + this.lblError.Padding = new System.Windows.Forms.Padding(10); + this.lblError.Size = new System.Drawing.Size(900, 249); + this.lblError.TabIndex = 21; + this.lblError.Text = "[lblError]"; + this.lblError.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // ConnectionFailedControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(11F, 24F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.lblError); + this.Controls.Add(this.llOpenConnectionLog); + this.Name = "ConnectionFailedControl"; + this.Size = new System.Drawing.Size(900, 274); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.LinkLabel llOpenConnectionLog; + private System.Windows.Forms.Label lblError; + } +} diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionFailedControl.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionFailedControl.cs new file mode 100644 index 0000000..2b0bf89 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionFailedControl.cs @@ -0,0 +1,43 @@ +using System; +using System.Diagnostics; +using System.Reflection; +using System.Windows.Forms; + +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + public partial class ConnectionFailedControl : UserControl, IConnectionWizardControl + { + public ConnectionFailedControl() + { + InitializeComponent(); + } + + public string ErrorMEssage + { + set => lblError.Text = value; + } + + private void llOpenConnectionLog_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + // Log folder is defined by configuration file and follows Microsoft + // SDK tools configuration. It stores connection log file in path + // path\Company\Product\Version + var assembly = Assembly.GetEntryAssembly(); + var companyName = ((AssemblyCompanyAttribute)assembly.GetCustomAttribute(typeof(AssemblyCompanyAttribute))).Company; + var productName = ((AssemblyProductAttribute)assembly.GetCustomAttribute(typeof(AssemblyProductAttribute))).Product; + var version = assembly.GetName().Version.ToString(); + + var logFolder = + $"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}\\{companyName}\\{productName}\\{version}"; + + if (string.IsNullOrEmpty(logFolder)) + { + MessageBox.Show(this, @"There is no connection log folder available currently!"); + } + else + { + Process.Start(logFolder); + } + } + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionFailedControl.resx b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionFailedControl.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionFailedControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionFirstStepControl.Designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionFirstStepControl.Designer.cs new file mode 100644 index 0000000..099bb17 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionFirstStepControl.Designer.cs @@ -0,0 +1,183 @@ +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + partial class ConnectionFirstStepControl + { + /// + /// Variable nécessaire au concepteur. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Nettoyage des ressources utilisées. + /// + /// true si les ressources managées doivent être supprimées ; sinon, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Code généré par le Concepteur de composants + + /// + /// Méthode requise pour la prise en charge du concepteur - ne modifiez pas + /// le contenu de cette méthode avec l'éditeur de code. + /// + private void InitializeComponent() + { + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.lblUrl = new System.Windows.Forms.Label(); + this.txtOrganizationUrl = new System.Windows.Forms.TextBox(); + this.lblWindowsAuth = new System.Windows.Forms.Label(); + this.chkUseIntegratedAuthentication = new System.Windows.Forms.CheckBox(); + this.lblUseMfa = new System.Windows.Forms.Label(); + this.chkUseMfa = new System.Windows.Forms.CheckBox(); + this.label4 = new System.Windows.Forms.Label(); + this.txtTimeout = new System.Windows.Forms.TextBox(); + this.tableLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 2; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 349F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.Controls.Add(this.lblUrl, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.txtOrganizationUrl, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.lblWindowsAuth, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.chkUseIntegratedAuthentication, 1, 1); + this.tableLayoutPanel1.Controls.Add(this.lblUseMfa, 0, 2); + this.tableLayoutPanel1.Controls.Add(this.chkUseMfa, 1, 2); + this.tableLayoutPanel1.Controls.Add(this.label4, 0, 3); + this.tableLayoutPanel1.Controls.Add(this.txtTimeout, 1, 3); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 5; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 52F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 52F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 52F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 52F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.Size = new System.Drawing.Size(982, 285); + this.tableLayoutPanel1.TabIndex = 0; + // + // lblUrl + // + this.lblUrl.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblUrl.Location = new System.Drawing.Point(4, 0); + this.lblUrl.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblUrl.Name = "lblUrl"; + this.lblUrl.Size = new System.Drawing.Size(341, 52); + this.lblUrl.TabIndex = 11; + this.lblUrl.Text = "Organization url"; + this.lblUrl.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // txtOrganizationUrl + // + this.txtOrganizationUrl.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtOrganizationUrl.Location = new System.Drawing.Point(353, 10); + this.txtOrganizationUrl.Margin = new System.Windows.Forms.Padding(4, 10, 4, 4); + this.txtOrganizationUrl.Name = "txtOrganizationUrl"; + this.txtOrganizationUrl.Size = new System.Drawing.Size(625, 31); + this.txtOrganizationUrl.TabIndex = 1; + this.txtOrganizationUrl.Text = "https://organization.crm.dynamics.com"; + // + // lblWindowsAuth + // + this.lblWindowsAuth.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblWindowsAuth.Location = new System.Drawing.Point(4, 52); + this.lblWindowsAuth.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblWindowsAuth.Name = "lblWindowsAuth"; + this.lblWindowsAuth.Size = new System.Drawing.Size(341, 52); + this.lblWindowsAuth.TabIndex = 14; + this.lblWindowsAuth.Text = "Use your current credentials"; + this.lblWindowsAuth.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // chkUseIntegratedAuthentication + // + this.chkUseIntegratedAuthentication.AutoSize = true; + this.chkUseIntegratedAuthentication.Dock = System.Windows.Forms.DockStyle.Fill; + this.chkUseIntegratedAuthentication.Location = new System.Drawing.Point(353, 56); + this.chkUseIntegratedAuthentication.Margin = new System.Windows.Forms.Padding(4); + this.chkUseIntegratedAuthentication.Name = "chkUseIntegratedAuthentication"; + this.chkUseIntegratedAuthentication.Size = new System.Drawing.Size(625, 44); + this.chkUseIntegratedAuthentication.TabIndex = 2; + this.chkUseIntegratedAuthentication.Text = "(AD and IFD instances only)"; + this.chkUseIntegratedAuthentication.UseVisualStyleBackColor = true; + // + // lblUseMfa + // + this.lblUseMfa.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblUseMfa.Location = new System.Drawing.Point(4, 104); + this.lblUseMfa.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblUseMfa.Name = "lblUseMfa"; + this.lblUseMfa.Size = new System.Drawing.Size(341, 52); + this.lblUseMfa.TabIndex = 16; + this.lblUseMfa.Text = "Use OAuth, MFA, S2S or Application user"; + this.lblUseMfa.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // chkUseMfa + // + this.chkUseMfa.AutoSize = true; + this.chkUseMfa.Dock = System.Windows.Forms.DockStyle.Fill; + this.chkUseMfa.Location = new System.Drawing.Point(353, 108); + this.chkUseMfa.Margin = new System.Windows.Forms.Padding(4); + this.chkUseMfa.Name = "chkUseMfa"; + this.chkUseMfa.Size = new System.Drawing.Size(625, 44); + this.chkUseMfa.TabIndex = 3; + this.chkUseMfa.Text = "(CRM online only - preview)"; + this.chkUseMfa.UseVisualStyleBackColor = true; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Dock = System.Windows.Forms.DockStyle.Fill; + this.label4.Location = new System.Drawing.Point(4, 156); + this.label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(341, 52); + this.label4.TabIndex = 18; + this.label4.Text = "Service timeout"; + this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // txtTimeout + // + this.txtTimeout.Dock = System.Windows.Forms.DockStyle.Left; + this.txtTimeout.Location = new System.Drawing.Point(353, 166); + this.txtTimeout.Margin = new System.Windows.Forms.Padding(4, 10, 4, 4); + this.txtTimeout.Name = "txtTimeout"; + this.txtTimeout.Size = new System.Drawing.Size(91, 31); + this.txtTimeout.TabIndex = 4; + this.txtTimeout.Text = "00:02:00"; + // + // ConnectionFirstStepControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.tableLayoutPanel1); + this.Name = "ConnectionFirstStepControl"; + this.Size = new System.Drawing.Size(982, 285); + this.Load += new System.EventHandler(this.ConnectionFirstStepControl_Load); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.Label lblUrl; + private System.Windows.Forms.TextBox txtOrganizationUrl; + private System.Windows.Forms.Label lblWindowsAuth; + private System.Windows.Forms.CheckBox chkUseIntegratedAuthentication; + private System.Windows.Forms.Label lblUseMfa; + private System.Windows.Forms.CheckBox chkUseMfa; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.TextBox txtTimeout; + } +} diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionFirstStepControl.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionFirstStepControl.cs new file mode 100644 index 0000000..3b9b223 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionFirstStepControl.cs @@ -0,0 +1,156 @@ +using System; +using System.Windows.Forms; + +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + public partial class ConnectionFirstStepControl : UserControl, IConnectionWizardControl + { + private bool invalidUrlWarned; + + public ConnectionFirstStepControl() + { + InitializeComponent(); + } + + public string HostName + { + get + { + if (!txtOrganizationUrl.Text.StartsWith("http")) + { + if (!invalidUrlWarned) + { + invalidUrlWarned = true; + MessageBox.Show(this, + @"Please enter a valid url", + @"Warning", + MessageBoxButtons.OK, + MessageBoxIcon.Warning); + } + + return null; + } + + var urlWithoutProtocol = txtOrganizationUrl.Text.Remove(0, UseSsl ? 8 : 7); + var urlParts = urlWithoutProtocol.Split('/'); + var host = urlParts[0]; + var hostParts = host.Split(':'); + + return hostParts[0]; + } + } + + public int HostPort + { + get + { + if (!txtOrganizationUrl.Text.StartsWith("http")) + { + if (!invalidUrlWarned) + { + invalidUrlWarned = true; + MessageBox.Show(this, + @"Please enter a valid url", + @"Warning", + MessageBoxButtons.OK, + MessageBoxIcon.Warning); + } + + return -1; + } + + var urlWithoutProtocol = txtOrganizationUrl.Text.Remove(0, UseSsl ? 8 : 7); + var urlParts = urlWithoutProtocol.Split('/'); + var host = urlParts[0]; + var hostParts = host.Split(':'); + + var hostPort = hostParts.Length == 2 ? int.Parse(hostParts[1]) : new int?(); + if (!hostPort.HasValue) + { + return UseSsl ? 443 : 80; + } + + return hostPort.Value; + } + } + + public string OrganizationUrlName + { + get + { + if (!txtOrganizationUrl.Text.StartsWith("http")) + { + if (!invalidUrlWarned) + { + invalidUrlWarned = true; + MessageBox.Show(this, + @"Please enter a valid url", + @"Warning", + MessageBoxButtons.OK, + MessageBoxIcon.Warning); + } + + return null; + } + + var urlWithoutProtocol = txtOrganizationUrl.Text.Remove(0, UseSsl ? 8 : 7); + if (urlWithoutProtocol.EndsWith("/")) + { + urlWithoutProtocol = urlWithoutProtocol.Substring(0, urlWithoutProtocol.Length - 1); + } + var urlParts = urlWithoutProtocol.Split('/'); + + return urlParts.Length > 1 && !urlParts[1].ToLower().StartsWith("main.aspx") ? urlParts[1] : urlParts[0].Split('.')[0]; + } + } + + public TimeSpan Timeout + { + get + { + if (!TimeSpan.TryParse(txtTimeout.Text, out TimeSpan result)) + { + MessageBox.Show(this, + @"Please enter a valid timeout (format => HH:mm:ss)", + @"Warning", + MessageBoxButtons.OK, + MessageBoxIcon.Warning); + + return new TimeSpan(); + } + return result; + } + set => txtTimeout.Text = $@"{value:hh\:mm\:ss}"; + } + + public string Url + { + get => txtOrganizationUrl.Text.ToLower(); + set => txtOrganizationUrl.Text = string.IsNullOrEmpty(value) ? txtOrganizationUrl.Text : value; + } + + public bool UseIntegratedAuth + { + get => chkUseIntegratedAuthentication.Checked; + set => chkUseIntegratedAuthentication.Checked = value; + } + + public bool UseMfa + { + get => chkUseMfa.Checked; + set => chkUseMfa.Checked = value; + } + + public bool UseSsl => Url.StartsWith("https://"); + + private void ConnectionFirstStepControl_Load(object sender, EventArgs e) + { + if (txtOrganizationUrl.Text == "https://organization.crm.dynamics.com") + { + txtOrganizationUrl.Select(8, 12); + } + + txtOrganizationUrl.Focus(); + } + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionFirstStepControl.resx b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionFirstStepControl.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionFirstStepControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionIfdControl.Designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionIfdControl.Designer.cs new file mode 100644 index 0000000..dc71389 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionIfdControl.Designer.cs @@ -0,0 +1,119 @@ +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + partial class ConnectionIfdControl + { + /// + /// Variable nécessaire au concepteur. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Nettoyage des ressources utilisées. + /// + /// true si les ressources managées doivent être supprimées ; sinon, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Code généré par le Concepteur de composants + + /// + /// Méthode requise pour la prise en charge du concepteur - ne modifiez pas + /// le contenu de cette méthode avec l'éditeur de code. + /// + private void InitializeComponent() + { + this.lblIfdQuestion = new System.Windows.Forms.Label(); + this.lblHomeRealmQuestion = new System.Windows.Forms.Label(); + this.txtHomeRealm = new System.Windows.Forms.TextBox(); + this.rbIfdNo = new System.Windows.Forms.RadioButton(); + this.rbIfdYes = new System.Windows.Forms.RadioButton(); + this.SuspendLayout(); + // + // lblIfdQuestion + // + this.lblIfdQuestion.AutoSize = true; + this.lblIfdQuestion.Location = new System.Drawing.Point(4, 18); + this.lblIfdQuestion.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblIfdQuestion.Name = "lblIfdQuestion"; + this.lblIfdQuestion.Size = new System.Drawing.Size(593, 25); + this.lblIfdQuestion.TabIndex = 13; + this.lblIfdQuestion.Text = "Are you connecting to an Internet Facing Deployment organization?"; + // + // lblHomeRealmQuestion + // + this.lblHomeRealmQuestion.AutoSize = true; + this.lblHomeRealmQuestion.Location = new System.Drawing.Point(4, 94); + this.lblHomeRealmQuestion.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblHomeRealmQuestion.Name = "lblHomeRealmQuestion"; + this.lblHomeRealmQuestion.Size = new System.Drawing.Size(427, 25); + this.lblHomeRealmQuestion.TabIndex = 11; + this.lblHomeRealmQuestion.Text = "If necessary, you can specify the home realm url"; + // + // txtHomeRealm + // + this.txtHomeRealm.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtHomeRealm.Enabled = false; + this.txtHomeRealm.Location = new System.Drawing.Point(9, 123); + this.txtHomeRealm.Margin = new System.Windows.Forms.Padding(4); + this.txtHomeRealm.Name = "txtHomeRealm"; + this.txtHomeRealm.Size = new System.Drawing.Size(877, 29); + this.txtHomeRealm.TabIndex = 3; + // + // rbIfdNo + // + this.rbIfdNo.AutoSize = true; + this.rbIfdNo.Checked = true; + this.rbIfdNo.Location = new System.Drawing.Point(9, 47); + this.rbIfdNo.Margin = new System.Windows.Forms.Padding(4); + this.rbIfdNo.Name = "rbIfdNo"; + this.rbIfdNo.Size = new System.Drawing.Size(62, 29); + this.rbIfdNo.TabIndex = 1; + this.rbIfdNo.TabStop = true; + this.rbIfdNo.Text = "No"; + this.rbIfdNo.UseVisualStyleBackColor = true; + this.rbIfdNo.CheckedChanged += new System.EventHandler(this.rbIfdNo_CheckedChanged); + // + // rbIfdYes + // + this.rbIfdYes.AutoSize = true; + this.rbIfdYes.Location = new System.Drawing.Point(90, 47); + this.rbIfdYes.Margin = new System.Windows.Forms.Padding(4); + this.rbIfdYes.Name = "rbIfdYes"; + this.rbIfdYes.Size = new System.Drawing.Size(71, 29); + this.rbIfdYes.TabIndex = 2; + this.rbIfdYes.Text = "Yes"; + this.rbIfdYes.UseVisualStyleBackColor = true; + // + // ConnectionIfdControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(11F, 24F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.lblIfdQuestion); + this.Controls.Add(this.lblHomeRealmQuestion); + this.Controls.Add(this.txtHomeRealm); + this.Controls.Add(this.rbIfdNo); + this.Controls.Add(this.rbIfdYes); + this.Name = "ConnectionIfdControl"; + this.Size = new System.Drawing.Size(900, 274); + this.Load += new System.EventHandler(this.ConnectionIfdControl_Load); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label lblIfdQuestion; + private System.Windows.Forms.Label lblHomeRealmQuestion; + private System.Windows.Forms.TextBox txtHomeRealm; + private System.Windows.Forms.RadioButton rbIfdNo; + private System.Windows.Forms.RadioButton rbIfdYes; + } +} diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionIfdControl.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionIfdControl.cs new file mode 100644 index 0000000..8f4783d --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionIfdControl.cs @@ -0,0 +1,38 @@ +using System.Windows.Forms; + +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + public partial class ConnectionIfdControl : UserControl, IConnectionWizardControl + { + public ConnectionIfdControl() + { + InitializeComponent(); + } + + public string HomeRealmUrl + { + get => txtHomeRealm.Text; + set => txtHomeRealm.Text = value; + } + + public bool IsIfd + { + get => rbIfdYes.Checked; + set + { + rbIfdYes.Checked = value; + rbIfdNo.Checked = !value; + } + } + + private void ConnectionIfdControl_Load(object sender, System.EventArgs e) + { + rbIfdNo_CheckedChanged(null, null); + } + + private void rbIfdNo_CheckedChanged(object sender, System.EventArgs e) + { + txtHomeRealm.Enabled = rbIfdYes.Checked; + } + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionIfdControl.resx b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionIfdControl.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionIfdControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionLoadingControl.Designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionLoadingControl.Designer.cs new file mode 100644 index 0000000..31ebcb8 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionLoadingControl.Designer.cs @@ -0,0 +1,75 @@ +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + partial class ConnectionLoadingControl + { + /// + /// Variable nécessaire au concepteur. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Nettoyage des ressources utilisées. + /// + /// true si les ressources managées doivent être supprimées ; sinon, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Code généré par le Concepteur de composants + + /// + /// Méthode requise pour la prise en charge du concepteur - ne modifiez pas + /// le contenu de cette méthode avec l'éditeur de code. + /// + private void InitializeComponent() + { + this.label3 = new System.Windows.Forms.Label(); + this.progressBar1 = new System.Windows.Forms.ProgressBar(); + this.SuspendLayout(); + // + // label3 + // + this.label3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label3.Location = new System.Drawing.Point(0, 154); + this.label3.Margin = new System.Windows.Forms.Padding(5, 0, 5, 0); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(900, 40); + this.label3.TabIndex = 3; + this.label3.Text = "Trying to connect to your Microsoft Dynamics CRM organization"; + this.label3.TextAlign = System.Drawing.ContentAlignment.TopCenter; + // + // progressBar1 + // + this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.progressBar1.Location = new System.Drawing.Point(0, 91); + this.progressBar1.Margin = new System.Windows.Forms.Padding(4); + this.progressBar1.Name = "progressBar1"; + this.progressBar1.Size = new System.Drawing.Size(900, 37); + this.progressBar1.Style = System.Windows.Forms.ProgressBarStyle.Marquee; + this.progressBar1.TabIndex = 2; + // + // ConnectionLoadingControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(11F, 24F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.label3); + this.Controls.Add(this.progressBar1); + this.Name = "ConnectionLoadingControl"; + this.Size = new System.Drawing.Size(900, 274); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Label label3; + private System.Windows.Forms.ProgressBar progressBar1; + } +} diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionLoadingControl.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionLoadingControl.cs new file mode 100644 index 0000000..a651e46 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionLoadingControl.cs @@ -0,0 +1,12 @@ +using System.Windows.Forms; + +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + public partial class ConnectionLoadingControl : UserControl, IConnectionWizardControl + { + public ConnectionLoadingControl() + { + InitializeComponent(); + } + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionLoadingControl.resx b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionLoadingControl.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionLoadingControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionMfaControl.Designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionMfaControl.Designer.cs new file mode 100644 index 0000000..68dfdc8 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionMfaControl.Designer.cs @@ -0,0 +1,176 @@ +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + partial class ConnectionMfaControl + { + /// + /// Variable nécessaire au concepteur. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Nettoyage des ressources utilisées. + /// + /// true si les ressources managées doivent être supprimées ; sinon, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Code généré par le Concepteur de composants + + /// + /// Méthode requise pour la prise en charge du concepteur - ne modifiez pas + /// le contenu de cette méthode avec l'éditeur de code. + /// + private void InitializeComponent() + { + this.lblOauthDesc = new System.Windows.Forms.Label(); + this.llMoreInfo = new System.Windows.Forms.LinkLabel(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.txtUsername = new System.Windows.Forms.TextBox(); + this.lblAzureAdAppId = new System.Windows.Forms.Label(); + this.txtAzureAdAppId = new System.Windows.Forms.TextBox(); + this.lblReplyUrl = new System.Windows.Forms.Label(); + this.txtReplyUrl = new System.Windows.Forms.TextBox(); + this.lblUsername = new System.Windows.Forms.Label(); + this.tableLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // lblOauthDesc + // + this.lblOauthDesc.AutoSize = true; + this.lblOauthDesc.Dock = System.Windows.Forms.DockStyle.Top; + this.lblOauthDesc.Location = new System.Drawing.Point(0, 0); + this.lblOauthDesc.Name = "lblOauthDesc"; + this.lblOauthDesc.Padding = new System.Windows.Forms.Padding(0, 10, 0, 10); + this.lblOauthDesc.Size = new System.Drawing.Size(984, 45); + this.lblOauthDesc.TabIndex = 7; + this.lblOauthDesc.Text = "To connect to Microsoft Dynamics 365 with Oauth, it is required to connect to an " + + "Azure AD application"; + // + // llMoreInfo + // + this.llMoreInfo.Dock = System.Windows.Forms.DockStyle.Bottom; + this.llMoreInfo.Location = new System.Drawing.Point(0, 251); + this.llMoreInfo.Name = "llMoreInfo"; + this.llMoreInfo.Padding = new System.Windows.Forms.Padding(0, 0, 0, 10); + this.llMoreInfo.Size = new System.Drawing.Size(982, 34); + this.llMoreInfo.TabIndex = 3; + this.llMoreInfo.TabStop = true; + this.llMoreInfo.Text = "Show me how to create an Azure AD application"; + this.llMoreInfo.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.llMoreInfo_LinkClicked); + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 2; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 327F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.Controls.Add(this.txtUsername, 1, 2); + this.tableLayoutPanel1.Controls.Add(this.lblAzureAdAppId, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.txtAzureAdAppId, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.lblReplyUrl, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.txtReplyUrl, 1, 1); + this.tableLayoutPanel1.Controls.Add(this.lblUsername, 0, 2); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 45); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 4; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 47F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 47F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 47F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 47F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(982, 206); + this.tableLayoutPanel1.TabIndex = 15; + // + // txtUsername + // + this.txtUsername.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtUsername.Location = new System.Drawing.Point(330, 101); + this.txtUsername.Margin = new System.Windows.Forms.Padding(3, 7, 3, 3); + this.txtUsername.Name = "txtUsername"; + this.txtUsername.Size = new System.Drawing.Size(649, 31); + this.txtUsername.TabIndex = 16; + // + // lblAzureAdAppId + // + this.lblAzureAdAppId.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblAzureAdAppId.Location = new System.Drawing.Point(4, 0); + this.lblAzureAdAppId.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblAzureAdAppId.Name = "lblAzureAdAppId"; + this.lblAzureAdAppId.Size = new System.Drawing.Size(319, 47); + this.lblAzureAdAppId.TabIndex = 11; + this.lblAzureAdAppId.Text = "Azure AD Application Id"; + this.lblAzureAdAppId.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // txtAzureAdAppId + // + this.txtAzureAdAppId.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtAzureAdAppId.Location = new System.Drawing.Point(331, 10); + this.txtAzureAdAppId.Margin = new System.Windows.Forms.Padding(4, 10, 4, 4); + this.txtAzureAdAppId.Name = "txtAzureAdAppId"; + this.txtAzureAdAppId.Size = new System.Drawing.Size(647, 31); + this.txtAzureAdAppId.TabIndex = 1; + // + // lblReplyUrl + // + this.lblReplyUrl.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblReplyUrl.Location = new System.Drawing.Point(4, 47); + this.lblReplyUrl.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblReplyUrl.Name = "lblReplyUrl"; + this.lblReplyUrl.Size = new System.Drawing.Size(319, 47); + this.lblReplyUrl.TabIndex = 14; + this.lblReplyUrl.Text = "Reply Url"; + this.lblReplyUrl.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // txtReplyUrl + // + this.txtReplyUrl.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtReplyUrl.Location = new System.Drawing.Point(331, 57); + this.txtReplyUrl.Margin = new System.Windows.Forms.Padding(4, 10, 4, 4); + this.txtReplyUrl.Name = "txtReplyUrl"; + this.txtReplyUrl.Size = new System.Drawing.Size(647, 31); + this.txtReplyUrl.TabIndex = 2; + // + // lblUsername + // + this.lblUsername.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblUsername.Location = new System.Drawing.Point(3, 94); + this.lblUsername.Name = "lblUsername"; + this.lblUsername.Size = new System.Drawing.Size(321, 47); + this.lblUsername.TabIndex = 15; + this.lblUsername.Text = "Username / Email address"; + this.lblUsername.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // ConnectionMfaControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.tableLayoutPanel1); + this.Controls.Add(this.llMoreInfo); + this.Controls.Add(this.lblOauthDesc); + this.Name = "ConnectionMfaControl"; + this.Size = new System.Drawing.Size(982, 285); + this.Load += new System.EventHandler(this.ConnectionOauthControl_Load); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + private System.Windows.Forms.Label lblOauthDesc; + private System.Windows.Forms.LinkLabel llMoreInfo; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.Label lblAzureAdAppId; + private System.Windows.Forms.TextBox txtAzureAdAppId; + private System.Windows.Forms.Label lblReplyUrl; + private System.Windows.Forms.TextBox txtReplyUrl; + private System.Windows.Forms.TextBox txtUsername; + private System.Windows.Forms.Label lblUsername; + } +} diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionMfaControl.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionMfaControl.cs new file mode 100644 index 0000000..9ca0cd0 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionMfaControl.cs @@ -0,0 +1,51 @@ +using System; +using System.Diagnostics; +using System.Globalization; +using System.Windows.Forms; + +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + public partial class ConnectionMfaControl : UserControl, IConnectionWizardControl + { + public ConnectionMfaControl() + { + InitializeComponent(); + } + + public Guid AzureAdAppId + { + get + { + if (!Guid.TryParse(txtAzureAdAppId.Text, out Guid id)) + { + return Guid.Empty; + } + + return id; + } + set => txtAzureAdAppId.Text = value.ToString(); + } + + public string ReplyUrl + { + get => txtReplyUrl.Text; + set => txtReplyUrl.Text = value; + } + + public string Username + { + get => txtUsername.Text; + set => txtUsername.Text = value; + } + + private void ConnectionOauthControl_Load(object sender, EventArgs e) + { + txtAzureAdAppId.Focus(); + } + + private void llMoreInfo_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Process.Start($"https://docs.microsoft.com/{CultureInfo.CurrentUICulture.Name}/dynamics365/customer-engagement/developer/walkthrough-register-dynamics-365-app-azure-active-directory"); + } + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionMfaControl.resx b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionMfaControl.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionMfaControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionOauthControl.Designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionOauthControl.Designer.cs new file mode 100644 index 0000000..f98066e --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionOauthControl.Designer.cs @@ -0,0 +1,178 @@ +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + partial class ConnectionOauthControl + { + /// + /// Variable nécessaire au concepteur. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Nettoyage des ressources utilisées. + /// + /// true si les ressources managées doivent être supprimées ; sinon, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Code généré par le Concepteur de composants + + /// + /// Méthode requise pour la prise en charge du concepteur - ne modifiez pas + /// le contenu de cette méthode avec l'éditeur de code. + /// + private void InitializeComponent() + { + this.lblOauthDesc = new System.Windows.Forms.Label(); + this.llMoreInfo = new System.Windows.Forms.LinkLabel(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.txtClientSecret = new System.Windows.Forms.TextBox(); + this.lblAzureAdAppId = new System.Windows.Forms.Label(); + this.txtAzureAdAppId = new System.Windows.Forms.TextBox(); + this.lblReplyUrl = new System.Windows.Forms.Label(); + this.txtReplyUrl = new System.Windows.Forms.TextBox(); + this.lblClientSecret = new System.Windows.Forms.Label(); + this.tableLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // lblOauthDesc + // + this.lblOauthDesc.AutoSize = true; + this.lblOauthDesc.Dock = System.Windows.Forms.DockStyle.Top; + this.lblOauthDesc.Location = new System.Drawing.Point(0, 0); + this.lblOauthDesc.Name = "lblOauthDesc"; + this.lblOauthDesc.Padding = new System.Windows.Forms.Padding(0, 10, 0, 10); + this.lblOauthDesc.Size = new System.Drawing.Size(984, 45); + this.lblOauthDesc.TabIndex = 7; + this.lblOauthDesc.Text = "To connect to Microsoft Dynamics 365 with Oauth, it is required to connect to an " + + "Azure AD application"; + // + // llMoreInfo + // + this.llMoreInfo.Dock = System.Windows.Forms.DockStyle.Bottom; + this.llMoreInfo.Location = new System.Drawing.Point(0, 251); + this.llMoreInfo.Name = "llMoreInfo"; + this.llMoreInfo.Padding = new System.Windows.Forms.Padding(0, 0, 0, 10); + this.llMoreInfo.Size = new System.Drawing.Size(982, 34); + this.llMoreInfo.TabIndex = 3; + this.llMoreInfo.TabStop = true; + this.llMoreInfo.Text = "Show me how to create an Azure AD application"; + this.llMoreInfo.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.llMoreInfo_LinkClicked); + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 2; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 327F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.Controls.Add(this.txtClientSecret, 1, 2); + this.tableLayoutPanel1.Controls.Add(this.lblAzureAdAppId, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.txtAzureAdAppId, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.lblReplyUrl, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.txtReplyUrl, 1, 1); + this.tableLayoutPanel1.Controls.Add(this.lblClientSecret, 0, 2); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 45); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 4; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 47F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 47F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 47F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 47F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(982, 206); + this.tableLayoutPanel1.TabIndex = 15; + // + // txtClientSecret + // + this.txtClientSecret.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtClientSecret.Location = new System.Drawing.Point(330, 101); + this.txtClientSecret.Margin = new System.Windows.Forms.Padding(3, 7, 3, 3); + this.txtClientSecret.Name = "txtClientSecret"; + this.txtClientSecret.PasswordChar = '*'; + this.txtClientSecret.Size = new System.Drawing.Size(649, 31); + this.txtClientSecret.TabIndex = 16; + this.txtClientSecret.TextChanged += new System.EventHandler(this.txtClientSecret_TextChanged); + // + // lblAzureAdAppId + // + this.lblAzureAdAppId.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblAzureAdAppId.Location = new System.Drawing.Point(4, 0); + this.lblAzureAdAppId.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblAzureAdAppId.Name = "lblAzureAdAppId"; + this.lblAzureAdAppId.Size = new System.Drawing.Size(319, 47); + this.lblAzureAdAppId.TabIndex = 11; + this.lblAzureAdAppId.Text = "Azure AD Application Id"; + this.lblAzureAdAppId.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // txtAzureAdAppId + // + this.txtAzureAdAppId.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtAzureAdAppId.Location = new System.Drawing.Point(331, 10); + this.txtAzureAdAppId.Margin = new System.Windows.Forms.Padding(4, 10, 4, 4); + this.txtAzureAdAppId.Name = "txtAzureAdAppId"; + this.txtAzureAdAppId.Size = new System.Drawing.Size(647, 31); + this.txtAzureAdAppId.TabIndex = 1; + // + // lblReplyUrl + // + this.lblReplyUrl.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblReplyUrl.Location = new System.Drawing.Point(4, 47); + this.lblReplyUrl.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblReplyUrl.Name = "lblReplyUrl"; + this.lblReplyUrl.Size = new System.Drawing.Size(319, 47); + this.lblReplyUrl.TabIndex = 14; + this.lblReplyUrl.Text = "Reply Url"; + this.lblReplyUrl.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // txtReplyUrl + // + this.txtReplyUrl.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtReplyUrl.Location = new System.Drawing.Point(331, 57); + this.txtReplyUrl.Margin = new System.Windows.Forms.Padding(4, 10, 4, 4); + this.txtReplyUrl.Name = "txtReplyUrl"; + this.txtReplyUrl.Size = new System.Drawing.Size(647, 31); + this.txtReplyUrl.TabIndex = 2; + // + // lblClientSecret + // + this.lblClientSecret.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblClientSecret.Location = new System.Drawing.Point(3, 94); + this.lblClientSecret.Name = "lblClientSecret"; + this.lblClientSecret.Size = new System.Drawing.Size(321, 47); + this.lblClientSecret.TabIndex = 15; + this.lblClientSecret.Text = "Client Secret (OAuth or S2S)"; + this.lblClientSecret.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // ConnectionOauthControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.tableLayoutPanel1); + this.Controls.Add(this.llMoreInfo); + this.Controls.Add(this.lblOauthDesc); + this.Name = "ConnectionOauthControl"; + this.Size = new System.Drawing.Size(982, 285); + this.Load += new System.EventHandler(this.ConnectionOauthControl_Load); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + private System.Windows.Forms.Label lblOauthDesc; + private System.Windows.Forms.LinkLabel llMoreInfo; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.Label lblAzureAdAppId; + private System.Windows.Forms.TextBox txtAzureAdAppId; + private System.Windows.Forms.Label lblReplyUrl; + private System.Windows.Forms.TextBox txtReplyUrl; + private System.Windows.Forms.TextBox txtClientSecret; + private System.Windows.Forms.Label lblClientSecret; + } +} diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionOauthControl.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionOauthControl.cs new file mode 100644 index 0000000..36db84e --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionOauthControl.cs @@ -0,0 +1,64 @@ +using System; +using System.Diagnostics; +using System.Globalization; +using System.Windows.Forms; + +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + public partial class ConnectionOauthControl : UserControl, IConnectionWizardControl + { + private string clientSecretTemp = "********************************************************"; + + public ConnectionOauthControl() + { + InitializeComponent(); + } + + public Guid AzureAdAppId + { + get + { + if (!Guid.TryParse(txtAzureAdAppId.Text, out Guid id)) + { + MessageBox.Show(this, @"The Azure AD Application Id is not a valid GUID!", @"Error", + MessageBoxButtons.OK, MessageBoxIcon.Error); + + return Guid.Empty; + } + + return id; + } + set => txtAzureAdAppId.Text = value.ToString(); + } + + public string ClientSecret => txtClientSecret.Text == clientSecretTemp ? null : txtClientSecret.Text; + + public bool ClientSecretChanged { get; private set; } + + public bool HasClientSecret { get; set; } + + public string ReplyUrl + { + get => txtReplyUrl.Text; + set => txtReplyUrl.Text = value; + } + + private void ConnectionOauthControl_Load(object sender, EventArgs e) + { + txtAzureAdAppId.Focus(); + + if (HasClientSecret) + txtClientSecret.Text = clientSecretTemp; + } + + private void llMoreInfo_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Process.Start($"https://docs.microsoft.com/{CultureInfo.CurrentUICulture.Name}/dynamics365/customer-engagement/developer/walkthrough-register-dynamics-365-app-azure-active-directory"); + } + + private void txtClientSecret_TextChanged(object sender, EventArgs e) + { + ClientSecretChanged = true; + } + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionOauthControl.resx b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionOauthControl.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionOauthControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionStringControl.Designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionStringControl.Designer.cs new file mode 100644 index 0000000..0b76f05 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionStringControl.Designer.cs @@ -0,0 +1,107 @@ +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + partial class ConnectionStringControl + { + /// + /// Variable nécessaire au concepteur. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Nettoyage des ressources utilisées. + /// + /// true si les ressources managées doivent être supprimées ; sinon, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Code généré par le Concepteur de composants + + /// + /// Méthode requise pour la prise en charge du concepteur - ne modifiez pas + /// le contenu de cette méthode avec l'éditeur de code. + /// + private void InitializeComponent() + { + this.llConnectionStringHelp = new System.Windows.Forms.LinkLabel(); + this.lblConnectionString = new System.Windows.Forms.Label(); + this.txtConnectionString = new System.Windows.Forms.TextBox(); + this.pnlMain = new System.Windows.Forms.Panel(); + this.pnlMain.SuspendLayout(); + this.SuspendLayout(); + // + // llConnectionStringHelp + // + this.llConnectionStringHelp.AutoSize = true; + this.llConnectionStringHelp.Dock = System.Windows.Forms.DockStyle.Bottom; + this.llConnectionStringHelp.Location = new System.Drawing.Point(0, 249); + this.llConnectionStringHelp.Margin = new System.Windows.Forms.Padding(5, 0, 5, 0); + this.llConnectionStringHelp.Name = "llConnectionStringHelp"; + this.llConnectionStringHelp.Size = new System.Drawing.Size(307, 25); + this.llConnectionStringHelp.TabIndex = 2; + this.llConnectionStringHelp.TabStop = true; + this.llConnectionStringHelp.Text = "Help me with the connection string"; + this.llConnectionStringHelp.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.llConnectionStringHelp_LinkClicked); + // + // lblConnectionString + // + this.lblConnectionString.AutoSize = true; + this.lblConnectionString.Dock = System.Windows.Forms.DockStyle.Top; + this.lblConnectionString.Location = new System.Drawing.Point(0, 0); + this.lblConnectionString.Margin = new System.Windows.Forms.Padding(5, 0, 5, 0); + this.lblConnectionString.Name = "lblConnectionString"; + this.lblConnectionString.Size = new System.Drawing.Size(164, 25); + this.lblConnectionString.TabIndex = 19; + this.lblConnectionString.Text = "Connection string"; + // + // txtConnectionString + // + this.txtConnectionString.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtConnectionString.Font = new System.Drawing.Font("Consolas", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtConnectionString.Location = new System.Drawing.Point(10, 10); + this.txtConnectionString.Margin = new System.Windows.Forms.Padding(5); + this.txtConnectionString.Multiline = true; + this.txtConnectionString.Name = "txtConnectionString"; + this.txtConnectionString.Size = new System.Drawing.Size(880, 204); + this.txtConnectionString.TabIndex = 1; + // + // pnlMain + // + this.pnlMain.Controls.Add(this.txtConnectionString); + this.pnlMain.Dock = System.Windows.Forms.DockStyle.Fill; + this.pnlMain.Location = new System.Drawing.Point(0, 25); + this.pnlMain.Name = "pnlMain"; + this.pnlMain.Padding = new System.Windows.Forms.Padding(10); + this.pnlMain.Size = new System.Drawing.Size(900, 224); + this.pnlMain.TabIndex = 23; + // + // ConnectionStringControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(11F, 24F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.pnlMain); + this.Controls.Add(this.llConnectionStringHelp); + this.Controls.Add(this.lblConnectionString); + this.Name = "ConnectionStringControl"; + this.Size = new System.Drawing.Size(900, 274); + this.Load += new System.EventHandler(this.ConnectionStringControl_Load); + this.pnlMain.ResumeLayout(false); + this.pnlMain.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.LinkLabel llConnectionStringHelp; + private System.Windows.Forms.Label lblConnectionString; + private System.Windows.Forms.TextBox txtConnectionString; + private System.Windows.Forms.Panel pnlMain; + } +} diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionStringControl.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionStringControl.cs new file mode 100644 index 0000000..708d9e5 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionStringControl.cs @@ -0,0 +1,32 @@ +using System.Diagnostics; +using System.Globalization; +using System.Windows.Forms; + +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + public partial class ConnectionStringControl : UserControl, IConnectionWizardControl + { + public ConnectionStringControl() + { + InitializeComponent(); + } + + public string ConnectionString + { + get => txtConnectionString.Text; + set => txtConnectionString.Text = value; + } + + private void ConnectionStringControl_Load(object sender, System.EventArgs e) + { + txtConnectionString.Focus(); + } + + private void llConnectionStringHelp_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Process.Start($"https://msdn.microsoft.com/{CultureInfo.CurrentUICulture.Name}/library/mt608573.aspx"); + + txtConnectionString.Focus(); + } + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionStringControl.resx b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionStringControl.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionStringControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionSucceededControl.Designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionSucceededControl.Designer.cs new file mode 100644 index 0000000..4f18d49 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionSucceededControl.Designer.cs @@ -0,0 +1,153 @@ +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + partial class ConnectionSucceededControl + { + /// + /// Variable nécessaire au concepteur. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Nettoyage des ressources utilisées. + /// + /// true si les ressources managées doivent être supprimées ; sinon, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Code généré par le Concepteur de composants + + /// + /// Méthode requise pour la prise en charge du concepteur - ne modifiez pas + /// le contenu de cette méthode avec l'éditeur de code. + /// + private void InitializeComponent() + { + this.label2 = new System.Windows.Forms.Label(); + this.txtConnectionName = new System.Windows.Forms.TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.btnClearEnvHighlight = new System.Windows.Forms.Button(); + this.btnSetEnvHighlight = new System.Windows.Forms.Button(); + this.lblHighlight = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.comboBoxSolutions = new System.Windows.Forms.ComboBox(); + this.SuspendLayout(); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(3, 47); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(35, 13); + this.label2.TabIndex = 18; + this.label2.Text = "Name"; + // + // txtConnectionName + // + this.txtConnectionName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtConnectionName.Location = new System.Drawing.Point(84, 45); + this.txtConnectionName.Name = "txtConnectionName"; + this.txtConnectionName.Size = new System.Drawing.Size(406, 20); + this.txtConnectionName.TabIndex = 19; + // + // label1 + // + this.label1.Dock = System.Windows.Forms.DockStyle.Top; + this.label1.Location = new System.Drawing.Point(0, 0); + this.label1.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(491, 40); + this.label1.TabIndex = 17; + this.label1.Text = "The connection was created successfully. If you want to save this connection, ple" + + "ase provide a name for this connection."; + // + // btnClearEnvHighlight + // + this.btnClearEnvHighlight.Location = new System.Drawing.Point(163, 178); + this.btnClearEnvHighlight.Margin = new System.Windows.Forms.Padding(2); + this.btnClearEnvHighlight.Name = "btnClearEnvHighlight"; + this.btnClearEnvHighlight.Size = new System.Drawing.Size(183, 22); + this.btnClearEnvHighlight.TabIndex = 23; + this.btnClearEnvHighlight.Text = "Clear Environment Highlight"; + this.btnClearEnvHighlight.UseVisualStyleBackColor = true; + this.btnClearEnvHighlight.Visible = false; + this.btnClearEnvHighlight.Click += new System.EventHandler(this.btnClearEnvHighlight_Click); + // + // btnSetEnvHighlight + // + this.btnSetEnvHighlight.Location = new System.Drawing.Point(6, 178); + this.btnSetEnvHighlight.Margin = new System.Windows.Forms.Padding(2); + this.btnSetEnvHighlight.Name = "btnSetEnvHighlight"; + this.btnSetEnvHighlight.Size = new System.Drawing.Size(154, 22); + this.btnSetEnvHighlight.TabIndex = 22; + this.btnSetEnvHighlight.Text = "Set Environment Highlight"; + this.btnSetEnvHighlight.UseVisualStyleBackColor = true; + this.btnSetEnvHighlight.Click += new System.EventHandler(this.btnSetEnvHighlight_Click); + // + // lblHighlight + // + this.lblHighlight.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.lblHighlight.Location = new System.Drawing.Point(3, 153); + this.lblHighlight.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.lblHighlight.Name = "lblHighlight"; + this.lblHighlight.Size = new System.Drawing.Size(488, 23); + this.lblHighlight.TabIndex = 21; + this.lblHighlight.Text = "You can also define an environment highlight for this connection"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(3, 81); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(45, 13); + this.label3.TabIndex = 18; + this.label3.Text = "Solution"; + // + // comboBoxSolutions + // + this.comboBoxSolutions.FormattingEnabled = true; + this.comboBoxSolutions.Location = new System.Drawing.Point(84, 74); + this.comboBoxSolutions.Name = "comboBoxSolutions"; + this.comboBoxSolutions.Size = new System.Drawing.Size(406, 21); + this.comboBoxSolutions.TabIndex = 24; + // + // ConnectionSucceededControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.comboBoxSolutions); + this.Controls.Add(this.btnClearEnvHighlight); + this.Controls.Add(this.btnSetEnvHighlight); + this.Controls.Add(this.lblHighlight); + this.Controls.Add(this.label3); + this.Controls.Add(this.label2); + this.Controls.Add(this.txtConnectionName); + this.Controls.Add(this.label1); + this.Margin = new System.Windows.Forms.Padding(2); + this.Name = "ConnectionSucceededControl"; + this.Size = new System.Drawing.Size(491, 219); + this.Load += new System.EventHandler(this.ConnectionSucceededControl_Load); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox txtConnectionName; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Button btnClearEnvHighlight; + private System.Windows.Forms.Button btnSetEnvHighlight; + private System.Windows.Forms.Label lblHighlight; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.ComboBox comboBoxSolutions; + } +} diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionSucceededControl.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionSucceededControl.cs new file mode 100644 index 0000000..4f51b2c --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionSucceededControl.cs @@ -0,0 +1,78 @@ +using System.Linq; +using System.Windows.Forms; + +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + public partial class ConnectionSucceededControl : UserControl, IConnectionWizardControl + { + public ConnectionSucceededControl() + { + InitializeComponent(); + } + + public ConnectionDetail ConnectionDetail { private get; set; } + + public string ConnectionName + { + get => txtConnectionName.Text; + set => txtConnectionName.Text = value; + } + + public SolutionDetail SelectedSolution + { + get => ((Solution)comboBoxSolutions.SelectedItem).SolutionDetail; + } + private void btnClearEnvHighlight_Click(object sender, System.EventArgs e) + { + ConnectionDetail.EnvironmentHighlightingInfo = null; + //ConnectionDetail.EnvironmentColor = null; + //ConnectionDetail.EnvironmentTextColor = null; + //ConnectionDetail.EnvironmentText = null; + + btnClearEnvHighlight.Visible = false; + } + + private void btnSetEnvHighlight_Click(object sender, System.EventArgs e) + { + var dialog = new EnvHighlightDialog(ConnectionDetail); + if (dialog.ShowDialog(this) == DialogResult.OK) + { + ConnectionDetail.EnvironmentHighlightingInfo = new EnvironmentHighlighting + { + Color = dialog.BackColorSelected, + TextColor = dialog.TextColorSelected, + Text = dialog.TextSelected + }; + + btnClearEnvHighlight.Visible = true; + } + } + + private void ConnectionSucceededControl_Load(object sender, System.EventArgs e) + { + var solutions = ConnectionDetail.Solutions.Select(x => new Solution() { SolutionDetail = x }).ToList(); + comboBoxSolutions.Items.AddRange(solutions.ToArray()); + if(ConnectionDetail != null && ConnectionDetail.SelectedSolution != null) + { + var selectedSolution = ConnectionDetail.Solutions.FirstOrDefault(x => x.SolutionId == ConnectionDetail.SelectedSolution.SolutionId); + if (selectedSolution != null) + { + var index = ConnectionDetail.Solutions.IndexOf(selectedSolution); + comboBoxSolutions.SelectedIndex = index; + } + } + if (!ConnectionManager.Instance.FromXrmToolBox) + { + lblHighlight.Visible = false; + btnClearEnvHighlight.Visible = ConnectionDetail.IsEnvironmentHighlightSet; + btnSetEnvHighlight.Visible = false; + } + else + { + btnClearEnvHighlight.Visible = ConnectionDetail.IsEnvironmentHighlightSet; + lblHighlight.Visible = true; + btnSetEnvHighlight.Visible = true; + } + } + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionSucceededControl.resx b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionSucceededControl.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionSucceededControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionUrlControl.Designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionUrlControl.Designer.cs new file mode 100644 index 0000000..c96f0e7 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionUrlControl.Designer.cs @@ -0,0 +1,122 @@ +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + partial class ConnectionUrlControl + { + /// + /// Variable nécessaire au concepteur. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Nettoyage des ressources utilisées. + /// + /// true si les ressources managées doivent être supprimées ; sinon, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Code généré par le Concepteur de composants + + /// + /// Méthode requise pour la prise en charge du concepteur - ne modifiez pas + /// le contenu de cette méthode avec l'éditeur de code. + /// + private void InitializeComponent() + { + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.lblUrl = new System.Windows.Forms.Label(); + this.txtOrganizationUrl = new System.Windows.Forms.TextBox(); + this.txtTimeout = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 2; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 349F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.Controls.Add(this.label4, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.lblUrl, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.txtOrganizationUrl, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.txtTimeout, 1, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 3; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 52F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 52F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(982, 285); + this.tableLayoutPanel1.TabIndex = 0; + // + // lblUrl + // + this.lblUrl.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblUrl.Location = new System.Drawing.Point(4, 0); + this.lblUrl.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblUrl.Name = "lblUrl"; + this.lblUrl.Size = new System.Drawing.Size(341, 52); + this.lblUrl.TabIndex = 11; + this.lblUrl.Text = "Organization url"; + this.lblUrl.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // txtOrganizationUrl + // + this.txtOrganizationUrl.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtOrganizationUrl.Location = new System.Drawing.Point(353, 10); + this.txtOrganizationUrl.Margin = new System.Windows.Forms.Padding(4, 10, 4, 4); + this.txtOrganizationUrl.Name = "txtOrganizationUrl"; + this.txtOrganizationUrl.Size = new System.Drawing.Size(625, 31); + this.txtOrganizationUrl.TabIndex = 1; + // + // txtTimeout + // + this.txtTimeout.Location = new System.Drawing.Point(353, 62); + this.txtTimeout.Margin = new System.Windows.Forms.Padding(4, 10, 4, 4); + this.txtTimeout.Name = "txtTimeout"; + this.txtTimeout.Size = new System.Drawing.Size(91, 31); + this.txtTimeout.TabIndex = 4; + this.txtTimeout.Text = "00:02:00"; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Dock = System.Windows.Forms.DockStyle.Fill; + this.label4.Location = new System.Drawing.Point(8, 104); + this.label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(682, 104); + this.label4.TabIndex = 19; + this.label4.Text = "Service timeout"; + this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // ConnectionUrlControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.tableLayoutPanel1); + this.Name = "ConnectionUrlControl"; + this.Size = new System.Drawing.Size(982, 285); + this.Load += new System.EventHandler(this.ConnectionUrlControl_Load); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.Label lblUrl; + private System.Windows.Forms.TextBox txtOrganizationUrl; + private System.Windows.Forms.TextBox txtTimeout; + private System.Windows.Forms.Label label4; + } +} diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionUrlControl.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionUrlControl.cs new file mode 100644 index 0000000..84ff464 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionUrlControl.cs @@ -0,0 +1,52 @@ +using System; +using System.Windows.Forms; + +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + public partial class ConnectionUrlControl : UserControl, IConnectionWizardControl + { + public ConnectionUrlControl(ConnectionDetail detail) + { + InitializeComponent(); + + txtOrganizationUrl.Text = string.IsNullOrEmpty(detail.OriginalUrl) ? "https://organization.crm.dynamics.com" : detail.OriginalUrl; + } + + public TimeSpan Timeout + { + get + { + if (!TimeSpan.TryParse(txtTimeout.Text, out TimeSpan result)) + { + MessageBox.Show(this, + @"Please enter a valid timeout (format => HH:mm:ss)", + @"Warning", + MessageBoxButtons.OK, + MessageBoxIcon.Warning); + + return new TimeSpan(); + } + return result; + } + set => txtTimeout.Text = $@"{value:hh\:mm\:ss}"; + } + + public string Url + { + get => txtOrganizationUrl.Text.ToLower(); + set => txtOrganizationUrl.Text = value; + } + + public bool UseSsl => Url.StartsWith("https://"); + + private void ConnectionUrlControl_Load(object sender, EventArgs e) + { + if (txtOrganizationUrl.Text == @"https://organization.crm.dynamics.com") + { + txtOrganizationUrl.Select(8, 12); + } + + txtOrganizationUrl.Focus(); + } + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionUrlControl.resx b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionUrlControl.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/ConnectionUrlControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/IConnectionWizardControl.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/IConnectionWizardControl.cs new file mode 100644 index 0000000..d8a3f88 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/IConnectionWizardControl.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + interface IConnectionWizardControl + { + } +} diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/SdkLoginControlControl.Designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/SdkLoginControlControl.Designer.cs new file mode 100644 index 0000000..6104e74 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/SdkLoginControlControl.Designer.cs @@ -0,0 +1,194 @@ +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + partial class SdkLoginControlControl + { + /// + /// Variable nécessaire au concepteur. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Nettoyage des ressources utilisées. + /// + /// true si les ressources managées doivent être supprimées ; sinon, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Code généré par le Concepteur de composants + + /// + /// Méthode requise pour la prise en charge du concepteur - ne modifiez pas + /// le contenu de cette méthode avec l'éditeur de code. + /// + private void InitializeComponent() + { + this.rdbUseDefault = new System.Windows.Forms.RadioButton(); + this.rdbUseCustom = new System.Windows.Forms.RadioButton(); + this.panel1 = new System.Windows.Forms.Panel(); + this.panel2 = new System.Windows.Forms.Panel(); + this.btnOpenSdkLoginCtrl = new System.Windows.Forms.Button(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.lblAzureAdAppId = new System.Windows.Forms.Label(); + this.txtAzureAdAppId = new System.Windows.Forms.TextBox(); + this.lblReplyUrl = new System.Windows.Forms.Label(); + this.txtReplyUrl = new System.Windows.Forms.TextBox(); + this.panel1.SuspendLayout(); + this.panel2.SuspendLayout(); + this.tableLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // rdbUseDefault + // + this.rdbUseDefault.AutoSize = true; + this.rdbUseDefault.Checked = true; + this.rdbUseDefault.Location = new System.Drawing.Point(3, 3); + this.rdbUseDefault.Name = "rdbUseDefault"; + this.rdbUseDefault.Size = new System.Drawing.Size(251, 29); + this.rdbUseDefault.TabIndex = 0; + this.rdbUseDefault.TabStop = true; + this.rdbUseDefault.Text = "Use default configuration"; + this.rdbUseDefault.UseVisualStyleBackColor = true; + // + // rdbUseCustom + // + this.rdbUseCustom.AutoSize = true; + this.rdbUseCustom.Location = new System.Drawing.Point(3, 38); + this.rdbUseCustom.Name = "rdbUseCustom"; + this.rdbUseCustom.Size = new System.Drawing.Size(668, 29); + this.rdbUseCustom.TabIndex = 1; + this.rdbUseCustom.Text = "Provide your own details for OAuth (Required only for IFD on ADFS 4.0+)"; + this.rdbUseCustom.UseVisualStyleBackColor = true; + this.rdbUseCustom.CheckedChanged += new System.EventHandler(this.rdbUseCustom_CheckedChanged); + // + // panel1 + // + this.panel1.Controls.Add(this.rdbUseDefault); + this.panel1.Controls.Add(this.rdbUseCustom); + this.panel1.Dock = System.Windows.Forms.DockStyle.Top; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(900, 85); + this.panel1.TabIndex = 2; + // + // panel2 + // + this.panel2.Controls.Add(this.btnOpenSdkLoginCtrl); + this.panel2.Dock = System.Windows.Forms.DockStyle.Bottom; + this.panel2.Location = new System.Drawing.Point(0, 214); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(900, 60); + this.panel2.TabIndex = 17; + // + // btnOpenSdkLoginCtrl + // + this.btnOpenSdkLoginCtrl.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnOpenSdkLoginCtrl.Location = new System.Drawing.Point(621, 7); + this.btnOpenSdkLoginCtrl.Margin = new System.Windows.Forms.Padding(4); + this.btnOpenSdkLoginCtrl.Name = "btnOpenSdkLoginCtrl"; + this.btnOpenSdkLoginCtrl.Size = new System.Drawing.Size(275, 42); + this.btnOpenSdkLoginCtrl.TabIndex = 4; + this.btnOpenSdkLoginCtrl.Text = "Open Sdk Login Control"; + this.btnOpenSdkLoginCtrl.UseVisualStyleBackColor = true; + this.btnOpenSdkLoginCtrl.Click += new System.EventHandler(this.btnOpenSdkLoginCtrl_Click); + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 2; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 300F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.Controls.Add(this.lblAzureAdAppId, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.txtAzureAdAppId, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.lblReplyUrl, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.txtReplyUrl, 1, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Enabled = false; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 85); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 3; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 50F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 50F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(900, 129); + this.tableLayoutPanel1.TabIndex = 18; + // + // lblAzureAdAppId + // + this.lblAzureAdAppId.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblAzureAdAppId.Location = new System.Drawing.Point(4, 0); + this.lblAzureAdAppId.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblAzureAdAppId.Name = "lblAzureAdAppId"; + this.lblAzureAdAppId.Size = new System.Drawing.Size(292, 50); + this.lblAzureAdAppId.TabIndex = 11; + this.lblAzureAdAppId.Text = "Application Id"; + this.lblAzureAdAppId.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // txtAzureAdAppId + // + this.txtAzureAdAppId.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtAzureAdAppId.Location = new System.Drawing.Point(304, 10); + this.txtAzureAdAppId.Margin = new System.Windows.Forms.Padding(4, 10, 4, 4); + this.txtAzureAdAppId.Name = "txtAzureAdAppId"; + this.txtAzureAdAppId.Size = new System.Drawing.Size(592, 29); + this.txtAzureAdAppId.TabIndex = 2; + // + // lblReplyUrl + // + this.lblReplyUrl.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblReplyUrl.Location = new System.Drawing.Point(4, 50); + this.lblReplyUrl.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblReplyUrl.Name = "lblReplyUrl"; + this.lblReplyUrl.Size = new System.Drawing.Size(292, 50); + this.lblReplyUrl.TabIndex = 14; + this.lblReplyUrl.Text = "Reply Url"; + this.lblReplyUrl.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // txtReplyUrl + // + this.txtReplyUrl.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtReplyUrl.Location = new System.Drawing.Point(304, 60); + this.txtReplyUrl.Margin = new System.Windows.Forms.Padding(4, 10, 4, 4); + this.txtReplyUrl.Name = "txtReplyUrl"; + this.txtReplyUrl.Size = new System.Drawing.Size(592, 29); + this.txtReplyUrl.TabIndex = 3; + // + // SdkLoginControlControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(11F, 24F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.tableLayoutPanel1); + this.Controls.Add(this.panel2); + this.Controls.Add(this.panel1); + this.Name = "SdkLoginControlControl"; + this.Size = new System.Drawing.Size(900, 274); + this.Load += new System.EventHandler(this.SdkLoginControlControl_Load); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.panel2.ResumeLayout(false); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.RadioButton rdbUseDefault; + private System.Windows.Forms.RadioButton rdbUseCustom; + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.Panel panel2; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.Label lblAzureAdAppId; + private System.Windows.Forms.TextBox txtAzureAdAppId; + private System.Windows.Forms.Label lblReplyUrl; + private System.Windows.Forms.TextBox txtReplyUrl; + private System.Windows.Forms.Button btnOpenSdkLoginCtrl; + } +} diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/SdkLoginControlControl.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/SdkLoginControlControl.cs new file mode 100644 index 0000000..e63d5a5 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/SdkLoginControlControl.cs @@ -0,0 +1,78 @@ +using Microsoft.Xrm.Sdk.Client; +using Microsoft.Xrm.Tooling.Connector; +using Microsoft.Xrm.Tooling.CrmConnectControl; +using System; +using System.Windows.Forms; + +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + public partial class SdkLoginControlControl : UserControl, IConnectionWizardControl + { + private readonly Guid connectionDetailId; + private readonly bool isNew; + + public SdkLoginControlControl(Guid connectionDetailId, bool isNew) + { + InitializeComponent(); + + this.connectionDetailId = connectionDetailId; + this.isNew = isNew; + } + + public event EventHandler ConnectionSucceeded; + + public AuthenticationProviderType AuthType { get; private set; } + public CrmConnectionManager ConnectionManager { get; private set; } + + private void btnOpenSdkLoginCtrl_Click(object sender, EventArgs e) + { + var ctrl = new CRMLoginForm1(connectionDetailId, !isNew); + + if (rdbUseCustom.Checked) + { + ctrl.AppId = txtAzureAdAppId.Text; + ctrl.RedirectUri = new Uri(txtReplyUrl.Text); + } + else + { + ctrl.AppId = "2ad88395-b77d-4561-9441-d0e40824f9bc"; + ctrl.RedirectUri = new Uri("app://5d3e90d6-aa8e-48a8-8f2c-58b45cc67315"); + } + ctrl.ConnectionToCrmCompleted += (loginCtrl, evt) => + { + ConnectionManager = ((CRMLoginForm1)loginCtrl).CrmConnectionMgr; + SetAuthType(); + ConnectionSucceeded?.Invoke(this, null); + }; + ctrl.ShowDialog(); + } + + private void rdbUseCustom_CheckedChanged(object sender, EventArgs e) + { + tableLayoutPanel1.Enabled = rdbUseCustom.Checked; + } + + private void SdkLoginControlControl_Load(object sender, System.EventArgs e) + { + } + + private void SetAuthType() + { + switch (ConnectionManager.CrmSvc.ActiveAuthenticationType) + { + case AuthenticationType.AD: + AuthType = AuthenticationProviderType.ActiveDirectory; + break; + + case AuthenticationType.IFD: + case AuthenticationType.Claims: + AuthType = AuthenticationProviderType.Federation; + break; + + default: + AuthType = AuthenticationProviderType.OnlineFederation; + break; + } + } + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/SdkLoginControlControl.resx b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/SdkLoginControlControl.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/SdkLoginControlControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/StartPageControl.Designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/StartPageControl.Designer.cs new file mode 100644 index 0000000..cda559c --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/StartPageControl.Designer.cs @@ -0,0 +1,189 @@ +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + partial class StartPageControl + { + /// + /// Variable nécessaire au concepteur. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Nettoyage des ressources utilisées. + /// + /// true si les ressources managées doivent être supprimées ; sinon, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Code généré par le Concepteur de composants + + /// + /// Méthode requise pour la prise en charge du concepteur - ne modifiez pas + /// le contenu de cette méthode avec l'éditeur de code. + /// + private void InitializeComponent() + { + this.btnStandard = new System.Windows.Forms.Button(); + this.btnSdkLoginControl = new System.Windows.Forms.Button(); + this.btnConnectionString = new System.Windows.Forms.Button(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.btnMfa = new System.Windows.Forms.Button(); + this.btnClientSecret = new System.Windows.Forms.Button(); + this.btnCertificate = new System.Windows.Forms.Button(); + this.tableLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // btnStandard + // + this.btnStandard.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.btnStandard.Dock = System.Windows.Forms.DockStyle.Fill; + this.btnStandard.Font = new System.Drawing.Font("Segoe UI", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.btnStandard.Image = global::McTools.Xrm.Connection.WinForms.Properties.Resources.connection_wizard_32; + this.btnStandard.Location = new System.Drawing.Point(10, 10); + this.btnStandard.Margin = new System.Windows.Forms.Padding(10); + this.btnStandard.Name = "btnStandard"; + this.btnStandard.Size = new System.Drawing.Size(471, 75); + this.btnStandard.TabIndex = 0; + this.btnStandard.Text = "Connection Wizard"; + this.btnStandard.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + this.btnStandard.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText; + this.btnStandard.UseVisualStyleBackColor = true; + this.btnStandard.Click += new System.EventHandler(this.btn_Click); + // + // btnSdkLoginControl + // + this.btnSdkLoginControl.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; + this.btnSdkLoginControl.Dock = System.Windows.Forms.DockStyle.Fill; + this.btnSdkLoginControl.Font = new System.Drawing.Font("Segoe UI", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.btnSdkLoginControl.Image = global::McTools.Xrm.Connection.WinForms.Properties.Resources.LogoDyn365_32; + this.btnSdkLoginControl.Location = new System.Drawing.Point(501, 10); + this.btnSdkLoginControl.Margin = new System.Windows.Forms.Padding(10); + this.btnSdkLoginControl.Name = "btnSdkLoginControl"; + this.btnSdkLoginControl.Size = new System.Drawing.Size(471, 75); + this.btnSdkLoginControl.TabIndex = 1; + this.btnSdkLoginControl.Text = "SDK Login Control"; + this.btnSdkLoginControl.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + this.btnSdkLoginControl.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText; + this.btnSdkLoginControl.UseVisualStyleBackColor = true; + this.btnSdkLoginControl.Click += new System.EventHandler(this.btn_Click); + // + // btnConnectionString + // + this.btnConnectionString.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; + this.btnConnectionString.Dock = System.Windows.Forms.DockStyle.Fill; + this.btnConnectionString.Font = new System.Drawing.Font("Segoe UI", 10F); + this.btnConnectionString.Image = global::McTools.Xrm.Connection.WinForms.Properties.Resources.connection_string_32; + this.btnConnectionString.Location = new System.Drawing.Point(501, 105); + this.btnConnectionString.Margin = new System.Windows.Forms.Padding(10); + this.btnConnectionString.Name = "btnConnectionString"; + this.btnConnectionString.Size = new System.Drawing.Size(471, 75); + this.btnConnectionString.TabIndex = 2; + this.btnConnectionString.Text = "Connection String"; + this.btnConnectionString.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + this.btnConnectionString.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText; + this.btnConnectionString.UseVisualStyleBackColor = true; + this.btnConnectionString.Click += new System.EventHandler(this.btn_Click); + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 2; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel1.Controls.Add(this.btnMfa, 0, 2); + this.tableLayoutPanel1.Controls.Add(this.btnClientSecret, 0, 2); + this.tableLayoutPanel1.Controls.Add(this.btnCertificate, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.btnSdkLoginControl, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.btnStandard, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.btnConnectionString, 1, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(10, 20, 10, 20); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 3; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(982, 285); + this.tableLayoutPanel1.TabIndex = 3; + // + // btnMfa + // + this.btnMfa.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; + this.btnMfa.Dock = System.Windows.Forms.DockStyle.Fill; + this.btnMfa.Font = new System.Drawing.Font("Segoe UI", 10F); + this.btnMfa.Image = global::McTools.Xrm.Connection.WinForms.Properties.Resources.connection_mfa_32; + this.btnMfa.Location = new System.Drawing.Point(10, 200); + this.btnMfa.Margin = new System.Windows.Forms.Padding(10); + this.btnMfa.Name = "btnMfa"; + this.btnMfa.Size = new System.Drawing.Size(471, 75); + this.btnMfa.TabIndex = 5; + this.btnMfa.Text = "Multi Factor Auth."; + this.btnMfa.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + this.btnMfa.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText; + this.btnMfa.UseVisualStyleBackColor = true; + this.btnMfa.Click += new System.EventHandler(this.btn_Click); + // + // btnClientSecret + // + this.btnClientSecret.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; + this.btnClientSecret.Dock = System.Windows.Forms.DockStyle.Fill; + this.btnClientSecret.Font = new System.Drawing.Font("Segoe UI", 10F); + this.btnClientSecret.Image = global::McTools.Xrm.Connection.WinForms.Properties.Resources.connection_secret_32; + this.btnClientSecret.Location = new System.Drawing.Point(501, 200); + this.btnClientSecret.Margin = new System.Windows.Forms.Padding(10); + this.btnClientSecret.Name = "btnClientSecret"; + this.btnClientSecret.Size = new System.Drawing.Size(471, 75); + this.btnClientSecret.TabIndex = 4; + this.btnClientSecret.Text = "Client Id / Secret"; + this.btnClientSecret.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + this.btnClientSecret.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText; + this.btnClientSecret.UseVisualStyleBackColor = true; + this.btnClientSecret.Click += new System.EventHandler(this.btn_Click); + // + // btnCertificate + // + this.btnCertificate.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; + this.btnCertificate.Dock = System.Windows.Forms.DockStyle.Fill; + this.btnCertificate.Font = new System.Drawing.Font("Segoe UI", 10F); + this.btnCertificate.Image = global::McTools.Xrm.Connection.WinForms.Properties.Resources.connection_certificate_32; + this.btnCertificate.Location = new System.Drawing.Point(10, 105); + this.btnCertificate.Margin = new System.Windows.Forms.Padding(10); + this.btnCertificate.Name = "btnCertificate"; + this.btnCertificate.Size = new System.Drawing.Size(471, 75); + this.btnCertificate.TabIndex = 3; + this.btnCertificate.Text = "Certificate"; + this.btnCertificate.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + this.btnCertificate.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText; + this.btnCertificate.UseVisualStyleBackColor = true; + this.btnCertificate.Click += new System.EventHandler(this.btn_Click); + // + // StartPageControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.Controls.Add(this.tableLayoutPanel1); + this.Name = "StartPageControl"; + this.Size = new System.Drawing.Size(982, 285); + this.tableLayoutPanel1.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Button btnStandard; + private System.Windows.Forms.Button btnSdkLoginControl; + private System.Windows.Forms.Button btnConnectionString; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.Button btnCertificate; + private System.Windows.Forms.Button btnClientSecret; + private System.Windows.Forms.Button btnMfa; + } +} diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/StartPageControl.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/StartPageControl.cs new file mode 100644 index 0000000..0b30b13 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/StartPageControl.cs @@ -0,0 +1,64 @@ +using System; +using System.Windows.Forms; + +namespace McTools.Xrm.Connection.WinForms.CustomControls +{ + public enum ConnectionType + { + Wizard, + Sdk, + ConnectionString, + Certificate, + ClientSecret, + Mfa + } + + public partial class StartPageControl : UserControl, IConnectionWizardControl + { + public StartPageControl() + { + InitializeComponent(); + + var tt = new ToolTip(); + tt.SetToolTip(btnStandard, @"Connect using the wizard included with XrmToolBox"); + tt.SetToolTip(btnSdkLoginControl, @"Connect using the wizard included in official Microsoft tools like Plugin Registration Tool or Configuration Manager. + +Connections created with this wizard cannot be transported across multiple computers (Preview)"); + tt.SetToolTip(btnConnectionString, @"Connect by writing your own connection string"); + } + + public event EventHandler TypeSelected; + + public ConnectionType Type { get; private set; } + + private void btn_Click(object sender, EventArgs e) + { + if (sender == btnStandard) + { + Type = ConnectionType.Wizard; + } + else if (sender == btnSdkLoginControl) + { + Type = ConnectionType.Sdk; + } + else if (sender == btnCertificate) + { + Type = ConnectionType.Certificate; + } + else if (sender == btnClientSecret) + { + Type = ConnectionType.ClientSecret; + } + else if (sender == btnMfa) + { + Type = ConnectionType.Mfa; + } + else + { + Type = ConnectionType.ConnectionString; + } + + TypeSelected?.Invoke(this, new EventArgs()); + } + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/StartPageControl.resx b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/StartPageControl.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/CustomControls/StartPageControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/EnvHighlightDialog.Designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/EnvHighlightDialog.Designer.cs new file mode 100644 index 0000000..07e788c --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/EnvHighlightDialog.Designer.cs @@ -0,0 +1,248 @@ +namespace McTools.Xrm.Connection.WinForms +{ + partial class EnvHighlightDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.pnlFooter = new System.Windows.Forms.Panel(); + this.btnOK = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.pnlHeader = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.pnlMain = new System.Windows.Forms.Panel(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.pbUAT = new System.Windows.Forms.PictureBox(); + this.pbCustom = new System.Windows.Forms.PictureBox(); + this.rdbCustom = new System.Windows.Forms.RadioButton(); + this.rdbUAT = new System.Windows.Forms.RadioButton(); + this.rdbProd = new System.Windows.Forms.RadioButton(); + this.pbProd = new System.Windows.Forms.PictureBox(); + this.pnlFooter.SuspendLayout(); + this.pnlHeader.SuspendLayout(); + this.pnlMain.SuspendLayout(); + this.tableLayoutPanel1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pbUAT)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.pbCustom)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.pbProd)).BeginInit(); + this.SuspendLayout(); + // + // pnlFooter + // + this.pnlFooter.Controls.Add(this.btnOK); + this.pnlFooter.Controls.Add(this.btnCancel); + this.pnlFooter.Dock = System.Windows.Forms.DockStyle.Bottom; + this.pnlFooter.Location = new System.Drawing.Point(0, 751); + this.pnlFooter.Name = "pnlFooter"; + this.pnlFooter.Size = new System.Drawing.Size(1680, 62); + this.pnlFooter.TabIndex = 0; + // + // btnOK + // + this.btnOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK; + this.btnOK.Location = new System.Drawing.Point(1382, 10); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(140, 40); + this.btnOK.TabIndex = 19; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + this.btnOK.Click += new System.EventHandler(this.btnOK_Click); + // + // btnCancel + // + this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(1528, 10); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(140, 40); + this.btnCancel.TabIndex = 18; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); + // + // pnlHeader + // + this.pnlHeader.BackColor = System.Drawing.Color.White; + this.pnlHeader.Controls.Add(this.label1); + this.pnlHeader.Dock = System.Windows.Forms.DockStyle.Top; + this.pnlHeader.Location = new System.Drawing.Point(0, 0); + this.pnlHeader.Name = "pnlHeader"; + this.pnlHeader.Size = new System.Drawing.Size(1680, 100); + this.pnlHeader.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Segoe UI Light", 16F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(13, 13); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(546, 51); + this.label1.TabIndex = 0; + this.label1.Text = "Choose an environment highlight"; + // + // pnlMain + // + this.pnlMain.Controls.Add(this.tableLayoutPanel1); + this.pnlMain.Dock = System.Windows.Forms.DockStyle.Fill; + this.pnlMain.Location = new System.Drawing.Point(0, 100); + this.pnlMain.Name = "pnlMain"; + this.pnlMain.Size = new System.Drawing.Size(1680, 651); + this.pnlMain.TabIndex = 2; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 3; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 34F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33F)); + this.tableLayoutPanel1.Controls.Add(this.pbUAT, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.pbCustom, 1, 1); + this.tableLayoutPanel1.Controls.Add(this.rdbCustom, 2, 0); + this.tableLayoutPanel1.Controls.Add(this.rdbUAT, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.rdbProd, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.pbProd, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 50F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.Size = new System.Drawing.Size(1680, 651); + this.tableLayoutPanel1.TabIndex = 0; + // + // pbUAT + // + this.pbUAT.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.pbUAT.Image = global::McTools.Xrm.Connection.WinForms.Properties.Resources.XTB_HIGHLIGHT_UAT; + this.pbUAT.Location = new System.Drawing.Point(557, 53); + this.pbUAT.Name = "pbUAT"; + this.pbUAT.Size = new System.Drawing.Size(565, 565); + this.pbUAT.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.pbUAT.TabIndex = 5; + this.pbUAT.TabStop = false; + // + // pbCustom + // + this.pbCustom.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.pbCustom.Image = global::McTools.Xrm.Connection.WinForms.Properties.Resources.XTB_HIGHLIGHT_CUSTOM; + this.pbCustom.Location = new System.Drawing.Point(1128, 53); + this.pbCustom.Name = "pbCustom"; + this.pbCustom.Size = new System.Drawing.Size(549, 565); + this.pbCustom.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.pbCustom.TabIndex = 4; + this.pbCustom.TabStop = false; + // + // rdbCustom + // + this.rdbCustom.Dock = System.Windows.Forms.DockStyle.Fill; + this.rdbCustom.Location = new System.Drawing.Point(1128, 3); + this.rdbCustom.Name = "rdbCustom"; + this.rdbCustom.Size = new System.Drawing.Size(549, 44); + this.rdbCustom.TabIndex = 2; + this.rdbCustom.TabStop = true; + this.rdbCustom.Text = "Custom"; + this.rdbCustom.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.rdbCustom.UseVisualStyleBackColor = true; + this.rdbCustom.MouseClick += new System.Windows.Forms.MouseEventHandler(this.rdbCustom_MouseClick); + // + // rdbUAT + // + this.rdbUAT.Dock = System.Windows.Forms.DockStyle.Fill; + this.rdbUAT.Location = new System.Drawing.Point(557, 3); + this.rdbUAT.Name = "rdbUAT"; + this.rdbUAT.Size = new System.Drawing.Size(565, 44); + this.rdbUAT.TabIndex = 1; + this.rdbUAT.TabStop = true; + this.rdbUAT.Text = "UAT"; + this.rdbUAT.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.rdbUAT.UseVisualStyleBackColor = true; + // + // rdbProd + // + this.rdbProd.Dock = System.Windows.Forms.DockStyle.Fill; + this.rdbProd.Location = new System.Drawing.Point(3, 3); + this.rdbProd.Name = "rdbProd"; + this.rdbProd.Size = new System.Drawing.Size(548, 44); + this.rdbProd.TabIndex = 0; + this.rdbProd.TabStop = true; + this.rdbProd.Text = "Production"; + this.rdbProd.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.rdbProd.UseVisualStyleBackColor = true; + // + // pbProd + // + this.pbProd.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.pbProd.Image = global::McTools.Xrm.Connection.WinForms.Properties.Resources.XTB_HIGHLIGHT_PRODUCTION; + this.pbProd.Location = new System.Drawing.Point(3, 53); + this.pbProd.Name = "pbProd"; + this.pbProd.Size = new System.Drawing.Size(548, 565); + this.pbProd.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.pbProd.TabIndex = 3; + this.pbProd.TabStop = false; + // + // EnvHighlightDialog + // + this.AutoScaleDimensions = new System.Drawing.SizeF(11F, 24F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(1680, 813); + this.Controls.Add(this.pnlMain); + this.Controls.Add(this.pnlHeader); + this.Controls.Add(this.pnlFooter); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "EnvHighlightDialog"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.pnlFooter.ResumeLayout(false); + this.pnlHeader.ResumeLayout(false); + this.pnlHeader.PerformLayout(); + this.pnlMain.ResumeLayout(false); + this.tableLayoutPanel1.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.pbUAT)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.pbCustom)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.pbProd)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Panel pnlFooter; + private System.Windows.Forms.Panel pnlHeader; + private System.Windows.Forms.Panel pnlMain; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.PictureBox pbCustom; + private System.Windows.Forms.RadioButton rdbCustom; + private System.Windows.Forms.RadioButton rdbUAT; + private System.Windows.Forms.RadioButton rdbProd; + private System.Windows.Forms.PictureBox pbProd; + private System.Windows.Forms.PictureBox pbUAT; + private System.Windows.Forms.Button btnOK; + private System.Windows.Forms.Button btnCancel; + private System.Windows.Forms.Label label1; + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/EnvHighlightDialog.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/EnvHighlightDialog.cs new file mode 100644 index 0000000..60a9195 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/EnvHighlightDialog.cs @@ -0,0 +1,158 @@ +using System.Drawing; +using System.Drawing.Imaging; +using System.Windows.Forms; + +namespace McTools.Xrm.Connection.WinForms +{ + public partial class EnvHighlightDialog : Form + { + private readonly ConnectionDetail detail; + private readonly Image template; + private Color backColor = Color.FromArgb(255, 255, 0, 255); + private string text; + private Color textColor = Color.White; + + public EnvHighlightDialog(ConnectionDetail detail) + { + InitializeComponent(); + + template = pbCustom.Image; + this.detail = detail; + + if (detail.IsEnvironmentHighlightSet) + { + rdbProd.Checked = detail.EnvironmentColor == Color.Red && detail.EnvironmentTextColor == Color.White && + detail.EnvironmentText == "PRODUCTION"; + rdbUAT.Checked = detail.EnvironmentColor == Color.Yellow && detail.EnvironmentTextColor == Color.Black && + detail.EnvironmentText == "UAT"; + rdbCustom.Checked = !rdbProd.Checked && !rdbUAT.Checked; + if (rdbCustom.Checked) + { + Dialog_OnTemplateSettingsChanged(null, new TemplateChangeEventArgs + { + BackColor = detail.EnvironmentColor ?? backColor, + TextColor = detail.EnvironmentTextColor ?? textColor, + Text = detail.EnvironmentText + }); + } + } + } + + public Color BackColorSelected + { + get + { + if (rdbProd.Checked) + { + return Color.Red; + } + + if (rdbUAT.Checked) + { + return Color.Yellow; + } + + return backColor; + } + } + + public Color TextColorSelected + { + get + { + if (rdbProd.Checked) + { + return Color.White; + } + + if (rdbUAT.Checked) + { + return Color.Black; + } + + return textColor; + } + } + + public string TextSelected + { + get + { + if (rdbProd.Checked) + { + return "PRODUCTION"; + } + + if (rdbUAT.Checked) + { + return "UAT"; + } + + return text; + } + } + + private void btnCancel_Click(object sender, System.EventArgs e) + { + Close(); + } + + private void btnOK_Click(object sender, System.EventArgs e) + { + if (!rdbUAT.Checked && !rdbProd.Checked && !rdbCustom.Checked) + { + MessageBox.Show(this, @"Please select a template", @"Warning", MessageBoxButtons.OK, + MessageBoxIcon.Warning); + return; + } + Close(); + } + + private void Dialog_OnTemplateSettingsChanged(object sender, TemplateChangeEventArgs e) + { + textColor = e.TextColor; + backColor = e.BackColor; + text = e.Text; + + var font = new Font(new FontFamily("Calibri"), 30, FontStyle.Bold); + + var image = (Image)template.Clone(); + var g = Graphics.FromImage(image); + StringFormat sf = new StringFormat { Alignment = StringAlignment.Center }; + g.DrawString(text, font, new SolidBrush(textColor), new Rectangle(0, 50, image.Width, 50), sf); + + ImageAttributes imageAttributes = new ImageAttributes(); + + ColorMap[] remapTable = + { + new ColorMap + { + OldColor = Color.FromArgb(255, 255, 0, 255), + NewColor = Color.FromArgb(255, e.BackColor.R, e.BackColor.G, e.BackColor.B) + } + }; + + imageAttributes.SetRemapTable(remapTable, ColorAdjustType.Bitmap); + + g.DrawImage(image, 0, 0, image.Width, image.Height); + g.DrawImage( + image, + new Rectangle(0, 0, image.Width, image.Height), // destination rectangle + 0, 0, // upper-left corner of source rectangle + image.Width, // width of source rectangle + image.Height, // height of source rectangle + GraphicsUnit.Pixel, + imageAttributes); + + pbCustom.Image = image; + pbCustom.Invalidate(); + } + + private void rdbCustom_MouseClick(object sender, MouseEventArgs e) + { + var dialog = new EnvHighlightSettingsDialog(null, null, "", detail); + dialog.OnTemplateSettingsChanged += Dialog_OnTemplateSettingsChanged; + dialog.ShowDialog(this); + } + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/EnvHighlightDialog.resx b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/EnvHighlightDialog.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/EnvHighlightDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/EnvHighlightSettingsDialog.Designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/EnvHighlightSettingsDialog.Designer.cs new file mode 100644 index 0000000..84fb760 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/EnvHighlightSettingsDialog.Designer.cs @@ -0,0 +1,182 @@ +namespace McTools.Xrm.Connection.WinForms +{ + partial class EnvHighlightSettingsDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.label2 = new System.Windows.Forms.Label(); + this.btnTextColor = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.lblBackColor = new System.Windows.Forms.Label(); + this.btnBackColor = new System.Windows.Forms.Button(); + this.txtText = new System.Windows.Forms.TextBox(); + this.btnClose = new System.Windows.Forms.Button(); + this.btnUseOrgTheme = new System.Windows.Forms.Button(); + this.tableLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 2; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 218F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.Controls.Add(this.label2, 0, 2); + this.tableLayoutPanel1.Controls.Add(this.btnTextColor, 1, 1); + this.tableLayoutPanel1.Controls.Add(this.label1, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.lblBackColor, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.btnBackColor, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.txtText, 1, 2); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Top; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 4; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 52F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 52F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 52F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.Size = new System.Drawing.Size(873, 152); + this.tableLayoutPanel1.TabIndex = 0; + // + // label2 + // + this.label2.Dock = System.Windows.Forms.DockStyle.Fill; + this.label2.Location = new System.Drawing.Point(3, 104); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(212, 52); + this.label2.TabIndex = 4; + this.label2.Text = "Text"; + this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // btnTextColor + // + this.btnTextColor.Dock = System.Windows.Forms.DockStyle.Left; + this.btnTextColor.Location = new System.Drawing.Point(221, 55); + this.btnTextColor.Name = "btnTextColor"; + this.btnTextColor.Size = new System.Drawing.Size(82, 46); + this.btnTextColor.TabIndex = 3; + this.btnTextColor.Text = "..."; + this.btnTextColor.UseVisualStyleBackColor = true; + this.btnTextColor.Click += new System.EventHandler(this.btnTextColor_Click); + // + // label1 + // + this.label1.Dock = System.Windows.Forms.DockStyle.Fill; + this.label1.Location = new System.Drawing.Point(3, 52); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(212, 52); + this.label1.TabIndex = 2; + this.label1.Text = "Text color"; + this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // lblBackColor + // + this.lblBackColor.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblBackColor.Location = new System.Drawing.Point(3, 0); + this.lblBackColor.Name = "lblBackColor"; + this.lblBackColor.Size = new System.Drawing.Size(212, 52); + this.lblBackColor.TabIndex = 0; + this.lblBackColor.Text = "Background color"; + this.lblBackColor.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // btnBackColor + // + this.btnBackColor.Dock = System.Windows.Forms.DockStyle.Left; + this.btnBackColor.Location = new System.Drawing.Point(221, 3); + this.btnBackColor.Name = "btnBackColor"; + this.btnBackColor.Size = new System.Drawing.Size(82, 46); + this.btnBackColor.TabIndex = 1; + this.btnBackColor.Text = "..."; + this.btnBackColor.UseVisualStyleBackColor = true; + this.btnBackColor.Click += new System.EventHandler(this.btnBackColor_Click); + // + // txtText + // + this.txtText.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtText.Location = new System.Drawing.Point(221, 107); + this.txtText.Name = "txtText"; + this.txtText.Size = new System.Drawing.Size(649, 31); + this.txtText.TabIndex = 5; + this.txtText.TextChanged += new System.EventHandler(this.txtText_TextChanged); + // + // btnClose + // + this.btnClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnClose.DialogResult = System.Windows.Forms.DialogResult.OK; + this.btnClose.Location = new System.Drawing.Point(707, 158); + this.btnClose.Name = "btnClose"; + this.btnClose.Size = new System.Drawing.Size(153, 42); + this.btnClose.TabIndex = 20; + this.btnClose.Text = "Close"; + this.btnClose.UseVisualStyleBackColor = true; + this.btnClose.Click += new System.EventHandler(this.btnClose_Click); + // + // btnUseOrgTheme + // + this.btnUseOrgTheme.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnUseOrgTheme.Location = new System.Drawing.Point(404, 158); + this.btnUseOrgTheme.Name = "btnUseOrgTheme"; + this.btnUseOrgTheme.Size = new System.Drawing.Size(297, 42); + this.btnUseOrgTheme.TabIndex = 21; + this.btnUseOrgTheme.Text = "Use organization theme"; + this.btnUseOrgTheme.UseVisualStyleBackColor = true; + this.btnUseOrgTheme.Click += new System.EventHandler(this.btnUseOrgTheme_Click); + // + // EnvHighlightSettingsDialog + // + this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(873, 212); + this.Controls.Add(this.btnUseOrgTheme); + this.Controls.Add(this.btnClose); + this.Controls.Add(this.tableLayoutPanel1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "EnvHighlightSettingsDialog"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Custom template settings"; + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Button btnTextColor; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label lblBackColor; + private System.Windows.Forms.Button btnBackColor; + private System.Windows.Forms.TextBox txtText; + private System.Windows.Forms.Button btnClose; + private System.Windows.Forms.Button btnUseOrgTheme; + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/EnvHighlightSettingsDialog.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/EnvHighlightSettingsDialog.cs new file mode 100644 index 0000000..9edf6c0 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/EnvHighlightSettingsDialog.cs @@ -0,0 +1,157 @@ +using Microsoft.Xrm.Sdk; +using Microsoft.Xrm.Sdk.Query; +using System; +using System.ComponentModel; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; + +namespace McTools.Xrm.Connection.WinForms +{ + public partial class EnvHighlightSettingsDialog : Form + { + private readonly ConnectionDetail detail; + private Color backColor; + private Color textColor; + + public EnvHighlightSettingsDialog(Color? backColor, Color? textColor, string text, ConnectionDetail detail) + { + InitializeComponent(); + + this.detail = detail; + + this.backColor = backColor.HasValue ? this.backColor : Color.FromArgb(255, 0, 255); + this.textColor = textColor.HasValue ? this.textColor : Color.White; + txtText.Text = text; + btnBackColor.BackColor = this.backColor; + btnTextColor.BackColor = this.textColor; + + btnUseOrgTheme.Visible = detail.OrganizationMajorVersion > 7 || + detail.OrganizationMajorVersion == 7 && detail.OrganizationMinorVersion >= 1; + } + + public event EventHandler OnTemplateSettingsChanged; + + private void btnBackColor_Click(object sender, EventArgs e) + { + var dialog = new ColorDialog { Color = backColor }; + if (dialog.ShowDialog(this) == DialogResult.OK) + { + backColor = dialog.Color; + ((Button)sender).BackColor = dialog.Color; + + OnTemplateSettingsChanged?.Invoke(this, new TemplateChangeEventArgs + { + BackColor = backColor, + Text = txtText.Text, + TextColor = textColor + }); + } + } + + private void btnClose_Click(object sender, EventArgs e) + { + Close(); + } + + private void btnTextColor_Click(object sender, EventArgs e) + { + var dialog = new ColorDialog { Color = textColor }; + if (dialog.ShowDialog(this) == DialogResult.OK) + { + textColor = dialog.Color; + ((Button)sender).BackColor = dialog.Color; + + OnTemplateSettingsChanged?.Invoke(this, new TemplateChangeEventArgs + { + BackColor = backColor, + Text = txtText.Text, + TextColor = textColor + }); + } + } + + private void btnUseOrgTheme_Click(object sender, EventArgs e) + { + btnUseOrgTheme.Text = @"Connecting..."; + btnUseOrgTheme.Enabled = false; + Cursor = Cursors.WaitCursor; + + var bw = new BackgroundWorker { WorkerReportsProgress = true }; + bw.DoWork += (s, evt) => + { + var svc = detail.ServiceClient; + + ((BackgroundWorker)s).ReportProgress(50); + + evt.Result = svc.RetrieveMultiple(new QueryExpression + { + EntityName = "theme", + ColumnSet = new ColumnSet("navbarbackgroundcolor"), + Criteria = new FilterExpression + { + Conditions = + { + new ConditionExpression("isdefaulttheme", ConditionOperator.Equal, true) + } + } + }).Entities.FirstOrDefault(); + }; + bw.RunWorkerCompleted += (s, evt) => + { + btnUseOrgTheme.Text = @"Use organization theme"; + btnUseOrgTheme.Enabled = true; + Cursor = Cursors.Default; + + if (evt.Error != null) + { + MessageBox.Show(this, + $@"An error occured when retrieving theme: {evt.Error.Message}", + @"Error", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + } + else if (evt.Result is Entity theme) + { + backColor = ColorTranslator.FromHtml(theme.GetAttributeValue("navbarbackgroundcolor")); + btnBackColor.BackColor = backColor; + textColor = Color.White; + btnTextColor.BackColor = textColor; + txtText.Text = txtText.Text.Length == 0 ? detail.ConnectionName : txtText.Text; + + OnTemplateSettingsChanged?.Invoke(this, new TemplateChangeEventArgs + { + BackColor = backColor, + Text = txtText.Text, + TextColor = textColor + }); + } + }; + bw.ProgressChanged += (s, evt) => + { + if (evt.ProgressPercentage == 50) + { + btnUseOrgTheme.Text = @"Retrieving theme..."; + } + }; + bw.RunWorkerAsync(); + } + + private void txtText_TextChanged(object sender, EventArgs e) + { + OnTemplateSettingsChanged?.Invoke(this, new TemplateChangeEventArgs + { + BackColor = backColor, + Text = txtText.Text, + TextColor = textColor + }); + } + } + + public class TemplateChangeEventArgs : EventArgs + { + public Color BackColor { get; set; } + public string Text { get; set; } + public Color TextColor { get; set; } + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/EnvHighlightSettingsDialog.resx b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/EnvHighlightSettingsDialog.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/EnvHighlightSettingsDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/FormHelper.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/FormHelper.cs index fb117d8..80b111a 100644 --- a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/FormHelper.cs +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/FormHelper.cs @@ -1,138 +1,178 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; -using System.Net; using System.Windows.Forms; -using Microsoft.Crm.Sdk.Messages; namespace McTools.Xrm.Connection.WinForms { public class FormHelper { - public FormHelper(Form innerAppForm, ConnectionManager connectionManager) + private readonly Control innerAppForm; + + public FormHelper(Control innerAppForm) { - _innerAppForm = innerAppForm; - _connectionManager = connectionManager; + this.innerAppForm = innerAppForm; } - private readonly Form _innerAppForm; - private readonly ConnectionManager _connectionManager; - /// - /// Checks the existence of a user password and returns it + /// Asks this manager to select a Crm connection to use /// - /// Details of the Crm connection - /// True if password defined - public bool RequestPassword(ConnectionDetail detail) + /// The connection parameter. + /// The action to be performed before the async call to create the connection. Useful to display a please wait message + /// + public bool AskForConnection(object connectionParameter, Action> preConnectionRequestAction) { - if (!string.IsNullOrEmpty(detail.UserPassword)) - return true; - - bool returnValue = false; - - var pForm = new PasswordForm + var cs = new ConnectionSelector { - UserLogin = detail.UserName, - UserDomain = detail.UserDomain, - StartPosition = FormStartPosition.CenterParent + StartPosition = FormStartPosition.CenterParent, }; - MethodInvoker mi = delegate + if (cs.ShowDialog(innerAppForm) == DialogResult.OK) { - if (pForm.ShowDialog(_innerAppForm) == DialogResult.OK) + if (cs.SelectedConnections.Any(c => c.IsFromSdkLoginCtrl) + && cs.SelectedConnections.Count > 1) { - detail.UserPassword = pForm.UserPassword; - detail.SavePassword = pForm.SavePassword; - returnValue = true; + MessageBox.Show(innerAppForm, @"You cannot select multiple connections that used SDK Login control", + @"Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return false; } - }; - if (_innerAppForm.InvokeRequired) - { - _innerAppForm.Invoke(mi); - } - else - { - mi(); + foreach (var connectionDetail in cs.SelectedConnections) + { + if (!connectionDetail.UseConnectionString && connectionDetail.IsCustomAuth) + { + if (connectionDetail.PasswordIsEmpty && connectionDetail.Certificate == null) + { + var pForm = new PasswordForm(connectionDetail) + { + UserDomain = connectionDetail.UserDomain, + UserLogin = connectionDetail.UserName + }; + if (pForm.ShowDialog(innerAppForm) == DialogResult.OK) + { + connectionDetail.SetPassword(pForm.UserPassword); + connectionDetail.SavePassword = pForm.SavePassword; + } + else + { + return false; + } + } + } + } + + preConnectionRequestAction?.Invoke(cs.SelectedConnections); + + if (cs.SelectedConnections.First().IsFromSdkLoginCtrl) + { + var cd = cs.SelectedConnections.First(); + + var ctrl = new CRMLoginForm1(cd.ConnectionId.Value); + if (cd.AzureAdAppId != Guid.Empty) + { + ctrl.AppId = cd.AzureAdAppId.ToString(); + ctrl.RedirectUri = new Uri(cd.ReplyUrl); + } + + ctrl.ShowDialog(); + + ConnectionManager.Instance.ConnectToServerWithSdkLoginCtrl(cd, ctrl.CrmConnectionMgr.CrmSvc, + connectionParameter); + } + else + { + ConnectionManager.Instance.ConnectToServer(cs.SelectedConnections, connectionParameter); + } + + return true; } - return returnValue; + return false; } /// /// Asks this manager to select a Crm connection to use /// - public bool AskForConnection(object connectionParameter) + /// The to use + /// The connection parameter. + /// The action to be performed before the async call to create the connection. Useful to display a please wait message + /// + public bool AskForConnection(ConnectionDetail connectionDetail, object connectionParameter, Action preConnectionRequestAction) { - var cs = new ConnectionSelector(_connectionManager.LoadConnectionsList(), _connectionManager) + if (!connectionDetail.UseConnectionString && connectionDetail.IsCustomAuth) { - StartPosition = FormStartPosition.CenterParent, - ConnectionList = _connectionManager.LoadConnectionsList() - }; - - if (cs.ShowDialog(_innerAppForm) == DialogResult.OK) - { - var connectionDetail = cs.SelectedConnections.First(); - if (connectionDetail.IsCustomAuth) + if (connectionDetail.PasswordIsEmpty && connectionDetail.Certificate == null) { - if (string.IsNullOrEmpty(connectionDetail.UserPassword)) + var pForm = new PasswordForm(connectionDetail) { - var pForm = new PasswordForm() - { - UserDomain = connectionDetail.UserDomain, - UserLogin = connectionDetail.UserName - }; - if (pForm.ShowDialog(_innerAppForm) == DialogResult.OK) - { - connectionDetail.UserPassword = pForm.UserPassword; - connectionDetail.SavePassword = pForm.SavePassword; - } - else - { - return false; - } + UserDomain = connectionDetail.UserDomain, + UserLogin = connectionDetail.UserName + }; + if (pForm.ShowDialog(innerAppForm) == DialogResult.OK) + { + connectionDetail.SetPassword(pForm.UserPassword); + connectionDetail.SavePassword = pForm.SavePassword; } - } + else + { + return false; + } + } + } - _connectionManager.ConnectToServer(connectionDetail, connectionParameter); + preConnectionRequestAction?.Invoke(); + + if (connectionDetail.IsFromSdkLoginCtrl) + { + var cd = connectionDetail; - if (cs.HadCreatedNewConnection) + var ctrl = new CRMLoginForm1(cd.ConnectionId.Value); + if (cd.AzureAdAppId != Guid.Empty) { - if (!_connectionManager.ConnectionsList.Connections.Contains(connectionDetail)) - _connectionManager.ConnectionsList.Connections.Add(connectionDetail); - //_connectionManager.SaveConnectionsFile(_connectionManager.ConnectionsList); + ctrl.AppId = cd.AzureAdAppId.ToString(); + ctrl.RedirectUri = new Uri(cd.ReplyUrl); } - return true; - } + ctrl.ShowDialog(); - return false; + ConnectionManager.Instance.ConnectToServerWithSdkLoginCtrl(cd, ctrl.CrmConnectionMgr.CrmSvc, + connectionParameter); + } + else + { + ConnectionManager.Instance.ConnectToServer(new List { connectionDetail }, connectionParameter); + } + return true; } - //public void DisplayConnectionsList(Form form) - //{ - // var cs = new ConnectionSelector(_connectionManager.LoadConnectionsList(), _connectionManager, true, false) - // { - // StartPosition = FormStartPosition.CenterParent, - // ConnectionList = _connectionManager.LoadConnectionsList() - // }; + /// + /// Asks this manager to select a Crm connection to use + /// + public bool AskForConnection(object connectionParameter) => + AskForConnection(connectionParameter, null); + + /// + /// Deletes a Crm connection from the connections list + /// + /// Id of the connection to delete + public void DeleteConnection(Guid? connectionId) + { + var connection = ConnectionManager.Instance.ConnectionsList.Connections.FirstOrDefault(x => x.ConnectionId == connectionId); - // cs.ShowDialog(form); - //} + if (connection != null) + { + ConnectionManager.Instance.ConnectionsList.Connections.Remove(connection); + } + } - public List SelectMultipleConnectionDetails() + public void DisplayConnectionsList(Form form) { - var cs = new ConnectionSelector(_connectionManager.LoadConnectionsList(), _connectionManager, null, true) + var cs = new ConnectionSelector(false) { StartPosition = FormStartPosition.CenterParent, - ConnectionList = _connectionManager.LoadConnectionsList() }; - if (cs.ShowDialog(_innerAppForm) == DialogResult.OK) - { - return cs.SelectedConnections; - } - - return new List(); + cs.ShowDialog(form); } /// @@ -140,90 +180,124 @@ public List SelectMultipleConnectionDetails() /// /// Indicates if it is a connection creation /// Details of the connection to update + /// List of connections where the connection is edited from /// Created or updated connection - public ConnectionDetail EditConnection(bool isCreation, ConnectionDetail connectionToUpdate) + public ConnectionDetail EditConnection(bool isCreation, ConnectionDetail connectionToUpdate, ConnectionFile connectionFile = null) { - var cForm = new ConnectionForm(isCreation) { StartPosition = FormStartPosition.CenterParent }; + var cForm = new ConnectionWizard2(connectionToUpdate) { StartPosition = FormStartPosition.CenterParent }; - if (!isCreation) - { - cForm.CrmConnectionDetail = connectionToUpdate; - } - - if (cForm.ShowDialog(_innerAppForm) == DialogResult.OK) + if (cForm.ShowDialog(innerAppForm) == DialogResult.OK) { if (isCreation) { - if (!_connectionManager.ConnectionsList.Connections.Contains(cForm.CrmConnectionDetail)) - _connectionManager.ConnectionsList.Connections.Add(cForm.CrmConnectionDetail); + if (connectionFile == null) + { + if (ConnectionManager.Instance.ConnectionsList.Connections.FirstOrDefault( + d => d.ConnectionId == cForm.CrmConnectionDetail.ConnectionId) == null) + { + ConnectionManager.Instance.ConnectionsList.Connections.Add(cForm.CrmConnectionDetail); + } + + } + else + { + var connections = CrmConnections.LoadFromFile(connectionFile.Path); + if (connections.Connections.FirstOrDefault( + d => d.ConnectionId == cForm.CrmConnectionDetail.ConnectionId) == null) + { + connections.Connections.Add(cForm.CrmConnectionDetail); + } + + connections.SerializeToFile(connectionFile.Path); + } } else { - foreach (ConnectionDetail detail in _connectionManager.ConnectionsList.Connections) + if (connectionFile == null) { - if (detail.ConnectionId == cForm.CrmConnectionDetail.ConnectionId) + ConnectionManager.Instance.ConnectionsList.Connections + .Where(x => x.ConnectionId == cForm.CrmConnectionDetail.ConnectionId) + .ToList() + .ForEach(x => x.UpdateAfterEdit(cForm.CrmConnectionDetail)); + + } + else + { + var connections = CrmConnections.LoadFromFile(connectionFile.Path); + foreach (ConnectionDetail detail in connections.Connections) { - #region Update connection details - - detail.ConnectionName = cForm.CrmConnectionDetail.ConnectionName; - detail.OrganizationServiceUrl = cForm.CrmConnectionDetail.OrganizationServiceUrl; - detail.CrmTicket = cForm.CrmConnectionDetail.CrmTicket; - detail.IsCustomAuth = cForm.CrmConnectionDetail.IsCustomAuth; - detail.Organization = cForm.CrmConnectionDetail.Organization; - detail.OrganizationFriendlyName = cForm.CrmConnectionDetail.OrganizationFriendlyName; - detail.ServerName = cForm.CrmConnectionDetail.ServerName; - detail.ServerPort = cForm.CrmConnectionDetail.ServerPort; - detail.UseIfd = cForm.CrmConnectionDetail.UseIfd; - detail.UseOnline = cForm.CrmConnectionDetail.UseOnline; - detail.UseOsdp = cForm.CrmConnectionDetail.UseOsdp; - detail.UserDomain = cForm.CrmConnectionDetail.UserDomain; - detail.UserName = cForm.CrmConnectionDetail.UserName; - detail.UserPassword = cForm.CrmConnectionDetail.UserPassword; - detail.UseSsl = cForm.CrmConnectionDetail.UseSsl; - detail.HomeRealmUrl = cForm.CrmConnectionDetail.HomeRealmUrl; - - #endregion + if (detail.ConnectionId == cForm.CrmConnectionDetail.ConnectionId) + { + detail.UpdateAfterEdit(cForm.CrmConnectionDetail); + } } - } - } - if (cForm.DoConnect) - { - _connectionManager.ConnectToServer(cForm.CrmConnectionDetail); + connections.SerializeToFile(connectionFile.Path); + } } - //_connectionManager.SaveConnectionsFile(_connectionManager.ConnectionsList); - return cForm.CrmConnectionDetail; } return null; } - public IWebProxy SelectProxy() + /// + /// Checks the existence of a user password and returns it + /// + /// Details of the Crm connection + /// True if password defined + public bool RequestPassword(ConnectionDetail detail) { - if (_connectionManager.ConnectionsList.UseCustomProxy) + if (!string.IsNullOrEmpty(detail.ConnectionString)) + return true; + + if (!detail.PasswordIsEmpty || detail.Certificate != null) + return true; + + bool returnValue = false; + + var pForm = new PasswordForm(detail) { - var proxy = new WebProxy(_connectionManager.ConnectionsList.ProxyAddress + ":" + _connectionManager.ConnectionsList.ProxyPort, true) + UserLogin = detail.UserName, + UserDomain = detail.UserDomain, + }; + + MethodInvoker mi = delegate + { + if (pForm.ShowDialog(innerAppForm) == DialogResult.OK) { - Credentials = - new NetworkCredential(_connectionManager.ConnectionsList.UserName, _connectionManager.ConnectionsList.Password) - }; + detail.SetPassword(pForm.UserPassword); + detail.SavePassword = pForm.SavePassword; + returnValue = true; + } + }; - return proxy; + if (innerAppForm.InvokeRequired) + { + innerAppForm.Invoke(mi); + } + else + { + mi(); } - return null; + return returnValue; } - /// - /// Deletes a Crm connection from the connections list - /// - /// Details of the connection to delete - public void DeleteConnection(ConnectionDetail connectionToDelete) + public List SelectMultipleConnectionDetails() { - _connectionManager.ConnectionsList.Connections.Remove(connectionToDelete); - //_connectionManager.SaveConnectionsFile(_connectionManager.ConnectionsList); + var cs = new ConnectionSelector + { + StartPosition = FormStartPosition.CenterParent, + }; + + if (cs.ShowDialog(innerAppForm) == DialogResult.OK) + { + return cs.SelectedConnections; + } + + return new List(); } } -} +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ListViewItemComparer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ListViewItemComparer.cs index dd88564..dd7ba2e 100644 --- a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ListViewItemComparer.cs +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ListViewItemComparer.cs @@ -4,10 +4,18 @@ namespace McTools.Xrm.Connection.WinForms { + internal class GroupComparer : IComparer + { + public int Compare(object objA, object objB) + { + return String.Compare(((ListViewGroup)objA).Header, ((ListViewGroup)objB).Header, StringComparison.Ordinal); + } + } + /// /// Compares two listview items for sorting /// - class ListViewItemComparer : IComparer + internal class ListViewItemComparer : IComparer { #region Variables @@ -21,7 +29,7 @@ class ListViewItemComparer : IComparer /// private SortOrder innerOrder; - #endregion + #endregion Variables #region Constructors @@ -39,13 +47,13 @@ public ListViewItemComparer() /// /// Index of sorting column /// Sort order - public ListViewItemComparer(int column,SortOrder order) + public ListViewItemComparer(int column, SortOrder order) { this.col = column; this.innerOrder = order; } - #endregion + #endregion Constructors #region Methods @@ -77,15 +85,7 @@ public int Compare(ListViewItem x, ListViewItem y) return String.Compare(y.SubItems[this.col].Text, x.SubItems[this.col].Text); } } - - #endregion - } - class GroupComparer : IComparer - { - public int Compare(object objA, object objB) - { - return String.Compare(((ListViewGroup)objA).Header, ((ListViewGroup)objB).Header, StringComparison.Ordinal); - } + #endregion Methods } } \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/McTools.Xrm.Connection.WinForms.csproj b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/McTools.Xrm.Connection.WinForms.csproj index 95305da..76314e5 100644 --- a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/McTools.Xrm.Connection.WinForms.csproj +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/McTools.Xrm.Connection.WinForms.csproj @@ -10,13 +10,23 @@ Properties McTools.Xrm.Connection.WinForms McTools.Xrm.Connection.WinForms - v4.6.1 + v4.6.2 512 SAK SAK SAK SAK + Properties\AssemblyInfo.cs + False + False + False + + + + + + true @@ -51,63 +61,232 @@ true - Key.snk + snk.snk - - True - - - ..\..\packages\Microsoft.CrmSdk.CoreAssemblies.8.0.1\lib\net45\Microsoft.Crm.Sdk.Proxy.dll + + ..\..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.23\lib\net462\Microsoft.Crm.Sdk.Proxy.dll ..\..\packages\Microsoft.IdentityModel.7.0.0\lib\net35\microsoft.identitymodel.dll - - ..\..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.22.302111727\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll + + ..\..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.19.8\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll + + + ..\..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.19.8\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll + + + ..\..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.1.0.38\lib\net462\Microsoft.Rest.ClientRuntime.dll + + + ..\..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.23\lib\net462\Microsoft.Xrm.Sdk.dll + + + ..\..\packages\Microsoft.CrmSdk.Deployment.9.0.2.23\lib\net462\Microsoft.Xrm.Sdk.Deployment.dll - - ..\..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.22.302111727\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll + + ..\..\packages\Microsoft.CrmSdk.Workflow.9.0.2.23\lib\net462\Microsoft.Xrm.Sdk.Workflow.dll - - ..\..\packages\Microsoft.CrmSdk.CoreAssemblies.8.0.1\lib\net45\Microsoft.Xrm.Sdk.dll + + ..\..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.1.0.38\lib\net462\Microsoft.Xrm.Tooling.Connector.dll - - ..\..\packages\Microsoft.CrmSdk.Deployment.8.0.0\lib\net45\Microsoft.Xrm.Sdk.Deployment.dll + + ..\..\packages\Microsoft.CrmSdk.XrmTooling.WpfControls.9.1.0.38\lib\net462\Microsoft.Xrm.Tooling.CrmConnectControl.dll - - ..\..\packages\Microsoft.CrmSdk.Workflow.8.0.0\lib\net45\Microsoft.Xrm.Sdk.Workflow.dll + + ..\..\packages\Microsoft.CrmSdk.XrmTooling.WpfControls.9.1.0.38\lib\net462\Microsoft.Xrm.Tooling.Ui.Styles.dll - - ..\..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.8.0.0\lib\net45\Microsoft.Xrm.Tooling.Connector.dll + + ..\..\packages\Microsoft.CrmSdk.XrmTooling.WpfControls.9.1.0.38\lib\net462\Microsoft.Xrm.Tooling.WebResourceUtility.dll + + ..\..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll + + + + + + + + + + ..\..\packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll + + + + + + ..\..\packages\System.Security.Cryptography.Algorithms.4.3.1\lib\net461\System.Security.Cryptography.Algorithms.dll + + + ..\..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll + + + ..\..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll + + + ..\..\packages\System.Security.Cryptography.X509Certificates.4.3.2\lib\net461\System.Security.Cryptography.X509Certificates.dll + + + + - + + + + + + - + + Form + + + ConnectionStringDialog.cs + + + Form + + + ConnectionWizard2.cs + + + CRMLoginForm1.xaml + + + UserControl + + + ConnectionCredentialsControl.cs + + + UserControl + + + ConnectionFailedControl.cs + + + UserControl + + + ConnectionClientSecretControl.cs + + + UserControl + + + ConnectionMfaControl.cs + + + UserControl + + + ConnectionUrlControl.cs + + + UserControl + + + ConnectionFirstStepControl.cs + + + UserControl + + + ConnectionAppIdControl.cs + + + UserControl + + + ConnectionIfdControl.cs + + + UserControl + + + ConnectionLoadingControl.cs + + + UserControl + + + ConnectionOauthControl.cs + + + UserControl + + + ConnectionCertificateControl.cs + + + UserControl + + + StartPageControl.cs + + + UserControl + + + SdkLoginControlControl.cs + + + UserControl + + + ConnectionStringControl.cs + + + UserControl + + + ConnectionSucceededControl.cs + + + + Form + + + EnvHighlightDialog.cs + + + Form + + + EnvHighlightSettingsDialog.cs + + + Form + + + RenameConnectionFileDialog.cs + + Form - - ConnectionForm.cs + + UpdatePasswordForm.cs Form @@ -122,6 +301,12 @@ CrmConnectionStatusBar.cs + + Form + + + AddConnectionFileDialog.cs + Form @@ -135,6 +320,12 @@ True Resources.resx + + Form + + + NewConnectionFileDialog.cs + Form @@ -142,28 +333,121 @@ ProxySettingsForm.cs + + Form + + + UpdateSolutionForm.cs + - - ConnectionForm.cs + + ConnectionStringDialog.cs + Designer + + + ConnectionWizard2.cs + Designer + + + ConnectionCredentialsControl.cs + Designer + + + ConnectionFailedControl.cs + Designer + + + ConnectionClientSecretControl.cs + Designer + + + ConnectionMfaControl.cs + Designer + + + ConnectionUrlControl.cs + Designer + + + ConnectionFirstStepControl.cs + Designer + + + ConnectionAppIdControl.cs + Designer + + + ConnectionIfdControl.cs + Designer + + + ConnectionLoadingControl.cs + + + ConnectionOauthControl.cs + Designer + + + ConnectionCertificateControl.cs + Designer + + + StartPageControl.cs + + + SdkLoginControlControl.cs + Designer + + + ConnectionStringControl.cs + Designer + + + ConnectionSucceededControl.cs + Designer + + + EnvHighlightDialog.cs + + + EnvHighlightSettingsDialog.cs + + + RenameConnectionFileDialog.cs + + + UpdatePasswordForm.cs ConnectionSelector.cs + Designer CrmConnectionStatusBar.cs Designer + + AddConnectionFileDialog.cs + Designer + PasswordForm.cs ResXFileCodeGenerator Resources.Designer.cs + Designer + + + NewConnectionFileDialog.cs ProxySettingsForm.cs + + UpdateSolutionForm.cs + @@ -191,8 +475,71 @@ - + + + + + + + + + + + + + + + + + MSBuild:Compile + Designer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -200,9 +547,6 @@ McTools.Xrm.Connection - - - @@ -213,7 +557,7 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/PasswordForm.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/PasswordForm.cs index 9d3fe54..68a9c4d 100644 --- a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/PasswordForm.cs +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/PasswordForm.cs @@ -4,7 +4,7 @@ namespace McTools.Xrm.Connection.WinForms { /// - /// Formulaire Windows permettant de demander le mot de + /// Formulaire Windows permettant de demander le mot de /// passe d'un utilisateur /// public partial class PasswordForm : Form @@ -12,44 +12,39 @@ public partial class PasswordForm : Form #region Variables /// - /// Login de l'utilisateur + /// Nom de domaine pour l'utilisateur /// - string userLogin; + private string userDomain; /// - /// Nom de domaine pour l'utilisateur + /// Login de l'utilisateur /// - string userDomain; + private string userLogin; /// /// Mot de passe de l'utilisateur /// - string userPassword; + private string userPassword; - #endregion + #endregion Variables #region Constructeur /// /// Créé une nouvelle instance de la classe PasswordForm /// - public PasswordForm() + public PasswordForm(ConnectionDetail detail) { InitializeComponent(); + + lblConnectionName.Text = detail.ConnectionName; } - #endregion + #endregion Constructeur #region Propriétés - /// - /// Obtient ou définit le login de l'utilisateur - /// - public string UserLogin - { - get { return userLogin; } - set { userLogin = value; } - } + public bool SavePassword { get; set; } /// /// Obtient ou définit le nom de domaine pour l'utilisateur @@ -60,6 +55,15 @@ public string UserDomain set { userDomain = value; } } + /// + /// Obtient ou définit le login de l'utilisateur + /// + public string UserLogin + { + get { return userLogin; } + set { userLogin = value; } + } + /// /// Obtient le mot de passe de l'utilisateur /// @@ -68,9 +72,7 @@ public string UserPassword get { return userPassword; } } - public bool SavePassword { get; set; } - - #endregion + #endregion Propriétés #region Méthodes @@ -81,9 +83,17 @@ protected override void OnLoad(EventArgs e) userDomain.Length > 0 ? "\\" : "", userLogin); + tbPassword.Focus(); + base.OnLoad(e); } + private void bCancel_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.Cancel; + this.Close(); + } + private void bValidate_Click(object sender, EventArgs e) { bool go = true; @@ -105,10 +115,9 @@ private void bValidate_Click(object sender, EventArgs e) } } - private void bCancel_Click(object sender, EventArgs e) + private void chkShowCharacters_CheckedChanged(object sender, EventArgs e) { - this.DialogResult = DialogResult.Cancel; - this.Close(); + this.tbPassword.PasswordChar = this.chkShowCharacters.Checked ? (char)0 : '•'; } private void tbPassword_KeyPress(object sender, KeyPressEventArgs e) @@ -119,11 +128,6 @@ private void tbPassword_KeyPress(object sender, KeyPressEventArgs e) } } - private void chkShowCharacters_CheckedChanged(object sender, EventArgs e) - { - this.tbPassword.PasswordChar = this.chkShowCharacters.Checked ? (char)0 : '•'; - } - - #endregion + #endregion Méthodes } } \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/PasswordForm.designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/PasswordForm.designer.cs index fbdc396..beeb266 100644 --- a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/PasswordForm.designer.cs +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/PasswordForm.designer.cs @@ -36,59 +36,73 @@ private void InitializeComponent() this.bValidate = new System.Windows.Forms.Button(); this.chkShowCharacters = new System.Windows.Forms.CheckBox(); this.chkSavePassword = new System.Windows.Forms.CheckBox(); + this.pnlFooter = new System.Windows.Forms.Panel(); + this.pnlHeader = new System.Windows.Forms.Panel(); + this.label3 = new System.Windows.Forms.Label(); + this.lblConnectionName = new System.Windows.Forms.Label(); + this.pnlFooter.SuspendLayout(); + this.pnlHeader.SuspendLayout(); this.SuspendLayout(); // // label1 // this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(12, 9); + this.label1.Location = new System.Drawing.Point(15, 112); + this.label1.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(58, 13); + this.label1.Size = new System.Drawing.Size(106, 25); this.label1.TabIndex = 0; this.label1.Text = "User Login"; // // tbUserLogin // - this.tbUserLogin.Location = new System.Drawing.Point(76, 6); + this.tbUserLogin.Location = new System.Drawing.Point(162, 109); + this.tbUserLogin.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); this.tbUserLogin.Name = "tbUserLogin"; this.tbUserLogin.ReadOnly = true; - this.tbUserLogin.Size = new System.Drawing.Size(196, 20); + this.tbUserLogin.Size = new System.Drawing.Size(396, 29); this.tbUserLogin.TabIndex = 4; // // bCancel // - this.bCancel.Location = new System.Drawing.Point(197, 111); + this.bCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.bCancel.Location = new System.Drawing.Point(449, 6); + this.bCancel.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); this.bCancel.Name = "bCancel"; - this.bCancel.Size = new System.Drawing.Size(75, 23); - this.bCancel.TabIndex = 3; + this.bCancel.Size = new System.Drawing.Size(138, 42); + this.bCancel.TabIndex = 5; this.bCancel.Text = "Cancel"; this.bCancel.UseVisualStyleBackColor = true; this.bCancel.Click += new System.EventHandler(this.bCancel_Click); // // tbPassword // - this.tbPassword.Location = new System.Drawing.Point(76, 32); + this.tbPassword.Location = new System.Drawing.Point(162, 150); + this.tbPassword.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); this.tbPassword.Name = "tbPassword"; this.tbPassword.PasswordChar = '•'; - this.tbPassword.Size = new System.Drawing.Size(196, 20); + this.tbPassword.Size = new System.Drawing.Size(396, 29); this.tbPassword.TabIndex = 1; this.tbPassword.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.tbPassword_KeyPress); // // label2 // this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(12, 35); + this.label2.Location = new System.Drawing.Point(15, 153); + this.label2.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(53, 13); + this.label2.Size = new System.Drawing.Size(98, 25); this.label2.TabIndex = 3; this.label2.Text = "Password"; // // bValidate // - this.bValidate.Location = new System.Drawing.Point(116, 111); + this.bValidate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.bValidate.Location = new System.Drawing.Point(299, 8); + this.bValidate.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); this.bValidate.Name = "bValidate"; - this.bValidate.Size = new System.Drawing.Size(75, 23); - this.bValidate.TabIndex = 2; + this.bValidate.Size = new System.Drawing.Size(138, 42); + this.bValidate.TabIndex = 4; this.bValidate.Text = "OK"; this.bValidate.UseVisualStyleBackColor = true; this.bValidate.Click += new System.EventHandler(this.bValidate_Click); @@ -96,10 +110,11 @@ private void InitializeComponent() // chkShowCharacters // this.chkShowCharacters.AutoSize = true; - this.chkShowCharacters.Location = new System.Drawing.Point(76, 58); + this.chkShowCharacters.Location = new System.Drawing.Point(162, 191); + this.chkShowCharacters.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); this.chkShowCharacters.Name = "chkShowCharacters"; - this.chkShowCharacters.Size = new System.Drawing.Size(154, 17); - this.chkShowCharacters.TabIndex = 5; + this.chkShowCharacters.Size = new System.Drawing.Size(273, 29); + this.chkShowCharacters.TabIndex = 2; this.chkShowCharacters.Text = "Show password characters"; this.chkShowCharacters.UseVisualStyleBackColor = true; this.chkShowCharacters.CheckedChanged += new System.EventHandler(this.chkShowCharacters_CheckedChanged); @@ -107,30 +122,76 @@ private void InitializeComponent() // chkSavePassword // this.chkSavePassword.AutoSize = true; - this.chkSavePassword.Location = new System.Drawing.Point(76, 81); + this.chkSavePassword.Location = new System.Drawing.Point(162, 232); + this.chkSavePassword.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); this.chkSavePassword.Name = "chkSavePassword"; - this.chkSavePassword.Size = new System.Drawing.Size(206, 17); - this.chkSavePassword.TabIndex = 6; + this.chkSavePassword.Size = new System.Drawing.Size(371, 29); + this.chkSavePassword.TabIndex = 3; this.chkSavePassword.Text = "Save this password (will be encrypted)"; this.chkSavePassword.UseVisualStyleBackColor = true; // + // pnlFooter + // + this.pnlFooter.Controls.Add(this.bCancel); + this.pnlFooter.Controls.Add(this.bValidate); + this.pnlFooter.Dock = System.Windows.Forms.DockStyle.Bottom; + this.pnlFooter.Location = new System.Drawing.Point(0, 291); + this.pnlFooter.Name = "pnlFooter"; + this.pnlFooter.Size = new System.Drawing.Size(592, 60); + this.pnlFooter.TabIndex = 6; + // + // pnlHeader + // + this.pnlHeader.BackColor = System.Drawing.Color.White; + this.pnlHeader.Controls.Add(this.lblConnectionName); + this.pnlHeader.Controls.Add(this.label3); + this.pnlHeader.Dock = System.Windows.Forms.DockStyle.Top; + this.pnlHeader.Location = new System.Drawing.Point(0, 0); + this.pnlHeader.Name = "pnlHeader"; + this.pnlHeader.Size = new System.Drawing.Size(592, 100); + this.pnlHeader.TabIndex = 7; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Segoe UI Light", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(13, 13); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(409, 38); + this.label3.TabIndex = 0; + this.label3.Text = "Password required for connection"; + // + // lblConnectionName + // + this.lblConnectionName.AutoSize = true; + this.lblConnectionName.Font = new System.Drawing.Font("Segoe UI Light", 10F); + this.lblConnectionName.Location = new System.Drawing.Point(14, 51); + this.lblConnectionName.Name = "lblConnectionName"; + this.lblConnectionName.Size = new System.Drawing.Size(212, 32); + this.lblConnectionName.TabIndex = 1; + this.lblConnectionName.Text = "[Connection Name]"; + // // PasswordForm // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleDimensions = new System.Drawing.SizeF(11F, 24F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(284, 146); + this.ClientSize = new System.Drawing.Size(592, 351); + this.Controls.Add(this.pnlHeader); + this.Controls.Add(this.pnlFooter); this.Controls.Add(this.chkSavePassword); this.Controls.Add(this.chkShowCharacters); - this.Controls.Add(this.bValidate); this.Controls.Add(this.tbPassword); this.Controls.Add(this.label2); - this.Controls.Add(this.bCancel); this.Controls.Add(this.tbUserLogin); this.Controls.Add(this.label1); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); this.Name = "PasswordForm"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "Type password"; + this.Text = "Password required"; + this.pnlFooter.ResumeLayout(false); + this.pnlHeader.ResumeLayout(false); + this.pnlHeader.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); @@ -146,5 +207,9 @@ private void InitializeComponent() private System.Windows.Forms.Button bValidate; private System.Windows.Forms.CheckBox chkShowCharacters; private System.Windows.Forms.CheckBox chkSavePassword; + private System.Windows.Forms.Panel pnlFooter; + private System.Windows.Forms.Panel pnlHeader; + private System.Windows.Forms.Label lblConnectionName; + private System.Windows.Forms.Label label3; } } \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Properties/AssemblyInfo.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Properties/AssemblyInfo.cs index 0516ba0..4585570 100644 --- a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Properties/AssemblyInfo.cs +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Properties/AssemblyInfo.cs @@ -1,21 +1,20 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("McTools.Xrm.Connection.WinForms")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] +[assembly: AssemblyCompany("MscrmTools")] [assembly: AssemblyProduct("McTools.Xrm.Connection.WinForms")] -[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyCopyright("Copyright © MscrmTools 2012")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] @@ -25,12 +24,12 @@ // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // -// You can specify all the values or you can default the Build and Revision Numbers +// You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("1.2020.1.29")] +[assembly: AssemblyFileVersion("1.2020.1.29")] \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Properties/Resources.Designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Properties/Resources.Designer.cs index ee617d4..d293d03 100644 --- a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Properties/Resources.Designer.cs +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Properties/Resources.Designer.cs @@ -59,5 +59,333 @@ internal Resources() { resourceCulture = value; } } + + /// + /// Поиск локализованного ресурса типа System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Certificate32 { + get { + object obj = ResourceManager.GetObject("Certificate32", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Поиск локализованного ресурса типа System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap connection_certificate_32 { + get { + object obj = ResourceManager.GetObject("connection-certificate-32", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Поиск локализованного ресурса типа System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap connection_mfa_32 { + get { + object obj = ResourceManager.GetObject("connection-mfa-32", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Поиск локализованного ресурса типа System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap connection_secret_32 { + get { + object obj = ResourceManager.GetObject("connection-secret-32", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Поиск локализованного ресурса типа System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap connection_string_32 { + get { + object obj = ResourceManager.GetObject("connection-string-32", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Поиск локализованного ресурса типа System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap connection_wizard_32 { + get { + object obj = ResourceManager.GetObject("connection-wizard-32", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Поиск локализованного ресурса типа System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap ConnectionStringImage1 { + get { + object obj = ResourceManager.GetObject("ConnectionStringImage1", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Поиск локализованного ресурса типа System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap ConnectionStringImage32 { + get { + object obj = ResourceManager.GetObject("ConnectionStringImage32", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Ищет локализованную строку, похожую на Please wait while the wizard is trying to connect to your Microsoft Dynamics CRM organization. + /// + internal static string ConnectionWizard_ConnectingHeaderDescription { + get { + return ResourceManager.GetString("ConnectionWizard_ConnectingHeaderDescription", resourceCulture); + } + } + + /// + /// Ищет локализованную строку, похожую на Please provide the connection string you want to use to connect to your Microsoft Dynamics CRM organization. + /// + internal static string ConnectionWizard_ConnectionStringConnectionHeaderDescription { + get { + return ResourceManager.GetString("ConnectionWizard_ConnectionStringConnectionHeaderDescription", resourceCulture); + } + } + + /// + /// Ищет локализованную строку, похожую на Enter credentials required to connect to Microsoft Dynamics CRM organization. + /// + internal static string ConnectionWizard_CredentialsHeaderDescription { + get { + return ResourceManager.GetString("ConnectionWizard_CredentialsHeaderDescription", resourceCulture); + } + } + + /// + /// Ищет локализованную строку, похожую на Enter the url displayed in the browser when you are connected to your Microsoft Dynamics CRM organization. + /// + internal static string ConnectionWizard_EnterUrlHeaderDescription { + get { + return ResourceManager.GetString("ConnectionWizard_EnterUrlHeaderDescription", resourceCulture); + } + } + + /// + /// Ищет локализованную строку, похожую на Your information have not been validated. + /// + internal static string ConnectionWizard_ErrorHeaderDescription { + get { + return ResourceManager.GetString("ConnectionWizard_ErrorHeaderDescription", resourceCulture); + } + } + + /// + /// Ищет локализованную строку, похожую на Help us to determine if your Microsoft Dynamics CRM deployment is exposed via IFD. + /// + internal static string ConnectionWizard_IfdSelectionHeaderDescription { + get { + return ResourceManager.GetString("ConnectionWizard_IfdSelectionHeaderDescription", resourceCulture); + } + } + + /// + /// Ищет локализованную строку, похожую на The url you specified does not look like a valid url for an IFD deployment. Please correct the url. + /// + internal static string ConnectionWizard_InvalidIfUrl { + get { + return ResourceManager.GetString("ConnectionWizard_InvalidIfUrl", resourceCulture); + } + } + + /// + /// Ищет локализованную строку, похожую на Wrong timeout value! + /// + ///Expected format : HH:mm:ss. + /// + internal static string ConnectionWizard_InvalidTimeoutValue { + get { + return ResourceManager.GetString("ConnectionWizard_InvalidTimeoutValue", resourceCulture); + } + } + + /// + /// Ищет локализованную строку, похожую на The url you specified is invalid!. + /// + internal static string ConnectionWizard_InvalidUrl { + get { + return ResourceManager.GetString("ConnectionWizard_InvalidUrl", resourceCulture); + } + } + + /// + /// Ищет локализованную строку, похожую на You changed some values that require to test the connection. Would you like to test it now? + /// + ///Note that this is required to validate this wizard. + /// + internal static string ConnectionWizard_NeedToTestConnectionAgain { + get { + return ResourceManager.GetString("ConnectionWizard_NeedToTestConnectionAgain", resourceCulture); + } + } + + /// + /// Ищет локализованную строку, похожую на Please enter your credentials before trying to connect. + /// + internal static string ConnectionWizard_PleaseEnterCredentials { + get { + return ResourceManager.GetString("ConnectionWizard_PleaseEnterCredentials", resourceCulture); + } + } + + /// + /// Ищет локализованную строку, похожую на Question. + /// + internal static string ConnectionWizard_QuestionHeaderTitle { + get { + return ResourceManager.GetString("ConnectionWizard_QuestionHeaderTitle", resourceCulture); + } + } + + /// + /// Ищет локализованную строку, похожую на Your information have been validated. + /// + internal static string ConnectionWizard_SuccessHeaderDescription { + get { + return ResourceManager.GetString("ConnectionWizard_SuccessHeaderDescription", resourceCulture); + } + } + + /// + /// Ищет локализованную строку, похожую на We were unable to determine the organization name based on the information you specified. Please complete the url to add the organization name inside. + /// + internal static string ConnectionWizard_UnableToDetermineOrganization { + get { + return ResourceManager.GetString("ConnectionWizard_UnableToDetermineOrganization", resourceCulture); + } + } + + /// + /// Ищет локализованную строку, похожую на Unable to identify organization from url, please review it!. + /// + internal static string ConnectionWizard_UnableToDetermineOrganizationFromUrl { + get { + return ResourceManager.GetString("ConnectionWizard_UnableToDetermineOrganizationFromUrl", resourceCulture); + } + } + + /// + /// Ищет локализованную строку, похожую на Warning. + /// + internal static string ConnectionWizard_WarningTitle { + get { + return ResourceManager.GetString("ConnectionWizard_WarningTitle", resourceCulture); + } + } + + /// + /// Поиск локализованного ресурса типа System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap database_link { + get { + object obj = ResourceManager.GetObject("database_link", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Поиск локализованного ресурса типа System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap ico_16_7100 { + get { + object obj = ResourceManager.GetObject("ico_16_7100", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Поиск локализованного ресурса типа System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap logo_0100 { + get { + object obj = ResourceManager.GetObject("logo_0100", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Поиск локализованного ресурса типа System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap logo_0200 { + get { + object obj = ResourceManager.GetObject("logo_0200", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Поиск локализованного ресурса типа System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap logo_32 { + get { + object obj = ResourceManager.GetObject("logo_32", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Поиск локализованного ресурса типа System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap LogoDyn365 { + get { + object obj = ResourceManager.GetObject("LogoDyn365", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Поиск локализованного ресурса типа System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap LogoDyn365_32 { + get { + object obj = ResourceManager.GetObject("LogoDyn365_32", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Поиск локализованного ресурса типа System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap XTB_HIGHLIGHT_CUSTOM { + get { + object obj = ResourceManager.GetObject("XTB_HIGHLIGHT_CUSTOM", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Поиск локализованного ресурса типа System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap XTB_HIGHLIGHT_PRODUCTION { + get { + object obj = ResourceManager.GetObject("XTB_HIGHLIGHT_PRODUCTION", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Поиск локализованного ресурса типа System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap XTB_HIGHLIGHT_UAT { + get { + object obj = ResourceManager.GetObject("XTB_HIGHLIGHT_UAT", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } } } diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Properties/Resources.resx b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Properties/Resources.resx index 1af7de1..aa73f92 100644 --- a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Properties/Resources.resx +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Properties/Resources.resx @@ -117,4 +117,111 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + The url you specified is invalid! + + + The url you specified does not look like a valid url for an IFD deployment. Please correct the url + + + Please enter your credentials before trying to connect + + + + ..\Resources\LogoDyn365.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Your information have not been validated + + + Question + + + ..\Resources\Certificate32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\connection-secret-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Please wait while the wizard is trying to connect to your Microsoft Dynamics CRM organization + + + Enter the url displayed in the browser when you are connected to your Microsoft Dynamics CRM organization + + + Enter credentials required to connect to Microsoft Dynamics CRM organization + + + ..\Resources\database_link.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\logo_0200.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Your information have been validated + + + ..\Resources\XTB_HIGHLIGHT_UAT.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\XTB_HIGHLIGHT_CUSTOM.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\ConnectionStringImage32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Wrong timeout value! + +Expected format : HH:mm:ss + + + ..\Resources\XTB_HIGHLIGHT_PRODUCTION.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\LogoDyn365_32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + You changed some values that require to test the connection. Would you like to test it now? + +Note that this is required to validate this wizard + + + Please provide the connection string you want to use to connect to your Microsoft Dynamics CRM organization + + + We were unable to determine the organization name based on the information you specified. Please complete the url to add the organization name inside + + + Unable to identify organization from url, please review it! + + + ..\Resources\logo_32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\ConnectionStringImage1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\connection-certificate-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\connection-wizard-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Help us to determine if your Microsoft Dynamics CRM deployment is exposed via IFD + + + ..\Resources\connection-mfa-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Warning + + + ..\Resources\logo_0100.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\connection-string-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\resources\ico_16_7100.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ProxySettingsForm.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ProxySettingsForm.cs index a4ce789..deff139 100644 --- a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ProxySettingsForm.cs +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ProxySettingsForm.cs @@ -5,17 +5,17 @@ namespace McTools.Xrm.Connection.WinForms { public partial class ProxySettingsForm : Form { - public string proxyAddress { get; set; } - public string proxyPort { get; set; } - public string UserName { get; set; } - public string Password { get; set; } - public bool UseCustomProxy { get; set; } - public ProxySettingsForm() { InitializeComponent(); } + public string Password { get; set; } + public string proxyAddress { get; set; } + public string proxyPort { get; set; } + public bool UseCustomProxy { get; set; } + public string UserName { get; set; } + protected override void OnLoad(EventArgs e) { this.chkCustomProxy.Checked = this.UseCustomProxy; @@ -25,23 +25,23 @@ protected override void OnLoad(EventArgs e) this.txtUserPassword.Text = this.Password ?? string.Empty; } - private void btnOk_Click(object sender, EventArgs e) + private void btnCancel_Click(object sender, EventArgs e) { - this.proxyAddress = this.txtProxyAddress.Text; - this.proxyPort = this.txtProxyPort.Text; - this.UserName = this.txtUserLogin.Text; - this.Password = this.txtUserPassword.Text; this.UseCustomProxy = this.chkCustomProxy.Checked; - this.DialogResult = DialogResult.OK; + this.DialogResult = DialogResult.Cancel; this.Close(); } - private void btnCancel_Click(object sender, EventArgs e) + private void btnOk_Click(object sender, EventArgs e) { + this.proxyAddress = this.txtProxyAddress.Text; + this.proxyPort = this.txtProxyPort.Text; + this.UserName = this.txtUserLogin.Text; + this.Password = this.txtUserPassword.Text; this.UseCustomProxy = this.chkCustomProxy.Checked; - this.DialogResult = DialogResult.Cancel; + this.DialogResult = DialogResult.OK; this.Close(); } @@ -62,4 +62,4 @@ private void txtProxyPort_TextChanged(object sender, EventArgs e) } } } -} +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ProxySettingsForm.designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ProxySettingsForm.designer.cs index 7d71a6c..ece91c7 100644 --- a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ProxySettingsForm.designer.cs +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ProxySettingsForm.designer.cs @@ -32,7 +32,6 @@ private void InitializeComponent() this.btnCancel = new System.Windows.Forms.Button(); this.chkCustomProxy = new System.Windows.Forms.CheckBox(); this.panel1 = new System.Windows.Forms.Panel(); - this.pictureBox1 = new System.Windows.Forms.PictureBox(); this.label1 = new System.Windows.Forms.Label(); this.pnlCustomSettings = new System.Windows.Forms.Panel(); this.txtUserPassword = new System.Windows.Forms.TextBox(); @@ -44,9 +43,10 @@ private void InitializeComponent() this.txtProxyAddress = new System.Windows.Forms.TextBox(); this.lblProxyAddress = new System.Windows.Forms.Label(); this.btnOk = new System.Windows.Forms.Button(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); this.panel1.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); this.pnlCustomSettings.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); this.SuspendLayout(); // // btnCancel @@ -82,15 +82,6 @@ private void InitializeComponent() this.panel1.Size = new System.Drawing.Size(402, 60); this.panel1.TabIndex = 11; // - // pictureBox1 - // - this.pictureBox1.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox1.Image"))); - this.pictureBox1.Location = new System.Drawing.Point(339, 5); - this.pictureBox1.Name = "pictureBox1"; - this.pictureBox1.Size = new System.Drawing.Size(48, 48); - this.pictureBox1.TabIndex = 13; - this.pictureBox1.TabStop = false; - // // label1 // this.label1.AutoSize = true; @@ -193,6 +184,15 @@ private void InitializeComponent() this.btnOk.UseVisualStyleBackColor = true; this.btnOk.Click += new System.EventHandler(this.btnOk_Click); // + // pictureBox1 + // + this.pictureBox1.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox1.Image"))); + this.pictureBox1.Location = new System.Drawing.Point(339, 5); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(48, 48); + this.pictureBox1.TabIndex = 13; + this.pictureBox1.TabStop = false; + // // ProxySettingsForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -206,13 +206,12 @@ private void InitializeComponent() this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; this.Name = "ProxySettingsForm"; this.ShowIcon = false; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "Custom proxy settings"; this.panel1.ResumeLayout(false); this.panel1.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); this.pnlCustomSettings.ResumeLayout(false); this.pnlCustomSettings.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ProxySettingsForm.resx b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ProxySettingsForm.resx index 454c350..4c16e1a 100644 --- a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ProxySettingsForm.resx +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/ProxySettingsForm.resx @@ -120,92 +120,91 @@ - iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAABGdBTUEAALGPC/xhBQAAE7BJREFUaEO9 - WHl0W+WdJYECJUBSEpICLQxQWkqZoVO6nA5tp8sc2tNhSoEWCIFAQkL2xfESL/G+b/Fuy7YkS5YlL7Is - W4ttydp3yfIqy5ZtedHiNd4dx7Z+39ObT0Zzzpye+afYnXvO9XuS3jn3d7/f/Zbn+/4e5LMlnzTKuupr - 2821VUI9my7S1TPFRj6mkCE2tuGrjCky6ugCg4khMpqrW43WIq6iq5irNBXWy+V57A5RHlvaWFArYxfV - K6jFDcq8ojpFWmG9Mr6wXnWzoFZ5rYCjOJvPln+Sz1a8n8WS/jKFLn48KL978KRmibJn1CPvGnU3qXon - ucruySZNv5uL2ajp93C1/V6OosfL6uiaYkmtU0U87Ux6jWwms0Y2lcnq8GC6Ayzgqtx0sdlV1d7pouEr - pdngKmoyuEqbTa4KkcVVITS76K3dd8p4emUWVfSToPzuUdKomG0xDG/m8wz3MmoUmzElwq0ozBiK2BdX - 3ubLrtdDndkDVs8G0ePd8FM6nERms4NI4/VDSkP3dkKteSu5zrxVKLbdY8iH7lFa+zZKhT138/mW9cRq - 1Vo8Q7GaUatbSWdrVjJrdRvZNUpLWnnzL4Pyu4es07mh7XeTHyc2Em9ep6GfncxGr/45Ab38XzHo9Q+S - 0EexbMRQjaM+110wOFcglmWF0EoTCqnUoisUNbpYpEDXK/VEKn/IT1NM+KsUE2S5dJzMFw6RYTSj/3Kp - xp/M6SGTOb1kUr2NTOOYHEllvH8Pyu8e7eaRuyRJ+gdcq4gqdQBVNgIFLb2Qz+sEtmoE1INLMDh9D6xj - a9DWOwsxTDM2YISQCjVco6jgSrECQsq1KI7TjXKa+hCtYwQVCu3oNr8PRdN16HJRB0TTtegWQ4eiGXoy - kaG0JZXy3gjK7x5i/eCOAUyE/6BVH4mmN0hwLiOYwByc2QSjcxlUw4s7Bm5Vm3Hxhh0DV8tUcKlYju+1 - KIrViaLoekRpc6D85n6UzetBsVUGdKlQBuH42WgafqbKQMZXKXuxgZ8G5XcPgdYeMEBs4eJ9mIC5tEUi - x+wm9Hs2wDy2CurhJdBgtmMDcTVfGrheroYrpUq4WNwBNyp16Ga1BcepA7J4fSiP348yGqwoodqEAh26 - XqKEyEoNiqDqAwa60ir4PwrK7x5Nqv71gIFNP4kCXEMkmt/wo4HpDeieXMe5XwWVYwnUQwEDc5BQ04kj - 9GUHrpUp4VKRDMKwgWhs4Fx+O8QyTTg+/Sit3ooSa0zoBkWFY4S7UK5C4VQtGU9TWNPLW34YlN896jq6 - 1nY6gIsPdGEFR+jOPdyB+U2wTqyCdgTHx7EISjwXAh1IYFu+nAOVmp05cBmPcBgVG8AR+iKvDcKwsSxe - L0qu7UTx1UYUjkf+chGOGe5WOE1LxtIV5pSy5leD8rtHldi4QuA5ECj+fzqwvE0i7zoBNpx/i3sDTONr - YBxbB+XQIqRze3FkDJjYQDmexKUBA3oUw7buGLhSKscmO1ESx4JuYQMRVC26ijt1naKG8Co9GVsl1yeX - 8r8flN89ypu1S4v3kH/Iu44M9mnUYR1FrfohxFcPQEWLGSqEVmB22KFO6wSOxgnhFCVE0IwQRtPvdOE6 - NhFON6Bb7G50oVCK5wSOC1UDSXVWbMCEIvHEDpi9Xq5BYXQdGUuTa5PL+C8F5XcPCjawsomIoal1JO9z - o1pFPyrlmVFKlRxOJ9XCJ/Ec+CKTD1eKpHCpUAK/v1AEkXQDRO4sp9qdTkQyTCiutgddLpHjSMlxtJQQ - h7sQy7KgSLwShdG02KwWhdP1ZBxNpk6mNL8QlN89ShtVS8tbiJjZINDkMkJWzz0ksi0gqmocovCK80VB - B5zNk8DZ/A44kdYCb3ycAVEMI+DM40zjKFF1EFXdiRIa+tBVimInUoG5Eckw4q5YUFS1ESKw4XCaEeHv - yIQquTy1vOXZoPzukVMvu+OY3iDUAzNIqB9FVFE3pDHwylIkgBNxLPhTSCW8F8WCEymN8FmmEN48XwS3 - mCaIxqtRRJUpMIHhVk0XSuHZUUiFCq5jBgyE0fUQx7HALZYFbuJu3WSYsRkzmcCQS7CBp4Lyu0dmXcfs - 0hZBDM/dRRq7F3GUA5DF1kJ4kQg+jWPCu6FUeD+6Gj5J4cLZHDH88XIpxOHNLLa2G6JYZojEJuI5PZDO - t+OI6HYMBZZYnHeI5VixCStE45UrpgZHimMlk5lKUWqF8HBQfvfIYUtmh2eWie6JRWTGlNjmoFIxDumN - vRCKR/NcvgQuFnbARbyWn73dCn+4VAzxNRZIqO/BI2/GhVkgsb4XMgV2FMkMzA0THm0DRGBG11jxc70Q - h80G5kh8XTeZwlI2p1D4jwXld4/sasms0TFLNKmHEbO1GxU1GOBmsRDOpdfvROiv0Uw4Hl8HpzMFuAMi - +OMV3AFceDI2GFfbCbF4dJMb+yBLNIRiWCbAuccjbsZzJGCuE5K4/ZC4QxtKaewjk6rlTbco9QeC8rtH - VrVkemh2A/V41pBqaA64xnG8EVnwzimDy3lCOJPVjNkCFwskcKGgHRsog0RcZFqLDRIbuiChrgtS+TaU - 2zaM4mutEB8wxQkY68T3Vkjh2SCNPwBpzXaUwbeRqSwVN6Gy+eGg/O6RwWj3ynvcqKJJh7AZSGV0QEhJ - Kx7xFjidJYTTOa07q9AXBVL4LFsMb+JlNLW+EzKFA5DM64Gkxm58b0cFklGU2Ig/c3vwaAfYDQnYYCq/ - H7JFDtwhB8oS2MiMGlVtapnggaD87pFCF3mcsyugwBsYo9kEt6tlEFPMh0tpHLiUzYMbhWKIouF1nWUA - fDTwfZpUB6m4sNzWQUhv7oPUpl5fDr4v7hiFFH4fHun+naJTmvogCRtMwc/kiB2Qiw3miO1kBkvOCkrv - DVLoQs8mSQImcq8g6HKtgrTPAw36UWgwjuFITUCz1QsifA7id3ogjqlHGTwbUYQLymsdQjkiOyqUjiAK - 3jfSBf0oU2CDjABxxDIE/TuGskV2KJKNoYL2ITKzRsEISu8NkqlC1+ImCYFj9IKfhIl7JPTgo7QSv8DI - RlagxuCFMskoUSxy+FXDS/6M+l4yT+AgK5Vuf4l0zF/Y5vSXycf9NJ2LwF0hcsV2lC2241HHFA1ANo5a - LjZQIhtFxR0OMoujpAel9wbJVMGE0DC0Xd2iI8rrZX5Gq4moU9tRU+cUtNlXiJbuBT+vc5bkGqdI/egy - mcWz+QvEo/4qtcdPkY77SyXjRIVi0s80eIiCtmHcmWGiUDKMCtuHUX77EBS0D+6wSDqMfx8gM6o7KoLS - e4PEypYJkdWzUCHsXr6QQFv48Erm0vGr2ZsnbpT4zyeyydjyDrKY303WqMbIer3bn8Qy+QtFw36W1ktU - yieJCtkEQVdPEjVGL1EmdRIU6djOtVQ2SpTJR1GZfAQCLFeOESUSbIAhKQlK7w0SKlomOGrHFM76THFr - 32RctXY1pBgf3G63oytFHSgMv4hEVqp9sdUWX0y1GZ1K5vpLWh3+OtM0Ua3xEAyNm2DpvUSDZYqgK10E - VTWJOYEqVeOIqhzDVyeiqp2oSjdOUGV2Mp0lKQhK7w0SKwVjFaIu1+0GzVx8ZcfK1SwenIyhwTuXi33v - R1T5PkvmbeFdePNGhW4jpFyz+UEMy1/WPkxwrTME2+AlWFoPqsWjz+ueIZg6D2Lq3IipncScQAzN+M41 - QLbRTVSphsnMasntoPTeIIkmdHL1484Gi2e9UDyEEln4rF8g3P7gRtn2f57N3XrrQsHGe6G0u58mcdeu - FLZvBDpQ0e4g+N1zqM40hThGL8JmkHBgHnFMXlSLyTF6cMFfkmN077Chc5qo0Y6S2UxpTlB6b5BEEzhT - mHJXdHErEcdQ+xJqLNsJLPN2JE1/L7RCczesQrMeVq5ZC6fqVsKomvWP49kEVTpEiPvnUaN1Ghc/jfi9 - c6htaAFxLVOosTNA/D2+Bj5zLV7gWjzQ1DNN1OqdZA6rIysovTdIpgudRS29c+m1ZjK8pHUrJLd580JK - 3caHoWXrx6PoqyfjOSv4KLF0pbhj4Ua5cuVUIoegyRxIOrSIhPglX4j3hzb7HaRwLiFh3zwSBfjl9/j3 - WRAE2DMDrfY7BNc0RuayJGlB6b1BKqN1NJ/XPZvGNhKxNOVGAsuwnsyxrN6kqVfCKNLF8FLpQmiJZD6i - XD4XxdAsnUmrI5jyEaR2riCpfdEvwS/70qElpBxdRG22hcA9SB3LO3uIfDTIkWW8r6z6+dYJspirTQpK - 7w12DPC73Gm1ZjgbR19750zy6jufpyz95Vrh4qmUuvmrhe1zYRWKmZsM7UwEXbN4OqWWqNU4CZN7fUPU - O+OmiLv8fPMY0o4vIpqkDypae6FQ0AkFzWYoEZiBJukBprwP7+Qusr3PvfcG0qvbRrPrTRMl7aPbOc39 - y/FM9WJoXtPCqZjKuVNx9JlzaZzpy7lNUzdK2rzRVar5c+kNRKmgBzVoh7bZasddiX0Od+IOaMeWQYzj - IhmYhfb+aWjrmwZxj3eHEvxZ2DNFsnVOSKfUVAalA9gXvH51ZLDaRqOKRSPXsnj3wvJbFkLymudDCwVz - OD7TsfgckdrU5U3ndXli8HoZgqP0/k0awZANgMW9AuK+KcRW2kFknQAd7gBD2o8Y8gFgye3AUQzg7ydB - 61yBet0ocHROvJuPb4XFpVECugcOHT3wwEMHHrxv//1fO/zMC/fvFPNVgA2MpNZoBjP4PespHO1cWB53 - 5mRozvSv377s/e37kZ53rxd6Pohhei7mt7ojGeq508lsohLHpMkwDM0mJ+icS6AZXYSe6XWkHl5E2pEF - 0I8tQJdnDXfBA9T2HuDqnaAeXSXLBabNC6Fx1KPPvfLAt19+/ZlnX/nJEcyD3/nhLx4MlvP3I2Agslgw - GFYkXMloME4XtNunclu6vbFVcndoYbP7TDLbfTaV47qUx3ddzhfMfY4N1KmHoWdqHTQjc9BiGgGNYwqs - niVU2CAFntYGWmwop04D+Y0GaFCNAL2tD3imCbLF4FgLvZVBPfTNF4899cKr//rMd1777rHnXj7y7Zd/ - 9NXfD3YMlAj6ziYzFz+PKvZeSqnyXkpjec6kVLuv5TW7witkrnCq3BVaLnNFMTVzp5LYBL29D9qtYyDq - HIPe6XWwTC6hgbkNQuOYRa1dbsRo7UF1KjvSO++gevUQYkr7oWPgDkkTdW6cPBdaf+jY8/9y+JmXXn/0 - iacOP/zYE7t7uQl2oDuWqVrMqNN5bzdZPCksuftyMt319pkE1++Ox7jeuZbvOpXCcZ1O4819HFdN8PVj - MLm6hTrdy6QYr/FtA/PQZHVDPt+CKtptiG/yEEzFCFElHyaEPbOECFPtXCMF5sG72AD3sSPPfvfRQ0cP - 79u/f3+wjK+OgIGbhfzOa7ebFs4nUDzHr2a4z8ZWuiMpYldqnd4VTmlznUmrd13NF7huVSnmIsvFRA0e - XcPEMkjt87j4BV+bfcEX2NQaDG6olAzAbV4nMPFBjip1oNJWBxL0rfrVznUyIqNk9vDTLx4/+ORzDxw4 - 9OTuV6AAMmraR0Jvc4236OqFQlGvOzSb7X7vbIL7r+eTXecSqK5zKWzXtdxGdwy13RtDk81fKeARFEk/ - 6CdWtpUjCz7ZyJIP78o+fLTwVatHobJjEFiaMaDhI3SVegLxu+f9RfVy8jdvneg8+I1j/3H/1x7euxf6 - AJIr+YOX02pMb59PXzh9s8AdWdziTmCp3Km1Blc2z+Iu4Fu80dTW6avFLRNhlW2eG6UioMkGfWbP2rZ6 - dGlbNbrokzuwicFFX2v/AlR1OCCbawHxwAqS4dx/EZG+9c0XfpDz9AuvPvH1Rw7uPjJ/i8TypqHrWQ3G - iArZQmQBzx2SxnSfupHj/uhK2vS717KmTtyiT1woEjuianT2aLZ+8nxuI6pSDPms3vVtvHkFTPhUzmVf - q23WR2mz+ViacVAOrxK3q8XkD9/4vePAN45++PWDRx4Jyu09YvOr1eeTmLrP4hnz0aXNnlyeeSqbb54K - LW5yvRde7Hg3rMj+cTKz/0KBYCCcrnBfKxEiumLQ1ztzd9swvrytw8WrsAn58IJPPbqG2qwe8tNLMfDE - U883Pnb46Zcffvzw3v0L5f9CEVtceiOrbiK8tG37bFz57M/fvjT2q49uDn4QW2m7Rmnvv8nS2m5Wq223 - avUD0TU618U8PqLK7b6+2Y1tM54HOtyFTve6r392E1Vw5eQrP/715MMHnvj8/oce+8eN+v9GCaf1kT9+ - doN1KbOOSKi3oIQ6w1pIcbPnTGrV4IeRJbY/hxTY3o0qt53K4A5cLWtzXSxoQTRswD6/uW31rm3b72yD - 2ub1H/8ibPuxI083P/7kt1598JFD/9hR/1u8eeLKQ2/8/q8vvfST39J+c/yq+9O40s14jm7rdqt9IbXR - NH69VDhwJptru1ggcN0oE6NK+YBveMm3PXhnC9itRuK1n/9u+IEHHz15/wMPPnTo2HN7szx+FTz/2i8e - /Lc/n3n0qed/8NZzr/y05WdvnZ45mUjfjKvRbGSJ7fOJTV1z5/P4UK0b9g0v3CMScyvvHTr6LOvAwaNP - PvT1x7/6gWyvcfTb39v/9Iv//LWjz37v2LF/+v5H3/ru68wf/e4vzhMR+RvJ9QbIbdTDb/90vPfAwSN/ - 2Ldv//9vXP5eYBP7jnzre/v37dv38BNPv/ir517+cdozL70WsX///Y8cevKZf0Bc7rvvvwEQp/0J6sll - 7AAAAABJRU5ErkJggg== + iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAABONSURBVGhDvZkJdFvVmcebQIESICkJoUALA5SWUmbolC6nQ9tp6Rza02FKgRYIgUBCQvbFsZ14 + ifd9i3dbtiVZiyUvsixbmy1Z+y5ZXmXZsi0vWrzGu+PY1nef3lyZ6Tk9PTPtKajjc/5+T9KTzvf7vv/9 + 7n33felLf8dfEUf2YbOiu7G+w1pfKzJy6GJDI1NiFmCJGBJzOz4qmGKzgS40WRhis5UlNdtLearuMp7a + UtKoVBZyOsWFHHlzcb2CU9qoopY1qQtLG1SZJY3qpJJGzfXievXlYq7qVBFH+WERR/VOLlv+s3S65KG/ + I8S/filfbpWpe8d8yu4xb4umb4qn7plq0Q14eVjNugEfTz/g56p6/ezO7mm23D5dytfPZtUpZnPqFNM5 + 7E4fljekYp7GS5dYPbUdXR4aPlJaTZ7SFpOnotXiqRbbPNUiq4cu7blVyTeqc6niH4YNoLxZNddmGtkq + 4pvuZNeptuLLRduxWPEUSSCxqj2Q12iEBqsP7L5Note/GaR0uomcVheRyR+A9KaeneR663Zag3W7ROK4 + w1AO36FI+zcrRL23iwS2jRSWZj2JoVrLrjesZnF0qzn1hs28OrUts6r1Z2EDUHS5N/UDXvKDlGbitSs0 + 9ONjeejF3yej5/8rHr38bip6P4GDGJoJ1O+5DSb3KiSw7RBZY0ERNXp0kaJF50pV6EqNkcgQDAdpqslg + rWqSrJJPkEWiYTKKZg5eqNAF07i9ZBq3j0xtdJCZXIsrtZL/72ED6LCO3iZJMjjoWUNUuQuoilEobuuD + In4XcDSjoB1ahqGZO2AfX4f2vjmIZ1oxgBkiqrVwmaKBi2UqiKjSo0RuD8pv6Ue0zlFUInKim4J+FEc3 + oAulnRBH16MbDAOKYxjJFIbakVrBfyVsABLj0C4AFsL/0FqARDObJLhXEExiDc1ugdm9ApqRpV2AGywr + Dt60C3CpUgPny5T4XI9i2V0olm5ElHYXKmodQHn8XpRQa0LnSxQQja+No+Frak1kUq26DwP8KGwAQr0z + BEBs4+ADWIC1vE0i19wWDPg2wTq+BtqRZdBhdWCAxLrPAK5UaeFihRrOlXXC1RoDus6yYTt1Qi6/HxUK + BlB2kx0lsywoVKEr5WqIqdGha1RjCKA7s1rw/bABtGgGNkIAW0EShbSOSLSwGUSDM5vQM7WBfb8GGtcy + aIdDAPOQXNeFLfRZBS5XquF8qQKiMEAcBjhd1AEJTAu2zwDKbLSjlDoLukrRYBvhKlRpUDRVTybRVPas + qrbvhQ2gobN7fbcCOPhQFVaxhW7dwRVY2AL75BroR7F9XEugxmMhVIFkju2zMVCj2x0DF3CGo6gYAFvo + 08J2iMJgufw+lFbfhZJYZhSNM3+hFNsMVyuapicT6CpremXri2EDqJWYVwk8BkLB/6kCKzsk8m8Q4MD+ + t3k3wTKxDubxDVAPL0EWrw9bxoSFAarwIK4IARhRPMe+C3CxQokhu1Aq14ZuYIBrVD26hCt1haKF6Foj + mVCrNKZVCL4TNoCqVv3y0h0UHPZvIJNzBnXax5DUOIwE2kGobrNCtcgOzE4nNOjdwNW5IZqihms0M0TR + jLtVuIIhoukmdIPTg86WyPGYwHah6iC1wY4BLCgGD+wQ7JUqHYqiG8gEmlKfVil4LmwAFAywuoWI4ekN + pOz3onrVAKrgW1F6rRJOpNbDh0lc+DRHABdL5XC+RAa/PlsKMXQTxOy2U/1uJWIYFpRY34sulCuxpZTY + WmpIxFVIYNtQDO5EUTQ9htWjaLqRTKQptGmU1mfCBlDRrFle2UbE7CaBplYQsvvuILFjEVE1ExCLO86n + xZ1wqlAGp4o64WhmG7zyQTbEMsyAPY89ja1ENUAsqwslN/WjSxTVrqVCYyOGYcZVsaFYlhmuYeBomhnh + 98jkWqUyo6rtybAB5DcqbrlmNgnt4CwSGccQVdwDmQzcWUqFcDSRDb+LqIG3Y9lwNL0ZPs4RwWtnSuEG + 0wJxuBtdq7WEBjDcqOtG6XwniqjWwBWsEEAU3QiJXBvcYNvgOq7WdYYVw1jJZIZShgEeCxtATkPn3PI2 + QYzM30Y6px9x1YOQy9FDdKkYPkpkwluRVHgnjgUfpvPgVL4EfnuhAhLxZJZQ3wOxbCvEYIgkbi9kCZzY + IoZdoFCLxX6HBK4dQ9ghDneu+DpsKa6dTGOqxRnVooNhA8jnyOZGZleInsklZMWSOeahRjUBWc19EImz + ebpIBudKOuEc7uWnbkrhN+fLIKnOBsmNvTjzVhyYDVIa+yBH6EQxzNDYsOBsm+AaVlydHV/XB4kYNjRG + khp6yHS2ujWdIngwbAB5LNmc2TVHtGhHEFPag0qbTHC9TASnsxp3LfTHOCYcSWqAEzlCXAEx/PYirgAO + PA0DJtZ3QQLOblpzP+SKh1E82wLY9zjjVjxGQnBdkMobgJRdOVB6cz+ZylK23KA07gsbQC5LNjM8t4l6 + fetIMzwPPPMEnohseOZUwIVCEZzMbcVqg3PFMjhb3IEBKiEFB5nZ5oCUpm5IbuiGDIEDFbSPoKR6OySF + oLghsC58bod0vgMyBYOQ2epE2QIHmcHW8JJrWu8LG0A2o8Ov7PWi6hYDwjCQweiEiHIpzngbnMgVwYl8 + 6W4X+rRYDh/nSeA13EYzGrsgRzQIafxeSG3uwedOVCwbQynN+DWvF2c7pB5IxoAZggHIE7twhVwoV+gg + s+s09RmVwrvDBpBOF/vcc6ugwhMYo9UCN1kKiC8TwPlMLpzP48PVEgnE0nBfZ5sALw0CH6U2QAYOrEA6 + BFmt/ZDR0hfIx+dlnWOQLujHmR7YDTq9pR9SMWA6viZf4oICDJgvcZLZbCU7bMGHfiidLvJtkSRgIe8q + gm7PGsj7fdBkHIMm8zi21CS02v0gxusgQZcPEplGlM13EKU4oELpMMoXO1GJfBRR8LyRJRxAOUIHZIeE + LZYtHNgFyhM7oVQxjoo7hsmcOhUjrABpVJFnaYuE0DJ6MUjC5B0SevFSWo1vYBSjq1Bn8kOlbIwoE7uC + mpHlYHZjH1kodJE1am+wXD4eLGl3ByuVE0GawUPgqhAFEifKkzhx1rHEg5CHrVaAAcoVY6is00XmctX0 + MAMIJ0Wm4R1Wm4GoalQEGVIL0aB1opauaWh3rhJtPYtBftccyTNPk8axFTKX7wgWS8aCtVpfkCKfCFbI + Johq1VSQafIRxe0juDIjRIlsBJV0jKCijmEo7hjaVal8BH8+SGazOqvDCpBS0zYptvsWq0U9K2eTaYvv + XcxZPnIpb+vo1fLgmRQOmVDVSZYJesg6zTjZaPQGU9mWYIl4JMjW+4ka5RRRrZgk6Nopos7sJyrlboIi + H989VijGiErlGKpUjkJIVepxolyGARiy8rACJFe3TXK1rmns9dkyaf9UIku/FlGGF243O9DF0k4UhW9E + Ymq0gQSWLRDPsqLjabxgudQVbLDMECydj2DovATb6CeabNMEXe0hqJoprElUgzcCqOpxfHQjqtaNag0T + BFXhJLPYsuKwAqTUCMerxd2em026+aSaztVLuXw4Fk+DNy+UBd65Vhv4OI2/jWfhravVhs2IKt3Wu/Hs + YGXHCMGzzxIck59g632oHmef3zNLMA0+xDR4EVM/hTWJGLqJ3WNIHLOXqNWMkDks2c2wAqTSRG6eccLd + ZPNtlEiGUQobr/WLRTvvXq3c+c9TBduvny3efDuSdvujVN76xZKOzVAFqjtchKBnHjVYphHX7EcYBokG + FxDX4kf1WFyzDwf8mbhm766aumaIOv0YmceU54cZQOhOZyo9cWVSIpGhDSTX2XaS2dadGJrxTmS17nZU + tW4jqkq3Hk01rEZRdRsfJHEIqnyYkAwsoGb7DA5+Bgn65lH78CLi2aZRc1dI+H18DL3m2fzAs/mgpXeG + qDe6yXx2Z25YAdLoIndpW998Vr2VjC6XbkcUtG6dTW/YfC+ycuNILH3tWBJ3FS8lli+WdS5erVKvHk/h + EjSFC8mHl5AI3+SL8PzQ7ryFVO5lJOpfQOKQPnsffz4HwpB6Z0HqvEXwLONkAVuWGVaADIZ0rIjfM5fJ + MRMJNPVmMtu0kca1rV2naVejKPKl6Ar5YmS5bOFalXI+lqFbPpnZQDCVo0jrXkVy51JQhm/25cPLSD22 + hNodi6FzkLtWducQ5dj/CG8MqMfXggL7JFnG06eGH0DQ7c2st8KpRPr6myfT1t78JH35D5dLlo6nNyxc + KumYj6pWzV5n6Gev0XVLJ9LriXqdm7B4NzbFfbNeiqQ7KLCOI/3EEqLJ+qFa2gclwi4obrVCudAKNFkv + MJX9eCb3kB393vADZLHax/IaLZPlHWM7+a0DK0lM7VJkYcvi8fia+eOJ9NnTmdyZCwUt01fL2/1xtZqF + 01lNRIWwFzXph3c4WtdtmXMeV+IW6MdXQILtIhucg46BGWjvnwFJr39XMvxa1DtNcgxuyKLU1fxZBfZ8 + 4Wpks9vHYsvEo5dz+XeiitoWIwpbFyJLhPPYPjMJeB2R0dLtz+J3++Jxv4zAVnrnOo1gKAbxdssqSPqn + EUftBLF9Egy4Agz5AGIoB4GtdAJXNYjfnwI93hBuNIwB1+DGs/nEdlRiJiUU9L4Dh/fdfe++e760964v + H3zimbs+NwgGGM2o0w1lC3o30rn6+ahC3uyxyPyZX7xxwf/qOzG+t66U+N6NZ/rOFUm9MQzt/Ik0DlGD + bdJiGoFWixsMbrztOLYEvTMbSDuyhPSji2AcX4RuH94MxotCakcv8Ixu0I6tkVVCy9bZyETq4adeuPsb + z7/8xJMv/PAQ1v5vfu+n93whgJgy4VBUqWg1u8k8U9zhnC5o6/HjDShvZEmr92Qax3sqg+s5XyjwXCgS + zn+CARq0I9A7vQG60Xlos4yCzjWNnx8so5ImOfD1DtBjoPwGHRQ1m6AJ73DT2/uBb5kk20yu9cgb2dQD + X3v20ceeefFfn/jmS9969KnnD33j+e9//vuDUAViyoX9p9KYS5/ElvnPp9f6z2eyfSfTWd7Lha2e6GqF + J5qq9ERWKTyxTN388VQOQe/ohw77OIi7xqFvZgNsU8tocH6T0LnmkLTbixjSXtSgcSKj+xZq1A4jpnwA + OgdvkTRx1+ax05GNBx59+l8OPvHcyw88/NjB+x58+PMHHyrbLkCZsCeBqVnKbjD4b7bYfOlspfdCGt3z + xslkz6+OxHvevFzkOZ7O9ZzI5M9/kMgiBMZxmFrbRl3eFVKCe3z74AK02L2An8qg6g4HElh8BFM1StQq + RwhR7xwhxtK610mhdeg2BuA9eOjJbz1w4PDBPXv37v3c1vnTF0MA10sEXZdvtiyeSab4jlzK9p5KqPHG + UCSejAajJ5rS7jmZ2ei5VCT03KhVzcdUSYg6nF3T5ArInQs4+MVAu3MxEJrUmkxeqJENwk38cISJF3L4 + gQmqkLqQsH8tqHVvkNeyy+cOPv7skf2PPHX3vgOPfPEOtFuBuo7RyJs88w26drFE3OeNzON43z6V7P3j + mTTP6WSq53Q6x3O5oNkbT+3wx9MUCxeL+QRFNgDGydUd9ehiQDG6HMCzcgAvLQIs7RjUdA4BWzcONLyE + rtVOIkHPQrC0UUn+8vWjXfu/+uh/3PXl+8J3Qx8CSKsRDF3IrLO8cSZr8cT1Ym9MWZs3ma3xZtSbPHl8 + m7dYYPPHUaUzl8raJqNq2n1XK8RAUwwFrL71He3Y8o5mbCmgdGGIoaWAdGARajtdkMezgWRwFSmw7z+9 + lrX9tWe+m//4My8+/JX7939xy/yl51KqWoav5DaZr1UrFmOK+d6ITKb3+NV87/sXM2feupw7ffQGffJs + qcQVW2dwxnGMU2cKmlGtajhg92/s4MkrBBHQuFcCUsdcgNLuCLB1E6AeWSNusiTk9175tWvfVw+/95X9 + h+7/wl7/v34goYilPZPKNHycxFiIq2j1FfCt03kC63RkWYvn7egy11tRpc4P0pgDZ4uFg9F0lfdyuQjR + VUOBvtnbO6aJlR0DDl6DIZQjiwHt2Dpqt/vIj87Hw8OPPd384MHHn7/voYNfrMv8LfJSjqTiam7DZHRF + +86pxKq5n7xxfvzn718fejehxnGZ0jFwna13XGdpHTfqjYNxdQbPuUIBoiqdgf65zR0rHgcGXIUu70Zg + YG4LVfOU5As/+MXUffse/uSuex/8x2X9z6HKudL7f/vxVfb5nAYiudGGkhtM6xFlrb6TGbVD78WUO34f + Uex4K7bKcTybN3ipst1zrrgN0TCAc2Frx+5f33He2gGtwx888mnUzoOHHm996JGvv3jP/Qf+sVn/y6q8 + dvTiva/8+o/PPffDV2m/PHLJ+1FixVYS17B9U+pczGi2TFypEA2ezOM5zhULPVcrJahGORgYWQ7sDN3a + Bo7UTLz0k1+N3H3PA8fuuvueew88+lR42uPfss7/9vnTL/30nn/7/ckHHnv6u68/9cKP2n78+onZYyn0 + rcQ63WauxLmQ0tI9f6ZQACzDSGBk8Q6RUlBz58DhJ9n79h9+5N6vPPT5F2SfJ9i/9p3D3/j23sef/ecv + H37y248++k/fef/r33qZ+f1f/cF99FrRZlqjCQqajfDq74707dt/6Dd79uz9/7XL3wuLIfYc+vq39+7Z + s+e+hx9/9udPPf+DzCeee+na3r133X/gkSf+IXb5bxCn/QlLsRndAAAAAElFTkSuQmCC \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/RenameConnectionFileDialog.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/RenameConnectionFileDialog.cs new file mode 100644 index 0000000..8be6e92 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/RenameConnectionFileDialog.cs @@ -0,0 +1,28 @@ +using System; +using System.Windows.Forms; + +namespace McTools.Xrm.Connection.WinForms +{ + public partial class RenameConnectionFileDialog : Form + { + public RenameConnectionFileDialog(string name) + { + InitializeComponent(); + + txtConnectionName.Text = name; + } + + public string NewName { get; private set; } + + private void btnCancel_Click(object sender, EventArgs e) + { + Close(); + } + + private void btnOk_Click(object sender, EventArgs e) + { + NewName = txtConnectionName.Text; + Close(); + } + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/RenameConnectionFileDialog.designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/RenameConnectionFileDialog.designer.cs new file mode 100644 index 0000000..297d7c5 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/RenameConnectionFileDialog.designer.cs @@ -0,0 +1,154 @@ +namespace McTools.Xrm.Connection.WinForms +{ + partial class RenameConnectionFileDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label2 = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.btnOk = new System.Windows.Forms.Button(); + this.label3 = new System.Windows.Forms.Label(); + this.txtConnectionName = new System.Windows.Forms.TextBox(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(954, 201); + this.btnCancel.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(150, 44); + this.btnCancel.TabIndex = 1; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); + // + // panel1 + // + this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel1.BackColor = System.Drawing.Color.White; + this.panel1.Controls.Add(this.label2); + this.panel1.Controls.Add(this.label1); + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(1144, 115); + this.panel1.TabIndex = 11; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label2.Location = new System.Drawing.Point(26, 73); + this.label2.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(516, 30); + this.label2.TabIndex = 13; + this.label2.Text = "Please provide the new name for the connection file"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Segoe UI", 14F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(6, 17); + this.label1.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(416, 51); + this.label1.TabIndex = 12; + this.label1.Text = "Rename connection file"; + // + // btnOk + // + this.btnOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnOk.DialogResult = System.Windows.Forms.DialogResult.OK; + this.btnOk.Location = new System.Drawing.Point(792, 201); + this.btnOk.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); + this.btnOk.Name = "btnOk"; + this.btnOk.Size = new System.Drawing.Size(150, 44); + this.btnOk.TabIndex = 13; + this.btnOk.Text = "OK"; + this.btnOk.UseVisualStyleBackColor = true; + this.btnOk.Click += new System.EventHandler(this.btnOk_Click); + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(24, 133); + this.label3.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(221, 25); + this.label3.TabIndex = 14; + this.label3.Text = "Connection File name"; + // + // txtConnectionName + // + this.txtConnectionName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtConnectionName.Location = new System.Drawing.Point(254, 127); + this.txtConnectionName.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); + this.txtConnectionName.Name = "txtConnectionName"; + this.txtConnectionName.Size = new System.Drawing.Size(846, 31); + this.txtConnectionName.TabIndex = 15; + // + // RenameConnectionFileDialog + // + this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(1128, 269); + this.Controls.Add(this.txtConnectionName); + this.Controls.Add(this.label3); + this.Controls.Add(this.btnOk); + this.Controls.Add(this.panel1); + this.Controls.Add(this.btnCancel); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; + this.Margin = new System.Windows.Forms.Padding(6, 6, 6, 6); + this.Name = "RenameConnectionFileDialog"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button btnCancel; + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Button btnOk; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.TextBox txtConnectionName; + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/RenameConnectionFileDialog.resx b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/RenameConnectionFileDialog.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/RenameConnectionFileDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/CRMOnlineLive_16.png b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/CRMOnlineLive_16.png index 5dc2c4a..479c2fd 100644 Binary files a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/CRMOnlineLive_16.png and b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/CRMOnlineLive_16.png differ diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/Certificate32.png b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/Certificate32.png new file mode 100644 index 0000000..09edfeb Binary files /dev/null and b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/Certificate32.png differ diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/ConnectionStringImage1.png b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/ConnectionStringImage1.png new file mode 100644 index 0000000..afeb941 Binary files /dev/null and b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/ConnectionStringImage1.png differ diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/ConnectionStringImage32.png b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/ConnectionStringImage32.png new file mode 100644 index 0000000..a872f3f Binary files /dev/null and b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/ConnectionStringImage32.png differ diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/LogoDyn365.png b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/LogoDyn365.png new file mode 100644 index 0000000..287524b Binary files /dev/null and b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/LogoDyn365.png differ diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/LogoDyn365_32.png b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/LogoDyn365_32.png new file mode 100644 index 0000000..1e84a9f Binary files /dev/null and b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/LogoDyn365_32.png differ diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/XTB_HIGHLIGHT_CUSTOM.png b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/XTB_HIGHLIGHT_CUSTOM.png new file mode 100644 index 0000000..5ab26a6 Binary files /dev/null and b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/XTB_HIGHLIGHT_CUSTOM.png differ diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/XTB_HIGHLIGHT_PRODUCTION.png b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/XTB_HIGHLIGHT_PRODUCTION.png new file mode 100644 index 0000000..daa5b16 Binary files /dev/null and b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/XTB_HIGHLIGHT_PRODUCTION.png differ diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/XTB_HIGHLIGHT_UAT.png b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/XTB_HIGHLIGHT_UAT.png new file mode 100644 index 0000000..3359bec Binary files /dev/null and b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/XTB_HIGHLIGHT_UAT.png differ diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/connection-certificate-32.png b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/connection-certificate-32.png new file mode 100644 index 0000000..f0fd8cb Binary files /dev/null and b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/connection-certificate-32.png differ diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/connection-mfa-32.png b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/connection-mfa-32.png new file mode 100644 index 0000000..6afe104 Binary files /dev/null and b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/connection-mfa-32.png differ diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/connection-secret-32.png b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/connection-secret-32.png new file mode 100644 index 0000000..fb4834c Binary files /dev/null and b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/connection-secret-32.png differ diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/connection-string-32.png b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/connection-string-32.png new file mode 100644 index 0000000..a03601d Binary files /dev/null and b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/connection-string-32.png differ diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/connection-wizard-32.png b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/connection-wizard-32.png new file mode 100644 index 0000000..1dddbd9 Binary files /dev/null and b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/connection-wizard-32.png differ diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/database_link.png b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/database_link.png new file mode 100644 index 0000000..9cd1d0a Binary files /dev/null and b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/database_link.png differ diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/ico_16_7100.gif b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/ico_16_7100.gif new file mode 100644 index 0000000..219d607 Binary files /dev/null and b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/ico_16_7100.gif differ diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/logo_0100.png b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/logo_0100.png new file mode 100644 index 0000000..a3b094a Binary files /dev/null and b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/logo_0100.png differ diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/logo_0200.png b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/logo_0200.png new file mode 100644 index 0000000..4cf6a32 Binary files /dev/null and b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/logo_0200.png differ diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/logo_32.png b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/logo_32.png new file mode 100644 index 0000000..6a8f38f Binary files /dev/null and b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/logo_32.png differ diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/powerapps16.png b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/powerapps16.png new file mode 100644 index 0000000..2a51247 Binary files /dev/null and b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/Resources/powerapps16.png differ diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/RessourceManager.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/RessourceManager.cs index 409aa2c..04bc6fa 100644 --- a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/RessourceManager.cs +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/RessourceManager.cs @@ -15,4 +15,4 @@ public static Image GetImage(string name) } } } -} +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/UpdatePasswordForm.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/UpdatePasswordForm.cs new file mode 100644 index 0000000..85b55e5 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/UpdatePasswordForm.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; + +namespace McTools.Xrm.Connection.WinForms +{ + public partial class UpdatePasswordForm : Form + { + private readonly IEnumerable connections; + + public UpdatePasswordForm(IEnumerable connections) + { + InitializeComponent(); + + this.connections = connections; + + lblHeaderDesc.Text = string.Format(lblHeaderDesc.Text, + connections.Count(), + connections.Count() > 1 ? "s" : ""); + + txtNewPassword.Focus(); + } + + private void btnCancel_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.Cancel; + Close(); + } + + private void btnOk_Click(object sender, EventArgs e) + { + try + { + int updated = 0; + + foreach (var connection in connections) + { + if (!connection.SavePassword) + { + continue; + } + + connection.SetPassword(txtNewPassword.Text); + updated++; + } + + DialogResult = updated > 0 ? DialogResult.OK : DialogResult.Ignore; + Close(); + } + catch (Exception error) + { + MessageBox.Show(this, "It seems something went wrong when updating the password: " + error, + "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/UpdatePasswordForm.designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/UpdatePasswordForm.designer.cs new file mode 100644 index 0000000..87cd9e8 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/UpdatePasswordForm.designer.cs @@ -0,0 +1,153 @@ +namespace McTools.Xrm.Connection.WinForms +{ + partial class UpdatePasswordForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.panel1 = new System.Windows.Forms.Panel(); + this.lblHeaderDesc = new System.Windows.Forms.Label(); + this.lblHeaderTitle = new System.Windows.Forms.Label(); + this.btnOk = new System.Windows.Forms.Button(); + this.txtNewPassword = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnCancel.Location = new System.Drawing.Point(716, 275); + this.btnCancel.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(112, 35); + this.btnCancel.TabIndex = 3; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); + // + // panel1 + // + this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel1.BackColor = System.Drawing.Color.White; + this.panel1.Controls.Add(this.lblHeaderDesc); + this.panel1.Controls.Add(this.lblHeaderTitle); + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(858, 92); + this.panel1.TabIndex = 11; + // + // lblHeaderDesc + // + this.lblHeaderDesc.AutoSize = true; + this.lblHeaderDesc.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblHeaderDesc.Location = new System.Drawing.Point(20, 58); + this.lblHeaderDesc.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblHeaderDesc.Name = "lblHeaderDesc"; + this.lblHeaderDesc.Size = new System.Drawing.Size(432, 23); + this.lblHeaderDesc.TabIndex = 13; + this.lblHeaderDesc.Text = "You are about to update password for {0} connection{1}"; + // + // lblHeaderTitle + // + this.lblHeaderTitle.AutoSize = true; + this.lblHeaderTitle.Font = new System.Drawing.Font("Segoe UI", 14F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblHeaderTitle.Location = new System.Drawing.Point(4, 14); + this.lblHeaderTitle.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblHeaderTitle.Name = "lblHeaderTitle"; + this.lblHeaderTitle.Size = new System.Drawing.Size(230, 38); + this.lblHeaderTitle.TabIndex = 12; + this.lblHeaderTitle.Text = "Update password"; + // + // btnOk + // + this.btnOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnOk.Location = new System.Drawing.Point(594, 275); + this.btnOk.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.btnOk.Name = "btnOk"; + this.btnOk.Size = new System.Drawing.Size(112, 35); + this.btnOk.TabIndex = 2; + this.btnOk.Text = "OK"; + this.btnOk.UseVisualStyleBackColor = true; + this.btnOk.Click += new System.EventHandler(this.btnOk_Click); + // + // txtNewPassword + // + this.txtNewPassword.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtNewPassword.Location = new System.Drawing.Point(190, 105); + this.txtNewPassword.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.txtNewPassword.Name = "txtNewPassword"; + this.txtNewPassword.Size = new System.Drawing.Size(643, 26); + this.txtNewPassword.TabIndex = 1; + this.txtNewPassword.UseSystemPasswordChar = true; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(18, 109); + this.label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(112, 20); + this.label4.TabIndex = 17; + this.label4.Text = "New password"; + // + // UpdatePasswordForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(846, 329); + this.Controls.Add(this.label4); + this.Controls.Add(this.txtNewPassword); + this.Controls.Add(this.btnOk); + this.Controls.Add(this.panel1); + this.Controls.Add(this.btnCancel); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; + this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.Name = "UpdatePasswordForm"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button btnCancel; + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.Label lblHeaderTitle; + private System.Windows.Forms.Button btnOk; + private System.Windows.Forms.Label lblHeaderDesc; + private System.Windows.Forms.TextBox txtNewPassword; + private System.Windows.Forms.Label label4; + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/UpdatePasswordForm.resx b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/UpdatePasswordForm.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/UpdatePasswordForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/UpdateSolutionForm.Designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/UpdateSolutionForm.Designer.cs new file mode 100644 index 0000000..6ce2e05 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/UpdateSolutionForm.Designer.cs @@ -0,0 +1,173 @@ +namespace McTools.Xrm.Connection.WinForms +{ + partial class UpdateSolutionForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.panel1 = new System.Windows.Forms.Panel(); + this.lblHeaderDesc = new System.Windows.Forms.Label(); + this.lblHeaderTitle = new System.Windows.Forms.Label(); + this.lbSolution = new System.Windows.Forms.Label(); + this.comboBoxSolutions = new System.Windows.Forms.ComboBox(); + this.btnOk = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.lbProgressBar = new System.Windows.Forms.Label(); + this.progressBar1 = new System.Windows.Forms.ProgressBar(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // panel1 + // + this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel1.BackColor = System.Drawing.Color.White; + this.panel1.Controls.Add(this.lblHeaderDesc); + this.panel1.Controls.Add(this.lblHeaderTitle); + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(572, 60); + this.panel1.TabIndex = 11; + // + // lblHeaderDesc + // + this.lblHeaderDesc.AutoSize = true; + this.lblHeaderDesc.Font = new System.Drawing.Font("Segoe UI", 8.25F); + this.lblHeaderDesc.Location = new System.Drawing.Point(13, 38); + this.lblHeaderDesc.Name = "lblHeaderDesc"; + this.lblHeaderDesc.Size = new System.Drawing.Size(272, 13); + this.lblHeaderDesc.TabIndex = 13; + this.lblHeaderDesc.Text = "You are about to update solution for connection {0}"; + // + // lblHeaderTitle + // + this.lblHeaderTitle.AutoSize = true; + this.lblHeaderTitle.Font = new System.Drawing.Font("Segoe UI", 14F); + this.lblHeaderTitle.Location = new System.Drawing.Point(3, 9); + this.lblHeaderTitle.Name = "lblHeaderTitle"; + this.lblHeaderTitle.Size = new System.Drawing.Size(146, 25); + this.lblHeaderTitle.TabIndex = 12; + this.lblHeaderTitle.Text = "Update solution"; + // + // lbSolution + // + this.lbSolution.AutoSize = true; + this.lbSolution.Location = new System.Drawing.Point(12, 71); + this.lbSolution.Name = "lbSolution"; + this.lbSolution.Size = new System.Drawing.Size(68, 13); + this.lbSolution.TabIndex = 17; + this.lbSolution.Text = "New solution"; + // + // comboBoxSolutions + // + this.comboBoxSolutions.FormattingEnabled = true; + this.comboBoxSolutions.Location = new System.Drawing.Point(127, 68); + this.comboBoxSolutions.Name = "comboBoxSolutions"; + this.comboBoxSolutions.Size = new System.Drawing.Size(430, 21); + this.comboBoxSolutions.TabIndex = 13; + // + // btnOk + // + this.btnOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnOk.Location = new System.Drawing.Point(396, 179); + this.btnOk.Name = "btnOk"; + this.btnOk.Size = new System.Drawing.Size(75, 23); + this.btnOk.TabIndex = 2; + this.btnOk.Text = "OK"; + this.btnOk.UseVisualStyleBackColor = true; + this.btnOk.Click += new System.EventHandler(this.btnOk_Click); + // + // btnCancel + // + this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnCancel.Location = new System.Drawing.Point(477, 179); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(75, 23); + this.btnCancel.TabIndex = 3; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); + // + // lbProgressBar + // + this.lbProgressBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.lbProgressBar.Location = new System.Drawing.Point(41, 128); + this.lbProgressBar.Name = "lbProgressBar"; + this.lbProgressBar.Size = new System.Drawing.Size(491, 22); + this.lbProgressBar.TabIndex = 19; + this.lbProgressBar.Text = "Loading solutions from your Microsoft Dynamics CRM organization"; + this.lbProgressBar.TextAlign = System.Drawing.ContentAlignment.TopCenter; + // + // progressBar1 + // + this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.progressBar1.Location = new System.Drawing.Point(41, 94); + this.progressBar1.Margin = new System.Windows.Forms.Padding(2); + this.progressBar1.Name = "progressBar1"; + this.progressBar1.Size = new System.Drawing.Size(491, 20); + this.progressBar1.Style = System.Windows.Forms.ProgressBarStyle.Marquee; + this.progressBar1.TabIndex = 18; + // + // UpdateSolutionForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(564, 214); + this.Controls.Add(this.lbProgressBar); + this.Controls.Add(this.progressBar1); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.btnOk); + this.Controls.Add(this.comboBoxSolutions); + this.Controls.Add(this.lbSolution); + this.Controls.Add(this.panel1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; + this.Name = "UpdateSolutionForm"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Update Solution"; + this.Load += new System.EventHandler(this.UpdateSolutionForm_Load); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.Label lblHeaderDesc; + private System.Windows.Forms.Label lblHeaderTitle; + private System.Windows.Forms.Label lbSolution; + private System.Windows.Forms.ComboBox comboBoxSolutions; + private System.Windows.Forms.Button btnOk; + private System.Windows.Forms.Button btnCancel; + private System.Windows.Forms.Label lbProgressBar; + private System.Windows.Forms.ProgressBar progressBar1; + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/UpdateSolutionForm.cs b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/UpdateSolutionForm.cs new file mode 100644 index 0000000..8ee44a1 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/UpdateSolutionForm.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace McTools.Xrm.Connection.WinForms +{ + public partial class UpdateSolutionForm : Form + { + private readonly ConnectionDetail connectionDetail; + public UpdateSolutionForm(ConnectionDetail connectionDetail) + { + InitializeComponent(); + lbSolution.Visible = false; + comboBoxSolutions.Visible = false; + btnOk.Visible = false; + + this.connectionDetail = connectionDetail; + lblHeaderDesc.Text = string.Format(lblHeaderDesc.Text, connectionDetail.ConnectionName); + } + + private void btnOk_Click(object sender, EventArgs e) + { + var cbItem = (Solution)comboBoxSolutions.SelectedItem; + if(cbItem != null) + { + connectionDetail.SelectedSolution = cbItem.SolutionDetail; + } + else + { + connectionDetail.SelectedSolution = null; + } + + DialogResult = DialogResult.OK; + Close(); + } + + private void btnCancel_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.Cancel; + Close(); + } + + private async void UpdateSolutionForm_Load(object sender, EventArgs e) + { + try + { + var solutionDetails = new List(); + if (connectionDetail.IsFromSdkLoginCtrl) + { + var cd = connectionDetail; + + var ctrl = new CRMLoginForm1(cd.ConnectionId.Value); + if (cd.AzureAdAppId != Guid.Empty) + { + ctrl.AppId = cd.AzureAdAppId.ToString(); + ctrl.RedirectUri = new Uri(cd.ReplyUrl); + } + + ctrl.ShowDialog(); + + ConnectionManager.Instance.ConnectToServerWithSdkLoginCtrl(connectionDetail, ctrl.CrmConnectionMgr.CrmSvc, null); + } + solutionDetails = await connectionDetail.GetSolutionsListAsync(); + + if (solutionDetails.Count == 0) + { + throw new Exception("Failed to load solutions"); + } + var solutions = solutionDetails.Select(x => new Solution() { SolutionDetail = x }); + comboBoxSolutions.Items.AddRange(solutions.ToArray()); + if (connectionDetail != null && connectionDetail.SelectedSolution != null) + { + var selectedSolution = connectionDetail.Solutions.FirstOrDefault(x => x.SolutionId == connectionDetail.SelectedSolution.SolutionId); + if (selectedSolution != null) + { + var index = connectionDetail.Solutions.IndexOf(selectedSolution); + comboBoxSolutions.SelectedIndex = index; + } + } + + lbProgressBar.Visible = false; + progressBar1.Visible = false; + + lbSolution.Visible = true; + comboBoxSolutions.Visible = true; + btnOk.Visible = true; + + comboBoxSolutions.Focus(); + } + catch(Exception ex) + { + MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + Close(); + } + } + } +} diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/UpdateSolutionForm.resx b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/UpdateSolutionForm.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/UpdateSolutionForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/app.config b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/app.config index 7fb3ea1..dfb6497 100644 --- a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/app.config +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/app.config @@ -1,93 +1,25 @@  - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - + - - + + diff --git a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/packages.config b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/packages.config index 0ddbd02..87b204d 100644 --- a/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/packages.config +++ b/CrmConnectionProjects/McTools.Xrm.Connection.WinForms/packages.config @@ -1,9 +1,17 @@  - - - - - - + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection/ConnectionDetail.cs b/CrmConnectionProjects/McTools.Xrm.Connection/ConnectionDetail.cs index 82c8c6f..ca5a11c 100644 --- a/CrmConnectionProjects/McTools.Xrm.Connection/ConnectionDetail.cs +++ b/CrmConnectionProjects/McTools.Xrm.Connection/ConnectionDetail.cs @@ -1,20 +1,80 @@ -using System; -using System.ComponentModel; -using System.ServiceModel.Description; -using System.Xml.Serialization; +using McTools.Xrm.Connection.Forms; +using McTools.Xrm.Connection.Utils; using Microsoft.Xrm.Sdk.Client; using Microsoft.Xrm.Sdk.Discovery; +using Microsoft.Xrm.Sdk.Query; +using Microsoft.Xrm.Tooling.Connector; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data.Common; +using System.Drawing; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.Xml.Serialization; namespace McTools.Xrm.Connection { + public enum SensitiveDataNotFoundReason + { + NotAllowedByUser, + NotAccessible, + None + } + + public class CertificateInfo + { + public string Issuer { get; set; } + public string Name { get; set; } + public string Thumbprint { get; set; } + } + /// /// Stores data regarding a specific connection to Crm server /// - public class ConnectionDetail : IComparable + [XmlInclude(typeof(CertificateInfo))] + [XmlInclude(typeof(EnvironmentHighlighting))] + public class ConnectionDetail : IComparable, ICloneable { - #region Properties + private string clientSecret; + private string userPassword; + + #region Constructeur + + public ConnectionDetail() + { + } + + public ConnectionDetail(bool createNewId = false) + { + if (createNewId) + { + ConnectionId = Guid.NewGuid(); + } + } + + #endregion Constructeur + + #region Propriétés + + [XmlIgnore] + private CrmServiceClient crmSvc; + + [XmlIgnore] + public bool AllowPasswordSharing { get; set; } public AuthenticationProviderType AuthType { get; set; } + public Guid AzureAdAppId { get; set; } + + [XmlElement("CertificateInfo")] + public CertificateInfo Certificate { get; set; } + + [XmlIgnore] + public bool ClientSecretIsEmpty => string.IsNullOrEmpty(clientSecret); /// /// Gets or sets the connection unique identifier @@ -26,55 +86,139 @@ public class ConnectionDetail : IComparable /// public string ConnectionName { get; set; } + public string ConnectionString { get; set; } + + [XmlIgnore] + public Color? EnvironmentColor { get; set; } + + ///// + ///// Gets or sets custom information for use by consuming application + ///// + //public Dictionary CustomInformation { get; set; } + public EnvironmentHighlighting EnvironmentHighlightingInfo { get; set; } + + public string EnvironmentId { get; set; } + + [XmlIgnore] + public string EnvironmentText { get; set; } + + [XmlIgnore] + public Color? EnvironmentTextColor { get; set; } /// - /// Get or set flag to know if custom authentication + /// Gets or sets the Home realm url for ADFS authentication /// - public bool IsCustomAuth { get; set; } + public string HomeRealmUrl { get; set; } /// - /// Get or set flag to know if we use IFD + /// Get or set flag to know if custom authentication /// - public bool UseIfd { get; set; } + public bool IsCustomAuth { get; set; } + + [XmlIgnore] public bool IsEnvironmentHighlightSet => EnvironmentHighlightingInfo != null; + public bool IsFromSdkLoginCtrl { get; set; } + + [XmlIgnore] + public DateTime LastUsedOn { get; set; } + + [XmlElement("LastUsedOn")] + public string LastUsedOnString + { + get => LastUsedOn.ToString("yyyy-MM-dd HH:mm:ss"); + set + { + //if (DateTime.TryParse(value, CultureInfo.CurrentUICulture, DateTimeStyles.AssumeLocal, out DateTime parsed)) + if (DateTime.TryParseExact(value, "MM/dd/yyyy HH:mm:ss", CultureInfo.CurrentUICulture, DateTimeStyles.AssumeLocal, out DateTime parsed)) + { + LastUsedOn = parsed; + } + else + { + LastUsedOn = DateTime.Parse(value); + } + } + } + + public async Task> GetSolutionsListAsync(bool forceNewService = false) + { + var task = Task.Run(() => GetSolutionsList(forceNewService)); + return await task; + } + + public List GetSolutionsList(bool forceNewService = false) + { + var client = GetCrmServiceClient(forceNewService); + + QueryExpression query = new QueryExpression + { + EntityName = "solution", + ColumnSet = new ColumnSet(new string[] { "friendlyname", "uniquename", "publisherid" }), + Criteria = new FilterExpression() + }; + query.Criteria.AddCondition("isvisible", ConditionOperator.Equal, true); + query.AddOrder("friendlyname", OrderType.Ascending); + + query.LinkEntities.Add(new LinkEntity("solution", "publisher", "publisherid", "publisherid", JoinOperator.Inner)); + query.LinkEntities[0].Columns.AddColumns("customizationprefix"); + query.LinkEntities[0].EntityAlias = "publisher"; + + var solutions = client.RetrieveMultiple(query).Entities; + this.Solutions = solutions.Select(x => new SolutionDetail() + { + UniqueName = x.GetAttributeValue("uniquename"), + FriendlyName = x.GetAttributeValue("friendlyname"), + PublisherPrefix = x.GetAttributeValue("publisher.customizationprefix") == null ? null : x.GetAttributeValue("publisher.customizationprefix").Value.ToString(), + SolutionId = x.Id + }).ToList(); + return this.Solutions; + } + + public AuthenticationType NewAuthType { get; set; } /// - /// Get or set flag to know if we use CRM Online + /// Get or set the organization name /// - public bool UseOnline { get; set; } + public string Organization { get; set; } + + public string OrganizationDataServiceUrl { get; set; } /// - /// Get or set flag to know if we use Online Services + /// Get or set the organization friendly name /// - public bool UseOsdp { get; set; } + public string OrganizationFriendlyName { get; set; } + + public int OrganizationMajorVersion => OrganizationVersion != null ? int.Parse(OrganizationVersion.Split('.')[0]) : -1; + public int OrganizationMinorVersion => OrganizationVersion != null ? int.Parse(OrganizationVersion.Split('.')[1]) : -1; /// - /// Get or set the Crm Ticket + /// Gets or sets the Crm Service Url /// - [System.Xml.Serialization.XmlIgnore] - public string CrmTicket { get; set; } + public string OrganizationServiceUrl { get; set; } /// - /// Get or set the user domain name + /// Get or set the organization name /// - public string UserDomain { get; set; } + public string OrganizationUrlName { get; set; } + + public string OrganizationVersion { get; set; } + public string OriginalUrl { get; set; } /// - /// Get or set user login + /// Gets an information if the password is empty /// - public string UserName { get; set; } + public bool PasswordIsEmpty => string.IsNullOrEmpty(userPassword); /// - /// Get or set the user password + /// OAuth Refresh Token /// - //[System.Xml.Serialization.XmlIgnore] - public string UserPassword { get; set; } + public string RefreshToken { get; set; } - public bool SavePassword { get; set; } + public string ReplyUrl { get; set; } /// - /// Get or set the use of SSL connection + /// Gets or sets the information if the password must be saved /// - public bool UseSsl { get; set; } + public bool SavePassword { get; set; } /// /// Get or set the server name @@ -85,259 +229,735 @@ public class ConnectionDetail : IComparable /// Get or set the server port /// [DefaultValue(80)] - public int ServerPort { get; set; } + [XmlIgnore] + public int? ServerPort { get; set; } + + [XmlIgnore] + public CrmServiceClient ServiceClient + { + get { return GetCrmServiceClient(); } + set { crmSvc = value; } + } + + public Guid TenantId { get; set; } + public TimeSpan Timeout { get; set; } + + public long TimeoutTicks + { + get { return Timeout.Ticks; } + set { Timeout = new TimeSpan(value); } + } + + [XmlIgnore] + public bool UseConnectionString => !string.IsNullOrEmpty(ConnectionString); /// - /// Get or set the organization Id + /// Get or set flag to know if we use IFD /// - public string OrganizationId { get; set; } + public bool UseIfd { get; set; } + /// - /// Get or set the organization name + /// Get or set flag to know if we use Multi Factor Authentication /// - public string Organization { get; set; } + public bool UseMfa { get; set; } /// - /// Get or set the organization name + /// Get or set flag to know if we use CRM Online /// - public string OrganizationUrlName { get; set; } + [XmlIgnore] + public bool UseOnline => OriginalUrl != null && OriginalUrl.IndexOf(".dynamics.com", StringComparison.InvariantCultureIgnoreCase) > 0; /// - /// Get or set the organization friendly name + /// Get or set the user domain name /// - public string OrganizationFriendlyName { get; set; } + public string UserDomain { get; set; } /// - /// Gets or sets the Crm Service Url + /// Get or set flag to know if we use Online Services /// - public string OrganizationServiceUrl { get; set; } + //public bool UseOsdp { get; set; } + /// + /// Get or set user login + /// + public string UserName { get; set; } + + [XmlElement("UserPassword")] + public string UserPasswordEncrypted + { + get => userPassword; + set => userPassword = value; + } /// - /// Gets or sets the Home realm url for ADFS authentication + /// Get or set the use of SSL connection /// - public string HomeRealmUrl { get; set; } + [XmlIgnore] + public bool UseSsl => WebApplicationUrl.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase); - public string OrganizationVersion { get; set; } + public string WebApplicationUrl { get; set; } - public string Solution { get; set; } - public string SolutionId { get; set; } - public string SolutionFriendlyName { get; set; } + /// + /// Client Secret used for S2S Auth + /// + public string S2SClientSecret + { + get => clientSecret; + set => clientSecret = value; + } - public string PublisherPrefix { get; set; } + [XmlElement("ServerPort")] + private string ServerPortString + { + get => ServerPort.ToString(); + set => ServerPort = string.IsNullOrEmpty(value) ? 80 : int.Parse(value); + } + public List Solutions { get; set; } + + public SolutionDetail SelectedSolution { get; set; } + public string SolutionName { get => SelectedSolution == null ? "" : SelectedSolution.FriendlyName; } + #endregion Propriétés - [XmlIgnore] - public TimeSpan Timeout { get; set; } + #region Méthodes - [XmlElement("Timeout")] - public long TimeoutTicks + public void ErasePassword() { - get { return Timeout.Ticks; } - set { Timeout = new TimeSpan(value); } + userPassword = null; } - public int OrganizationMajorVersion + public CrmServiceClient GetCrmServiceClient(bool forceNewService = false) { - get + if (forceNewService == false && crmSvc != null) + { + return crmSvc; + } + if (Timeout.Ticks == 0) + { + Timeout = new TimeSpan(0, 2, 0); + } + CrmServiceClient.MaxConnectionTimeout = Timeout; + + if (Certificate != null) + { + var cs = HandleConnectionString($"AuthType=Certificate;url={OriginalUrl};thumbprint={Certificate.Thumbprint};ClientId={AzureAdAppId};"); + crmSvc = new CrmServiceClient(cs); + } + else if (!string.IsNullOrEmpty(ConnectionString)) + { + var cs = HandleConnectionString(ConnectionString); + crmSvc = new CrmServiceClient(cs); + } + else if (NewAuthType == AuthenticationType.ClientSecret) + { + var cs = HandleConnectionString($"AuthType=ClientSecret;url={OriginalUrl};ClientId={AzureAdAppId};ClientSecret={clientSecret}"); + crmSvc = new CrmServiceClient(cs); + } + else if (NewAuthType == AuthenticationType.OAuth && UseMfa) + { + var path = Path.Combine(Path.GetTempPath(), ConnectionId.Value.ToString("B")); + + var cs = HandleConnectionString($"AuthType=OAuth;Username={UserName};Url={OriginalUrl};AppId={AzureAdAppId};RedirectUri={ReplyUrl};TokenCacheStorePath={path};LoginPrompt=Auto"); + crmSvc = new CrmServiceClient(cs); + } + else if (!string.IsNullOrEmpty(clientSecret)) { - return OrganizationVersion != null ? int.Parse(OrganizationVersion.Split('.')[0]) : -1; + ConnectOAuth(); } + else if (UseOnline) + { + ConnectOnline(); + } + else if (UseIfd) + { + ConnectIfd(); + } + else + { + ConnectOnprem(); + } + + if (!crmSvc.IsReady) + { + var error = crmSvc.LastCrmError; + crmSvc = null; + throw new Exception(error); + } + + OrganizationFriendlyName = crmSvc.ConnectedOrgFriendlyName; + OrganizationDataServiceUrl = crmSvc.ConnectedOrgPublishedEndpoints[EndpointType.OrganizationDataService]; + OrganizationServiceUrl = crmSvc.ConnectedOrgPublishedEndpoints[EndpointType.OrganizationService]; + WebApplicationUrl = crmSvc.ConnectedOrgPublishedEndpoints[EndpointType.WebApplication]; + Organization = crmSvc.ConnectedOrgUniqueName; + OrganizationVersion = crmSvc.ConnectedOrgVersion.ToString(); + TenantId = crmSvc.TenantId; + EnvironmentId = crmSvc.EnvironmentId; + + var webAppURi = new Uri(WebApplicationUrl); + ServerName = webAppURi.Host; + ServerPort = webAppURi.Port; + + UseIfd = crmSvc.ActiveAuthenticationType == AuthenticationType.IFD; + + switch (crmSvc.ActiveAuthenticationType) + { + case AuthenticationType.AD: + case AuthenticationType.Claims: + AuthType = AuthenticationProviderType.ActiveDirectory; + break; + + case AuthenticationType.IFD: + AuthType = AuthenticationProviderType.Federation; + break; + + case AuthenticationType.Live: + AuthType = AuthenticationProviderType.LiveId; + break; + + case AuthenticationType.OAuth: + // TODO add new property in ConnectionDetail class? + break; + + case AuthenticationType.Office365: + AuthType = AuthenticationProviderType.OnlineFederation; + break; + } + + return crmSvc; } - public int OrganizationMinorVersion + public async Task GetCrmServiceClientAsync(bool forceNewService = false) { - get + var task = Task.Run(() => GetCrmServiceClient(forceNewService)); + return await task; + } + + public void SetClientSecret(string secret, bool isEncrypted = false) + { + if (!string.IsNullOrEmpty(secret)) { - return OrganizationVersion != null ? int.Parse(OrganizationVersion.Split('.')[1]) : -1; + if (isEncrypted) + { + clientSecret = secret; + } + else + { + clientSecret = CryptoManager.Encrypt(secret, ConnectionManager.CryptoPassPhrase, + ConnectionManager.CryptoSaltValue, + ConnectionManager.CryptoHashAlgorythm, + ConnectionManager.CryptoPasswordIterations, + ConnectionManager.CryptoInitVector, + ConnectionManager.CryptoKeySize); + } } } - public string WebApplicationUrl { get; set; } + public void SetConnectionString(string connectionString) + { + var csb = new DbConnectionStringBuilder { ConnectionString = connectionString }; - #endregion + if (csb.ContainsKey("Password")) + { + csb["Password"] = CryptoManager.Encrypt(csb["Password"].ToString(), ConnectionManager.CryptoPassPhrase, + ConnectionManager.CryptoSaltValue, + ConnectionManager.CryptoHashAlgorythm, + ConnectionManager.CryptoPasswordIterations, + ConnectionManager.CryptoInitVector, + ConnectionManager.CryptoKeySize); + } + if (csb.ContainsKey("ClientSecret")) + { + csb["ClientSecret"] = CryptoManager.Encrypt(csb["ClientSecret"].ToString(), ConnectionManager.CryptoPassPhrase, + ConnectionManager.CryptoSaltValue, + ConnectionManager.CryptoHashAlgorythm, + ConnectionManager.CryptoPasswordIterations, + ConnectionManager.CryptoInitVector, + ConnectionManager.CryptoKeySize); + } + + ConnectionString = csb.ToString(); + } + + public void SetPassword(string password, bool isEncrypted = false) + { + if (!string.IsNullOrEmpty(password)) + { + if (isEncrypted) + { + userPassword = password; + } + else + { + userPassword = CryptoManager.Encrypt(password, ConnectionManager.CryptoPassPhrase, + ConnectionManager.CryptoSaltValue, + ConnectionManager.CryptoHashAlgorythm, + ConnectionManager.CryptoPasswordIterations, + ConnectionManager.CryptoInitVector, + ConnectionManager.CryptoKeySize); + } + } + } - #region Methods + public string GetPassword(string password) + { + return CryptoManager.Decrypt(password, ConnectionManager.CryptoPassPhrase, + ConnectionManager.CryptoSaltValue, + ConnectionManager.CryptoHashAlgorythm, + ConnectionManager.CryptoPasswordIterations, + ConnectionManager.CryptoInitVector, + ConnectionManager.CryptoKeySize); + } + /// + /// Retourne le nom de la connexion + /// + /// Nom de la connexion public override string ToString() { return ConnectionName; } - public string GetDiscoveryCrmConnectionString() + public bool TryRequestClientSecret(Control parent, string secretUsageDescription, out string secret, out SensitiveDataNotFoundReason notFoundReason) { - var connectionString = string.Format("Url={0}://{1}:{2};", - UseSsl ? "https" : "http", - UseIfd ? ServerName : UseOsdp ? "disco." + ServerName : UseOnline ? "dev." + ServerName : ServerName, - ServerPort == 0 ? (UseSsl ? 443 : 80) : ServerPort); - - if (IsCustomAuth) + var prd = new PasswordRequestDialog(secretUsageDescription, this, "client secret"); + if (AllowPasswordSharing || prd.ShowDialog(parent) == DialogResult.OK && prd.Accepted) { - if (!UseIfd) + if (string.IsNullOrEmpty(clientSecret)) { - if (!string.IsNullOrEmpty(UserDomain)) - { - connectionString += string.Format("Domain={0};", UserDomain); - } + secret = string.Empty; + notFoundReason = SensitiveDataNotFoundReason.NotAccessible; + return false; } - string username = UserName; - if (UseIfd) - { - if (!string.IsNullOrEmpty(UserDomain)) - { - username = string.Format("{0}\\{1}", UserDomain, UserName); - } - } + secret = CryptoManager.Decrypt(clientSecret, ConnectionManager.CryptoPassPhrase, + ConnectionManager.CryptoSaltValue, + ConnectionManager.CryptoHashAlgorythm, + ConnectionManager.CryptoPasswordIterations, + ConnectionManager.CryptoInitVector, + ConnectionManager.CryptoKeySize); - connectionString += string.Format("Username={0};Password={1};", username, UserPassword); + notFoundReason = SensitiveDataNotFoundReason.None; + return true; } - if (UseOnline && !UseOsdp) - { - ClientCredentials deviceCredentials; + notFoundReason = SensitiveDataNotFoundReason.NotAllowedByUser; + secret = string.Empty; + return false; + } - do + public bool TryRequestPassword(Control parent, string passwordUsageDescription, out string password, out SensitiveDataNotFoundReason notFoundReason) + { + var prd = new PasswordRequestDialog(passwordUsageDescription, this, "password"); + if (AllowPasswordSharing || prd.ShowDialog(parent) == DialogResult.OK && prd.Accepted) + { + if (string.IsNullOrEmpty(userPassword)) { - deviceCredentials = DeviceIdManager.LoadDeviceCredentials() ?? - DeviceIdManager.RegisterDevice(); - } while (deviceCredentials.UserName.Password.Contains(";") - || deviceCredentials.UserName.Password.Contains("=") - || deviceCredentials.UserName.Password.Contains(" ") - || deviceCredentials.UserName.UserName.Contains(";") - || deviceCredentials.UserName.UserName.Contains("=") - || deviceCredentials.UserName.UserName.Contains(" ")); + password = string.Empty; + notFoundReason = SensitiveDataNotFoundReason.NotAccessible; + return false; + } - connectionString += string.Format("DeviceID={0};DevicePassword={1};", - deviceCredentials.UserName.UserName, - deviceCredentials.UserName.Password); + password = CryptoManager.Decrypt(userPassword, ConnectionManager.CryptoPassPhrase, + ConnectionManager.CryptoSaltValue, + ConnectionManager.CryptoHashAlgorythm, + ConnectionManager.CryptoPasswordIterations, + ConnectionManager.CryptoInitVector, + ConnectionManager.CryptoKeySize); + + notFoundReason = SensitiveDataNotFoundReason.None; + return true; } - if (UseIfd && !string.IsNullOrEmpty(HomeRealmUrl)) + notFoundReason = SensitiveDataNotFoundReason.NotAllowedByUser; + password = string.Empty; + return false; + } + + public void UpdateAfterEdit(ConnectionDetail editedConnection) + { + ConnectionName = editedConnection.ConnectionName; + ConnectionString = editedConnection.ConnectionString; + OrganizationServiceUrl = editedConnection.OrganizationServiceUrl; + OrganizationDataServiceUrl = editedConnection.OrganizationDataServiceUrl; + Organization = editedConnection.Organization; + OrganizationFriendlyName = editedConnection.OrganizationFriendlyName; + ServerName = editedConnection.ServerName; + ServerPort = editedConnection.ServerPort; + UseIfd = editedConnection.UseIfd; + UserDomain = editedConnection.UserDomain; + UserName = editedConnection.UserName; + userPassword = editedConnection.userPassword; + HomeRealmUrl = editedConnection.HomeRealmUrl; + Timeout = editedConnection.Timeout; + UseMfa = editedConnection.UseMfa; + ReplyUrl = editedConnection.ReplyUrl; + AzureAdAppId = editedConnection.AzureAdAppId; + clientSecret = editedConnection.clientSecret; + RefreshToken = editedConnection.RefreshToken; + EnvironmentText = editedConnection.EnvironmentText; + EnvironmentColor = editedConnection.EnvironmentColor; + EnvironmentTextColor = editedConnection.EnvironmentTextColor; + } + + private void ConnectIfd() + { + AuthType = AuthenticationProviderType.Federation; + + if (!IsCustomAuth) + { + crmSvc = new CrmServiceClient(CredentialCache.DefaultNetworkCredentials, + AuthenticationType.IFD, + ServerName, + ServerPort.ToString(), + OrganizationUrlName, + true, + UseSsl); + } + else { - connectionString += string.Format("HomeRealmUri={0};", HomeRealmUrl); + var password = CryptoManager.Decrypt(userPassword, ConnectionManager.CryptoPassPhrase, + ConnectionManager.CryptoSaltValue, + ConnectionManager.CryptoHashAlgorythm, + ConnectionManager.CryptoPasswordIterations, + ConnectionManager.CryptoInitVector, + ConnectionManager.CryptoKeySize); + + crmSvc = new CrmServiceClient(UserName, CrmServiceClient.MakeSecureString(password), UserDomain, + HomeRealmUrl, + ServerName, + ServerPort.ToString(), + OrganizationUrlName, + true, + UseSsl); } + } - return connectionString; + private void ConnectOAuth() + { + if (!string.IsNullOrEmpty(RefreshToken)) + { + CrmServiceClient.AuthOverrideHook = new RefreshTokenAuthOverride(this); + crmSvc = new CrmServiceClient(new Uri($"https://{ServerName}:{ServerPort}"), true); + CrmServiceClient.AuthOverrideHook = null; + } + else + { + var secret = CryptoManager.Decrypt(clientSecret, ConnectionManager.CryptoPassPhrase, + ConnectionManager.CryptoSaltValue, + ConnectionManager.CryptoHashAlgorythm, + ConnectionManager.CryptoPasswordIterations, + ConnectionManager.CryptoInitVector, + ConnectionManager.CryptoKeySize); + + var path = Path.Combine(Path.GetTempPath(), ConnectionId.Value.ToString("B"), "oauth-cache.txt"); + crmSvc = new CrmServiceClient(new Uri($"https://{ServerName}:{ServerPort}"), AzureAdAppId.ToString(), CrmServiceClient.MakeSecureString(secret), true, path); + } } - public string GetOrganizationCrmConnectionString() + private void ConnectOnline() { - var currentServerName = string.Empty; - var authType = "AD"; + AuthType = AuthenticationProviderType.OnlineFederation; - if (UseOsdp || UseOnline) + if (string.IsNullOrEmpty(userPassword)) { - currentServerName = string.Format("{0}.{1}", OrganizationUrlName, ServerName); + throw new Exception("Unable to read user password"); } - else if (UseIfd) - { - var serverNameParts = ServerName.Split('.'); - serverNameParts[0] = OrganizationUrlName; + var password = CryptoManager.Decrypt(userPassword, ConnectionManager.CryptoPassPhrase, + ConnectionManager.CryptoSaltValue, + ConnectionManager.CryptoHashAlgorythm, + ConnectionManager.CryptoPasswordIterations, + ConnectionManager.CryptoInitVector, + ConnectionManager.CryptoKeySize); + Utilities.GetOrgnameAndOnlineRegionFromServiceUri(new Uri(OriginalUrl), out var region, out var orgName, out _); - currentServerName = string.Format("{0}:{1}", - string.Join(".", serverNameParts), - ServerPort == 0 ? (UseSsl ? 443 : 80) : ServerPort); + if (UseMfa) + { + var path = Path.Combine(Path.GetTempPath(), ConnectionId.Value.ToString("B"), "oauth-cache.txt"); + + crmSvc = new CrmServiceClient(UserName, CrmServiceClient.MakeSecureString(password), + region, + orgName, + false, + null, + null, + AzureAdAppId.ToString(), + new Uri(ReplyUrl), + path, + null, Microsoft.IdentityModel.Clients.ActiveDirectory.PromptBehavior.Auto, false); } else { - currentServerName = string.Format("{0}:{1}/{2}", - ServerName, - ServerPort == 0 ? (UseSsl ? 443 : 80) : ServerPort, - Organization); + crmSvc = new CrmServiceClient(UserName, CrmServiceClient.MakeSecureString(password), + region, + orgName, + true, + true, + null, + true); } + } - var connectionString = string.Format("Url={0}://{1};", - UseSsl ? "https" : "http", - currentServerName); + private void ConnectOnprem() + { + AuthType = AuthenticationProviderType.ActiveDirectory; - //var connectionString = string.Format("Url={0};", OrganizationServiceUrl.Replace("/XRMServices/2011/Organization.svc", "")); + NetworkCredential credential; + if (!IsCustomAuth) + { + credential = CredentialCache.DefaultNetworkCredentials; + } + else + { + var password = CryptoManager.Decrypt(userPassword, ConnectionManager.CryptoPassPhrase, + ConnectionManager.CryptoSaltValue, + ConnectionManager.CryptoHashAlgorythm, + ConnectionManager.CryptoPasswordIterations, + ConnectionManager.CryptoInitVector, + ConnectionManager.CryptoKeySize); + + credential = new NetworkCredential(UserName, password, UserDomain); + } - if (IsCustomAuth) + crmSvc = new CrmServiceClient(credential, + AuthenticationType.AD, + ServerName, + ServerPort.ToString(), + OrganizationUrlName, + true, + UseSsl); + } + + private string HandleConnectionString(string connectionString) + { + var csb = new DbConnectionStringBuilder { ConnectionString = connectionString }; + if (csb.ContainsKey("timeout")) { - if (!UseIfd) - { - if (!string.IsNullOrEmpty(UserDomain)) - { - connectionString += string.Format("Domain={0};", UserDomain); - } - } + var csTimeout = TimeSpan.Parse(csb["timeout"].ToString()); + csb.Remove("timeout"); + CrmServiceClient.MaxConnectionTimeout = csTimeout; + } + + OriginalUrl = csb["Url"].ToString(); + UserName = csb.ContainsKey("username") ? csb["username"].ToString() : + csb.ContainsKey("clientid") ? csb["clientid"].ToString() : null; + + if (csb.ContainsKey("Password")) + { + csb["Password"] = CryptoManager.Decrypt(csb["Password"].ToString(), ConnectionManager.CryptoPassPhrase, + ConnectionManager.CryptoSaltValue, + ConnectionManager.CryptoHashAlgorythm, + ConnectionManager.CryptoPasswordIterations, + ConnectionManager.CryptoInitVector, + ConnectionManager.CryptoKeySize); + } + if (csb.ContainsKey("ClientSecret")) + { + csb["ClientSecret"] = CryptoManager.Decrypt(csb["ClientSecret"].ToString(), ConnectionManager.CryptoPassPhrase, + ConnectionManager.CryptoSaltValue, + ConnectionManager.CryptoHashAlgorythm, + ConnectionManager.CryptoPasswordIterations, + ConnectionManager.CryptoInitVector, + ConnectionManager.CryptoKeySize); + } - string username = UserName; - if (UseIfd) + var cs = csb.ToString(); + + if (cs.IndexOf("RequireNewInstance=", StringComparison.Ordinal) < 0) + { + if (!cs.EndsWith(";")) { - if (!string.IsNullOrEmpty(UserDomain)) - { - username = string.Format("{0}\\{1}", UserDomain, UserName); - } + cs += ";"; } - connectionString += string.Format("Username={0};Password={1};", username, UserPassword); + cs += "RequireNewInstance=True;"; } - if (UseOnline) - { - ClientCredentials deviceCredentials; + return cs; + } - do + #endregion Méthodes + + public object Clone() + { + var cd = new ConnectionDetail + { + AuthType = AuthType, + ConnectionId = Guid.NewGuid(), + ConnectionName = ConnectionName, + ConnectionString = ConnectionString, + HomeRealmUrl = HomeRealmUrl, + Organization = Organization, + OrganizationFriendlyName = OrganizationFriendlyName, + OrganizationServiceUrl = OrganizationServiceUrl, + OrganizationDataServiceUrl = OrganizationDataServiceUrl, + OrganizationUrlName = OrganizationUrlName, + OrganizationVersion = OrganizationVersion, + SavePassword = SavePassword, + ServerName = ServerName, + ServerPort = ServerPort, + TimeoutTicks = TimeoutTicks, + UseIfd = UseIfd, + UserDomain = UserDomain, + UserName = UserName, + userPassword = userPassword, + WebApplicationUrl = WebApplicationUrl, + OriginalUrl = OriginalUrl, + Timeout = Timeout, + UseMfa = UseMfa, + AzureAdAppId = AzureAdAppId, + ReplyUrl = ReplyUrl, + EnvironmentText = EnvironmentText, + EnvironmentColor = EnvironmentColor, + EnvironmentTextColor = EnvironmentTextColor, + RefreshToken = RefreshToken, + S2SClientSecret = S2SClientSecret, + IsFromSdkLoginCtrl = IsFromSdkLoginCtrl, + }; + + if (Certificate != null) + { + cd.Certificate = new CertificateInfo { - deviceCredentials = DeviceIdManager.LoadDeviceCredentials() ?? - DeviceIdManager.RegisterDevice(); - } while (deviceCredentials.UserName.Password.Contains(";") - || deviceCredentials.UserName.Password.Contains("=") - || deviceCredentials.UserName.Password.Contains(" ") - || deviceCredentials.UserName.UserName.Contains(";") - || deviceCredentials.UserName.UserName.Contains("=") - || deviceCredentials.UserName.UserName.Contains(" ")); + Issuer = Certificate.Issuer, + Thumbprint = Certificate.Thumbprint, + Name = Certificate.Name + }; + } + + return cd; + } + + public void CopyClientSecretTo(ConnectionDetail detail) + { + detail.clientSecret = clientSecret; + } + + public void CopyPasswordTo(ConnectionDetail detail) + { + detail.userPassword = userPassword; + } - connectionString += string.Format("DeviceID={0};DevicePassword={1};", - deviceCredentials.UserName.UserName, - deviceCredentials.UserName.Password); + public string GetConnectionString() + { + var csb = new DbConnectionStringBuilder(); + + switch (AuthType) + { + default: + csb["AuthType"] = "AD"; + break; - authType = "Office365"; + case AuthenticationProviderType.OnlineFederation: + csb["AuthType"] = "Office365"; + break; + + case AuthenticationProviderType.Federation: + csb["AuthType"] = "IFD"; + break; } - if (UseIfd && !string.IsNullOrEmpty(HomeRealmUrl)) + csb["Url"] = WebApplicationUrl; + + if (Certificate != null) { - connectionString += string.Format("HomeRealmUri={0};", HomeRealmUrl); + csb["AuthType"] = "Certificate"; + csb["ClientId"] = AzureAdAppId; + csb["Thumbprint"] = Certificate.Thumbprint; + + return csb.ToString(); } - if (UseIfd) + + if (!string.IsNullOrEmpty(UserDomain)) + csb["Domain"] = UserDomain; + csb["Username"] = UserName; + csb["Password"] = "********"; + + if (!string.IsNullOrEmpty(HomeRealmUrl)) + csb["HomeRealmUri"] = HomeRealmUrl; + + if (UseMfa) { - authType = "IFD"; + csb["AuthType"] = "OAuth"; + csb["ClientId"] = AzureAdAppId.ToString("B"); + csb["LoginPrompt"] = "Auto"; + csb["RedirectUri"] = ReplyUrl; + csb["TokenCacheStorePath"] = Path.Combine(Path.GetTempPath(), ConnectionId.Value.ToString("B"), "oauth-cache.txt"); } - connectionString += string.Format("AuthType={0};", authType); - //append timeout in seconds to connectionstring - connectionString += string.Format("Timeout={0};", Timeout.ToString(@"hh\:mm\:ss")); - return connectionString; + return csb.ToString(); } - public string GetConnectionLongName() + public bool IsConnectionBrokenWithUpdatedData(ConnectionDetail originalDetail) { - return ConnectionName + " - " + OrganizationFriendlyName + " - " + SolutionFriendlyName; + if (originalDetail == null) + { + return true; + } + + if (originalDetail.HomeRealmUrl != HomeRealmUrl + || originalDetail.IsCustomAuth != IsCustomAuth + || originalDetail.Organization != Organization + || originalDetail.OrganizationUrlName != OrganizationUrlName + || originalDetail.ServerName.ToLower() != ServerName.ToLower() + || originalDetail.ServerPort != ServerPort + || originalDetail.UseIfd != UseIfd + || originalDetail.UseOnline != UseOnline + || originalDetail.UseSsl != UseSsl + || originalDetail.UseMfa != UseMfa + || originalDetail.clientSecret != clientSecret + || originalDetail.AzureAdAppId != AzureAdAppId + || originalDetail.ReplyUrl != ReplyUrl + || originalDetail.UserDomain?.ToLower() != UserDomain?.ToLower() + || originalDetail.UserName?.ToLower() != UserName?.ToLower() + || SavePassword && !string.IsNullOrEmpty(userPassword) && originalDetail.userPassword != userPassword + || originalDetail.Certificate.Thumbprint != Certificate.Thumbprint) + { + return true; + } + + return false; } - #endregion + public bool PasswordIsDifferent(string password) + { + return password != userPassword; + } #region IComparable Members public int CompareTo(object obj) { - return String.CompareOrdinal(ConnectionName, ((ConnectionDetail)obj).ConnectionName); + var detail = (ConnectionDetail)obj; + + return String.Compare(ConnectionName, detail.ConnectionName, StringComparison.Ordinal); } + #endregion IComparable Members + } + public class EnvironmentHighlighting + { + [XmlIgnore] + public Color? Color { get; set; } + [XmlElement("Color")] + public string ColorString + { + get => ColorTranslator.ToHtml(Color ?? System.Drawing.Color.Black); + set => Color = ColorTranslator.FromHtml(value); + } - #endregion + public string Text { get; set; } + + [XmlIgnore] + public Color? TextColor { get; set; } - public string GetDiscoveryServiceUrl() + [XmlElement("TextColor")] + public string TextColorString { - var url = string.Format("{0}://{1}:{2}/XRMServices/2011/Discovery.svc", - UseSsl ? "https" : "http", - UseIfd ? ServerName : UseOsdp ? "disco." + ServerName : UseOnline ? "dev." + ServerName : ServerName, - ServerPort == 0 ? UseSsl ? 443 : 80 : ServerPort); //"" : !UseSsl && ServerPort == 80 ? "" : UseSsl && ServerPort == 443 ? "" : ":" + ServerPort.ToString()); - return url; + get => ColorTranslator.ToHtml(TextColor ?? System.Drawing.Color.Black); + set => TextColor = ColorTranslator.FromHtml(value); } } } \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection/ConnectionDetailDeprecated.cs b/CrmConnectionProjects/McTools.Xrm.Connection/ConnectionDetailDeprecated.cs new file mode 100644 index 0000000..537c8f9 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection/ConnectionDetailDeprecated.cs @@ -0,0 +1,343 @@ +using System; +using System.ComponentModel; +using System.ServiceModel.Description; +using System.Xml.Serialization; +using Microsoft.Xrm.Sdk.Client; +using Microsoft.Xrm.Sdk.Discovery; + +namespace McTools.Xrm.Connection.Deprecated +{ + /// + /// Stores data regarding a specific connection to Crm server + /// + public class ConnectionDetail : IComparable + { + #region Properties + + public AuthenticationProviderType AuthType { get; set; } + + /// + /// Gets or sets the connection unique identifier + /// + public Guid? ConnectionId { get; set; } + + /// + /// Gets or sets the name of the connection + /// + public string ConnectionName { get; set; } + + + /// + /// Get or set flag to know if custom authentication + /// + public bool IsCustomAuth { get; set; } + + /// + /// Get or set flag to know if we use IFD + /// + public bool UseIfd { get; set; } + + /// + /// Get or set flag to know if we use CRM Online + /// + public bool UseOnline { get; set; } + + /// + /// Get or set flag to know if we use Online Services + /// + public bool UseOsdp { get; set; } + + /// + /// Get or set the Crm Ticket + /// + [System.Xml.Serialization.XmlIgnore] + public string CrmTicket { get; set; } + + /// + /// Get or set the user domain name + /// + public string UserDomain { get; set; } + + /// + /// Get or set user login + /// + public string UserName { get; set; } + + /// + /// Get or set the user password + /// + //[System.Xml.Serialization.XmlIgnore] + public string UserPassword { get; set; } + + public bool SavePassword { get; set; } + + /// + /// Get or set the use of SSL connection + /// + public bool UseSsl { get; set; } + + /// + /// Get or set the server name + /// + public string ServerName { get; set; } + + /// + /// Get or set the server port + /// + [DefaultValue(80)] + public int ServerPort { get; set; } + + /// + /// Get or set the organization Id + /// + public string OrganizationId { get; set; } + /// + /// Get or set the organization name + /// + public string Organization { get; set; } + + /// + /// Get or set the organization name + /// + public string OrganizationUrlName { get; set; } + + /// + /// Get or set the organization friendly name + /// + public string OrganizationFriendlyName { get; set; } + + /// + /// Gets or sets the Crm Service Url + /// + public string OrganizationServiceUrl { get; set; } + + /// + /// Gets or sets the Home realm url for ADFS authentication + /// + public string HomeRealmUrl { get; set; } + + public string OrganizationVersion { get; set; } + + public string Solution { get; set; } + public string SolutionId { get; set; } + public string SolutionFriendlyName { get; set; } + + public string PublisherPrefix { get; set; } + + + [XmlIgnore] + public TimeSpan Timeout { get; set; } + + [XmlElement("Timeout")] + public long TimeoutTicks + { + get { return Timeout.Ticks; } + set { Timeout = new TimeSpan(value); } + } + + public int OrganizationMajorVersion + { + get + { + return OrganizationVersion != null ? int.Parse(OrganizationVersion.Split('.')[0]) : -1; + } + } + + public int OrganizationMinorVersion + { + get + { + return OrganizationVersion != null ? int.Parse(OrganizationVersion.Split('.')[1]) : -1; + } + } + + public string WebApplicationUrl { get; set; } + + #endregion + + #region Methods + + public override string ToString() + { + return ConnectionName; + } + + public string GetDiscoveryCrmConnectionString() + { + var connectionString = string.Format("Url={0}://{1}:{2};", + UseSsl ? "https" : "http", + UseIfd ? ServerName : UseOsdp ? "disco." + ServerName : UseOnline ? "dev." + ServerName : ServerName, + ServerPort == 0 ? (UseSsl ? 443 : 80) : ServerPort); + + if (IsCustomAuth) + { + if (!UseIfd) + { + if (!string.IsNullOrEmpty(UserDomain)) + { + connectionString += string.Format("Domain={0};", UserDomain); + } + } + + string username = UserName; + if (UseIfd) + { + if (!string.IsNullOrEmpty(UserDomain)) + { + username = string.Format("{0}\\{1}", UserDomain, UserName); + } + } + + connectionString += string.Format("Username={0};Password={1};", username, UserPassword); + } + + if (UseOnline && !UseOsdp) + { + ClientCredentials deviceCredentials; + + do + { + deviceCredentials = DeviceIdManager.LoadDeviceCredentials() ?? + DeviceIdManager.RegisterDevice(); + } while (deviceCredentials.UserName.Password.Contains(";") + || deviceCredentials.UserName.Password.Contains("=") + || deviceCredentials.UserName.Password.Contains(" ") + || deviceCredentials.UserName.UserName.Contains(";") + || deviceCredentials.UserName.UserName.Contains("=") + || deviceCredentials.UserName.UserName.Contains(" ")); + + connectionString += string.Format("DeviceID={0};DevicePassword={1};", + deviceCredentials.UserName.UserName, + deviceCredentials.UserName.Password); + } + + if (UseIfd && !string.IsNullOrEmpty(HomeRealmUrl)) + { + connectionString += string.Format("HomeRealmUri={0};", HomeRealmUrl); + } + + return connectionString; + } + + public string GetOrganizationCrmConnectionString() + { + var currentServerName = string.Empty; + var authType = "AD"; + + if (UseOsdp || UseOnline) + { + currentServerName = string.Format("{0}.{1}", OrganizationUrlName, ServerName); + } + else if (UseIfd) + { + var serverNameParts = ServerName.Split('.'); + + serverNameParts[0] = OrganizationUrlName; + + + currentServerName = string.Format("{0}:{1}", + string.Join(".", serverNameParts), + ServerPort == 0 ? (UseSsl ? 443 : 80) : ServerPort); + } + else + { + currentServerName = string.Format("{0}:{1}/{2}", + ServerName, + ServerPort == 0 ? (UseSsl ? 443 : 80) : ServerPort, + Organization); + } + + var connectionString = string.Format("Url={0}://{1};", + UseSsl ? "https" : "http", + currentServerName); + + //var connectionString = string.Format("Url={0};", OrganizationServiceUrl.Replace("/XRMServices/2011/Organization.svc", "")); + + if (IsCustomAuth) + { + if (!UseIfd) + { + if (!string.IsNullOrEmpty(UserDomain)) + { + connectionString += string.Format("Domain={0};", UserDomain); + } + } + + string username = UserName; + if (UseIfd) + { + if (!string.IsNullOrEmpty(UserDomain)) + { + username = string.Format("{0}\\{1}", UserDomain, UserName); + } + } + + connectionString += string.Format("Username={0};Password={1};", username, UserPassword); + } + + if (UseOnline) + { + ClientCredentials deviceCredentials; + + do + { + deviceCredentials = DeviceIdManager.LoadDeviceCredentials() ?? + DeviceIdManager.RegisterDevice(); + } while (deviceCredentials.UserName.Password.Contains(";") + || deviceCredentials.UserName.Password.Contains("=") + || deviceCredentials.UserName.Password.Contains(" ") + || deviceCredentials.UserName.UserName.Contains(";") + || deviceCredentials.UserName.UserName.Contains("=") + || deviceCredentials.UserName.UserName.Contains(" ")); + + connectionString += string.Format("DeviceID={0};DevicePassword={1};", + deviceCredentials.UserName.UserName, + deviceCredentials.UserName.Password); + + authType = "Office365"; + } + + if (UseIfd && !string.IsNullOrEmpty(HomeRealmUrl)) + { + connectionString += string.Format("HomeRealmUri={0};", HomeRealmUrl); + } + if (UseIfd) + { + authType = "IFD"; + } + connectionString += string.Format("AuthType={0};", authType); + + //append timeout in seconds to connectionstring + connectionString += string.Format("Timeout={0};", Timeout.ToString(@"hh\:mm\:ss")); + return connectionString; + } + + public string GetConnectionLongName() + { + return ConnectionName + " - " + OrganizationFriendlyName + " - " + SolutionFriendlyName; + } + + #endregion + + #region IComparable Members + + public int CompareTo(object obj) + { + return String.CompareOrdinal(ConnectionName, ((ConnectionDetail)obj).ConnectionName); + } + + + + + #endregion + + public string GetDiscoveryServiceUrl() + { + var url = string.Format("{0}://{1}:{2}/XRMServices/2011/Discovery.svc", + UseSsl ? "https" : "http", + UseIfd ? ServerName : UseOsdp ? "disco." + ServerName : UseOnline ? "dev." + ServerName : ServerName, + ServerPort == 0 ? UseSsl ? 443 : 80 : ServerPort); //"" : !UseSsl && ServerPort == 80 ? "" : UseSsl && ServerPort == 443 ? "" : ":" + ServerPort.ToString()); + return url; + } + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection/ConnectionManager.cs b/CrmConnectionProjects/McTools.Xrm.Connection/ConnectionManager.cs index 08b6e0d..f42ed11 100644 --- a/CrmConnectionProjects/McTools.Xrm.Connection/ConnectionManager.cs +++ b/CrmConnectionProjects/McTools.Xrm.Connection/ConnectionManager.cs @@ -1,4 +1,8 @@ -using System; +using Microsoft.Crm.Sdk.Messages; +using Microsoft.Xrm.Sdk; +using Microsoft.Xrm.Sdk.Organization; +using Microsoft.Xrm.Tooling.Connector; +using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; @@ -6,56 +10,57 @@ using System.Net; using System.Net.Security; using System.Security.Cryptography.X509Certificates; -using Microsoft.Crm.Sdk.Messages; -using Microsoft.Xrm.Sdk; -using Microsoft.Xrm.Sdk.Client; -using Microsoft.Xrm.Tooling.Connector; +using EndpointCollection = Microsoft.Xrm.Sdk.Organization.EndpointCollection; namespace McTools.Xrm.Connection { #region Event Args Class Definition + public class ConnectionFailedEventArgs : EventArgs + { + public ConnectionDetail ConnectionDetail { get; set; } + public string FailureReason { get; set; } + public int NumberOfConnectionsRequested { get; set; } + public object Parameter { get; set; } + } + public class ConnectionSucceedEventArgs : EventArgs { - public IOrganizationService OrganizationService { get; set; } public ConnectionDetail ConnectionDetail { get; set; } + public int NumberOfConnectionsRequested { get; set; } + public IOrganizationService OrganizationService { get; set; } public object Parameter { get; set; } } - public class ConnectionFailedEventArgs : EventArgs + public class DeleteConnectionEventArgs : EventArgs { - public string FailureReason { get; set; } } - public class StepChangedEventArgs : EventArgs + public class EditConnectEventArgs : EventArgs { - public string CurrentStep { get; set; } } public class RequestPasswordEventArgs : EventArgs { - public ConnectionDetail ConnectionDetail { get; set; } - public RequestPasswordEventArgs(ConnectionDetail connectionDetail) { ConnectionDetail = connectionDetail; } - } - public class UseProxyEventArgs : EventArgs - { - public IWebProxy Proxy { get; set; } + public ConnectionDetail ConnectionDetail { get; set; } } - public class EditConnectEventArgs : EventArgs + public class StepChangedEventArgs : EventArgs { + public string CurrentStep { get; set; } } - public class DeleteConnectionEventArgs : EventArgs + public class UseProxyEventArgs : EventArgs { + public IWebProxy Proxy { get; set; } } - #endregion + #endregion Event Args Class Definition /// /// Manager that handles all connection operations @@ -64,37 +69,53 @@ public class ConnectionManager { #region Delegates - public delegate void ConnectionSucceedEventHandler(object sender, ConnectionSucceedEventArgs e); public delegate void ConnectionFailedEventHandler(object sender, ConnectionFailedEventArgs e); - public delegate void StepChangedEventHandler(object sender, StepChangedEventArgs e); + + public delegate void ConnectionListUpdatedEventHandler(object sender, EventArgs e); + + public delegate void ConnectionSucceedEventHandler(object sender, ConnectionSucceedEventArgs e); + public delegate bool RequestPasswordEventHandler(object sender, RequestPasswordEventArgs e); - public delegate void UseProxyEventHandler(object sender, UseProxyEventArgs e); + public delegate void StepChangedEventHandler(object sender, StepChangedEventArgs e); - #endregion + public delegate void UseProxyEventHandler(object sender, UseProxyEventArgs e); + + #endregion Delegates #region Event Handlers - public event ConnectionSucceedEventHandler ConnectionSucceed; public event ConnectionFailedEventHandler ConnectionFailed; + + public event ConnectionListUpdatedEventHandler ConnectionListUpdated; + + public event ConnectionSucceedEventHandler ConnectionSucceed; + + //public event RequestPasswordEventHandler RequestPassword; + public event StepChangedEventHandler StepChanged; - public event RequestPasswordEventHandler RequestPassword; - public event UseProxyEventHandler UseProxy; - #endregion + //public event UseProxyEventHandler UseProxy; + + #endregion Event Handlers #region Constants - const string ConfigFileName = "mscrmtools2011.config"; - const string CryptoPassPhrase = "MsCrmTools"; - const string CryptoSaltValue = "Tanguy 92*"; - const string CryptoInitVector = "ahC3@bCa2Didfc3d"; - const string CryptoHashAlgorythm = "SHA1"; - const int CryptoPasswordIterations = 2; - const int CryptoKeySize = 256; + internal const string CryptoHashAlgorythm = "SHA1"; + internal const string CryptoInitVector = "ahC3@bCa2Didfc3d"; + internal const int CryptoKeySize = 256; + internal const string CryptoPassPhrase = "MsCrmTools"; + internal const int CryptoPasswordIterations = 2; + internal const string CryptoSaltValue = "Tanguy 92*"; + private const string DefaultConfigFileName = "mscrmtools2011.config"; #endregion Constants + private static string configfile; + private static Lazy instance = new Lazy(() => new ConnectionManager()); + private Dictionary crmServices; + private FileSystemWatcher fsw; + #region Constructor /// @@ -102,139 +123,192 @@ public class ConnectionManager /// public ConnectionManager() { - //ConnectionsList = LoadConnectionsList(); - + crmServices = new Dictionary(); + ConnectionsList = LoadConnectionsList(); + SetupFileSystemWatcher(); + ServicePointManager.ServerCertificateValidationCallback += ValidateRemoteCertificate; } - - #endregion - - #region Properties - /// - /// List of Crm connections - /// - public CrmConnections ConnectionsList { get; set; } - - #endregion Properties - - #region Methods - - /// - /// Launch the Crm connection process - /// - /// Details of the Crm connection - /// A parameter to retrieve after connection - public void ConnectToServer(ConnectionDetail detail, object connectionParameter) + // callback used to validate the certificate in an SSL conversation + private static bool ValidateRemoteCertificate( + object sender, + X509Certificate certificate, + X509Chain chain, + SslPolicyErrors policyErrors + ) { - var parameters = new List { detail, connectionParameter }; - - // Runs the connection asynchronously - var worker = new BackgroundWorker(); - worker.DoWork += WorkerDoWork; - worker.RunWorkerCompleted += WorkerRunWorkerCompleted; - worker.RunWorkerAsync(parameters); + return true; } - /// - /// Launch the Crm connection process - /// - /// Details of the Crm connection - public void ConnectToServer(ConnectionDetail detail) + private void fsw_Changed(object sender, FileSystemEventArgs e) { - ConnectToServer(detail, null); + if (e.ChangeType == WatcherChangeTypes.Changed) + { + ConnectionsList = LoadConnectionsList(); + } } - /// - /// Working process - /// - /// BackgroundWorker object - /// BackgroundWorker object parameters - void WorkerDoWork(object sender, DoWorkEventArgs e) + private void SetupFileSystemWatcher() { - object result = Connect((List)e.Argument); - e.Result = e.Argument; - ((List)e.Result).Add(result); + if (fsw != null) + { // If it was already watching something, stop that! + fsw.EnableRaisingEvents = false; + fsw.Changed -= fsw_Changed; + fsw.Dispose(); + } + + if (Uri.IsWellFormedUriString(ConfigurationFile, UriKind.Absolute)) + return; + + var path = new FileInfo(ConfigurationFile).Directory.FullName; + + if (Directory.Exists(path)) + { + fsw = new FileSystemWatcher(path, Path.GetFileName(ConfigurationFile)) + { + NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size, + EnableRaisingEvents = true + }; + fsw.Changed += fsw_Changed; + } } - void WorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) - { - var parameters = (List)e.Result; + #endregion Constructor - if (parameters.Count == 3) + #region Properties + + public static string ConfigurationFile + { + get { - var error = parameters[2] as Exception; - if (error != null) + if (string.IsNullOrEmpty(configfile)) { - SendFailureMessage(CrmExceptionHelper.GetErrorMessage(error, false)); + var lastUsedFile = Connection.ConnectionsList.Instance.Files.OrderByDescending(f => f.LastUsed).FirstOrDefault(); + if (lastUsedFile != null) + { + return lastUsedFile.Path; + } } - else + + return string.IsNullOrEmpty(configfile) ? DefaultConfigFileName : configfile; + } + set + { + configfile = value; + if (instance != null) { - var service = parameters[2] as IOrganizationService; - if (service != null) + var existingFile = Connection.ConnectionsList.Instance.Files.FirstOrDefault(f => f.Path == value); + if (existingFile == null) { - SendSuccessMessage(service, parameters); + CrmConnections newCc = CrmConnections.LoadFromFile(value); + + Connection.ConnectionsList.Instance.Files.Add(new ConnectionFile(newCc) { Path = configfile, LastUsed = DateTime.Now }); + Connection.ConnectionsList.Instance.Save(); } + + Instance.ConnectionsList = Instance.LoadConnectionsList(); + Instance.SetupFileSystemWatcher(); + Instance.ConnectionListUpdated?.Invoke(null, new EventArgs()); } } } + public static ConnectionManager Instance + { + get => + instance.Value; + } + /// - /// Connects to a Crm server + /// List of Crm connections /// - /// List of parameters - /// An exception or an IOrganizationService - private object Connect(List parameters) + public CrmConnections ConnectionsList { - WebRequest.DefaultWebProxy = WebRequest.GetSystemWebProxy(); - - var detail = (ConnectionDetail)parameters[0]; - SendStepChange("Creating Organization service proxy..."); + get; + set; + } - // Connecting to Crm server - try - { - var service = CrmConnectionHelper.GetOrganizationServiceProxy(detail); + public bool FromXrmToolBox + { + get; + set; + } - TestConnection(service); + public bool ReuseConnections + { + get; + set; + } - var vRequest = new RetrieveVersionRequest(); - var vResponse = (RetrieveVersionResponse) service.Execute(vRequest); + #endregion Properties - detail.OrganizationVersion = vResponse.Version; + #region Methods - var currentConnection = ConnectionsList.Connections.FirstOrDefault(x => x.ConnectionId == detail.ConnectionId); - if (currentConnection != null) + /// + /// Checks if a configuration file exists + /// + /// The file to check for + /// true if the exists, or false otherwise + public static bool FileExists(string path) + { + if (Uri.IsWellFormedUriString(path, UriKind.Absolute)) + { + try { - currentConnection.OrganizationVersion = vResponse.Version; - currentConnection.SavePassword = detail.SavePassword; - currentConnection.UserPassword = detail.UserPassword; + var req = WebRequest.Create(path); + req.Credentials = CredentialCache.DefaultCredentials; + using (req.GetResponse()) + { + return true; + } + } + catch (WebException) + { + return false; } + } - //SaveConnectionsFile(ConnectionsList); + return File.Exists(path); + } - return service; - } - catch (Exception error) + /// + /// Launch the Crm connection process + /// + /// Details of the Crm connection + /// A parameter to retrieve after connection + public void ConnectToServer(List details, object connectionParameter) + { + foreach (var detail in details) { - return error; + var parameters = new List { detail, connectionParameter, details.Count }; + + // Runs the connection asynchronously + var worker = new BackgroundWorker(); + worker.DoWork += WorkerDoWork; + worker.RunWorkerCompleted += WorkerRunWorkerCompleted; + worker.RunWorkerAsync(parameters); } } + /// + /// Launch the Crm connection process + /// + /// Details of the Crm connection + public void ConnectToServer(List details) => + ConnectToServer(details, null); + /// /// Restore Crm connections list from the file /// /// List of Crm connections public CrmConnections LoadConnectionsList() { - CrmConnections crmConnections; try { - if (File.Exists(ConfigFileName)) + CrmConnections crmConnections; + if (FileExists(ConfigurationFile)) { - using (var configReader = new StreamReader(ConfigFileName)) - { - crmConnections = (CrmConnections)XmlSerializerHelper.Deserialize(configReader.ReadToEnd(), typeof(CrmConnections)); - } + crmConnections = CrmConnections.LoadFromFile(ConfigurationFile); if (!string.IsNullOrEmpty(crmConnections.Password)) { @@ -249,21 +323,10 @@ public CrmConnections LoadConnectionsList() foreach (var detail in crmConnections.Connections) { - if (!string.IsNullOrEmpty(detail.UserPassword)) - { - detail.UserPassword = CryptoManager.Decrypt(detail.UserPassword, - CryptoPassPhrase, - CryptoSaltValue, - CryptoHashAlgorythm, - CryptoPasswordIterations, - CryptoInitVector, - CryptoKeySize); - } - // Fix for new connection code if (string.IsNullOrEmpty(detail.OrganizationUrlName)) { - if (detail.UseIfd || detail.UseOnline || detail.UseOsdp) + if (detail.UseIfd || detail.UseOnline) { var uri = new Uri(detail.OrganizationServiceUrl); detail.OrganizationUrlName = uri.Host.Split('.')[0]; @@ -283,7 +346,7 @@ public CrmConnections LoadConnectionsList() } else { - crmConnections = new CrmConnections + crmConnections = new CrmConnections("Default") { Connections = new List() }; @@ -300,11 +363,11 @@ public CrmConnections LoadConnectionsList() /// /// Saves Crm connections list to file /// - public void SaveConnectionsFile(CrmConnections connectionsList) + public void SaveConnectionsFile() { - if (!string.IsNullOrEmpty(connectionsList.Password)) + if (!string.IsNullOrEmpty(ConnectionsList.Password)) { - connectionsList.Password = CryptoManager.Encrypt(connectionsList.Password, + ConnectionsList.Password = CryptoManager.Encrypt(ConnectionsList.Password, CryptoPassPhrase, CryptoSaltValue, CryptoHashAlgorythm, @@ -313,115 +376,173 @@ public void SaveConnectionsFile(CrmConnections connectionsList) CryptoKeySize); } - var cache = new Dictionary(); + ConnectionsList.SerializeToFile(ConfigurationFile); + } - foreach (var detail in connectionsList.Connections) + /// + /// Tests the specified connection + /// + /// Organization service + public void TestConnection(IOrganizationService service) + { + try { - if (!detail.ConnectionId.HasValue) - continue; + SendStepChange("Testing connection..."); - cache.Add(detail.ConnectionId.Value, detail.UserPassword); + var request = new WhoAmIRequest(); + service.Execute(request); + } + catch (Exception error) + { + throw new Exception("Test connection failed: " + CrmExceptionHelper.GetErrorMessage(error, false)); + } + } - if (detail.SavePassword) - { - if (!string.IsNullOrEmpty(detail.UserPassword)) - { + /// + /// Connects to a Crm server + /// + /// List of parameters + /// An exception or an IOrganizationService + private object Connect(List parameters) + { + if (WebRequest.DefaultWebProxy == null) + WebRequest.DefaultWebProxy = WebRequest.GetSystemWebProxy(); - detail.UserPassword = CryptoManager.Encrypt(detail.UserPassword, - CryptoPassPhrase, - CryptoSaltValue, - CryptoHashAlgorythm, - CryptoPasswordIterations, - CryptoInitVector, - CryptoKeySize); - } - } - else + //Use default credentials if no proxy credentials + if (WebRequest.DefaultWebProxy.Credentials == null) + WebRequest.DefaultWebProxy.Credentials = CredentialCache.DefaultCredentials; + + var detail = (ConnectionDetail)parameters[0]; + + if (ReuseConnections && crmServices.ContainsKey(detail.ConnectionId ?? Guid.Empty)) + { + var service = crmServices[detail.ConnectionId ?? Guid.Empty]; + if (service.IsReady) { - detail.UserPassword = null; + detail.LastUsedOn = DateTime.Now; + return service; } } - XmlSerializerHelper.SerializeToFile(connectionsList, ConfigFileName); + SendStepChange("Creating Organization service proxy..."); - foreach (var detail in connectionsList.Connections) + // Connecting to Crm server + try { - if (!detail.ConnectionId.HasValue) - continue; + var service = detail.GetCrmServiceClient(); - if (detail.UserPassword == null) + // The connection did not succeeded + if (!service.IsReady) { - detail.UserPassword = cache[detail.ConnectionId.Value]; - continue; + // If the connection really failed, the service has no endpoints + if (service.ConnectedOrgPublishedEndpoints == null) + { + throw new Exception(service.LastCrmError); + } + + // When the configuration seems to be wrong, endpoints are available + // so we can check if there is a difference between what the user + // specified for connection. + var returnedWebAppUrl = service.ConnectedOrgPublishedEndpoints[Microsoft.Xrm.Sdk.Discovery.EndpointType.WebApplication]; + if (detail.OriginalUrl.ToLower().IndexOf(returnedWebAppUrl.ToLower(), StringComparison.Ordinal) < 0) + { + string message = + "It seems that the connection information your provided are different from the one configured in your CRM deployment. Please review your connection information or contact your system administrator to ensure Microsoft Dynamics CRM is properly configured"; + + throw new Exception(string.Format("{0}{1}{1}{2}", service.LastCrmError, Environment.NewLine, message)); + } } - if (!string.IsNullOrEmpty(detail.UserPassword)) + var endpoints = service.ConnectedOrgPublishedEndpoints != null ? EndpointCollection.FromDiscovery(service.ConnectedOrgPublishedEndpoints) : null; + + if (endpoints == null) { - detail.UserPassword = CryptoManager.Decrypt(detail.UserPassword, - CryptoPassPhrase, - CryptoSaltValue, - CryptoHashAlgorythm, - CryptoPasswordIterations, - CryptoInitVector, - CryptoKeySize); + // Some connection methods do not automatically retrieve the endpoints - get them now + var orgDetails = (RetrieveCurrentOrganizationResponse)service.Execute(new RetrieveCurrentOrganizationRequest()); + endpoints = orgDetails.Detail.Endpoints; } - } - } - /// - /// Tests the specified connection - /// - /// Organization service - public void TestConnection(IOrganizationService service) - { - try - { - SendStepChange("Testing connection..."); + detail.WebApplicationUrl = endpoints[EndpointType.WebApplication]; + detail.OrganizationDataServiceUrl = endpoints[EndpointType.OrganizationDataService]; + detail.OrganizationVersion = service.ConnectedOrgVersion.ToString(); - var request = new WhoAmIRequest(); - service.Execute(request); + var currentConnection = ConnectionsList.Connections.FirstOrDefault(x => x.ConnectionId == detail.ConnectionId); + if (currentConnection != null) + { + currentConnection.WebApplicationUrl = detail.WebApplicationUrl; + currentConnection.OrganizationDataServiceUrl = detail.OrganizationDataServiceUrl; + currentConnection.OrganizationVersion = detail.OrganizationVersion; + currentConnection.SavePassword = detail.SavePassword; + detail.CopyPasswordTo(currentConnection); + detail.CopyClientSecretTo(currentConnection); + } + + detail.LastUsedOn = DateTime.Now; + + if (ReuseConnections && !crmServices.ContainsKey(detail.ConnectionId ?? Guid.Empty)) + { + crmServices.Add(detail.ConnectionId ?? Guid.Empty, service); + } + + return service; } catch (Exception error) { - throw new Exception("Test connection failed: " + CrmExceptionHelper.GetErrorMessage(error, false)); + return error; } } - #endregion - - #region Send Events - /// - /// Sends a connection success message + /// Working process /// - /// IOrganizationService generated - /// Lsit of parameter - private void SendSuccessMessage(IOrganizationService service, List parameters) + /// BackgroundWorker object + /// BackgroundWorker object parameters + private void WorkerDoWork(object sender, DoWorkEventArgs e) { - if (ConnectionSucceed != null) + object result = Connect((List)e.Argument); + e.Result = e.Argument; + ((List)e.Result).Add(result); + } + + private void WorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) + { + var parameters = (List)e.Result; + + if (parameters.Count == 4) { - var args = new ConnectionSucceedEventArgs + if (parameters[3] is Exception error) { - OrganizationService = service, - ConnectionDetail = (ConnectionDetail)parameters[0], - Parameter = parameters[1] - }; - - ConnectionSucceed(this, args); + SendFailureMessage(parameters, CrmExceptionHelper.GetErrorMessage(error, false)); + } + else + { + if (parameters[3] is CrmServiceClient service) + { + SendSuccessMessage(service, parameters); + } + } } } + #endregion Methods + + #region Send Events + /// /// Sends a connection failure message /// /// Reason of the failure - private void SendFailureMessage(string failureReason) + /// Connection returned parameters + private void SendFailureMessage(List parameters, string failureReason) { if (ConnectionFailed != null) { var args = new ConnectionFailedEventArgs { - FailureReason = failureReason + FailureReason = failureReason, + ConnectionDetail = (ConnectionDetail)parameters[0], + Parameter = parameters[1], + NumberOfConnectionsRequested = (int)parameters[2] }; ConnectionFailed(this, args); @@ -439,12 +560,48 @@ private void SendStepChange(string step) CurrentStep = step }; - if (StepChanged != null) + StepChanged?.Invoke(this, args); + } + + /// + /// Sends a connection success message + /// + /// IOrganizationService generated + /// List of parameters + private void SendSuccessMessage(IOrganizationService service, List parameters) + { + if (ConnectionSucceed != null) { - StepChanged(this, args); + var args = new ConnectionSucceedEventArgs + { + OrganizationService = service, + ConnectionDetail = (ConnectionDetail)parameters[0], + Parameter = parameters[1], + NumberOfConnectionsRequested = (int)parameters[2] + }; + + ConnectionSucceed(this, args); } } - #endregion + #endregion Send Events + + public void ConnectToServerWithSdkLoginCtrl(ConnectionDetail detail, CrmServiceClient crmSvc, object connectionParameter) + { + detail.ServiceClient = crmSvc; + + var parameters = new List { detail, connectionParameter, 1 }; + + if (crmSvc == null) return; + + if (crmSvc.IsReady) + { + SendSuccessMessage(crmSvc, parameters); + } + else + { + SendFailureMessage(parameters, crmSvc.LastCrmError); + } + } } -} +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection/ConnectionResult.cs b/CrmConnectionProjects/McTools.Xrm.Connection/ConnectionResult.cs new file mode 100644 index 0000000..d4fbfd2 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection/ConnectionResult.cs @@ -0,0 +1,15 @@ +using Microsoft.Xrm.Tooling.Connector; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace McTools.Xrm.Connection +{ + public class ConnectionResult + { + public CrmServiceClient CrmServiceClient { get; set; } + public List Solutions { get; set; } + } +} diff --git a/CrmConnectionProjects/McTools.Xrm.Connection/ConnectionsList.cs b/CrmConnectionProjects/McTools.Xrm.Connection/ConnectionsList.cs new file mode 100644 index 0000000..8f11dd2 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection/ConnectionsList.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; + +namespace McTools.Xrm.Connection +{ + public class ConnectionFile + { + public ConnectionFile() + { + } + + public ConnectionFile(string name) + { + Name = name; + } + + public ConnectionFile(CrmConnections connections) + { + Name = connections.Name; + } + + public DateTime LastUsed { get; set; } + public string Name { get; set; } + public string Path { get; set; } + + public override string ToString() + { + return Name?.Length > 0 ? Name : "N/A"; + } + } + + public class ConnectionsList + { + private static string _connectionsListFilePath = "MscrmTools.ConnectionsList.xml"; + private static ConnectionsList _instance; + + private ConnectionsList() + { + Files = new List(); + } + + public static string ConnectionsListFilePath + { + get => _connectionsListFilePath; + set => _connectionsListFilePath = value; + } + + public static ConnectionsList Instance + { + get + { + if (_instance == null) + { + var filename = Path.IsPathRooted(_connectionsListFilePath) ? _connectionsListFilePath : Path.Combine(new FileInfo(Assembly.GetExecutingAssembly().Location).DirectoryName, + _connectionsListFilePath); + + if (File.Exists(filename)) + { + using (var sr = new StreamReader(filename)) + { + _instance = (ConnectionsList)XmlSerializerHelper.Deserialize(sr.ReadToEnd(), typeof(ConnectionsList)); + } + } + else + { + var directory = new FileInfo(filename).DirectoryName; + + if (!Directory.Exists(directory)) + { + Directory.CreateDirectory(directory); + } + + var defaultFilePath = Path.Combine(directory, "ConnectionsList.Default.xml"); + + CrmConnections cc = new CrmConnections("Default"); + cc.SerializeToFile(defaultFilePath); + + _instance = new ConnectionsList(); + _instance.Files.Add(new ConnectionFile(cc) { Path = defaultFilePath }); + _instance.Save(); + } + } + + return _instance; + } + } + + public List Files { get; set; } + + public void Save() + { + var filename = Path.IsPathRooted(_connectionsListFilePath) ? _connectionsListFilePath : Path.Combine(new FileInfo(Assembly.GetExecutingAssembly().Location).DirectoryName, + _connectionsListFilePath); + + XmlSerializerHelper.SerializeToFile(_instance, filename); + } + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection/CrmConnectionHelper.cs b/CrmConnectionProjects/McTools.Xrm.Connection/CrmConnectionHelper.cs index 6824bf3..c9574ff 100644 --- a/CrmConnectionProjects/McTools.Xrm.Connection/CrmConnectionHelper.cs +++ b/CrmConnectionProjects/McTools.Xrm.Connection/CrmConnectionHelper.cs @@ -14,103 +14,103 @@ namespace McTools.Xrm.Connection { public static class CrmConnectionHelper { - public static OrganizationServiceProxy GetOrganizationServiceProxy(ConnectionDetail detail) - { - var serviceUrl = detail.OrganizationServiceUrl; - string homeRealmUrl = null; + //public static OrganizationServiceProxy GetOrganizationServiceProxy(ConnectionDetail detail) + //{ + // var serviceUrl = detail.OrganizationServiceUrl; + // string homeRealmUrl = null; - ClientCredentials clientCredentials = new ClientCredentials(); - ClientCredentials deviceCredentials = null; + // ClientCredentials clientCredentials = new ClientCredentials(); + // ClientCredentials deviceCredentials = null; - if (detail.IsCustomAuth) - { - string username = detail.UserName; - if (!string.IsNullOrEmpty(detail.UserDomain)) - { - username = string.Format("{0}\\{1}", detail.UserDomain, detail.UserName); - } - clientCredentials.UserName.UserName = username; - clientCredentials.UserName.Password = detail.UserPassword; - } + // if (detail.IsCustomAuth) + // { + // string username = detail.UserName; + // if (!string.IsNullOrEmpty(detail.UserDomain)) + // { + // username = string.Format("{0}\\{1}", detail.UserDomain, detail.UserName); + // } + // clientCredentials.UserName.UserName = username; + // clientCredentials.UserName.Password = detail.UserPassword; + // } - if (detail.UseOnline && !detail.UseOsdp) - { - do - { - deviceCredentials = DeviceIdManager.LoadDeviceCredentials() ?? - DeviceIdManager.RegisterDevice(); - } while (deviceCredentials.UserName.Password.Contains(";") - || deviceCredentials.UserName.Password.Contains("=") - || deviceCredentials.UserName.Password.Contains(" ") - || deviceCredentials.UserName.UserName.Contains(";") - || deviceCredentials.UserName.UserName.Contains("=") - || deviceCredentials.UserName.UserName.Contains(" ")); - } + // if (detail.UseOnline && !detail.UseOsdp) + // { + // do + // { + // deviceCredentials = DeviceIdManager.LoadDeviceCredentials() ?? + // DeviceIdManager.RegisterDevice(); + // } while (deviceCredentials.UserName.Password.Contains(";") + // || deviceCredentials.UserName.Password.Contains("=") + // || deviceCredentials.UserName.Password.Contains(" ") + // || deviceCredentials.UserName.UserName.Contains(";") + // || deviceCredentials.UserName.UserName.Contains("=") + // || deviceCredentials.UserName.UserName.Contains(" ")); + // } - if (detail.UseIfd && !string.IsNullOrEmpty(detail.HomeRealmUrl)) - { - homeRealmUrl = detail.HomeRealmUrl; - } + // if (detail.UseIfd && !string.IsNullOrEmpty(detail.HomeRealmUrl)) + // { + // homeRealmUrl = detail.HomeRealmUrl; + // } - Uri serviceUri = new Uri(serviceUrl); - Uri homeRealmUri = homeRealmUrl == null ? null : Uri.IsWellFormedUriString(homeRealmUrl, UriKind.RelativeOrAbsolute) ? new Uri(homeRealmUrl) : null; - return new OrganizationServiceProxy(serviceUri, homeRealmUri, clientCredentials, deviceCredentials); - } + // Uri serviceUri = new Uri(serviceUrl); + // Uri homeRealmUri = homeRealmUrl == null ? null : Uri.IsWellFormedUriString(homeRealmUrl, UriKind.RelativeOrAbsolute) ? new Uri(homeRealmUrl) : null; + // return new OrganizationServiceProxy(serviceUri, homeRealmUri, clientCredentials, deviceCredentials); + //} - public static async Task GetOrganizationServiceProxyAsync(ConnectionDetail detail) - { - var task = Task.Run(() => GetOrganizationServiceProxy(detail)); - return await task; - } + //public static async Task GetOrganizationServiceProxyAsync(ConnectionDetail detail) + //{ + // var task = Task.Run(() => GetOrganizationServiceProxy(detail)); + // return await task; + //} - public static async Task GetDiscoveryServiceAsync(ConnectionDetail detail) - { - var task = Task.Run(() => GetDiscoveryService(detail)); - return await task; - } + //public static async Task GetDiscoveryServiceAsync(ConnectionDetail detail) + //{ + // var task = Task.Run(() => GetDiscoveryService(detail)); + // return await task; + //} - public static DiscoveryServiceProxy GetDiscoveryService(ConnectionDetail detail) { + //public static DiscoveryServiceProxy GetDiscoveryService(ConnectionDetail detail) { - var serviceUrl = detail.GetDiscoveryServiceUrl(); - string homeRealmUrl = null; - ClientCredentials clientCredentials = new ClientCredentials(); - ClientCredentials deviceCredentials = null; + // var serviceUrl = detail.GetDiscoveryServiceUrl(); + // string homeRealmUrl = null; + // ClientCredentials clientCredentials = new ClientCredentials(); + // ClientCredentials deviceCredentials = null; - if (detail.IsCustomAuth) - { - string username = detail.UserName; - if (!string.IsNullOrEmpty(detail.UserDomain)) - { - username = string.Format("{0}\\{1}", detail.UserDomain, detail.UserName); - } - clientCredentials.UserName.UserName = username; - clientCredentials.UserName.Password = detail.UserPassword; - } + // if (detail.IsCustomAuth) + // { + // string username = detail.UserName; + // if (!string.IsNullOrEmpty(detail.UserDomain)) + // { + // username = string.Format("{0}\\{1}", detail.UserDomain, detail.UserName); + // } + // clientCredentials.UserName.UserName = username; + // clientCredentials.UserName.Password = detail.UserPassword; + // } - if (detail.UseOnline && !detail.UseOsdp) - { - do - { - deviceCredentials = DeviceIdManager.LoadDeviceCredentials() ?? - DeviceIdManager.RegisterDevice(); - } while (deviceCredentials.UserName.Password.Contains(";") - || deviceCredentials.UserName.Password.Contains("=") - || deviceCredentials.UserName.Password.Contains(" ") - || deviceCredentials.UserName.UserName.Contains(";") - || deviceCredentials.UserName.UserName.Contains("=") - || deviceCredentials.UserName.UserName.Contains(" ")); - } + // if (detail.UseOnline && !detail.UseOsdp) + // { + // do + // { + // deviceCredentials = DeviceIdManager.LoadDeviceCredentials() ?? + // DeviceIdManager.RegisterDevice(); + // } while (deviceCredentials.UserName.Password.Contains(";") + // || deviceCredentials.UserName.Password.Contains("=") + // || deviceCredentials.UserName.Password.Contains(" ") + // || deviceCredentials.UserName.UserName.Contains(";") + // || deviceCredentials.UserName.UserName.Contains("=") + // || deviceCredentials.UserName.UserName.Contains(" ")); + // } - if (detail.UseIfd && !string.IsNullOrEmpty(detail.HomeRealmUrl)) - { - homeRealmUrl = detail.HomeRealmUrl; - } + // if (detail.UseIfd && !string.IsNullOrEmpty(detail.HomeRealmUrl)) + // { + // homeRealmUrl = detail.HomeRealmUrl; + // } - Uri serviceUri = new Uri(serviceUrl); - Uri homeRealmUri = homeRealmUrl == null ? null : Uri.IsWellFormedUriString(homeRealmUrl, UriKind.RelativeOrAbsolute) ? new Uri(homeRealmUrl) : null; + // Uri serviceUri = new Uri(serviceUrl); + // Uri homeRealmUri = homeRealmUrl == null ? null : Uri.IsWellFormedUriString(homeRealmUrl, UriKind.RelativeOrAbsolute) ? new Uri(homeRealmUrl) : null; - return new DiscoveryServiceProxy(serviceUri, homeRealmUri, clientCredentials, deviceCredentials); - } + // return new DiscoveryServiceProxy(serviceUri, homeRealmUri, clientCredentials, deviceCredentials); + //} } } diff --git a/CrmConnectionProjects/McTools.Xrm.Connection/CrmConnections.cs b/CrmConnectionProjects/McTools.Xrm.Connection/CrmConnections.cs index c132aff..5011bbd 100644 --- a/CrmConnectionProjects/McTools.Xrm.Connection/CrmConnections.cs +++ b/CrmConnectionProjects/McTools.Xrm.Connection/CrmConnections.cs @@ -1,4 +1,8 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; namespace McTools.Xrm.Connection { @@ -9,72 +13,121 @@ public class CrmConnections { #region Variables - List _connections; + private static readonly object _fileAccess = new object(); - string _proxyAddress; + #endregion Variables - string _proxyPort; + public CrmConnections(string name) + { + Connections = new List(); + Name = name; + } + + public CrmConnections() + { + } + + #region Propriétés + + public bool ByPassProxyOnLocal { get; set; } + + /// + /// Obtient ou définit la liste des connexions + /// + public List Connections { get; set; } + + /// + /// Indicates if this connection list can be updated + /// + public bool IsReadOnly { get; set; } + + public string Name { get; set; } - string _userName; + public string Password { get; set; } - string _password; + public string ProxyAddress { get; set; } - bool _useCustomProxy; + public bool UseCustomProxy { get; set; } - bool _publishAfterUpload = true; + public bool UseDefaultCredentials { get; set; } - bool _ignoreExtensions = false; + public bool UseInternetExplorerProxy { get; set; } - bool _extendedLog = false; + public bool UseMruDisplay { get; set; } - #endregion + public string UserName { get; set; } + public bool PublishAfterUpload { get; set; } + public bool IgnoreExtensions { get; set; } + public bool ExtendedLog { get; set; } - #region Properties + #endregion Propriétés + #region methods - public List Connections + public static CrmConnections LoadFromFile(string filePath) { - get { return _connections; } - set { _connections = value; } + var crmConnections = new CrmConnections("Default"); + + if (!Uri.IsWellFormedUriString(filePath, UriKind.Absolute) && !File.Exists(filePath)) + { + return crmConnections; + } + + using (var fStream = OpenStream(filePath)) + { + return (CrmConnections)XmlSerializerHelper.Deserialize(fStream, typeof(CrmConnections), typeof(ConnectionDetail)); + } } - public string ProxyAddress + public ConnectionDetail CloneConnection(ConnectionDetail detail) { - get { return _proxyAddress; } - set { _proxyAddress = value; } - } + var newDetail = (ConnectionDetail)detail.Clone(); + newDetail.ConnectionId = Guid.NewGuid(); + int cloneId = 0; + string newName; + do + { + cloneId++; + newName = string.Format("{0} ({1})", newDetail.ConnectionName, cloneId); + } while (Connections.Any(c => c.ConnectionName == newName)); - public string ProxyPort - { - get { return _proxyPort; } - set { _proxyPort = value; } - } + newDetail.ConnectionName = newName; + Connections.Add(newDetail); - public string UserName - { - get { return _userName; } - set { _userName = value; } + return newDetail; } - - public string Password + public void SerializeToFile(string filePath) { - get { return _password; } - set { _password = value; } + if (Uri.IsWellFormedUriString(filePath, UriKind.Absolute)) + return; + + lock (_fileAccess) + { + XmlSerializerHelper.SerializeToFile(this, filePath, typeof(ConnectionDetail)); + } } + public override string ToString() + { + return Name; + } - public bool UseCustomProxy + private static Stream OpenStream(string filePath) { - get { return _useCustomProxy; } - set { _useCustomProxy = value; } + if (Uri.IsWellFormedUriString(filePath, UriKind.Absolute)) + { + var req = WebRequest.Create(filePath); + req.Credentials = CredentialCache.DefaultCredentials; + var resp = req.GetResponse(); + return resp.GetResponseStream(); + } + + return File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); } - public bool PublishAfterUpload { get { return _publishAfterUpload; } set { _publishAfterUpload = value; } } - public bool IgnoreExtensions { get { return _ignoreExtensions; } set { _ignoreExtensions = value; } } - public bool ExtendedLog { get { return _extendedLog; } set { _extendedLog = value; } } - #endregion + #endregion methods } } \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection/CrmExceptionHelper.cs b/CrmConnectionProjects/McTools.Xrm.Connection/CrmExceptionHelper.cs index 1bffa66..f8b7ee9 100644 --- a/CrmConnectionProjects/McTools.Xrm.Connection/CrmExceptionHelper.cs +++ b/CrmConnectionProjects/McTools.Xrm.Connection/CrmExceptionHelper.cs @@ -42,4 +42,4 @@ public static string GetErrorMessage(Exception error, bool returnWithStackTrace) } } } -} +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection/CryptoManager.cs b/CrmConnectionProjects/McTools.Xrm.Connection/CryptoManager.cs index 78ff615..ee05070 100644 --- a/CrmConnectionProjects/McTools.Xrm.Connection/CryptoManager.cs +++ b/CrmConnectionProjects/McTools.Xrm.Connection/CryptoManager.cs @@ -5,14 +5,13 @@ namespace McTools.Xrm.Connection { - class CryptoManager + internal class CryptoManager { /// - /// Encrypts specified plaintext using Rijndael symmetric key algorithm - /// and returns a base64-encoded result. + /// Decrypts specified ciphertext using Rijndael symmetric key algorithm. /// - /// - /// Plaintext value to be encrypted. + /// + /// Base64-formatted ciphertext value. /// /// /// Passphrase from which a pseudo-random password will be derived. The @@ -34,17 +33,24 @@ class CryptoManager /// /// /// Initialization vector (or IV). This value is required to encrypt the - /// first block of plaintext data. For RijndaelManaged class IV must be + /// first block of plaintext data. For RijndaelManaged class IV must be /// exactly 16 ASCII characters long. /// /// - /// Size of encryption key in bits. Allowed values are: 128, 192, and 256. + /// Size of encryption key in bits. Allowed values are: 128, 192, and 256. /// Longer keys are more secure than shorter keys. /// /// - /// Encrypted value formatted as a base64-encoded string. + /// Decrypted string value. /// - public static string Encrypt(string plainText, + /// + /// Most of the logic in this function is similar to the Encrypt + /// logic. In order for decryption to work, all parameters of this function + /// - except cipherText value - must match the corresponding parameters of + /// the Encrypt function which was called to generate the + /// ciphertext. + /// + public static string Decrypt(string cipherText, string passPhrase, string saltValue, string hashAlgorithm, @@ -52,21 +58,21 @@ public static string Encrypt(string plainText, string initVector, int keySize) { - // Convert strings into byte arrays. - // Let us assume that strings only contain ASCII codes. - // If strings include Unicode characters, use Unicode, UTF7, or UTF8 + // Convert strings defining encryption key characteristics into byte + // arrays. Let us assume that strings only contain ASCII codes. + // If strings include Unicode characters, use Unicode, UTF7, or UTF8 // encoding. byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector); byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue); - // Convert our plaintext into a byte array. - // Let us assume that plaintext contains UTF8-encoded characters. - byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText); + // Convert our ciphertext into a byte array. + byte[] cipherTextBytes = Convert.FromBase64String(cipherText); - // First, we must create a password, from which the key will be derived. - // This password will be generated from the specified passphrase and - // salt value. The password will be created using the specified hash - // algorithm. Password creation can be done in several iterations. + // First, we must create a password, from which the key will be + // derived. This password will be generated from the specified + // passphrase and salt value. The password will be created using + // the specified hash algorithm. Password creation can be done in + // several iterations. PasswordDeriveBytes password = new PasswordDeriveBytes( passPhrase, saltValueBytes, @@ -84,45 +90,51 @@ public static string Encrypt(string plainText, // (CBC). Use default options for other symmetric key parameters. symmetricKey.Mode = CipherMode.CBC; - // Generate encryptor from the existing key bytes and initialization - // vector. Key size will be defined based on the number of the key + // Generate decryptor from the existing key bytes and initialization + // vector. Key size will be defined based on the number of the key // bytes. - ICryptoTransform encryptor = symmetricKey.CreateEncryptor( + ICryptoTransform decryptor = symmetricKey.CreateDecryptor( keyBytes, initVectorBytes); // Define memory stream which will be used to hold encrypted data. - MemoryStream memoryStream = new MemoryStream(); + MemoryStream memoryStream = new MemoryStream(cipherTextBytes); - // Define cryptographic stream (always use Write mode for encryption). + // Define cryptographic stream (always use Read mode for encryption). CryptoStream cryptoStream = new CryptoStream(memoryStream, - encryptor, - CryptoStreamMode.Write); - // Start encrypting. - cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length); + decryptor, + CryptoStreamMode.Read); - // Finish encrypting. - cryptoStream.FlushFinalBlock(); + // Since at this point we don't know what the size of decrypted data + // will be, allocate the buffer long enough to hold ciphertext; + // plaintext is never longer than ciphertext. + byte[] plainTextBytes = new byte[cipherTextBytes.Length]; - // Convert our encrypted data from a memory stream into a byte array. - byte[] cipherTextBytes = memoryStream.ToArray(); + // Start decrypting. + int decryptedByteCount = cryptoStream.Read(plainTextBytes, + 0, + plainTextBytes.Length); // Close both streams. memoryStream.Close(); cryptoStream.Close(); - // Convert encrypted data into a base64-encoded string. - string cipherText = Convert.ToBase64String(cipherTextBytes); + // Convert decrypted data into a string. + // Let us assume that the original plaintext string was UTF8-encoded. + string plainText = Encoding.UTF8.GetString(plainTextBytes, + 0, + decryptedByteCount); - // Return encrypted string. - return cipherText; + // Return decrypted string. + return plainText; } /// - /// Decrypts specified ciphertext using Rijndael symmetric key algorithm. + /// Encrypts specified plaintext using Rijndael symmetric key algorithm + /// and returns a base64-encoded result. /// - /// - /// Base64-formatted ciphertext value. + /// + /// Plaintext value to be encrypted. /// /// /// Passphrase from which a pseudo-random password will be derived. The @@ -152,16 +164,9 @@ public static string Encrypt(string plainText, /// Longer keys are more secure than shorter keys. /// /// - /// Decrypted string value. + /// Encrypted value formatted as a base64-encoded string. /// - /// - /// Most of the logic in this function is similar to the Encrypt - /// logic. In order for decryption to work, all parameters of this function - /// - except cipherText value - must match the corresponding parameters of - /// the Encrypt function which was called to generate the - /// ciphertext. - /// - public static string Decrypt(string cipherText, + public static string Encrypt(string plainText, string passPhrase, string saltValue, string hashAlgorithm, @@ -169,21 +174,21 @@ public static string Decrypt(string cipherText, string initVector, int keySize) { - // Convert strings defining encryption key characteristics into byte - // arrays. Let us assume that strings only contain ASCII codes. + // Convert strings into byte arrays. + // Let us assume that strings only contain ASCII codes. // If strings include Unicode characters, use Unicode, UTF7, or UTF8 // encoding. byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector); byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue); - // Convert our ciphertext into a byte array. - byte[] cipherTextBytes = Convert.FromBase64String(cipherText); + // Convert our plaintext into a byte array. + // Let us assume that plaintext contains UTF8-encoded characters. + byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText); - // First, we must create a password, from which the key will be - // derived. This password will be generated from the specified - // passphrase and salt value. The password will be created using - // the specified hash algorithm. Password creation can be done in - // several iterations. + // First, we must create a password, from which the key will be derived. + // This password will be generated from the specified passphrase and + // salt value. The password will be created using the specified hash + // algorithm. Password creation can be done in several iterations. PasswordDeriveBytes password = new PasswordDeriveBytes( passPhrase, saltValueBytes, @@ -201,45 +206,38 @@ public static string Decrypt(string cipherText, // (CBC). Use default options for other symmetric key parameters. symmetricKey.Mode = CipherMode.CBC; - // Generate decryptor from the existing key bytes and initialization - // vector. Key size will be defined based on the number of the key + // Generate encryptor from the existing key bytes and initialization + // vector. Key size will be defined based on the number of the key // bytes. - ICryptoTransform decryptor = symmetricKey.CreateDecryptor( + ICryptoTransform encryptor = symmetricKey.CreateEncryptor( keyBytes, initVectorBytes); // Define memory stream which will be used to hold encrypted data. - MemoryStream memoryStream = new MemoryStream(cipherTextBytes); + MemoryStream memoryStream = new MemoryStream(); - // Define cryptographic stream (always use Read mode for encryption). + // Define cryptographic stream (always use Write mode for encryption). CryptoStream cryptoStream = new CryptoStream(memoryStream, - decryptor, - CryptoStreamMode.Read); + encryptor, + CryptoStreamMode.Write); + // Start encrypting. + cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length); - // Since at this point we don't know what the size of decrypted data - // will be, allocate the buffer long enough to hold ciphertext; - // plaintext is never longer than ciphertext. - byte[] plainTextBytes = new byte[cipherTextBytes.Length]; + // Finish encrypting. + cryptoStream.FlushFinalBlock(); - // Start decrypting. - int decryptedByteCount = cryptoStream.Read(plainTextBytes, - 0, - plainTextBytes.Length); + // Convert our encrypted data from a memory stream into a byte array. + byte[] cipherTextBytes = memoryStream.ToArray(); // Close both streams. memoryStream.Close(); cryptoStream.Close(); - // Convert decrypted data into a string. - // Let us assume that the original plaintext string was UTF8-encoded. - string plainText = Encoding.UTF8.GetString(plainTextBytes, - 0, - decryptedByteCount); + // Convert encrypted data into a base64-encoded string. + string cipherText = Convert.ToBase64String(cipherTextBytes); - // Return decrypted string. - return plainText; + // Return encrypted string. + return cipherText; } - } -} - +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection/DeviceIdManagerDeprecated.cs b/CrmConnectionProjects/McTools.Xrm.Connection/DeviceIdManagerDeprecated.cs new file mode 100644 index 0000000..23d2b4c --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection/DeviceIdManagerDeprecated.cs @@ -0,0 +1,796 @@ +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; + +namespace McTools.Xrm.Connection.Deprecated +{ + /// + /// 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/CrmConnectionProjects/McTools.Xrm.Connection/Forms/PasswordRequestDialog.Designer.cs b/CrmConnectionProjects/McTools.Xrm.Connection/Forms/PasswordRequestDialog.Designer.cs new file mode 100644 index 0000000..4244498 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection/Forms/PasswordRequestDialog.Designer.cs @@ -0,0 +1,234 @@ +namespace McTools.Xrm.Connection.Forms +{ + partial class PasswordRequestDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.pnlHeader = new System.Windows.Forms.Panel(); + this.label2 = new System.Windows.Forms.Label(); + this.lblHeaderTitle = new System.Windows.Forms.Label(); + this.pnlFooter = new System.Windows.Forms.Panel(); + this.bCancel = new System.Windows.Forms.Button(); + this.bValidate = new System.Windows.Forms.Button(); + this.pnlMain = new System.Windows.Forms.Panel(); + this.pnlReason = new System.Windows.Forms.Panel(); + this.lblReason = new System.Windows.Forms.Label(); + this.pnlDecision = new System.Windows.Forms.Panel(); + this.rdbThisSession = new System.Windows.Forms.RadioButton(); + this.rdbThisTimeOnly = new System.Windows.Forms.RadioButton(); + this.rdbDoNotAllow = new System.Windows.Forms.RadioButton(); + this.pnlHeader.SuspendLayout(); + this.pnlFooter.SuspendLayout(); + this.pnlMain.SuspendLayout(); + this.pnlReason.SuspendLayout(); + this.pnlDecision.SuspendLayout(); + this.SuspendLayout(); + // + // pnlHeader + // + this.pnlHeader.BackColor = System.Drawing.Color.White; + this.pnlHeader.Controls.Add(this.label2); + this.pnlHeader.Controls.Add(this.lblHeaderTitle); + this.pnlHeader.Dock = System.Windows.Forms.DockStyle.Top; + this.pnlHeader.Location = new System.Drawing.Point(0, 0); + this.pnlHeader.Name = "pnlHeader"; + this.pnlHeader.Size = new System.Drawing.Size(894, 100); + this.pnlHeader.TabIndex = 0; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(15, 59); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(705, 25); + this.label2.TabIndex = 1; + this.label2.Text = "The reason of this request is displayed below. Please provide an answer"; + // + // lblHeaderTitle + // + this.lblHeaderTitle.AutoSize = true; + this.lblHeaderTitle.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblHeaderTitle.Location = new System.Drawing.Point(13, 13); + this.lblHeaderTitle.Name = "lblHeaderTitle"; + this.lblHeaderTitle.Size = new System.Drawing.Size(446, 37); + this.lblHeaderTitle.TabIndex = 0; + this.lblHeaderTitle.Text = "The tool needs your password"; + // + // pnlFooter + // + this.pnlFooter.Controls.Add(this.bCancel); + this.pnlFooter.Controls.Add(this.bValidate); + this.pnlFooter.Dock = System.Windows.Forms.DockStyle.Bottom; + this.pnlFooter.Location = new System.Drawing.Point(0, 501); + this.pnlFooter.Name = "pnlFooter"; + this.pnlFooter.Size = new System.Drawing.Size(894, 60); + this.pnlFooter.TabIndex = 1; + // + // bCancel + // + this.bCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.bCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.bCancel.Location = new System.Drawing.Point(727, 9); + this.bCancel.Margin = new System.Windows.Forms.Padding(7, 6, 7, 6); + this.bCancel.Name = "bCancel"; + this.bCancel.Size = new System.Drawing.Size(151, 44); + this.bCancel.TabIndex = 7; + this.bCancel.Text = "Cancel"; + this.bCancel.UseVisualStyleBackColor = true; + // + // bValidate + // + this.bValidate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.bValidate.DialogResult = System.Windows.Forms.DialogResult.OK; + this.bValidate.Location = new System.Drawing.Point(562, 9); + this.bValidate.Margin = new System.Windows.Forms.Padding(7, 6, 7, 6); + this.bValidate.Name = "bValidate"; + this.bValidate.Size = new System.Drawing.Size(151, 44); + this.bValidate.TabIndex = 6; + this.bValidate.Text = "OK"; + this.bValidate.UseVisualStyleBackColor = true; + this.bValidate.Click += new System.EventHandler(this.bValidate_Click); + // + // pnlMain + // + this.pnlMain.Controls.Add(this.pnlReason); + this.pnlMain.Controls.Add(this.pnlDecision); + this.pnlMain.Dock = System.Windows.Forms.DockStyle.Fill; + this.pnlMain.Location = new System.Drawing.Point(0, 100); + this.pnlMain.Name = "pnlMain"; + this.pnlMain.Padding = new System.Windows.Forms.Padding(10); + this.pnlMain.Size = new System.Drawing.Size(894, 401); + this.pnlMain.TabIndex = 2; + // + // pnlReason + // + this.pnlReason.AutoScroll = true; + this.pnlReason.Controls.Add(this.lblReason); + this.pnlReason.Dock = System.Windows.Forms.DockStyle.Fill; + this.pnlReason.Location = new System.Drawing.Point(10, 10); + this.pnlReason.Name = "pnlReason"; + this.pnlReason.Size = new System.Drawing.Size(874, 257); + this.pnlReason.TabIndex = 2; + // + // lblReason + // + this.lblReason.Dock = System.Windows.Forms.DockStyle.Fill; + this.lblReason.Location = new System.Drawing.Point(0, 0); + this.lblReason.Name = "lblReason"; + this.lblReason.Size = new System.Drawing.Size(874, 257); + this.lblReason.TabIndex = 0; + this.lblReason.Text = "[reason]"; + // + // pnlDecision + // + this.pnlDecision.Controls.Add(this.rdbThisSession); + this.pnlDecision.Controls.Add(this.rdbThisTimeOnly); + this.pnlDecision.Controls.Add(this.rdbDoNotAllow); + this.pnlDecision.Dock = System.Windows.Forms.DockStyle.Bottom; + this.pnlDecision.Location = new System.Drawing.Point(10, 267); + this.pnlDecision.Name = "pnlDecision"; + this.pnlDecision.Padding = new System.Windows.Forms.Padding(10); + this.pnlDecision.Size = new System.Drawing.Size(874, 124); + this.pnlDecision.TabIndex = 1; + // + // rdbThisSession + // + this.rdbThisSession.AutoSize = true; + this.rdbThisSession.Dock = System.Windows.Forms.DockStyle.Top; + this.rdbThisSession.Location = new System.Drawing.Point(10, 68); + this.rdbThisSession.Name = "rdbThisSession"; + this.rdbThisSession.Size = new System.Drawing.Size(854, 29); + this.rdbThisSession.TabIndex = 2; + this.rdbThisSession.Text = "Share my password with ALL tools for this XrmToolBox instance that request it"; + this.rdbThisSession.UseVisualStyleBackColor = true; + // + // rdbThisTimeOnly + // + this.rdbThisTimeOnly.AutoSize = true; + this.rdbThisTimeOnly.Checked = true; + this.rdbThisTimeOnly.Dock = System.Windows.Forms.DockStyle.Top; + this.rdbThisTimeOnly.Location = new System.Drawing.Point(10, 39); + this.rdbThisTimeOnly.Name = "rdbThisTimeOnly"; + this.rdbThisTimeOnly.Size = new System.Drawing.Size(854, 29); + this.rdbThisTimeOnly.TabIndex = 1; + this.rdbThisTimeOnly.TabStop = true; + this.rdbThisTimeOnly.Text = "Share my password this time only"; + this.rdbThisTimeOnly.UseVisualStyleBackColor = true; + // + // rdbDoNotAllow + // + this.rdbDoNotAllow.AutoSize = true; + this.rdbDoNotAllow.Dock = System.Windows.Forms.DockStyle.Top; + this.rdbDoNotAllow.Location = new System.Drawing.Point(10, 10); + this.rdbDoNotAllow.Name = "rdbDoNotAllow"; + this.rdbDoNotAllow.Size = new System.Drawing.Size(854, 29); + this.rdbDoNotAllow.TabIndex = 0; + this.rdbDoNotAllow.Text = "Do NOT share my password"; + this.rdbDoNotAllow.UseVisualStyleBackColor = true; + // + // PasswordRequestDialog + // + this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(894, 561); + this.Controls.Add(this.pnlMain); + this.Controls.Add(this.pnlFooter); + this.Controls.Add(this.pnlHeader); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "PasswordRequestDialog"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Your password is required"; + this.pnlHeader.ResumeLayout(false); + this.pnlHeader.PerformLayout(); + this.pnlFooter.ResumeLayout(false); + this.pnlMain.ResumeLayout(false); + this.pnlReason.ResumeLayout(false); + this.pnlDecision.ResumeLayout(false); + this.pnlDecision.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Panel pnlHeader; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label lblHeaderTitle; + private System.Windows.Forms.Panel pnlFooter; + private System.Windows.Forms.Panel pnlMain; + private System.Windows.Forms.Panel pnlReason; + private System.Windows.Forms.Label lblReason; + private System.Windows.Forms.Panel pnlDecision; + private System.Windows.Forms.RadioButton rdbThisSession; + private System.Windows.Forms.RadioButton rdbThisTimeOnly; + private System.Windows.Forms.RadioButton rdbDoNotAllow; + private System.Windows.Forms.Button bCancel; + private System.Windows.Forms.Button bValidate; + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection/Forms/PasswordRequestDialog.cs b/CrmConnectionProjects/McTools.Xrm.Connection/Forms/PasswordRequestDialog.cs new file mode 100644 index 0000000..f6e316b --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection/Forms/PasswordRequestDialog.cs @@ -0,0 +1,32 @@ +using System.Windows.Forms; + +namespace McTools.Xrm.Connection.Forms +{ + public partial class PasswordRequestDialog : Form + { + private readonly ConnectionDetail _detail; + + public PasswordRequestDialog(string passwordUsageDescription, ConnectionDetail detail, string item) + { + _detail = detail; + + InitializeComponent(); + + lblReason.Text = passwordUsageDescription; + + Text = Text.Replace("password", item); + lblHeaderTitle.Text = lblHeaderTitle.Text.Replace("password", item); + rdbDoNotAllow.Text = rdbDoNotAllow.Text.Replace("password", item); + rdbThisSession.Text = rdbThisSession.Text.Replace("password", item); + rdbThisTimeOnly.Text = rdbThisTimeOnly.Text.Replace("password", item); + } + + public bool Accepted { get; private set; } + + private void bValidate_Click(object sender, System.EventArgs e) + { + Accepted = !rdbDoNotAllow.Checked; + _detail.AllowPasswordSharing = rdbThisSession.Checked; + } + } +} \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection/Forms/PasswordRequestDialog.resx b/CrmConnectionProjects/McTools.Xrm.Connection/Forms/PasswordRequestDialog.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CrmConnectionProjects/McTools.Xrm.Connection/Forms/PasswordRequestDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CrmConnectionProjects/McTools.Xrm.Connection/McTools.Xrm.Connection.csproj b/CrmConnectionProjects/McTools.Xrm.Connection/McTools.Xrm.Connection.csproj index ce9fb26..e0b4a45 100644 --- a/CrmConnectionProjects/McTools.Xrm.Connection/McTools.Xrm.Connection.csproj +++ b/CrmConnectionProjects/McTools.Xrm.Connection/McTools.Xrm.Connection.csproj @@ -10,7 +10,7 @@ Properties McTools.Xrm.Connection McTools.Xrm.Connection - v4.6.1 + v4.6.2 512 false @@ -32,6 +32,16 @@ 1.0.0.%2a false true + Properties\AssemblyInfo.cs + False + False + False + + + + + + true @@ -66,42 +76,86 @@ true - Key.snk + snk.snk - - ..\..\packages\Microsoft.CrmSdk.CoreAssemblies.8.0.1\lib\net45\Microsoft.Crm.Sdk.Proxy.dll + + ..\..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.23\lib\net462\Microsoft.Crm.Sdk.Proxy.dll + ..\..\packages\Microsoft.IdentityModel.7.0.0\lib\net35\microsoft.identitymodel.dll - - ..\..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.22.302111727\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll + + ..\..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.19.8\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll - - ..\..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.22.302111727\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll + + ..\..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.19.8\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll - - ..\..\packages\Microsoft.CrmSdk.CoreAssemblies.8.0.1\lib\net45\Microsoft.Xrm.Sdk.dll + + ..\..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.1.0.38\lib\net462\Microsoft.Rest.ClientRuntime.dll - - ..\..\packages\Microsoft.CrmSdk.Deployment.8.0.0\lib\net45\Microsoft.Xrm.Sdk.Deployment.dll + + ..\..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.23\lib\net462\Microsoft.Xrm.Sdk.dll - - ..\..\packages\Microsoft.CrmSdk.Workflow.8.0.0\lib\net45\Microsoft.Xrm.Sdk.Workflow.dll + + ..\..\packages\Microsoft.CrmSdk.Deployment.9.0.2.23\lib\net462\Microsoft.Xrm.Sdk.Deployment.dll - - ..\..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.8.0.0\lib\net45\Microsoft.Xrm.Tooling.Connector.dll + + ..\..\packages\Microsoft.CrmSdk.Workflow.9.0.2.23\lib\net462\Microsoft.Xrm.Sdk.Workflow.dll + + ..\..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.1.0.38\lib\net462\Microsoft.Xrm.Tooling.Connector.dll + + + ..\..\packages\Microsoft.CrmSdk.XrmTooling.WpfControls.9.1.0.38\lib\net462\Microsoft.Xrm.Tooling.CrmConnectControl.dll + + + ..\..\packages\Microsoft.CrmSdk.XrmTooling.WpfControls.9.1.0.38\lib\net462\Microsoft.Xrm.Tooling.Ui.Styles.dll + + + ..\..\packages\Microsoft.CrmSdk.XrmTooling.WpfControls.9.1.0.38\lib\net462\Microsoft.Xrm.Tooling.WebResourceUtility.dll + + + False + ..\..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll + + + + + + + + + ..\..\packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll + + + + + ..\..\packages\System.Security.Cryptography.Algorithms.4.3.1\lib\net461\System.Security.Cryptography.Algorithms.dll + True + True + + + ..\..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll + + + ..\..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll + + + ..\..\packages\System.Security.Cryptography.X509Certificates.4.3.2\lib\net461\System.Security.Cryptography.X509Certificates.dll + True + True + @@ -112,19 +166,31 @@ + + + + - - + + + Form + + + PasswordRequestDialog.cs + + + + @@ -146,21 +212,26 @@ - + + + + + PasswordRequestDialog.cs + Designer + - - + - + + + diff --git a/CrmConnectionProjects/McTools.Xrm.Connection/packages.config b/CrmConnectionProjects/McTools.Xrm.Connection/packages.config index 0ddbd02..87b204d 100644 --- a/CrmConnectionProjects/McTools.Xrm.Connection/packages.config +++ b/CrmConnectionProjects/McTools.Xrm.Connection/packages.config @@ -1,9 +1,17 @@  - - - - - - + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CrmPublisher.sln b/CrmPublisher.sln index 821979c..1d52be3 100644 --- a/CrmPublisher.sln +++ b/CrmPublisher.sln @@ -1,23 +1,23 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28803.156 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.136 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CrmConnectionProjects", "CrmConnectionProjects", "{73578E88-B589-432E-8BEA-47B0F466244A}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrmWebResourcesUpdater", "CrmWebResourcesUpdater\CrmWebResourcesUpdater.csproj", "{B348D47F-4380-4768-AD52-1E979613B710}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CrmConnectionProjects", "CrmConnectionProjects", "{690E77B2-AC70-4432-98B7-5E76A9C4F406}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "McTools.Xrm.Connection", "CrmConnectionProjects\McTools.Xrm.Connection\McTools.Xrm.Connection.csproj", "{C3824C2C-6E2E-4FDE-A2AA-229BBC7C3B1F}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "McTools.Xrm.Connection.WinForms", "CrmConnectionProjects\McTools.Xrm.Connection.WinForms\McTools.Xrm.Connection.WinForms.csproj", "{EEB5C09F-CEC6-4FB5-87B5-AE61AE89C9EB}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrmWebResourcesUpdater", "CrmWebResourcesUpdater\CrmWebResourcesUpdater.csproj", "{D903D192-561E-49A4-91F4-E900AB626941}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrmWebResourcesUpdater.Services", "CrmWebResourcesUpdater.Helpers\CrmWebResourcesUpdater.Services.csproj", "{8433C7D4-9AB0-47DA-8314-F39D02656C22}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrmWebResourcesUpdater.Common", "CrmWebResourcesUpdater.Common\CrmWebResourcesUpdater.Common.csproj", "{22260532-D32B-4762-86D9-6631E6F23FF4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrmWebResourcesUpdater.Common", "CrmWebResourcesUpdater.Common\CrmWebResourcesUpdater.Common.csproj", "{BEFB0758-1A24-49CC-9C1F-32E9A5351BCF}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrmWebResourcesUpdater.Forms", "CrmWebResourcesUpdater.Forms\CrmWebResourcesUpdater.Forms.csproj", "{80856A2A-E4ED-4459-91C3-C3EC7BCFA2FE}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrmWebResourcesUpdater.Settings", "CrmWebResourcesUpdater.Settings\CrmWebResourcesUpdater.Settings.csproj", "{2CF262F9-D0D9-4C45-84EB-430779973A05}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrmWebResourcesUpdater.Services", "CrmWebResourcesUpdater.Services\CrmWebResourcesUpdater.Services.csproj", "{D9C59FAB-CD1A-484B-8052-1F72CA1DEBB8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrmWebResourcesUpdater.Forms", "CrmWebResourcesUpdater.Froms\CrmWebResourcesUpdater.Forms.csproj", "{668B006C-BD03-4A67-8847-6C3792A97703}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrmWebResourcesUpdater.Settings", "CrmWebResourcesUpdater.Settings\CrmWebResourcesUpdater.Settings.csproj", "{E1A14C0B-41E8-479D-A3F6-B6438AF9D869}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -26,6 +26,12 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B348D47F-4380-4768-AD52-1E979613B710}.Debug Without GemBox|Any CPU.ActiveCfg = Debug|Any CPU + {B348D47F-4380-4768-AD52-1E979613B710}.Debug Without GemBox|Any CPU.Build.0 = Debug|Any CPU + {B348D47F-4380-4768-AD52-1E979613B710}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B348D47F-4380-4768-AD52-1E979613B710}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B348D47F-4380-4768-AD52-1E979613B710}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B348D47F-4380-4768-AD52-1E979613B710}.Release|Any CPU.Build.0 = Release|Any CPU {C3824C2C-6E2E-4FDE-A2AA-229BBC7C3B1F}.Debug Without GemBox|Any CPU.ActiveCfg = Debug Without GemBox|Any CPU {C3824C2C-6E2E-4FDE-A2AA-229BBC7C3B1F}.Debug Without GemBox|Any CPU.Build.0 = Debug Without GemBox|Any CPU {C3824C2C-6E2E-4FDE-A2AA-229BBC7C3B1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU @@ -38,45 +44,39 @@ Global {EEB5C09F-CEC6-4FB5-87B5-AE61AE89C9EB}.Debug|Any CPU.Build.0 = Debug|Any CPU {EEB5C09F-CEC6-4FB5-87B5-AE61AE89C9EB}.Release|Any CPU.ActiveCfg = Release|Any CPU {EEB5C09F-CEC6-4FB5-87B5-AE61AE89C9EB}.Release|Any CPU.Build.0 = Release|Any CPU - {D903D192-561E-49A4-91F4-E900AB626941}.Debug Without GemBox|Any CPU.ActiveCfg = Debug|Any CPU - {D903D192-561E-49A4-91F4-E900AB626941}.Debug Without GemBox|Any CPU.Build.0 = Debug|Any CPU - {D903D192-561E-49A4-91F4-E900AB626941}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D903D192-561E-49A4-91F4-E900AB626941}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D903D192-561E-49A4-91F4-E900AB626941}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D903D192-561E-49A4-91F4-E900AB626941}.Release|Any CPU.Build.0 = Release|Any CPU - {8433C7D4-9AB0-47DA-8314-F39D02656C22}.Debug Without GemBox|Any CPU.ActiveCfg = Debug|Any CPU - {8433C7D4-9AB0-47DA-8314-F39D02656C22}.Debug Without GemBox|Any CPU.Build.0 = Debug|Any CPU - {8433C7D4-9AB0-47DA-8314-F39D02656C22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8433C7D4-9AB0-47DA-8314-F39D02656C22}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8433C7D4-9AB0-47DA-8314-F39D02656C22}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8433C7D4-9AB0-47DA-8314-F39D02656C22}.Release|Any CPU.Build.0 = Release|Any CPU - {BEFB0758-1A24-49CC-9C1F-32E9A5351BCF}.Debug Without GemBox|Any CPU.ActiveCfg = Debug|Any CPU - {BEFB0758-1A24-49CC-9C1F-32E9A5351BCF}.Debug Without GemBox|Any CPU.Build.0 = Debug|Any CPU - {BEFB0758-1A24-49CC-9C1F-32E9A5351BCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BEFB0758-1A24-49CC-9C1F-32E9A5351BCF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BEFB0758-1A24-49CC-9C1F-32E9A5351BCF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BEFB0758-1A24-49CC-9C1F-32E9A5351BCF}.Release|Any CPU.Build.0 = Release|Any CPU - {2CF262F9-D0D9-4C45-84EB-430779973A05}.Debug Without GemBox|Any CPU.ActiveCfg = Debug|Any CPU - {2CF262F9-D0D9-4C45-84EB-430779973A05}.Debug Without GemBox|Any CPU.Build.0 = Debug|Any CPU - {2CF262F9-D0D9-4C45-84EB-430779973A05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2CF262F9-D0D9-4C45-84EB-430779973A05}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2CF262F9-D0D9-4C45-84EB-430779973A05}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2CF262F9-D0D9-4C45-84EB-430779973A05}.Release|Any CPU.Build.0 = Release|Any CPU - {668B006C-BD03-4A67-8847-6C3792A97703}.Debug Without GemBox|Any CPU.ActiveCfg = Debug|Any CPU - {668B006C-BD03-4A67-8847-6C3792A97703}.Debug Without GemBox|Any CPU.Build.0 = Debug|Any CPU - {668B006C-BD03-4A67-8847-6C3792A97703}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {668B006C-BD03-4A67-8847-6C3792A97703}.Debug|Any CPU.Build.0 = Debug|Any CPU - {668B006C-BD03-4A67-8847-6C3792A97703}.Release|Any CPU.ActiveCfg = Release|Any CPU - {668B006C-BD03-4A67-8847-6C3792A97703}.Release|Any CPU.Build.0 = Release|Any CPU + {22260532-D32B-4762-86D9-6631E6F23FF4}.Debug Without GemBox|Any CPU.ActiveCfg = Debug|Any CPU + {22260532-D32B-4762-86D9-6631E6F23FF4}.Debug Without GemBox|Any CPU.Build.0 = Debug|Any CPU + {22260532-D32B-4762-86D9-6631E6F23FF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {22260532-D32B-4762-86D9-6631E6F23FF4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {22260532-D32B-4762-86D9-6631E6F23FF4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {22260532-D32B-4762-86D9-6631E6F23FF4}.Release|Any CPU.Build.0 = Release|Any CPU + {80856A2A-E4ED-4459-91C3-C3EC7BCFA2FE}.Debug Without GemBox|Any CPU.ActiveCfg = Debug|Any CPU + {80856A2A-E4ED-4459-91C3-C3EC7BCFA2FE}.Debug Without GemBox|Any CPU.Build.0 = Debug|Any CPU + {80856A2A-E4ED-4459-91C3-C3EC7BCFA2FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {80856A2A-E4ED-4459-91C3-C3EC7BCFA2FE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {80856A2A-E4ED-4459-91C3-C3EC7BCFA2FE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {80856A2A-E4ED-4459-91C3-C3EC7BCFA2FE}.Release|Any CPU.Build.0 = Release|Any CPU + {D9C59FAB-CD1A-484B-8052-1F72CA1DEBB8}.Debug Without GemBox|Any CPU.ActiveCfg = Debug|Any CPU + {D9C59FAB-CD1A-484B-8052-1F72CA1DEBB8}.Debug Without GemBox|Any CPU.Build.0 = Debug|Any CPU + {D9C59FAB-CD1A-484B-8052-1F72CA1DEBB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D9C59FAB-CD1A-484B-8052-1F72CA1DEBB8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D9C59FAB-CD1A-484B-8052-1F72CA1DEBB8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D9C59FAB-CD1A-484B-8052-1F72CA1DEBB8}.Release|Any CPU.Build.0 = Release|Any CPU + {E1A14C0B-41E8-479D-A3F6-B6438AF9D869}.Debug Without GemBox|Any CPU.ActiveCfg = Debug|Any CPU + {E1A14C0B-41E8-479D-A3F6-B6438AF9D869}.Debug Without GemBox|Any CPU.Build.0 = Debug|Any CPU + {E1A14C0B-41E8-479D-A3F6-B6438AF9D869}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E1A14C0B-41E8-479D-A3F6-B6438AF9D869}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E1A14C0B-41E8-479D-A3F6-B6438AF9D869}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E1A14C0B-41E8-479D-A3F6-B6438AF9D869}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {C3824C2C-6E2E-4FDE-A2AA-229BBC7C3B1F} = {73578E88-B589-432E-8BEA-47B0F466244A} - {EEB5C09F-CEC6-4FB5-87B5-AE61AE89C9EB} = {73578E88-B589-432E-8BEA-47B0F466244A} + {C3824C2C-6E2E-4FDE-A2AA-229BBC7C3B1F} = {690E77B2-AC70-4432-98B7-5E76A9C4F406} + {EEB5C09F-CEC6-4FB5-87B5-AE61AE89C9EB} = {690E77B2-AC70-4432-98B7-5E76A9C4F406} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {883C5138-F27E-44C7-8FFA-A94C203D8FE1} + SolutionGuid = {FFF87AB1-3086-4963-BA40-B3EB63038338} EndGlobalSection EndGlobal diff --git a/CrmWebResourcesUpdater.Common/CrmWebResourcesUpdater.Common.csproj b/CrmWebResourcesUpdater.Common/CrmWebResourcesUpdater.Common.csproj index 67f58ec..14faeb2 100644 --- a/CrmWebResourcesUpdater.Common/CrmWebResourcesUpdater.Common.csproj +++ b/CrmWebResourcesUpdater.Common/CrmWebResourcesUpdater.Common.csproj @@ -1,21 +1,19 @@  - + Debug AnyCPU - {BEFB0758-1A24-49CC-9C1F-32E9A5351BCF} + {22260532-D32B-4762-86D9-6631E6F23FF4} Library Properties CrmWebResourcesUpdater.Common CrmWebResourcesUpdater.Common - v4.6.1 + v4.6.2 512 - SAK - SAK - SAK - SAK - + true + + true @@ -34,105 +32,106 @@ prompt 4 - - true - - - Key.snk - - - ..\packages\Microsoft.VisualStudio.Imaging.14.3.25407\lib\net45\Microsoft.VisualStudio.Imaging.dll + + ..\packages\Microsoft.VisualStudio.CoreUtility.15.6.27740\lib\net46\Microsoft.VisualStudio.CoreUtility.dll - - ..\packages\Microsoft.VisualStudio.Shell.14.0.14.3.25407\lib\Microsoft.VisualStudio.Shell.14.0.dll + + ..\packages\Microsoft.VisualStudio.ImageCatalog.15.9.28307\lib\net45\Microsoft.VisualStudio.ImageCatalog.dll - - ..\packages\Microsoft.VisualStudio.Shell.Framework.16.0.28729\lib\net45\Microsoft.VisualStudio.Shell.Framework.dll + + ..\packages\Microsoft.VisualStudio.Imaging.15.9.28307\lib\net45\Microsoft.VisualStudio.Imaging.dll - - ..\packages\Microsoft.VisualStudio.Shell.Immutable.10.0.10.0.30319\lib\net40\Microsoft.VisualStudio.Shell.Immutable.10.0.dll + + ..\packages\Microsoft.VisualStudio.Imaging.Interop.14.0.DesignTime.14.3.26930\lib\net20\Microsoft.VisualStudio.Imaging.Interop.14.0.DesignTime.dll + True - - ..\packages\Microsoft.VisualStudio.Shell.Immutable.11.0.11.0.50727\lib\net45\Microsoft.VisualStudio.Shell.Immutable.11.0.dll + + ..\packages\Microsoft.VisualStudio.OLE.Interop.7.10.6071\lib\Microsoft.VisualStudio.OLE.Interop.dll - - ..\packages\Microsoft.VisualStudio.Shell.Immutable.12.0.12.0.21003\lib\net45\Microsoft.VisualStudio.Shell.Immutable.12.0.dll + + ..\packages\Microsoft.VisualStudio.Shell.15.0.15.9.28307\lib\net45\Microsoft.VisualStudio.Shell.15.0.dll - - ..\packages\Microsoft.VisualStudio.Shell.Immutable.14.0.14.3.25407\lib\net45\Microsoft.VisualStudio.Shell.Immutable.14.0.dll + + ..\packages\Microsoft.VisualStudio.Shell.Framework.15.9.28307\lib\net45\Microsoft.VisualStudio.Shell.Framework.dll - ..\packages\Microsoft.VisualStudio.Shell.Interop.7.10.6071\lib\Microsoft.VisualStudio.Shell.Interop.dll + ..\packages\Microsoft.VisualStudio.Shell.Interop.7.10.6072\lib\net11\Microsoft.VisualStudio.Shell.Interop.dll + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.10.0.10.0.30320\lib\net20\Microsoft.VisualStudio.Shell.Interop.10.0.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.11.0.11.0.61031\lib\net20\Microsoft.VisualStudio.Shell.Interop.11.0.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.12.0.12.0.30111\lib\net20\Microsoft.VisualStudio.Shell.Interop.12.0.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime.14.3.26929\lib\net20\Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime.15.0.26929\lib\net20\Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.15.6.DesignTime.15.6.27413\lib\net20\Microsoft.VisualStudio.Shell.Interop.15.6.DesignTime.dll + True - ..\packages\Microsoft.VisualStudio.Shell.Interop.8.0.8.0.50727\lib\Microsoft.VisualStudio.Shell.Interop.8.0.dll + ..\packages\Microsoft.VisualStudio.Shell.Interop.8.0.8.0.50728\lib\net11\Microsoft.VisualStudio.Shell.Interop.8.0.dll - ..\packages\Microsoft.VisualStudio.Shell.Interop.9.0.9.0.30729\lib\Microsoft.VisualStudio.Shell.Interop.9.0.dll + ..\packages\Microsoft.VisualStudio.Shell.Interop.9.0.9.0.30730\lib\net11\Microsoft.VisualStudio.Shell.Interop.9.0.dll + + + ..\packages\Microsoft.VisualStudio.Text.Data.15.6.27740\lib\net46\Microsoft.VisualStudio.Text.Data.dll - ..\packages\Microsoft.VisualStudio.TextManager.Interop.7.10.6070\lib\Microsoft.VisualStudio.TextManager.Interop.dll + ..\packages\Microsoft.VisualStudio.TextManager.Interop.7.10.6071\lib\net11\Microsoft.VisualStudio.TextManager.Interop.dll - ..\packages\Microsoft.VisualStudio.TextManager.Interop.8.0.8.0.50727\lib\Microsoft.VisualStudio.TextManager.Interop.8.0.dll + ..\packages\Microsoft.VisualStudio.TextManager.Interop.8.0.8.0.50728\lib\net11\Microsoft.VisualStudio.TextManager.Interop.8.0.dll - - - ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll + + ..\packages\Microsoft.VisualStudio.Threading.15.8.122\lib\net46\Microsoft.VisualStudio.Threading.dll - - ..\packages\StreamJsonRpc.1.5.43\lib\net46\StreamJsonRpc.dll + + ..\packages\Microsoft.VisualStudio.Utilities.15.9.28307\lib\net46\Microsoft.VisualStudio.Utilities.dll - - - ..\packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll + + ..\packages\Microsoft.VisualStudio.Validation.15.3.15\lib\net45\Microsoft.VisualStudio.Validation.dll + + + ..\packages\Newtonsoft.Json.6.0.6\lib\net45\Newtonsoft.Json.dll + + + ..\packages\StreamJsonRpc.1.3.23\lib\net45\StreamJsonRpc.dll + - - ..\packages\System.IO.4.3.0\lib\net462\System.IO.dll - True - True - - - ..\packages\System.Net.Http.4.3.3\lib\net46\System.Net.Http.dll - True - True - - - ..\packages\System.Runtime.4.3.0\lib\net462\System.Runtime.dll - True - True - - - - ..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net463\System.Security.Cryptography.Algorithms.dll - True - True + + ..\packages\System.Security.Cryptography.Algorithms.4.3.1\lib\net461\System.Security.Cryptography.Algorithms.dll ..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll - True - True ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll - True - True - - - ..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll - True - True - - ..\packages\System.Threading.Tasks.Extensions.4.3.0\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll + + ..\packages\System.Security.Cryptography.X509Certificates.4.3.2\lib\net461\System.Security.Cryptography.X509Certificates.dll + @@ -145,23 +144,21 @@ - - - {c3824c2c-6e2e-4fde-a2aa-229bbc7c3b1f} - McTools.Xrm.Connection - - - + + + - + \ No newline at end of file diff --git a/CrmWebResourcesUpdater.Common/Properties/AssemblyInfo.cs b/CrmWebResourcesUpdater.Common/Properties/AssemblyInfo.cs index 1f9f722..e72eb1e 100644 --- a/CrmWebResourcesUpdater.Common/Properties/AssemblyInfo.cs +++ b/CrmWebResourcesUpdater.Common/Properties/AssemblyInfo.cs @@ -2,7 +2,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("CrmWebResourcesUpdater.Common")] @@ -10,26 +10,26 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("CrmWebResourcesUpdater.Common")] -[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyCopyright("Copyright © 2020")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("befb0758-1a24-49cc-9c1f-32e9a5351bcf")] +[assembly: Guid("22260532-d32b-4762-86d9-6631e6f23ff4")] // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // -// You can specify all the values or you can default the Build and Revision Numbers +// You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] diff --git a/CrmWebResourcesUpdater.Common/app.config b/CrmWebResourcesUpdater.Common/app.config index cbbf1ef..58d60c2 100644 --- a/CrmWebResourcesUpdater.Common/app.config +++ b/CrmWebResourcesUpdater.Common/app.config @@ -4,32 +4,12 @@ - + - - - - - - - - - - - - - - - - - - - - - - + + - + \ No newline at end of file diff --git a/CrmWebResourcesUpdater.Common/packages.config b/CrmWebResourcesUpdater.Common/packages.config index 4fd943c..99ace2d 100644 --- a/CrmWebResourcesUpdater.Common/packages.config +++ b/CrmWebResourcesUpdater.Common/packages.config @@ -1,32 +1,33 @@  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CrmWebResourcesUpdater.Froms/CreateWebResourceForm.Designer.cs b/CrmWebResourcesUpdater.Forms/CreateWebResourceForm.Designer.cs similarity index 100% rename from CrmWebResourcesUpdater.Froms/CreateWebResourceForm.Designer.cs rename to CrmWebResourcesUpdater.Forms/CreateWebResourceForm.Designer.cs diff --git a/CrmWebResourcesUpdater.Froms/CreateWebResourceForm.cs b/CrmWebResourcesUpdater.Forms/CreateWebResourceForm.cs similarity index 100% rename from CrmWebResourcesUpdater.Froms/CreateWebResourceForm.cs rename to CrmWebResourcesUpdater.Forms/CreateWebResourceForm.cs diff --git a/CrmWebResourcesUpdater.Forms/CreateWebResourceForm.resx b/CrmWebResourcesUpdater.Forms/CreateWebResourceForm.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CrmWebResourcesUpdater.Forms/CreateWebResourceForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CrmWebResourcesUpdater.Froms/CrmWebResourcesUpdater.Forms.csproj b/CrmWebResourcesUpdater.Forms/CrmWebResourcesUpdater.Forms.csproj similarity index 63% rename from CrmWebResourcesUpdater.Froms/CrmWebResourcesUpdater.Forms.csproj rename to CrmWebResourcesUpdater.Forms/CrmWebResourcesUpdater.Forms.csproj index 74c23c2..c73ec5a 100644 --- a/CrmWebResourcesUpdater.Froms/CrmWebResourcesUpdater.Forms.csproj +++ b/CrmWebResourcesUpdater.Forms/CrmWebResourcesUpdater.Forms.csproj @@ -4,12 +4,12 @@ Debug AnyCPU - {668B006C-BD03-4A67-8847-6C3792A97703} + {80856A2A-E4ED-4459-91C3-C3EC7BCFA2FE} Library Properties - CrmWebResourcesUpdater.Froms - CrmWebResourcesUpdater.Froms - v4.6.1 + CrmWebResourcesUpdater.Forms + CrmWebResourcesUpdater.Forms + v4.6.2 512 true @@ -30,21 +30,12 @@ prompt 4 - - true - - - Key.snk - - - ..\packages\Microsoft.CrmSdk.CoreAssemblies.8.0.1\lib\net45\Microsoft.Crm.Sdk.Proxy.dll - - - ..\packages\Microsoft.IdentityModel.7.0.0\lib\net35\microsoft.identitymodel.dll + + ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.23\lib\net462\Microsoft.Crm.Sdk.Proxy.dll - - ..\packages\Microsoft.CrmSdk.CoreAssemblies.8.0.1\lib\net45\Microsoft.Xrm.Sdk.dll + + ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.23\lib\net462\Microsoft.Xrm.Sdk.dll @@ -54,6 +45,18 @@ + + ..\packages\System.Security.Cryptography.Algorithms.4.3.1\lib\net461\System.Security.Cryptography.Algorithms.dll + + + ..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll + + + ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll + + + ..\packages\System.Security.Cryptography.X509Certificates.4.3.2\lib\net461\System.Security.Cryptography.X509Certificates.dll + @@ -79,16 +82,15 @@ CreateWebResourceForm.cs + + + + - {BEFB0758-1A24-49CC-9C1F-32E9A5351BCF} + {22260532-d32b-4762-86d9-6631e6f23ff4} CrmWebResourcesUpdater.Common - - - - - \ No newline at end of file diff --git a/CrmWebResourcesUpdater.Forms/Properties/AssemblyInfo.cs b/CrmWebResourcesUpdater.Forms/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..ef33cf5 --- /dev/null +++ b/CrmWebResourcesUpdater.Forms/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CrmWebResourcesUpdater.Forms")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CrmWebResourcesUpdater.Forms")] +[assembly: AssemblyCopyright("Copyright © 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("80856a2a-e4ed-4459-91c3-c3ec7bcfa2fe")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/CrmWebResourcesUpdater.Forms/app.config b/CrmWebResourcesUpdater.Forms/app.config new file mode 100644 index 0000000..58d60c2 --- /dev/null +++ b/CrmWebResourcesUpdater.Forms/app.config @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CrmWebResourcesUpdater.Forms/packages.config b/CrmWebResourcesUpdater.Forms/packages.config new file mode 100644 index 0000000..08e76d8 --- /dev/null +++ b/CrmWebResourcesUpdater.Forms/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/CrmWebResourcesUpdater.Froms/Properties/AssemblyInfo.cs b/CrmWebResourcesUpdater.Froms/Properties/AssemblyInfo.cs deleted file mode 100644 index 7d68fea..0000000 --- a/CrmWebResourcesUpdater.Froms/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// Общие сведения об этой сборке предоставляются следующим набором -// набора атрибутов. Измените значения этих атрибутов для изменения сведений, -// связанные со сборкой. -[assembly: AssemblyTitle("CrmWebResourcesUpdater.Forms")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("CrmWebResourcesUpdater.Forms")] -[assembly: AssemblyCopyright("Copyright © 2019")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Установка значения False для параметра ComVisible делает типы в этой сборке невидимыми -// для компонентов COM. Если необходимо обратиться к типу в этой сборке через -// COM, задайте атрибуту ComVisible значение TRUE для этого типа. -[assembly: ComVisible(false)] - -// Следующий GUID служит для идентификации библиотеки типов, если этот проект будет видимым для COM -[assembly: Guid("668b006c-bd03-4a67-8847-6c3792a97703")] - -// Сведения о версии сборки состоят из указанных ниже четырех значений: -// -// Основной номер версии -// Дополнительный номер версии -// Номер сборки -// Редакция -// -// Можно задать все значения или принять номера сборки и редакции по умолчанию -// используя "*", как показано ниже: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/CrmWebResourcesUpdater.Froms/packages.config b/CrmWebResourcesUpdater.Froms/packages.config deleted file mode 100644 index 94da683..0000000 --- a/CrmWebResourcesUpdater.Froms/packages.config +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/CrmWebResourcesUpdater.Services/CrmWebResourcesUpdater.Services.csproj b/CrmWebResourcesUpdater.Services/CrmWebResourcesUpdater.Services.csproj new file mode 100644 index 0000000..0339050 --- /dev/null +++ b/CrmWebResourcesUpdater.Services/CrmWebResourcesUpdater.Services.csproj @@ -0,0 +1,237 @@ + + + + + Debug + AnyCPU + {D9C59FAB-CD1A-484B-8052-1F72CA1DEBB8} + Library + Properties + CrmWebResourcesUpdater.Services + CrmWebResourcesUpdater.Services + v4.6.2 + 512 + true + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + True + + + True + + + ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.23\lib\net462\Microsoft.Crm.Sdk.Proxy.dll + + + ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.19.8\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll + + + ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.19.8\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll + + + ..\packages\Microsoft.Rest.ClientRuntime.2.3.21\lib\net461\Microsoft.Rest.ClientRuntime.dll + + + ..\packages\Microsoft.VisualStudio.CoreUtility.15.6.27740\lib\net46\Microsoft.VisualStudio.CoreUtility.dll + + + ..\packages\Microsoft.VisualStudio.ImageCatalog.15.9.28307\lib\net45\Microsoft.VisualStudio.ImageCatalog.dll + + + ..\packages\Microsoft.VisualStudio.Imaging.15.9.28307\lib\net45\Microsoft.VisualStudio.Imaging.dll + + + ..\packages\Microsoft.VisualStudio.Imaging.Interop.14.0.DesignTime.14.3.26930\lib\net20\Microsoft.VisualStudio.Imaging.Interop.14.0.DesignTime.dll + True + + + ..\packages\Microsoft.VisualStudio.OLE.Interop.7.10.6071\lib\Microsoft.VisualStudio.OLE.Interop.dll + + + ..\packages\Microsoft.VisualStudio.Shell.15.0.15.9.28307\lib\net45\Microsoft.VisualStudio.Shell.15.0.dll + + + ..\packages\Microsoft.VisualStudio.Shell.Framework.15.9.28307\lib\net45\Microsoft.VisualStudio.Shell.Framework.dll + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.7.10.6072\lib\net11\Microsoft.VisualStudio.Shell.Interop.dll + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.10.0.10.0.30320\lib\net20\Microsoft.VisualStudio.Shell.Interop.10.0.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.11.0.11.0.61031\lib\net20\Microsoft.VisualStudio.Shell.Interop.11.0.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.12.0.12.0.30111\lib\net20\Microsoft.VisualStudio.Shell.Interop.12.0.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime.14.3.26929\lib\net20\Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime.15.0.26929\lib\net20\Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.15.6.DesignTime.15.6.27413\lib\net20\Microsoft.VisualStudio.Shell.Interop.15.6.DesignTime.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.8.0.8.0.50728\lib\net11\Microsoft.VisualStudio.Shell.Interop.8.0.dll + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.9.0.9.0.30730\lib\net11\Microsoft.VisualStudio.Shell.Interop.9.0.dll + + + ..\packages\Microsoft.VisualStudio.Text.Data.15.6.27740\lib\net46\Microsoft.VisualStudio.Text.Data.dll + + + ..\packages\Microsoft.VisualStudio.TextManager.Interop.7.10.6071\lib\net11\Microsoft.VisualStudio.TextManager.Interop.dll + + + ..\packages\Microsoft.VisualStudio.TextManager.Interop.8.0.8.0.50728\lib\net11\Microsoft.VisualStudio.TextManager.Interop.8.0.dll + + + ..\packages\Microsoft.VisualStudio.Threading.15.8.122\lib\net46\Microsoft.VisualStudio.Threading.dll + + + ..\packages\Microsoft.VisualStudio.Utilities.15.9.28307\lib\net46\Microsoft.VisualStudio.Utilities.dll + + + ..\packages\Microsoft.VisualStudio.Validation.15.3.15\lib\net45\Microsoft.VisualStudio.Validation.dll + + + ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.23\lib\net462\Microsoft.Xrm.Sdk.dll + + + ..\packages\Microsoft.CrmSdk.Deployment.9.0.2.23\lib\net462\Microsoft.Xrm.Sdk.Deployment.dll + + + ..\packages\Microsoft.CrmSdk.Workflow.9.0.2.23\lib\net462\Microsoft.Xrm.Sdk.Workflow.dll + + + ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.1.0.38\lib\net462\Microsoft.Xrm.Tooling.Connector.dll + + + ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll + + + + ..\packages\StreamJsonRpc.1.3.23\lib\net45\StreamJsonRpc.dll + + + + + + + + + + + + + ..\packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll + + + + + + + ..\packages\System.Security.Cryptography.Algorithms.4.3.1\lib\net461\System.Security.Cryptography.Algorithms.dll + + + ..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll + + + ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll + + + ..\packages\System.Security.Cryptography.X509Certificates.4.3.2\lib\net461\System.Security.Cryptography.X509Certificates.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {eeb5c09f-cec6-4fb5-87b5-ae61ae89c9eb} + McTools.Xrm.Connection.WinForms + + + {c3824c2c-6e2e-4fde-a2aa-229bbc7c3b1f} + McTools.Xrm.Connection + + + {22260532-d32b-4762-86d9-6631e6f23ff4} + CrmWebResourcesUpdater.Common + + + {80856a2a-e4ed-4459-91c3-c3ec7bcfa2fe} + CrmWebResourcesUpdater.Forms + + + {e1a14c0b-41e8-479d-a3f6-b6438af9d869} + CrmWebResourcesUpdater.Settings + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + \ No newline at end of file diff --git a/CrmWebResourcesUpdater.Services/Extensions/OrgServiceExtensions.cs b/CrmWebResourcesUpdater.Services/Extensions/OrgServiceExtensions.cs new file mode 100644 index 0000000..23ad17f --- /dev/null +++ b/CrmWebResourcesUpdater.Services/Extensions/OrgServiceExtensions.cs @@ -0,0 +1,39 @@ +using Microsoft.Xrm.Sdk; +using Microsoft.Xrm.Sdk.Client; +using Microsoft.Xrm.Sdk.Query; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CrmWebResourcesUpdater.Services.Extensions +{ + public static class OrgServiceExtensions + { + public static async Task ExecuteAsync(this OrganizationServiceContext context, OrganizationRequest request) + { + var task = Task.Run(() => context.Execute(request)); + return await task; + } + + public static async Task RetrieveMultipleAsync(this IOrganizationService proxy, FetchExpression fetchExpression) + { + var task = Task.Run(() => proxy.RetrieveMultiple(fetchExpression)); + return await task; + } + + public static async Task RetrieveMultipleAsync(this IOrganizationService proxy, QueryExpression queryExpression) + { + var task = Task.Run(() => proxy.RetrieveMultiple(queryExpression)); + return await task; + } + + public static async Task UpdateAsync(this IOrganizationService proxy, Entity entity) + { + var task = Task.Run(() => proxy.Update(entity)); + await task; + } + + } +} diff --git a/CrmWebResourcesUpdater.Services/Helpers/MappingHelper.cs b/CrmWebResourcesUpdater.Services/Helpers/MappingHelper.cs new file mode 100644 index 0000000..3573375 --- /dev/null +++ b/CrmWebResourcesUpdater.Services/Helpers/MappingHelper.cs @@ -0,0 +1,162 @@ +using EnvDTE; +using Microsoft.VisualStudio.Shell; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace CrmWebResourcesUpdater.Services.Helpers +{ + public class MappingHelper + { + ProjectHelper projectHelper; + public MappingHelper(AsyncPackage asyncPackage) + { + this.projectHelper = new ProjectHelper(asyncPackage); + } + public Dictionary LoadMappings(Project project) + { + var projectRootPath = projectHelper.GetProjectRoot(project); + var projectFiles = projectHelper.GetProjectFiles(project); + var mappingFilePath = this.GetMappingFilePath(project); + if (mappingFilePath == null) + { + return null; + } + + var mappingList = new Dictionary(); + + XDocument doc = XDocument.Load(mappingFilePath); + var mappings = doc.Descendants("Mapping"); + foreach (var mapping in mappings) + { + var shortScriptPath = mapping.Attribute("localPath") == null ? null : mapping.Attribute("localPath").Value; + shortScriptPath = shortScriptPath ?? (mapping.Attribute("scriptPath") == null ? null : mapping.Attribute("scriptPath").Value); + if(shortScriptPath == null) + { + throw new ArgumentNullException("Mappings contains 'Mapping' tag without 'localPath' attribute"); + } + var scriptPath = projectRootPath + "\\" + shortScriptPath; + scriptPath = scriptPath.ToLower(); + var webResourceName = mapping.Attribute("webResourceName") == null ? null : mapping.Attribute("webResourceName").Value; + if (webResourceName == null) + { + throw new ArgumentNullException("Mappings contains 'Mapping' tag without 'webResourceName' attribute"); + } + if (mappingList.ContainsKey(scriptPath)) + { + throw new ArgumentException("Mappings contains dublicate for \"" + shortScriptPath + "\""); + } + projectFiles.RemoveAll(x => x.ToLower() == scriptPath); + mappingList.Add(scriptPath, webResourceName); + } + foreach(var mapping in mappingList) + { + var scriptPath = mapping.Key; + var webResourceName = mapping.Value; + var projectMappingDublicates = projectFiles.Where(x => Path.GetFileName(x).ToLower() == webResourceName.ToLower()); + if (projectMappingDublicates.Count() > 0) + { + throw new ArgumentException("Project contains dublicate(s) for mapped web resource \"" + webResourceName + "\""); + } + + } + return mappingList; + } + + public void CreateMapping(Project project, string filePath, string webresourceName) + { + var mappingFilePath = this.GetMappingFilePath(project); + if (mappingFilePath == null) + { + mappingFilePath = this.CreateMappingFile(project); + } + + var projectRootPath = projectHelper.GetProjectRoot(project) + "\\"; + var scriptShortPath = filePath.Replace(projectRootPath, ""); + + XDocument doc = XDocument.Load(mappingFilePath); + var mapping = new XElement("Mapping"); + mapping.SetAttributeValue("localPath", scriptShortPath); + mapping.SetAttributeValue("webResourceName", webresourceName); + doc.Element("Mappings").Add(mapping); + doc.Save(mappingFilePath); + } + + public bool IsMappingFileReadOnly(Project project) + { + var path = GetMappingFilePath(project); + if(path == null) + { + return false; + } + var fileInfo = new FileInfo(path); + return fileInfo.IsReadOnly; + } + + public async Task IsMappingRequiredAsync(Project project, string projectItemPath, string webresourceName) + { + var fileName = Path.GetFileName(projectItemPath); + var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(projectItemPath); + if (fileName == webresourceName) + { + return false; + } + var settings = await SettingsService.Instance.GetSettingsAsync(); + var uploadWithoutExtension = settings.CrmConnections.IgnoreExtensions; + if(fileNameWithoutExtension == webresourceName) + { + return false; + } + return true; + } + + public string CreateMappingFile(Project project) + { + var projectPath = projectHelper.GetProjectRoot(project); + var filePath = projectPath + "\\UploaderMapping.config"; + if (File.Exists(filePath)) + { + var path = GetMappingFilePath(project); + if (path == null) + { + project.ProjectItems.AddFromFile(filePath); + } + return filePath; + } + var writer = File.CreateText(projectPath + "\\UploaderMapping.config"); + writer.WriteLine(""); + writer.WriteLine(""); + writer.WriteLine(""); + writer.WriteLine(""); + writer.Flush(); + writer.Close(); + project.ProjectItems.AddFromFile(filePath); + return filePath; + } + + public string GetMappingFilePath(Project project) + { + var projectFiles = projectHelper.GetProjectFiles(project.ProjectItems); + if (projectFiles == null || projectFiles.Count == 0) + { + return null; + } + foreach (var file in projectFiles) + { + if (Path.GetFileName(file).ToLower() == Settings.MappingFileName.ToLower()) + { + return file.ToLower(); + } + } + return null; + } + } +} diff --git a/CrmWebResourcesUpdater.Services/Helpers/ProjectHelper.cs b/CrmWebResourcesUpdater.Services/Helpers/ProjectHelper.cs new file mode 100644 index 0000000..c66d1f1 --- /dev/null +++ b/CrmWebResourcesUpdater.Services/Helpers/ProjectHelper.cs @@ -0,0 +1,258 @@ +using CrmWebResourcesUpdater.Common; +using EnvDTE; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.Threading; +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel.Design; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; +using IAsyncServiceProvider = Microsoft.VisualStudio.Shell.IAsyncServiceProvider; + +namespace CrmWebResourcesUpdater.Services.Helpers +{ + public class ProjectHelper + { + + private IAsyncServiceProvider _serviceProvider; + private JoinableTaskFactory _joinableTaskFactory; + private Dictionary _settingsCache = new Dictionary(); + + public ProjectHelper(AsyncPackage asyncPackage): this(asyncPackage, asyncPackage.JoinableTaskFactory) {} + public ProjectHelper(IAsyncServiceProvider serviceProvider, JoinableTaskFactory joinableTaskFactory) + { + _serviceProvider = serviceProvider; + _joinableTaskFactory = joinableTaskFactory; + } + + public string GetProjectRoot(Project project) + { + return Path.GetDirectoryName(project.FullName).ToLower(); + } + + + /// + /// Creates context menu command for extension + /// + /// Guid for command set in context menu + /// Guid for command + /// Handler for menu command + /// Returns context menu command + public OleMenuCommand GetMenuCommand(Guid comandSet, int commandID, EventHandler invokeHandler) + { + CommandID menuCommandID = new CommandID(comandSet, commandID); + return new OleMenuCommand(invokeHandler, menuCommandID); + } + + /// + /// Shows Configuration Error Dialog + /// + /// Returns result of an error dialog + public DialogResult ShowErrorDialog() + { + var title = "Configuration error"; + var text = "It seems that Publisher has not been configured yet or connection is not selected.\r\n\r\n" + + "We can open configuration window for you now or you can do it later by clicking \"Publish options\" in the context menu of the project.\r\n\r\n" + + "Do you want to open configuration window now?"; + return MessageBox.Show(text, title, MessageBoxButtons.YesNo, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); + } + + /// + /// Gets Guid of project + /// + /// Project to get guid of + /// Returns project guid + public async Task GetProjectGuidAsync(Project project) + { + Guid projectGuid = Guid.Empty; + IVsHierarchy hierarchy; + IVsSolution solution = await _serviceProvider.GetServiceAsync(typeof(SVsSolution)) as IVsSolution; + solution.GetProjectOfUniqueName(project.FullName, out hierarchy); + if (hierarchy != null) + { + solution.GetGuidOfProject(hierarchy, out projectGuid); + } + return projectGuid; + } + + + + /// + /// Gets selected project + /// + /// Returns selected project + public async Task GetSelectedProjectAsync() + { + var dte = await _serviceProvider.GetServiceAsync(typeof(DTE)) as EnvDTE80.DTE2; + if (dte == null) + { + Logger.WriteLine("Failed to get DTE service."); + throw new Exception("Failed to get DTE service."); + } + UIHierarchyItem uiHierarchyItem = Enumerable.FirstOrDefault(Enumerable.OfType((IEnumerable)(object[])dte.ToolWindows.SolutionExplorer.SelectedItems)); + var project = uiHierarchyItem.Object as Project; + if (project != null) + { + return project; + } + var item = uiHierarchyItem.Object as ProjectItem; + if(item != null) + { + return item.ContainingProject; + } + + Document doc = dte.ActiveDocument; + if(doc != null && doc.ProjectItem != null) + { + return doc.ProjectItem.ContainingProject; + } + return null; + } + + + + public async System.Threading.Tasks.Task SetStatusBarAsync(string message, object icon = null) + { + var statusBar = await _serviceProvider.GetServiceAsync(typeof(SVsStatusbar)) as IVsStatusbar; + int frozen; + statusBar.IsFrozen(out frozen); + if (frozen == 0) + { + + + //object icon = (short)Microsoft.VisualStudio.Shell.Interop.Constants.SBAI_Deploy; + if (icon != null) + { + statusBar.Animation(1, ref icon); + } + // + statusBar.SetText(message); + } + } + + public async System.Threading.Tasks.Task SaveAllAsync() + { + var dte = await _serviceProvider.GetServiceAsync(typeof(DTE)) as EnvDTE80.DTE2; + if (dte == null) + { + Logger.WriteLine("Failed to get DTE service."); + throw new Exception("Failed to get DTE service."); + } + dte.ExecuteCommand("File.SaveAll"); + } + + /// + /// Gets items selected in solution explorer + /// + /// Returns list of items which was selected in solution explorer + public async Task> GetSelectedItemsAsync() + { + var dte = await _serviceProvider.GetServiceAsync(typeof(DTE)) as EnvDTE80.DTE2; + if (dte == null) + { + Logger.WriteLine("Failed to get DTE service."); + throw new Exception("Failed to get DTE service."); + } + + var uiHierarchyItems = Enumerable.OfType((IEnumerable)(object[])dte.ToolWindows.SolutionExplorer.SelectedItems); + var items = new List(); + foreach (var uiItem in uiHierarchyItems) + { + var item = uiItem.Object as ProjectItem; + if (item != null) + { + items.Add(item); + } + } + if(items.Count == 0) + { + Document doc = dte.ActiveDocument; + if (doc != null && doc.ProjectItem != null) + { + items.Add(doc.ProjectItem); + } + } + return items; + } + + /// + /// Iterates through ProjectItems list and adds files paths to the output list + /// + /// List of project items + public List GetProjectFiles(List list) + { + if(list == null) + { + return null; + } + + var files = new List(); + foreach (ProjectItem item in list) + { + if (item.Kind.ToLower() == Settings.FileKindGuid.ToLower()) + { + var path = Path.GetDirectoryName(item.FileNames[0]).ToLower(); + var fileName = Path.GetFileName(item.FileNames[0]); + files.Add(path + "\\" + fileName); + } + + if (item.ProjectItems != null) + { + var childItems = GetProjectFiles(item.ProjectItems); + files.AddRange(childItems); + } + } + + return files; + } + + public List GetProjectFiles(Project project) + { + return GetProjectFiles(project.ProjectItems); + } + + /// + /// Iterates through ProjectItems tree and adds files paths to the list + /// + /// List of project items + public List GetProjectFiles(ProjectItems projectItems) + { + var list = new List(); + foreach (ProjectItem item in projectItems) + { + list.Add(item); + } + var projectFiles = GetProjectFiles(list); + return projectFiles; + } + + public async Task> GetSelectedFilesAsync() + { + var selectedItems = await GetSelectedItemsAsync(); + return GetProjectFiles(selectedItems); + } + + public async Task GetSelectedFilePathAsync() + { + var files = await GetSelectedFilesAsync(); + return files.FirstOrDefault(); + } + + + + public async Task> GetProjectFilesAsync() + { + var selectedProject = await GetSelectedProjectAsync(); + if(selectedProject == null) + { + return null; + } + var projectFiles = GetProjectFiles(selectedProject.ProjectItems); + return projectFiles; + } + } +} diff --git a/CrmWebResourcesUpdater.Services/Properties/AssemblyInfo.cs b/CrmWebResourcesUpdater.Services/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..36202b4 --- /dev/null +++ b/CrmWebResourcesUpdater.Services/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CrmWebResourcesUpdater.Services")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CrmWebResourcesUpdater.Services")] +[assembly: AssemblyCopyright("Copyright © 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("d9c59fab-cd1a-484b-8052-1f72ca1debb8")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/CrmWebResourcesUpdater.Services/PublishService.cs b/CrmWebResourcesUpdater.Services/PublishService.cs new file mode 100644 index 0000000..b0b9f80 --- /dev/null +++ b/CrmWebResourcesUpdater.Services/PublishService.cs @@ -0,0 +1,638 @@ +using Microsoft.Xrm.Sdk.Client; +using Microsoft.Xrm.Sdk; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using McTools.Xrm.Connection; +using EnvDTE; +using Microsoft.Xrm.Sdk.Query; +using System.Threading.Tasks; +using CrmWebResourcesUpdater.Forms; +using System.Windows.Forms; +using System.Net; +using System.ComponentModel; +using CrmWebResourcesUpdater.Common; +using CrmWebResourcesUpdater.Services.Helpers; +using McTools.Xrm.Connection.WinForms; +using System.Diagnostics; +using System.Collections; +using Microsoft.VisualStudio.Shell; +using Microsoft.Xrm.Sdk.Messages; +using CrmWebResourcesUpdater.Common.Helpers; +using CrmWebResourcesUpdater.Services.Extensions; + +namespace CrmWebResourcesUpdater.Services +{ + /// + /// Provides methods for uploading and publishing web resources + /// + public class PublishService : IDisposable + { + private const string FetchWebResourcesQueryTemplate = @" + + + + + + + + + {1} + + "; + + private ProjectHelper projectHelper = null; + private MappingHelper mappingHelper = null; + private AsyncPackage asyncPackage = null; + + //private ConnectionDetail _connectionDetail = null; + //private bool autoPublish = true; + //private bool ignoreExtensions = false; + //private bool extendedLog = false; + + //private IOrganizationService _orgService = null; + + + public static PublishService Instance + { + get; + private set; + } + public static void Initialize(AsyncPackage asyncPackage) + { + Instance = new PublishService(asyncPackage); + } + + + /// + /// Publisher constructor + /// + /// Connection to CRM that will be used to upload webresources + /// Perform publishing or not + /// Try to upload without extension if item not found with it + /// Print extended uploading process information + private PublishService(AsyncPackage asyncPackage) + { + projectHelper = new ProjectHelper(asyncPackage); + mappingHelper = new MappingHelper(asyncPackage); + this.asyncPackage = asyncPackage; + } + + /// + /// Uploads and publishes files to CRM + /// + public async System.Threading.Tasks.Task PublishWebResourcesAsync(bool uploadSelectedItems) + { + var settings = await SettingsService.Instance.GetSettingsAsync(); + var connections = settings.CrmConnections; + var connectionDetail = settings.SelectedConnection; + + await projectHelper.SaveAllAsync(); + await Logger.ClearAsync(); + + await projectHelper.SetStatusBarAsync("Uploading..."); + + if (connections.PublishAfterUpload) + { + await Logger.WriteLineWithTimeAsync("Publishing web resources..."); + } + else + { + await Logger.WriteLineWithTimeAsync("Uploading web resources..."); + } + + await Logger.WriteLineAsync("Connecting to CRM..."); + await Logger.WriteLineAsync("URL: " + connectionDetail.WebApplicationUrl); + await Logger.WriteLineAsync("Solution Name: " + connectionDetail.SelectedSolution.FriendlyName); + await Logger.WriteLineAsync("--------------------------------------------------------------"); + + await Logger.WriteLineAsync("Loading files' paths", connections.ExtendedLog); + var selectedFiles = await GetSelectedFilesAsync(uploadSelectedItems); //TODO: FIX PARAM + if (selectedFiles == null || selectedFiles.Count == 0) + { + await Logger.WriteLineAsync("Failed to load files' paths", connections.ExtendedLog); + return; + } + + await Logger.WriteLineAsync(selectedFiles.Count + " path" + (selectedFiles.Count == 1 ? " was" : "s were") + " loaded", connections.ExtendedLog); + try + { + await Logger.WriteLineAsync("Starting uploading process", connections.ExtendedLog); + var webresources = await UploadWebResourcesAsync(selectedFiles); + await Logger.WriteLineAsync("Uploading process was finished", connections.ExtendedLog); + + if (webresources.Count > 0) + { + await Logger.WriteLineAsync("--------------------------------------------------------------"); + foreach (var name in webresources.Values) + { + await Logger.WriteLineAsync(name + " successfully uploaded"); + } + } + await Logger.WriteLineAsync("--------------------------------------------------------------"); + await Logger.WriteLineWithTimeAsync(webresources.Count + " file" + (webresources.Count == 1 ? " was" : "s were") + " uploaded"); + + if (connections.PublishAfterUpload) + { + await projectHelper.SetStatusBarAsync("Publishing..."); + await PublishWebResourcesAsync(webresources.Keys); + } + + if (connections.PublishAfterUpload) + { + await projectHelper.SetStatusBarAsync(webresources.Count + " web resource" + (webresources.Count == 1 ? " was" : "s were") + " published"); + } + else + { + await projectHelper.SetStatusBarAsync(webresources.Count + " web resource" + (webresources.Count == 1 ? " was" : "s were") + " uploaded"); + } + + } + catch (Exception ex) + { + await projectHelper.SetStatusBarAsync("Failed to publish script" + (selectedFiles.Count == 1 ? "" : "s")); + await Logger.WriteLineAsync("Failed to publish script" + (selectedFiles.Count == 1 ? "." : "s.")); + await Logger.WriteLineAsync(ex.Message); + await Logger.WriteLineAsync(ex.StackTrace, connections.ExtendedLog); + } + await Logger.WriteLineWithTimeAsync("Done."); + } + + + + /// + /// Dispose object + /// + public void Dispose() + { + + } + + + public async Task> GetSelectedFilesAsync(bool uploadSelectedItems) + { + var settings = await SettingsService.Instance.GetSettingsAsync(); + var connections = settings.CrmConnections; + + List projectFiles = null; + if (uploadSelectedItems) + { + await Logger.WriteLineAsync("Loading selected files' paths", connections.ExtendedLog); + projectFiles = await projectHelper.GetSelectedFilesAsync(); + } + else + { + await Logger.WriteLineAsync("Loading all files' paths", connections.ExtendedLog); + projectFiles = await projectHelper.GetProjectFilesAsync(); + } + + return projectFiles; + } + + /// + /// Uploads web resources + /// + /// List of guids of web resources that was updated + private async Task> UploadWebResourcesAsync() + { + var projectFiles = await GetSelectedFilesAsync(true); //TODO: FIX PARAM + + if (projectFiles == null || projectFiles.Count == 0) + { + return null; + } + + return await UploadWebResourcesAsync(projectFiles); + } + + /// + /// Uploads web resources + /// + /// + /// List of guids of web resources that was updateds + private async Task> UploadWebResourcesAsync(List selectedFiles) + { + var settings = await SettingsService.Instance.GetSettingsAsync(); + var connections = settings.CrmConnections; + + var ids = new Dictionary(); + + var project = await projectHelper.GetSelectedProjectAsync(); + var projectRootPath = projectHelper.GetProjectRoot(project); + var mappings = mappingHelper.LoadMappings(project); + + var filters = new List(); + foreach (var filePath in selectedFiles) + { + var webResourceName = Path.GetFileName(filePath); + var lowerFilePath = filePath.ToLower(); + + if (webResourceName.ToLower() == Settings.MappingFileName.ToLower()) + { + continue; + } + + if (mappings != null && mappings.ContainsKey(lowerFilePath)) + { + webResourceName = mappings[lowerFilePath]; + } + else if (settings.CrmConnections.IgnoreExtensions) + { + webResourceName = Path.GetFileNameWithoutExtension(filePath); + } + filters.Add(webResourceName); + } + var webResources = await RetrieveWebResourcesAsync(filters); + + foreach (var filePath in selectedFiles) + { + var webResourceName = Path.GetFileName(filePath); + var lowerFilePath = filePath.ToLower(); + + if (webResourceName.ToLower() == Settings.MappingFileName.ToLower()) + { + continue; + } + + if (mappings != null && mappings.ContainsKey(lowerFilePath)) + { + webResourceName = mappings[lowerFilePath]; + var relativePath = lowerFilePath.Replace(projectRootPath + "\\", ""); + await Logger.WriteLineAsync("Mapping found: " + relativePath + " to " + webResourceName, connections.ExtendedLog); + } + + var webResource = webResources.FirstOrDefault(x => x.GetAttributeValue("name") == webResourceName); + if(webResource == null && connections.IgnoreExtensions) + { + await Logger.WriteLineAsync(webResourceName + " does not exists in selected solution", connections.ExtendedLog); + webResourceName = Path.GetFileNameWithoutExtension(filePath); + await Logger.WriteLineAsync("Searching for " + webResourceName, connections.ExtendedLog); + webResource = webResources.FirstOrDefault(x => x.GetAttributeValue("name") == webResourceName); + } + if (webResource == null) + { + await Logger.WriteLineAsync("Uploading of " + webResourceName + " was skipped: web resource does not exists in selected solution", connections.ExtendedLog); + await Logger.WriteLineAsync(webResourceName + " does not exists in selected solution", !connections.ExtendedLog); + continue; + } + if(!File.Exists(lowerFilePath)) + { + await Logger.WriteLineAsync("Warning: File not found: " + lowerFilePath); + continue; + } + var isUpdated = await UpdateWebResourceByFileAsync(webResource, filePath); + if (isUpdated) + { + ids.Add(webResource.Id, webResourceName); + } + } + return ids; + } + + + + /// + /// Uploads web resource + /// + /// Web resource to be updated + /// File with a content to be set for web resource + /// Returns true if web resource is updated + private async Task UpdateWebResourceByFileAsync(Entity webResource, string filePath) + { + var settings = await SettingsService.Instance.GetSettingsAsync(); + var connections = settings.CrmConnections; + + var webResourceName = Path.GetFileName(filePath); + await Logger.WriteLineAsync("Uploading " + webResourceName, connections.ExtendedLog); + + var project = await projectHelper.GetSelectedProjectAsync(); + var projectRootPath = projectHelper.GetProjectRoot(project); + + var localContent = FileHelper.GetEncodedFileContent(filePath); + var remoteContent = webResource.GetAttributeValue("content"); + if (remoteContent.Length != localContent.Length || remoteContent != localContent) + { + await UpdateWebResourceByContentAsync(webResource, localContent); + var relativePath = filePath.Replace(projectRootPath + "\\", ""); + await Logger.WriteLineAsync(webResource.GetAttributeValue("name") + " uploaded from " + relativePath, !connections.ExtendedLog); + return true; + } + else + { + await Logger.WriteLineAsync("Uploading of " + webResourceName + " was skipped: there aren't any change in the web resource", connections.ExtendedLog); + await Logger.WriteLineAsync(webResourceName + " has no changes", !connections.ExtendedLog); + return false; + } + } + + /// + /// Uploads web resource + /// + /// Web resource to be updated + /// Content to be set for web resource + private async System.Threading.Tasks.Task UpdateWebResourceByContentAsync(Entity webResource, string content) + { + var settings = await SettingsService.Instance.GetSettingsAsync(); + var connections = settings.CrmConnections; + var selectedConnection = settings.SelectedConnection; + var orgService = selectedConnection.GetCrmServiceClient();// await CrmConnectionHelper.GetOrganizationServiceProxyAsync(selectedConnection); + + + var name = webResource.GetAttributeValue("name"); + webResource["content"] = content; + await orgService.UpdateAsync(webResource); + + await Logger.WriteLineAsync(name + " was successfully uploaded", connections.ExtendedLog); + } + + /// + /// Retrieves web resources for selected items + /// + /// List of web resources + private async System.Threading.Tasks.Task> RetrieveWebResourcesAsync(List webResourceNames = null) + { + var settings = await SettingsService.Instance.GetSettingsAsync(); + var connections = settings.CrmConnections; + var selectedConnection = settings.SelectedConnection; + var orgService = await selectedConnection.GetCrmServiceClientAsync(); + + await Logger.WriteLineAsync("Retrieving existing web resources", connections.ExtendedLog); + + var filter = ""; + if (webResourceNames != null && webResourceNames.Count > 0) + { + filter = ""; + foreach (var name in webResourceNames) + { + filter += $""; + } + filter += ""; + } + var fetchQuery = String.Format(FetchWebResourcesQueryTemplate, selectedConnection.SelectedSolution.SolutionId, filter); + var response = await orgService.RetrieveMultipleAsync(new FetchExpression(fetchQuery)); + var webResources = response.Entities.ToList(); + + return webResources; + } + + /// + /// Publishes webresources changes + /// + /// List of webresource IDs to publish + private async System.Threading.Tasks.Task PublishWebResourcesAsync(IEnumerable webresourcesIds) + { + var settings = await SettingsService.Instance.GetSettingsAsync(); + var selectedConnection = settings.SelectedConnection; + var orgService = await selectedConnection.GetCrmServiceClientAsync(); + + await Logger.WriteLineWithTimeAsync("Publishing..."); + //await Logger.WriteLineAsync("Publishing..."); + var orgContext = new OrganizationServiceContext(orgService); + if (webresourcesIds == null) + { + throw new ArgumentNullException("webresourcesId"); + } + if(webresourcesIds.Any()) + { + var request = GetPublishRequest(webresourcesIds); + await orgContext.ExecuteAsync(request); + } + var count = webresourcesIds.Count(); + await Logger.WriteLineWithTimeAsync(count + " file" + (count == 1 ? " was" : "s were") + " published"); + //await Logger.WriteLineAsync(count + " file" + (count == 1 ? " was" : "s were") + " published"); + } + + /// + /// Returns publish request + /// + /// List of web resources IDs + /// + private OrganizationRequest GetPublishRequest(IEnumerable webresourcesIds) + { + if (webresourcesIds == null || !webresourcesIds.Any()) + { + throw new ArgumentNullException("webresourcesId"); + } + + var request = new OrganizationRequest { RequestName = "PublishXml" }; + request.Parameters = new ParameterCollection(); + request.Parameters.Add(new KeyValuePair("ParameterXml", + string.Format("{0}", + string.Join("", webresourcesIds.Select(a => string.Format("{0}", a))) + ))); + + return request; + } + + private void CreateWebResource(IOrganizationService service, Entity webResource, string solution) + { + if (webResource == null) + { + throw new ArgumentNullException("Web resource can not be null"); + } + CreateRequest createRequest = new CreateRequest + { + Target = webResource + }; + createRequest.Parameters.Add("SolutionUniqueName", solution); + service.Execute(createRequest); + } + + private async Task IsResourceExistsAsync(IOrganizationService service, string webResourceName) + { + QueryExpression query = new QueryExpression + { + EntityName = "webresource", + ColumnSet = new ColumnSet(new string[] { "name" }), + Criteria = new FilterExpression() + }; + query.Criteria.AddCondition("name", ConditionOperator.Equal, webResourceName); + //query.Criteria.AddCondition("solutionid", ConditionOperator.Equal, _connectionDetail.SolutionId); + + var response = await service.RetrieveMultipleAsync(query); + var entity = response.Entities.FirstOrDefault(); + + return entity == null ? false : true; + } + + + public async System.Threading.Tasks.Task CreateWebResourceAsync() + { + var settings = await SettingsService.Instance.GetSettingsAsync(); + var selectedConnection = settings.SelectedConnection; + + string publisherPrefix = selectedConnection.SelectedSolution.PublisherPrefix; + if (publisherPrefix == null) + { + var result = MessageBox.Show("Publisher prefix is not loaded. Do you want to load it from CRM?", "Prefix is missing", MessageBoxButtons.YesNo, MessageBoxIcon.Question); + if (result == DialogResult.Yes) + { + await LoadPrefixAsync(); + } + + } + OpenCreateWebResourceFormAsync(); + } + + + private async void OpenCreateWebResourceFormAsync() + { + var settings = await SettingsService.Instance.GetSettingsAsync(); + var project = await projectHelper.GetSelectedProjectAsync(); + var path = await projectHelper.GetSelectedFilePathAsync(); + var dialog = new CreateWebResourceForm(path, settings.SelectedConnection.SelectedSolution.PublisherPrefix); + + dialog.OnCreate = async (Entity webResource) => + { + var connectionDetail = settings.SelectedConnection; + if (connectionDetail.SelectedSolution.SolutionId == null) + { + throw new ArgumentNullException("SolutionId"); + } + WebRequest.GetSystemWebProxy(); + var service = await connectionDetail.GetCrmServiceClientAsync(); + + var webresourceName = webResource["name"] as String; + if (await this.IsResourceExistsAsync(service, webresourceName)) + { + MessageBox.Show("Webresource with name '" + webresourceName + "' already exist in CRM.", "Webresource already exists.", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + try + { + Cursor.Current = Cursors.Arrow; + var isMappingRequired = await mappingHelper.IsMappingRequiredAsync(project, path, webresourceName); + var isMappingFileReadOnly = mappingHelper.IsMappingFileReadOnly(project); + if (isMappingRequired && isMappingFileReadOnly) + { + var message = "Mapping record can't be created. File \"UploaderMapping.config\" is read-only. Do you want to proceed? \r\n\r\n" + + "Schema name of the web resource you are creating is differ from the file name. " + + "Because of that new mapping record has to be created in the file \"UploaderMapping.config\". " + + "Unfortunately the file \"UploaderMapping.config\" is read-only (file might be under a source control), so mapping record cant be created. \r\n\r\n" + + "Press OK to proceed without mapping record creation (You have to do that manually later). Press Cancel to fix problem and try later."; + var result = MessageBox.Show(message, "Warning", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning); + if (result == DialogResult.Cancel) + { + return; + } + } + if (isMappingRequired && !isMappingFileReadOnly) + { + mappingHelper.CreateMapping(project, path, webresourceName); + } + //TODO: Check solution name + this.CreateWebResource(service, webResource, settings.SelectedConnection.SelectedSolution.UniqueName); + await Logger.WriteLineAsync("Webresource '" + webresourceName + "' was successfully created"); + dialog.Close(); + } + catch (Exception ex) + { + Cursor.Current = Cursors.Arrow; + MessageBox.Show("An error occured during web resource creation: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + }; + dialog.ShowDialog(); + } + + private async System.Threading.Tasks.Task LoadPrefixAsync() + { + var settings = await SettingsService.Instance.GetSettingsAsync(); + await Logger.WriteLineAsync("Retrieving Publisher prefix"); + var entity = await RetrieveSolutionAsync(); + + string prefix = entity.GetAttributeValue("publisher.customizationprefix") == null ? null : entity.GetAttributeValue("publisher.customizationprefix").Value.ToString(); + await Logger.WriteLineAsync("Publisher prefix successfully retrieved"); + + settings.SelectedConnection.SelectedSolution.PublisherPrefix = prefix; + settings.Save(); + } + + //private void BwGetSolutionRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) + //{ + // if (e.Error != null) + // { + // string errorMessage = e.Error.Message; + // var ex = e.Error.InnerException; + // while (ex != null) + // { + // errorMessage += "\r\nInner Exception: " + ex.Message; + // ex = ex.InnerException; + // } + // MessageBox.Show("An error occured while retrieving publisher prefix: " + errorMessage, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + // } + // else + // { + // if (e.Result != null) + // { + // var entity = e.Result as Entity; + // string prefix = entity.GetAttributeValue("publisher.customizationprefix") == null ? null : entity.GetAttributeValue("publisher.customizationprefix").Value.ToString(); + // await Logger.WriteLineAsync("Publisher prefix successfully retrieved"); + // _connectionDetail.PublisherPrefix = prefix; + // var settings = projectHelper.GetSettingsAsync().Result; + // settings.SelectedConnection.PublisherPrefix = prefix; + // settings.Save(); + // OpenCreateWebResourceFormAsync(); + // } + // } + //} + + //private void BwGetSolutionDoWork(object sender, DoWorkEventArgs e) + //{ + // e.Result = RetrieveSolution(); + //} + + private async Task RetrieveSolutionAsync() + { + var settings = await SettingsService.Instance.GetSettingsAsync(); + var selectedConnection = settings.SelectedConnection; + var orgService = await selectedConnection.GetCrmServiceClientAsync(); + + QueryExpression query = new QueryExpression + { + EntityName = "solution", + ColumnSet = new ColumnSet(new string[] { "friendlyname", "uniquename", "publisherid" }), + Criteria = new FilterExpression() + }; + query.Criteria.AddCondition("isvisible", ConditionOperator.Equal, true); + query.Criteria.AddCondition("solutionid", ConditionOperator.Equal, selectedConnection.SelectedSolution.SolutionId); + + query.LinkEntities.Add(new LinkEntity("solution", "publisher", "publisherid", "publisherid", JoinOperator.Inner)); + query.LinkEntities[0].Columns.AddColumns("customizationprefix"); + query.LinkEntities[0].EntityAlias = "publisher"; + + var response = await orgService.RetrieveMultipleAsync(query); + return response.Entities.FirstOrDefault(); + } + + /// + /// Shows Configuration Dialog + /// + /// Configuration mode for settings dialog + /// Project to manage configuration for + /// Returns result of a configuration dialog + public async Task ShowConfigurationDialogAsync(ConfigurationMode mode) + { + var settings = await SettingsService.Instance.GetSettingsAsync(); + var project = await projectHelper.GetSelectedProjectAsync(); + var crmConnections = settings.CrmConnections == null ? new CrmConnections() { Connections = new List() } : settings.CrmConnections; + var selector = new ConnectionSelector(crmConnections, settings.SelectedConnection, false, mode == ConfigurationMode.Update); + selector.OnCreateMappingFile = () => { + mappingHelper.CreateMappingFile(project); + MessageBox.Show("UploaderMapping.config successfully created", "Microsoft Dynamics CRM Web Resources Updater", MessageBoxButtons.OK, MessageBoxIcon.Information); + }; + selector.ShowDialog(); + settings.CrmConnections = selector.ConnectionList; + if (selector.DialogResult == DialogResult.OK || selector.DialogResult == DialogResult.Yes) + { + settings.SelectedConnection = selector.SelectedConnection; + } + settings.Save(); + return selector.DialogResult; + } + + + } +} + diff --git a/CrmWebResourcesUpdater.Services/SettingsService.cs b/CrmWebResourcesUpdater.Services/SettingsService.cs new file mode 100644 index 0000000..38cff13 --- /dev/null +++ b/CrmWebResourcesUpdater.Services/SettingsService.cs @@ -0,0 +1,53 @@ +using CrmWebResourcesUpdater.Services.Helpers; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Threading; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CrmWebResourcesUpdater.Services +{ + public class SettingsService + { + private IAsyncServiceProvider serviceProvider; + private JoinableTaskFactory joinableTaskFactory; + private ProjectHelper projectHelper; + private Dictionary settingsCache = new Dictionary(); + public static SettingsService Instance + { + get; + private set; + } + public static void Initialize(AsyncPackage asyncPackage) + { + Instance = new SettingsService(asyncPackage); + } + + public SettingsService(AsyncPackage asyncPackage) + { + serviceProvider = asyncPackage; + joinableTaskFactory = asyncPackage.JoinableTaskFactory; + projectHelper = new ProjectHelper(asyncPackage); + } + + /// + /// Gets Publisher settings for selected project + /// + /// Returns settings for selected project + public async Task GetSettingsAsync() + { + var project = await projectHelper.GetSelectedProjectAsync(); + var guid = await projectHelper.GetProjectGuidAsync(project); + await joinableTaskFactory.SwitchToMainThreadAsync(); + if (settingsCache.ContainsKey(guid)) + { + return settingsCache[guid]; + } + var settings = new Settings(serviceProvider, guid); + settingsCache.Add(guid, settings); + return settings; + } + } +} diff --git a/CrmWebResourcesUpdater.Froms/app.config b/CrmWebResourcesUpdater.Services/app.config similarity index 52% rename from CrmWebResourcesUpdater.Froms/app.config rename to CrmWebResourcesUpdater.Services/app.config index 37eadcc..c7a26bc 100644 --- a/CrmWebResourcesUpdater.Froms/app.config +++ b/CrmWebResourcesUpdater.Services/app.config @@ -3,20 +3,20 @@ - - + + - - + + - - + + - - + + diff --git a/CrmWebResourcesUpdater.Services/packages.config b/CrmWebResourcesUpdater.Services/packages.config new file mode 100644 index 0000000..9545a90 --- /dev/null +++ b/CrmWebResourcesUpdater.Services/packages.config @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CrmWebResourcesUpdater.Settings/CrmWebResourcesUpdater.Settings.csproj b/CrmWebResourcesUpdater.Settings/CrmWebResourcesUpdater.Settings.csproj index 3b44354..2836344 100644 --- a/CrmWebResourcesUpdater.Settings/CrmWebResourcesUpdater.Settings.csproj +++ b/CrmWebResourcesUpdater.Settings/CrmWebResourcesUpdater.Settings.csproj @@ -1,21 +1,17 @@  - + Debug AnyCPU - {2CF262F9-D0D9-4C45-84EB-430779973A05} + {E1A14C0B-41E8-479D-A3F6-B6438AF9D869} Library Properties CrmWebResourcesUpdater.Settings CrmWebResourcesUpdater.Settings - v4.6.1 + v4.6.2 512 - SAK - SAK - SAK - SAK - + true @@ -36,170 +32,28 @@ prompt 4 - - true - - - Key.snk - - - ..\packages\EnvDTE.8.0.2\lib\net10\EnvDTE.dll - True - - - ..\packages\EnvDTE100.10.0.3\lib\net20\EnvDTE100.dll - True - - - ..\packages\EnvDTE80.8.0.3\lib\net10\EnvDTE80.dll - True - - - ..\packages\EnvDTE90.9.0.3\lib\net10\EnvDTE90.dll - True - - - ..\packages\EnvDTE90a.9.0.3\lib\net10\EnvDTE90a.dll - True - - - ..\packages\Microsoft.Build.15.8.166\lib\net46\Microsoft.Build.dll - - - ..\packages\Microsoft.Build.Framework.15.8.166\lib\net46\Microsoft.Build.Framework.dll - - - ..\packages\Microsoft.Build.Tasks.Core.15.8.166\lib\net46\Microsoft.Build.Tasks.Core.dll - - - ..\packages\Microsoft.Build.Utilities.Core.15.8.166\lib\net46\Microsoft.Build.Utilities.Core.dll - - - ..\packages\Microsoft.VisualStudio.CommandBars.8.0.0.1\lib\net10\Microsoft.VisualStudio.CommandBars.dll - True - - - ..\packages\Microsoft.VisualStudio.ComponentModelHost.16.0.467\lib\net46\Microsoft.VisualStudio.ComponentModelHost.dll - - - ..\packages\Microsoft.VisualStudio.Composition.15.8.98\lib\net46\Microsoft.VisualStudio.Composition.dll - - - ..\packages\Microsoft.VisualStudio.Composition.NetFxAttributes.15.8.98\lib\net45\Microsoft.VisualStudio.Composition.NetFxAttributes.dll - - - ..\packages\Microsoft.VisualStudio.CoreUtility.16.0.467\lib\net472\Microsoft.VisualStudio.CoreUtility.dll - - - ..\packages\Microsoft.VisualStudio.Debugger.Interop.8.0.50729\lib\net11\Microsoft.VisualStudio.Debugger.Interop.dll - True - - - ..\packages\Microsoft.VisualStudio.Debugger.Interop.10.0.10.0.30320\lib\net20\Microsoft.VisualStudio.Debugger.Interop.10.0.dll - - - ..\packages\Microsoft.VisualStudio.Debugger.Interop.11.0.11.0.50728\lib\net20\Microsoft.VisualStudio.Debugger.Interop.11.0.dll - - - ..\packages\Microsoft.VisualStudio.Debugger.Interop.12.0.12.0.21006\lib\net20\Microsoft.VisualStudio.Debugger.Interop.12.0.dll - - - ..\packages\Microsoft.VisualStudio.Debugger.Interop.14.0.14.3.25408\lib\net20\Microsoft.VisualStudio.Debugger.Interop.14.0.dll - True - - - ..\packages\Microsoft.VisualStudio.Debugger.Interop.15.0.15.9.28307\lib\net20\Microsoft.VisualStudio.Debugger.Interop.15.0.dll + + ..\packages\Microsoft.VisualStudio.CoreUtility.15.6.27740\lib\net46\Microsoft.VisualStudio.CoreUtility.dll - - ..\packages\Microsoft.VisualStudio.Debugger.Interop.16.0.16.0.28727\lib\net20\Microsoft.VisualStudio.Debugger.Interop.16.0.dll + + ..\packages\Microsoft.VisualStudio.ImageCatalog.15.9.28307\lib\net45\Microsoft.VisualStudio.ImageCatalog.dll - - ..\packages\Microsoft.VisualStudio.Debugger.InteropA.9.0.21023\lib\net10\Microsoft.VisualStudio.Debugger.InteropA.dll - - - ..\packages\Microsoft.VisualStudio.Designer.Interfaces.1.1.4323\lib\net11\Microsoft.VisualStudio.Designer.Interfaces.dll - True - - - ..\packages\Microsoft.VisualStudio.DpiAwareness.6.0.28727\lib\net46\Microsoft.VisualStudio.DpiAwareness.dll - - - ..\packages\Microsoft.VisualStudio.Editor.16.0.467\lib\net472\Microsoft.VisualStudio.Editor.dll - - - ..\packages\Microsoft.VisualStudio.ImageCatalog.16.0.28727\lib\net45\Microsoft.VisualStudio.ImageCatalog.dll - - - ..\packages\Microsoft.VisualStudio.Imaging.16.0.28729\lib\net45\Microsoft.VisualStudio.Imaging.dll + + ..\packages\Microsoft.VisualStudio.Imaging.15.9.28307\lib\net45\Microsoft.VisualStudio.Imaging.dll ..\packages\Microsoft.VisualStudio.Imaging.Interop.14.0.DesignTime.14.3.26930\lib\net20\Microsoft.VisualStudio.Imaging.Interop.14.0.DesignTime.dll True - - ..\packages\Microsoft.VisualStudio.Language.16.0.467\lib\net472\Microsoft.VisualStudio.Language.dll - - - ..\packages\Microsoft.VisualStudio.Language.Intellisense.16.0.467\lib\net472\Microsoft.VisualStudio.Language.Intellisense.dll - - - ..\packages\Microsoft.VisualStudio.Language.NavigateTo.Interfaces.16.0.467\lib\net472\Microsoft.VisualStudio.Language.NavigateTo.Interfaces.dll - - - ..\packages\Microsoft.VisualStudio.Language.StandardClassification.16.0.467\lib\net472\Microsoft.VisualStudio.Language.StandardClassification.dll - - - ..\packages\Microsoft.VisualStudio.LanguageServer.Client.16.0.2264\lib\net46\Microsoft.VisualStudio.LanguageServer.Client.dll - - - ..\packages\Microsoft.VisualStudio.LanguageServer.Protocol.16.0.2264\lib\netstandard1.0\Microsoft.VisualStudio.LanguageServer.Protocol.dll - ..\packages\Microsoft.VisualStudio.OLE.Interop.7.10.6071\lib\Microsoft.VisualStudio.OLE.Interop.dll - - ..\packages\Microsoft.VisualStudio.Package.LanguageService.15.0.16.0.28729\lib\net45\Microsoft.VisualStudio.Package.LanguageService.15.0.dll - - - ..\packages\Microsoft.VisualStudio.ProjectAggregator.8.0.50728\lib\net20\Microsoft.VisualStudio.ProjectAggregator.dll - True - - - ..\packages\Microsoft.VisualStudio.ProjectSystem.15.8.243\lib\net46\Microsoft.VisualStudio.ProjectSystem.dll + + ..\packages\Microsoft.VisualStudio.Shell.15.0.15.9.28307\lib\net45\Microsoft.VisualStudio.Shell.15.0.dll - - ..\packages\Microsoft.VisualStudio.ProjectSystem.15.8.243\lib\net46\Microsoft.VisualStudio.ProjectSystem.Interop.dll - True - - - ..\packages\Microsoft.VisualStudio.ProjectSystem.15.8.243\lib\net46\Microsoft.VisualStudio.ProjectSystem.VS.dll - - - ..\packages\Microsoft.VisualStudio.Setup.Configuration.Interop.1.16.30\lib\net35\Microsoft.VisualStudio.Setup.Configuration.Interop.dll - True - - - ..\packages\Microsoft.VisualStudio.Shell.14.0.14.3.25407\lib\Microsoft.VisualStudio.Shell.14.0.dll - - - ..\packages\Microsoft.VisualStudio.Shell.Design.16.0.28729\lib\net45\Microsoft.VisualStudio.Shell.Design.dll - - - ..\packages\Microsoft.VisualStudio.Shell.Embeddable.16.0.28727\lib\net45\Microsoft.VisualStudio.Shell.Embeddable.dll - True - - - ..\packages\Microsoft.VisualStudio.Shell.Immutable.10.0.10.0.30319\lib\net40\Microsoft.VisualStudio.Shell.Immutable.10.0.dll - - - ..\packages\Microsoft.VisualStudio.Shell.Immutable.11.0.11.0.50727\lib\net45\Microsoft.VisualStudio.Shell.Immutable.11.0.dll - - - ..\packages\Microsoft.VisualStudio.Shell.Immutable.12.0.12.0.21003\lib\net45\Microsoft.VisualStudio.Shell.Immutable.12.0.dll - - - ..\packages\Microsoft.VisualStudio.Shell.Immutable.14.0.14.3.25407\lib\net45\Microsoft.VisualStudio.Shell.Immutable.14.0.dll + + ..\packages\Microsoft.VisualStudio.Shell.Framework.15.9.28307\lib\net45\Microsoft.VisualStudio.Shell.Framework.dll ..\packages\Microsoft.VisualStudio.Shell.Interop.7.10.6072\lib\net11\Microsoft.VisualStudio.Shell.Interop.dll @@ -220,253 +74,70 @@ ..\packages\Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime.14.3.26929\lib\net20\Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime.dll True - - ..\packages\Microsoft.VisualStudio.Shell.Interop.15.0.DesignTime.15.0.26932\lib\net20\Microsoft.VisualStudio.Shell.Interop.15.0.DesignTime.dll - True - - - ..\packages\Microsoft.VisualStudio.Shell.Interop.15.1.DesignTime.15.0.26929\lib\net20\Microsoft.VisualStudio.Shell.Interop.15.1.DesignTime.dll - True - ..\packages\Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime.15.0.26929\lib\net20\Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime.dll True - - ..\packages\Microsoft.VisualStudio.Shell.Interop.15.5.DesignTime.15.6.27413\lib\net20\Microsoft.VisualStudio.Shell.Interop.15.5.DesignTime.dll - True - ..\packages\Microsoft.VisualStudio.Shell.Interop.15.6.DesignTime.15.6.27413\lib\net20\Microsoft.VisualStudio.Shell.Interop.15.6.DesignTime.dll True - - ..\packages\Microsoft.VisualStudio.Shell.Interop.15.7.DesignTime.15.7.1\lib\net20\Microsoft.VisualStudio.Shell.Interop.15.7.DesignTime.dll - True - - - ..\packages\Microsoft.VisualStudio.Shell.Interop.15.8.DesignTime.15.8.1\lib\net20\Microsoft.VisualStudio.Shell.Interop.15.8.DesignTime.dll - True - ..\packages\Microsoft.VisualStudio.Shell.Interop.8.0.8.0.50728\lib\net11\Microsoft.VisualStudio.Shell.Interop.8.0.dll ..\packages\Microsoft.VisualStudio.Shell.Interop.9.0.9.0.30730\lib\net11\Microsoft.VisualStudio.Shell.Interop.9.0.dll - - ..\packages\Microsoft.VisualStudio.TaskRunnerExplorer.14.0.14.0.0\lib\net40\Microsoft.VisualStudio.TaskRunnerExplorer.14.0.dll - - - ..\packages\Microsoft.VisualStudio.Text.Data.16.0.467\lib\net472\Microsoft.VisualStudio.Text.Data.dll - - - ..\packages\Microsoft.VisualStudio.Text.Logic.16.0.467\lib\net472\Microsoft.VisualStudio.Text.Logic.dll - - - ..\packages\Microsoft.VisualStudio.Text.UI.16.0.467\lib\net472\Microsoft.VisualStudio.Text.UI.dll - - - ..\packages\Microsoft.VisualStudio.Text.UI.Wpf.16.0.467\lib\net472\Microsoft.VisualStudio.Text.UI.Wpf.dll + + ..\packages\Microsoft.VisualStudio.Text.Data.15.6.27740\lib\net46\Microsoft.VisualStudio.Text.Data.dll ..\packages\Microsoft.VisualStudio.TextManager.Interop.7.10.6071\lib\net11\Microsoft.VisualStudio.TextManager.Interop.dll - - ..\packages\Microsoft.VisualStudio.TextManager.Interop.12.1.DesignTime.12.1.30330\lib\net20\Microsoft.VisualStudio.TextManager.Interop.12.1.DesignTime.dll - True - ..\packages\Microsoft.VisualStudio.TextManager.Interop.8.0.8.0.50728\lib\net11\Microsoft.VisualStudio.TextManager.Interop.8.0.dll - - ..\packages\Microsoft.VisualStudio.TextTemplating.15.0.16.0.28727\lib\net45\Microsoft.VisualStudio.TextTemplating.15.0.dll - - - ..\packages\Microsoft.VisualStudio.TextTemplating.Interfaces.10.0.10.0.30320\lib\net40\Microsoft.VisualStudio.TextTemplating.Interfaces.10.0.dll - - - ..\packages\Microsoft.VisualStudio.TextTemplating.Interfaces.11.0.11.0.50728\lib\net45\Microsoft.VisualStudio.TextTemplating.Interfaces.11.0.dll - - - ..\packages\Microsoft.VisualStudio.TextTemplating.Interfaces.15.0.16.0.28727\lib\net45\Microsoft.VisualStudio.TextTemplating.Interfaces.15.0.dll + + ..\packages\Microsoft.VisualStudio.Threading.15.8.122\lib\net46\Microsoft.VisualStudio.Threading.dll - - ..\packages\Microsoft.VisualStudio.TextTemplating.VSHost.15.0.16.0.28729\lib\net45\Microsoft.VisualStudio.TextTemplating.VSHost.15.0.dll - - - ..\packages\Microsoft.VisualStudio.Threading.16.0.102\lib\net46\Microsoft.VisualStudio.Threading.dll - - - ..\packages\Microsoft.VisualStudio.Utilities.16.0.28729\lib\net46\Microsoft.VisualStudio.Utilities.dll + + ..\packages\Microsoft.VisualStudio.Utilities.15.9.28307\lib\net46\Microsoft.VisualStudio.Utilities.dll - ..\packages\Microsoft.VisualStudio.Validation.15.3.58\lib\net45\Microsoft.VisualStudio.Validation.dll - - - ..\packages\Microsoft.VisualStudio.Web.BrowserLink.12.0.12.0.0\lib\net40\Microsoft.VisualStudio.Web.BrowserLink.12.0.dll - - - ..\packages\Microsoft.VisualStudio.Workspace.VSIntegration.15.0.485\lib\net46\Microsoft.VisualStudio.Workspace.VSIntegration.Contracts.dll + ..\packages\Microsoft.VisualStudio.Validation.15.3.15\lib\net45\Microsoft.VisualStudio.Validation.dll - - ..\packages\Microsoft.Win32.Primitives.4.3.0\lib\net46\Microsoft.Win32.Primitives.dll - True - True + + + + ..\packages\Newtonsoft.Json.6.0.6\lib\net45\Newtonsoft.Json.dll - - ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll - - - - - ..\packages\stdole.7.0.3302\lib\net10\stdole.dll - True - - - ..\packages\StreamJsonRpc.1.5.43\lib\net46\StreamJsonRpc.dll + + ..\packages\StreamJsonRpc.1.3.23\lib\net45\StreamJsonRpc.dll - - ..\packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll - - - ..\packages\System.Collections.Immutable.1.5.0\lib\netstandard2.0\System.Collections.Immutable.dll - - - ..\packages\System.Composition.AttributedModel.1.0.31\lib\portable-net45+win8+wp8+wpa81\System.Composition.AttributedModel.dll - - - ..\packages\System.Composition.Convention.1.0.31\lib\portable-net45+win8+wp8+wpa81\System.Composition.Convention.dll - - - ..\packages\System.Composition.Hosting.1.0.31\lib\portable-net45+win8+wp8+wpa81\System.Composition.Hosting.dll - - - ..\packages\System.Composition.Runtime.1.0.31\lib\portable-net45+win8+wp8+wpa81\System.Composition.Runtime.dll - - - ..\packages\System.Composition.TypedParts.1.0.31\lib\portable-net45+win8+wp8+wpa81\System.Composition.TypedParts.dll - - - - - ..\packages\System.IO.4.3.0\lib\net462\System.IO.dll - True - True - - - ..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll - True - True - - - - ..\packages\System.Net.Http.4.3.3\lib\net46\System.Net.Http.dll - True - True - - - - - ..\packages\System.Reflection.Metadata.1.3.0\lib\portable-net45+win8\System.Reflection.Metadata.dll - - - ..\packages\System.Runtime.4.3.0\lib\net462\System.Runtime.dll - True - True - - - ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll - True - True - - - - ..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net463\System.Security.Cryptography.Algorithms.dll - True - True + + ..\packages\System.Security.Cryptography.Algorithms.4.3.1\lib\net461\System.Security.Cryptography.Algorithms.dll ..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll - True - True ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll - True - True - - - ..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll - True - True - - - ..\packages\System.Threading.Tasks.Dataflow.4.5.24\lib\portable-net45+win8+wpa81\System.Threading.Tasks.Dataflow.dll - - - ..\packages\System.Threading.Tasks.Extensions.4.3.0\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll - - ..\packages\System.ValueTuple.4.3.0\lib\netstandard1.0\System.ValueTuple.dll - True - True + + ..\packages\System.Security.Cryptography.X509Certificates.4.3.2\lib\net461\System.Security.Cryptography.X509Certificates.dll - - + - - - ..\packages\VSLangProj.7.0.3301\lib\net10\VSLangProj.dll - True - - - ..\packages\VSLangProj100.10.0.30320\lib\net20\VSLangProj100.dll - True - - - ..\packages\VSLangProj110.11.0.61031\lib\net20\VSLangProj110.dll - True - - - ..\packages\VSLangProj140.14.0.25030\lib\net20\VSLangProj140.dll - True - - - ..\packages\VSLangProj150.15.0.26229\lib\net20\VSLangProj150.dll - True - - - ..\packages\VSLangProj157.15.7.0\lib\net20\VSLangProj157.dll - True - - - ..\packages\VSLangProj158.15.8.0\lib\net20\VSLangProj158.dll - True - - - ..\packages\VSLangProj2.7.0.5001\lib\net11\VSLangProj2.dll - True - - - ..\packages\VSLangProj80.8.0.50728\lib\net11\VSLangProj80.dll - True - - - ..\packages\VSLangProj90.9.0.30730\lib\net10\VSLangProj90.dll - True - - @@ -478,40 +149,25 @@ McTools.Xrm.Connection - {befb0758-1a24-49cc-9c1f-32e9a5351bcf} + {22260532-d32b-4762-86d9-6631e6f23ff4} CrmWebResourcesUpdater.Common - - - + - + - Данный проект ссылается на пакеты NuGet, отсутствующие на этом компьютере. Используйте восстановление пакетов NuGet, чтобы скачать их. Дополнительную информацию см. по адресу: http://go.microsoft.com/fwlink/?LinkID=322105. Отсутствует следующий файл: {0}. + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - - - - - - + \ No newline at end of file diff --git a/CrmWebResourcesUpdater.Settings/Properties/AssemblyInfo.cs b/CrmWebResourcesUpdater.Settings/Properties/AssemblyInfo.cs index 38406be..656293d 100644 --- a/CrmWebResourcesUpdater.Settings/Properties/AssemblyInfo.cs +++ b/CrmWebResourcesUpdater.Settings/Properties/AssemblyInfo.cs @@ -2,7 +2,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("CrmWebResourcesUpdater.Settings")] @@ -10,26 +10,26 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("CrmWebResourcesUpdater.Settings")] -[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyCopyright("Copyright © 2020")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("2cf262f9-d0d9-4c45-84eb-430779973a05")] +[assembly: Guid("e1a14c0b-41e8-479d-a3f6-b6438af9d869")] // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // -// You can specify all the values or you can default the Build and Revision Numbers +// You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] diff --git a/CrmWebResourcesUpdater.Settings/Settings.cs b/CrmWebResourcesUpdater.Settings/Settings.cs index bec85b4..155563d 100644 --- a/CrmWebResourcesUpdater.Settings/Settings.cs +++ b/CrmWebResourcesUpdater.Settings/Settings.cs @@ -22,13 +22,16 @@ public class Settings const string ConnectionsPropertyName = "Connections"; const string SelectedConnectionIdPropertyName = "SelectedConnectionId"; const string AutoPublishPropertyName = "AutoPublishEnabled"; - const string IgnoreExtensionsProprtyName = "IgnoreExtensions"; - const string ExtendedLogProprtyName = "ExtendedLog"; + const string IgnoreExtensionsPropertyName = "IgnoreExtensions"; + const string ExtendedLogPropertyName = "ExtendedLog"; + const string SettingsVersionPropertyName = "SettingsVersion"; public const string FileKindGuid = "{6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C}"; public const string ProjectKindGuid = "{6BB5F8EE-4483-11D3-8BCF-00C04F8EC28C}"; public const string MappingFileName = "UploaderMapping.config"; + public const string CurrentConfigurationVersion = "1"; + private byte[] entropy = Encoding.Unicode.GetBytes("crm.publisher"); private WritableSettingsStore _settingsStore; private Guid _projectGuid; @@ -44,6 +47,11 @@ public class Settings /// public Guid? SelectedConnectionId { get; set; } + /// + /// Configuration version + /// + public string ConfigurationVersion { get; set; } + /// /// Collection Path based on project guid /// @@ -105,6 +113,7 @@ public Settings(IAsyncServiceProvider serviceProvider, Guid projectGuid) if (_settingsStore.CollectionExists(CollectionPath)) { + UpdateSettings(); Load(); } else @@ -113,6 +122,89 @@ public Settings(IAsyncServiceProvider serviceProvider, Guid projectGuid) } } + private void UpdateSettings() + { + string configVersion = null; + if (_settingsStore.PropertyExists(CollectionPath, SettingsVersionPropertyName)) + { + configVersion = _settingsStore.GetString(CollectionPath, SettingsVersionPropertyName); + } + if (configVersion == null) + { + try + { + var connections = new List(); + var deprecatedConnectionsXml = _settingsStore.GetString(CollectionPath, ConnectionsPropertyName); + var deprecatedConnections = (List)XmlSerializerHelper.Deserialize(deprecatedConnectionsXml, typeof(List)); + foreach (var connection in deprecatedConnections) + { + connections.Add(UpdateConnection(connection)); + } + var connectionsXml = XmlSerializerHelper.Serialize(connections); + _settingsStore.SetString(CollectionPath, ConnectionsPropertyName, connectionsXml); + _settingsStore.SetString(CollectionPath, SettingsVersionPropertyName, CurrentConfigurationVersion); + } + catch (Exception ex) + { + Logger.Write("Failed to convert connections: " + ex.Message); + } + } + } + + private ConnectionDetail UpdateConnection(McTools.Xrm.Connection.Deprecated.ConnectionDetail deprecatedConnection) + { + //deprecatedConnection.CrmTicket + //deprecatedConnection.OrganizationMajorVersion + //deprecatedConnection.OrganizationMinorVersion + //deprecatedConnection.PublisherPrefix + //deprecatedConnection.UseOnline + //deprecatedConnection.UseOsdp + //deprecatedConnection.UseSsl + + var connection = new ConnectionDetail() + { + AuthType = deprecatedConnection.AuthType, + ConnectionId = deprecatedConnection.ConnectionId, + ConnectionName = deprecatedConnection.ConnectionName, + IsCustomAuth = deprecatedConnection.IsCustomAuth, + IsFromSdkLoginCtrl = false, + LastUsedOn = DateTime.MinValue, + //NewAuthType = Microsoft.Xrm.Tooling.Connector.AuthenticationType.AD, + Organization = deprecatedConnection.Organization, + OrganizationDataServiceUrl = deprecatedConnection.OrganizationServiceUrl.Replace("Organization.svc", "OrganizationData.svc"), //TODO: May be wrong conversion + OrganizationFriendlyName = deprecatedConnection.OrganizationFriendlyName, + OrganizationServiceUrl = deprecatedConnection.OrganizationServiceUrl, + OrganizationUrlName = deprecatedConnection.OrganizationUrlName, + OrganizationVersion = deprecatedConnection.OrganizationVersion, + OriginalUrl = deprecatedConnection.WebApplicationUrl, //TODO: May be wrong conversion + SavePassword = deprecatedConnection.SavePassword, + ServerName = deprecatedConnection.OrganizationUrlName + "." + deprecatedConnection.ServerName, //TODO: May be wrong conversion + TenantId = Guid.Empty, + Timeout = deprecatedConnection.Timeout, + TimeoutTicks = deprecatedConnection.TimeoutTicks, + UseIfd = deprecatedConnection.UseIfd, + UseMfa = false, //TODO: May be wrong conversion + UserDomain = deprecatedConnection.UserDomain, + UserName = deprecatedConnection.UserName, + WebApplicationUrl = deprecatedConnection.WebApplicationUrl, + SelectedSolution = new SolutionDetail() + { + FriendlyName = deprecatedConnection.SolutionFriendlyName, + PublisherPrefix = deprecatedConnection.PublisherPrefix, + SolutionId = new Guid(deprecatedConnection.SolutionId), + UniqueName = deprecatedConnection.Solution + } + }; + if(connection.SavePassword) + { + connection.SetPassword(DecryptString(deprecatedConnection.UserPassword)); + connection.UserPasswordEncrypted = EncryptString(connection.UserPasswordEncrypted); + } + + return connection; + } + + /// /// Gets settings store for current user /// @@ -131,6 +223,7 @@ private void Load() { CrmConnections = GetCrmConnections(); SelectedConnectionId = _settingsStore.GetGuid(CollectionPath, SelectedConnectionIdPropertyName); + ConfigurationVersion = _settingsStore.GetString(CollectionPath, SettingsVersionPropertyName); } /// @@ -140,6 +233,10 @@ public void Save() { SetCrmConnections(CrmConnections); _settingsStore.SetGuid(CollectionPath, SelectedConnectionIdPropertyName, SelectedConnectionId); + if (ConfigurationVersion != null) + { + _settingsStore.SetString(CollectionPath, SettingsVersionPropertyName, ConfigurationVersion); + } } /// @@ -153,7 +250,7 @@ private CrmConnections GetCrmConnections() List connections; try { - connections = XmlSerializerHelper.Deserialize>(connectionsXml); + connections = (List)XmlSerializerHelper.Deserialize(connectionsXml, typeof(List)); var crmConnections = new CrmConnections() { Connections = connections }; var publisAfterUpload = true; if(_settingsStore.PropertyExists(CollectionPath, AutoPublishPropertyName)) @@ -163,25 +260,25 @@ private CrmConnections GetCrmConnections() crmConnections.PublishAfterUpload = publisAfterUpload; var ignoreExtensions = false; - if (_settingsStore.PropertyExists(CollectionPath, IgnoreExtensionsProprtyName)) + if (_settingsStore.PropertyExists(CollectionPath, IgnoreExtensionsPropertyName)) { - ignoreExtensions = _settingsStore.GetBoolean(CollectionPath, IgnoreExtensionsProprtyName); + ignoreExtensions = _settingsStore.GetBoolean(CollectionPath, IgnoreExtensionsPropertyName); } crmConnections.IgnoreExtensions = ignoreExtensions; var extendedLog = false; - if (_settingsStore.PropertyExists(CollectionPath, ExtendedLogProprtyName)) + if (_settingsStore.PropertyExists(CollectionPath, ExtendedLogPropertyName)) { - extendedLog = _settingsStore.GetBoolean(CollectionPath, ExtendedLogProprtyName); + extendedLog = _settingsStore.GetBoolean(CollectionPath, ExtendedLogPropertyName); } crmConnections.ExtendedLog = extendedLog; foreach (var connection in crmConnections.Connections) { - if (!String.IsNullOrEmpty(connection.UserPassword)) + if (!String.IsNullOrEmpty(connection.UserPasswordEncrypted)) { - connection.UserPassword = DecryptString(connection.UserPassword); + connection.UserPasswordEncrypted = DecryptString(connection.UserPasswordEncrypted); } } @@ -212,30 +309,30 @@ private void SetCrmConnections(CrmConnections crmConnections) { if (connection.ConnectionId != null && !passwordCache.ContainsKey(connection.ConnectionId.Value)) { - passwordCache.Add(connection.ConnectionId.Value, connection.UserPassword); + passwordCache.Add(connection.ConnectionId.Value, connection.UserPasswordEncrypted); } - if (!String.IsNullOrEmpty(connection.UserPassword) && connection.SavePassword) + if (!String.IsNullOrEmpty(connection.UserPasswordEncrypted) && connection.SavePassword) { - connection.UserPassword = EncryptString(connection.UserPassword); + connection.UserPasswordEncrypted = EncryptString(connection.UserPasswordEncrypted); } else { - connection.UserPassword = null; + connection.UserPasswordEncrypted = null; } } var connectionsXml = XmlSerializerHelper.Serialize(crmConnections.Connections); _settingsStore.SetString(CollectionPath, ConnectionsPropertyName, connectionsXml); _settingsStore.SetBoolean(CollectionPath, AutoPublishPropertyName, crmConnections.PublishAfterUpload); - _settingsStore.SetBoolean(CollectionPath, IgnoreExtensionsProprtyName, crmConnections.IgnoreExtensions); - _settingsStore.SetBoolean(CollectionPath, ExtendedLogProprtyName, crmConnections.ExtendedLog); + _settingsStore.SetBoolean(CollectionPath, IgnoreExtensionsPropertyName, crmConnections.IgnoreExtensions); + _settingsStore.SetBoolean(CollectionPath, ExtendedLogPropertyName, crmConnections.ExtendedLog); foreach (var connection in crmConnections.Connections) { - if (connection.ConnectionId!= null && passwordCache.ContainsKey(connection.ConnectionId.Value)) + if (connection.ConnectionId != null && passwordCache.ContainsKey(connection.ConnectionId.Value)) { - connection.UserPassword = passwordCache[connection.ConnectionId.Value]; + connection.UserPasswordEncrypted = passwordCache[connection.ConnectionId.Value]; } } } diff --git a/CrmWebResourcesUpdater.Settings/app.config b/CrmWebResourcesUpdater.Settings/app.config index 4f63318..9aa7f70 100644 --- a/CrmWebResourcesUpdater.Settings/app.config +++ b/CrmWebResourcesUpdater.Settings/app.config @@ -4,84 +4,20 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - + - - - - - - - - - - - - - - + + - - - - - + - + \ No newline at end of file diff --git a/CrmWebResourcesUpdater.Settings/packages.config b/CrmWebResourcesUpdater.Settings/packages.config index c79431d..99ace2d 100644 --- a/CrmWebResourcesUpdater.Settings/packages.config +++ b/CrmWebResourcesUpdater.Settings/packages.config @@ -1,126 +1,33 @@  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CrmWebResourcesUpdater/Commands/Base/BaseCommand.cs b/CrmWebResourcesUpdater/Commands/Base/BaseCommand.cs index 15262d9..ee794c5 100644 --- a/CrmWebResourcesUpdater/Commands/Base/BaseCommand.cs +++ b/CrmWebResourcesUpdater/Commands/Base/BaseCommand.cs @@ -3,7 +3,7 @@ using Microsoft.VisualStudio.Shell; using System.Windows.Forms; using CrmWebResourcesUpdater.Common; -using CrmWebResourcesUpdater.Helpers; +using CrmWebResourcesUpdater.Services.Helpers; namespace CrmWebResourcesUpdater { diff --git a/CrmWebResourcesUpdater/Commands/CreateWebResource.cs b/CrmWebResourcesUpdater/Commands/CreateWebResource.cs index 85d2860..d4dba7b 100644 --- a/CrmWebResourcesUpdater/Commands/CreateWebResource.cs +++ b/CrmWebResourcesUpdater/Commands/CreateWebResource.cs @@ -3,7 +3,8 @@ using Microsoft.VisualStudio.Shell; using System.Windows.Forms; using CrmWebResourcesUpdater.Common; -using CrmWebResourcesUpdater.Helpers; +using CrmWebResourcesUpdater.Services.Helpers; +using CrmWebResourcesUpdater.Services; namespace CrmWebResourcesUpdater { @@ -51,33 +52,40 @@ public static void Initialize(AsyncPackage package) /// Event args. public override async void MenuItemCallback(object sender, EventArgs e) { - var settings = await SettingsService.Instance.GetSettingsAsync(); - - var result = DialogResult.Cancel; - - if (settings.SelectedConnection == null) + try { + var settings = await SettingsService.Instance.GetSettingsAsync(); - if (projectHelper.ShowErrorDialog() == DialogResult.Yes) + var result = DialogResult.Cancel; + + if (settings.SelectedConnection == null) { - result = await PublishService.Instance.ShowConfigurationDialogAsync(ConfigurationMode.Normal); - if (result != DialogResult.OK) + + if (projectHelper.ShowErrorDialog() == DialogResult.Yes) + { + result = await PublishService.Instance.ShowConfigurationDialogAsync(ConfigurationMode.Normal); + if (result != DialogResult.OK) + { + return; + } + } + else { return; } } - else + if (settings.SelectedConnection == null) { + Logger.WriteLine("Error: Connection is not selected"); return; } + + await PublishService.Instance.CreateWebResourceAsync(); } - if (settings.SelectedConnection == null) + catch (Exception ex) { - Logger.WriteLine("Error: Connection is not selected"); - return; + Logger.Write("An error occured: " + ex.Message + "\r\n" + ex.StackTrace); } - - await PublishService.Instance.CreateWebResourceAsync(); } } } diff --git a/CrmWebResourcesUpdater/Commands/UpdateSelectedWebResources.cs b/CrmWebResourcesUpdater/Commands/UpdateSelectedWebResources.cs index 68b4887..9b86160 100644 --- a/CrmWebResourcesUpdater/Commands/UpdateSelectedWebResources.cs +++ b/CrmWebResourcesUpdater/Commands/UpdateSelectedWebResources.cs @@ -3,7 +3,8 @@ using Microsoft.VisualStudio.Shell; using System.Windows.Forms; using CrmWebResourcesUpdater.Common; -using CrmWebResourcesUpdater.Helpers; +using CrmWebResourcesUpdater.Services.Helpers; +using CrmWebResourcesUpdater.Services; namespace CrmWebResourcesUpdater { @@ -54,6 +55,7 @@ public static void Initialize(AsyncPackage package) /// Event args. public override async void MenuItemCallback(object sender, EventArgs e) { + try { var settings = await SettingsService.Instance.GetSettingsAsync(); if (settings.SelectedConnection == null) { @@ -78,6 +80,11 @@ public override async void MenuItemCallback(object sender, EventArgs e) } await PublishService.Instance.PublishWebResourcesAsync(true); + } + catch (Exception ex) + { + Logger.Write("An error occured: " + ex.Message + "\r\n" + ex.StackTrace); + } } } } diff --git a/CrmWebResourcesUpdater/Commands/UpdateWebResources.cs b/CrmWebResourcesUpdater/Commands/UpdateWebResources.cs index e971ae7..f3b0ddf 100644 --- a/CrmWebResourcesUpdater/Commands/UpdateWebResources.cs +++ b/CrmWebResourcesUpdater/Commands/UpdateWebResources.cs @@ -3,10 +3,11 @@ using Microsoft.VisualStudio.Shell; using System.Windows.Forms; using CrmWebResourcesUpdater.Common; -using CrmWebResourcesUpdater.Helpers; +using CrmWebResourcesUpdater.Services.Helpers; using McTools.Xrm.Connection.WinForms; using McTools.Xrm.Connection; using System.Collections.Generic; +using CrmWebResourcesUpdater.Services; namespace CrmWebResourcesUpdater { @@ -50,6 +51,7 @@ public static void Initialize(AsyncPackage package) /// Event args. public override async void MenuItemCallback(object sender, EventArgs e) { + try { var settings = await SettingsService.Instance.GetSettingsAsync(); if (settings.SelectedConnection == null) { @@ -73,6 +75,11 @@ public override async void MenuItemCallback(object sender, EventArgs e) } await PublishService.Instance.PublishWebResourcesAsync(false); + } + catch (Exception ex) + { + Logger.Write("An error occured: " + ex.Message + "\r\n" + ex.StackTrace); + } } } } diff --git a/CrmWebResourcesUpdater/Commands/UpdaterOptions.cs b/CrmWebResourcesUpdater/Commands/UpdaterOptions.cs index 8c8f16d..6182755 100644 --- a/CrmWebResourcesUpdater/Commands/UpdaterOptions.cs +++ b/CrmWebResourcesUpdater/Commands/UpdaterOptions.cs @@ -2,7 +2,8 @@ using System.ComponentModel.Design; using Microsoft.VisualStudio.Shell; using CrmWebResourcesUpdater.Common; -using CrmWebResourcesUpdater.Helpers; +using CrmWebResourcesUpdater.Services.Helpers; +using CrmWebResourcesUpdater.Services; namespace CrmWebResourcesUpdater { @@ -47,7 +48,13 @@ public static UpdaterOptions Instance /// Event args. public override async void MenuItemCallback(object sender, EventArgs e) { - await PublishService.Instance.ShowConfigurationDialogAsync(ConfigurationMode.Normal); + try { + await PublishService.Instance.ShowConfigurationDialogAsync(ConfigurationMode.Normal); + } + catch (Exception ex) + { + Logger.Write("An error occured: " + ex.Message + "\r\n" + ex.StackTrace); + } } } } diff --git a/CrmWebResourcesUpdater/CrmWebResourcesUpdater.cs b/CrmWebResourcesUpdater/CrmWebResourcesUpdater.cs index 29c973a..c151adb 100644 --- a/CrmWebResourcesUpdater/CrmWebResourcesUpdater.cs +++ b/CrmWebResourcesUpdater/CrmWebResourcesUpdater.cs @@ -2,12 +2,13 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using Microsoft.VisualStudio.Shell; -using CrmWebResourcesUpdater.Helpers; +using CrmWebResourcesUpdater.Services.Helpers; using CrmWebResourcesUpdater.Common; using Microsoft.VisualStudio.Shell.Interop; using System.Net; using Task = System.Threading.Tasks.Task; using System.Threading; +using CrmWebResourcesUpdater.Services; namespace CrmWebResourcesUpdater { @@ -79,7 +80,7 @@ private async Task InitializeDTE(CancellationToken cancellationToken) } catch (Exception ex) { - JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); } } } diff --git a/CrmWebResourcesUpdater/CrmWebResourcesUpdater.csproj b/CrmWebResourcesUpdater/CrmWebResourcesUpdater.csproj index 8284e76..f13dd7d 100644 --- a/CrmWebResourcesUpdater/CrmWebResourcesUpdater.csproj +++ b/CrmWebResourcesUpdater/CrmWebResourcesUpdater.csproj @@ -1,30 +1,28 @@  - - + 15.0 true $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - SAK - SAK - SAK - SAK true - + - true + false Key.snk + + false + Debug @@ -36,13 +34,16 @@ Properties CrmWebResourcesUpdater CrmWebResourcesUpdater - v4.6.1 + v4.6.2 true true true true true - false + true + Program + $(DevEnvDir)devenv.exe + /rootsuffix Exp true @@ -73,7 +74,9 @@ - + + true + true @@ -86,7 +89,9 @@ Always true - + + Designer + Designer @@ -129,19 +134,15 @@ McTools.Xrm.Connection - {befb0758-1a24-49cc-9c1f-32e9a5351bcf} + {22260532-d32b-4762-86d9-6631e6f23ff4} CrmWebResourcesUpdater.Common - - {668b006c-bd03-4a67-8847-6c3792a97703} - CrmWebResourcesUpdater.Forms - - - {8433C7D4-9AB0-47DA-8314-F39D02656C22} + + {d9c59fab-cd1a-484b-8052-1f72ca1debb8} CrmWebResourcesUpdater.Services - {2cf262f9-d0d9-4c45-84eb-430779973a05} + {e1a14c0b-41e8-479d-a3f6-b6438af9d869} CrmWebResourcesUpdater.Settings @@ -149,23 +150,21 @@ True - - True - - - ..\packages\Microsoft.CrmSdk.CoreAssemblies.8.0.1\lib\net45\Microsoft.Crm.Sdk.Proxy.dll + + + ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.19.8\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll - - ..\packages\Microsoft.IdentityModel.7.0.0\lib\net35\microsoft.identitymodel.dll + + ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.19.8\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll - - ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.22.302111727\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll + + ..\packages\Microsoft.VisualStudio.CoreUtility.15.6.27740\lib\net46\Microsoft.VisualStudio.CoreUtility.dll - - ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.22.302111727\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll + + ..\packages\Microsoft.VisualStudio.ImageCatalog.15.9.28307\lib\net45\Microsoft.VisualStudio.ImageCatalog.dll - - ..\packages\Microsoft.VisualStudio.Imaging.14.3.25407\lib\net45\Microsoft.VisualStudio.Imaging.dll + + ..\packages\Microsoft.VisualStudio.Imaging.15.9.28307\lib\net45\Microsoft.VisualStudio.Imaging.dll ..\packages\Microsoft.VisualStudio.Imaging.Interop.14.0.DesignTime.14.3.26930\lib\net20\Microsoft.VisualStudio.Imaging.Interop.14.0.DesignTime.dll @@ -174,19 +173,12 @@ ..\packages\Microsoft.VisualStudio.OLE.Interop.7.10.6071\lib\Microsoft.VisualStudio.OLE.Interop.dll - - ..\packages\Microsoft.VisualStudio.Shell.14.0.14.3.25407\lib\Microsoft.VisualStudio.Shell.14.0.dll + + ..\packages\Microsoft.VisualStudio.Shell.15.0.15.9.28307\lib\net45\Microsoft.VisualStudio.Shell.15.0.dll - - ..\packages\Microsoft.VisualStudio.Shell.Immutable.10.0.10.0.30319\lib\net40\Microsoft.VisualStudio.Shell.Immutable.10.0.dll + + ..\packages\Microsoft.VisualStudio.Shell.Framework.15.9.28307\lib\net45\Microsoft.VisualStudio.Shell.Framework.dll - - ..\packages\Microsoft.VisualStudio.Shell.Immutable.11.0.11.0.50727\lib\net45\Microsoft.VisualStudio.Shell.Immutable.11.0.dll - - - ..\packages\Microsoft.VisualStudio.Shell.Immutable.12.0.12.0.21003\lib\net45\Microsoft.VisualStudio.Shell.Immutable.12.0.dll - - ..\packages\Microsoft.VisualStudio.Shell.Interop.7.10.6072\lib\net11\Microsoft.VisualStudio.Shell.Interop.dll @@ -207,13 +199,21 @@ True + ..\packages\Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime.15.0.26929\lib\net20\Microsoft.VisualStudio.Shell.Interop.15.3.DesignTime.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.15.6.DesignTime.15.6.27413\lib\net20\Microsoft.VisualStudio.Shell.Interop.15.6.DesignTime.dll True ..\packages\Microsoft.VisualStudio.Shell.Interop.8.0.8.0.50728\lib\net11\Microsoft.VisualStudio.Shell.Interop.8.0.dll - ..\packages\Microsoft.VisualStudio.Shell.Interop.9.0.9.0.30729\lib\Microsoft.VisualStudio.Shell.Interop.9.0.dll + ..\packages\Microsoft.VisualStudio.Shell.Interop.9.0.9.0.30730\lib\net11\Microsoft.VisualStudio.Shell.Interop.9.0.dll + + + ..\packages\Microsoft.VisualStudio.Text.Data.15.6.27740\lib\net46\Microsoft.VisualStudio.Text.Data.dll ..\packages\Microsoft.VisualStudio.TextManager.Interop.7.10.6071\lib\net11\Microsoft.VisualStudio.TextManager.Interop.dll @@ -221,60 +221,62 @@ ..\packages\Microsoft.VisualStudio.TextManager.Interop.8.0.8.0.50728\lib\net11\Microsoft.VisualStudio.TextManager.Interop.8.0.dll - - ..\packages\Microsoft.VisualStudio.Threading.14.1.111\lib\net45\Microsoft.VisualStudio.Threading.dll - - - ..\packages\Microsoft.VisualStudio.Utilities.14.3.25407\lib\net45\Microsoft.VisualStudio.Utilities.dll + + ..\packages\Microsoft.VisualStudio.Threading.15.8.122\lib\net46\Microsoft.VisualStudio.Threading.dll - - ..\packages\Microsoft.VisualStudio.Validation.14.1.111\lib\net45\Microsoft.VisualStudio.Validation.dll + + ..\packages\Microsoft.VisualStudio.Utilities.15.9.28307\lib\net46\Microsoft.VisualStudio.Utilities.dll - - ..\packages\Microsoft.CrmSdk.CoreAssemblies.8.0.1\lib\net45\Microsoft.Xrm.Sdk.dll + + ..\packages\Microsoft.VisualStudio.Validation.15.3.15\lib\net45\Microsoft.VisualStudio.Validation.dll - - ..\packages\Microsoft.CrmSdk.Deployment.8.0.0\lib\net45\Microsoft.Xrm.Sdk.Deployment.dll + + ..\packages\Newtonsoft.Json.6.0.6\lib\net45\Newtonsoft.Json.dll - - ..\packages\Microsoft.CrmSdk.Workflow.8.0.0\lib\net45\Microsoft.Xrm.Sdk.Workflow.dll + + ..\packages\StreamJsonRpc.1.3.23\lib\net45\StreamJsonRpc.dll - - ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.8.0.0\lib\net45\Microsoft.Xrm.Tooling.Connector.dll - - - - + + + - - - - - - - - + + ..\packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll + + + ..\packages\System.Security.Cryptography.Algorithms.4.3.1\lib\net461\System.Security.Cryptography.Algorithms.dll + + + ..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll + + + ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll + + + ..\packages\System.Security.Cryptography.X509Certificates.4.3.2\lib\net461\System.Security.Cryptography.X509Certificates.dll + - - - + + + + - - - Данный проект ссылается на пакеты NuGet, отсутствующие на этом компьютере. Используйте восстановление пакетов NuGet, чтобы скачать их. Дополнительную информацию см. по адресу: http://go.microsoft.com/fwlink/?LinkID=322105. Отсутствует следующий файл: {0}. + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + \ No newline at end of file diff --git a/CrmWebResourcesUpdater/app.config b/CrmWebResourcesUpdater/app.config index 3faa350..446eadd 100644 --- a/CrmWebResourcesUpdater/app.config +++ b/CrmWebResourcesUpdater/app.config @@ -4,104 +4,20 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - + - - - - - - + + - - - - - + - + \ No newline at end of file diff --git a/CrmWebResourcesUpdater/packages.config b/CrmWebResourcesUpdater/packages.config index 63e3641..6c5faa9 100644 --- a/CrmWebResourcesUpdater/packages.config +++ b/CrmWebResourcesUpdater/packages.config @@ -1,30 +1,35 @@  - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CrmWebResourcesUpdater/source.extension.vsixmanifest b/CrmWebResourcesUpdater/source.extension.vsixmanifest index 438b033..bd80465 100644 --- a/CrmWebResourcesUpdater/source.extension.vsixmanifest +++ b/CrmWebResourcesUpdater/source.extension.vsixmanifest @@ -1,20 +1,20 @@  - - Microsoft Dynamics CRM Web Resources Updater - Microsoft Dynamics CRM Web Resources Updater gives you an easy way to update and publish web resources directly from Visual Studio. Add-on updates only web resources that are differ. So it takes as little time as possible to publish web resources. You can configure add-on to automatically publish just updated web resources. - http://happycrm.blogspot.ru/p/crm-publisher.html + + Microsoft Dynamics 365 CRM Web Resources Updater + Microsoft Dynamics 365 CRM Web Resources Updater gives you an easy way to update and publish web resources directly from Visual Studio. Add-on updates only web resources that are differ. So it takes as little time as possible to publish web resources. You can configure add-on to automatically publish just updated web resources. + https://happycrm.blogspot.ru/p/crm-publisher.html Resources\license.txt Resources\ReadMe.docx Resources\UpdaterLogo.png Resources\MenuItems.png - Microsoft Dynamics CRM, Web Resources, Web Resource, Publish, Publishing, Update, Updating + Microsoft Dynamics CRM 365, Microsoft Dynamics CRM, CRM, CRM Web Resources, D365 Web Resources, Dynamics 365, Dynamics CRM, D365, Dynamics 365 Customer Engagement - - - + + + @@ -23,6 +23,6 @@ - + diff --git a/misc/screenshots/Configuration.png b/misc/screenshots/Configuration.png new file mode 100644 index 0000000..7247795 Binary files /dev/null and b/misc/screenshots/Configuration.png differ diff --git a/misc/screenshots/ConnectionDialog.png b/misc/screenshots/ConnectionDialog.png new file mode 100644 index 0000000..f3a7a6d Binary files /dev/null and b/misc/screenshots/ConnectionDialog.png differ diff --git a/misc/screenshots/MappingFilesCreation.png b/misc/screenshots/MappingFilesCreation.png new file mode 100644 index 0000000..3cf8eff Binary files /dev/null and b/misc/screenshots/MappingFilesCreation.png differ diff --git a/misc/screenshots/NewConnectionButton.png b/misc/screenshots/NewConnectionButton.png new file mode 100644 index 0000000..128d95e Binary files /dev/null and b/misc/screenshots/NewConnectionButton.png differ diff --git a/misc/screenshots/PublishWebResource.png b/misc/screenshots/PublishWebResource.png new file mode 100644 index 0000000..a141baf Binary files /dev/null and b/misc/screenshots/PublishWebResource.png differ diff --git a/misc/screenshots/PublishWebResources.png b/misc/screenshots/PublishWebResources.png new file mode 100644 index 0000000..3544268 Binary files /dev/null and b/misc/screenshots/PublishWebResources.png differ diff --git a/misc/screenshots/SetUpWindow.png b/misc/screenshots/SetUpWindow.png new file mode 100644 index 0000000..e8b3fe6 Binary files /dev/null and b/misc/screenshots/SetUpWindow.png differ diff --git a/misc/screenshots/WithAndWithoutExtensions.png b/misc/screenshots/WithAndWithoutExtensions.png new file mode 100644 index 0000000..7c102ed Binary files /dev/null and b/misc/screenshots/WithAndWithoutExtensions.png differ