-
-
Save mrichman/40ced4a50589c9f0f119 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ModuleBase.ReportProgress() [CLTDEPAPI10] [1]% [Installing Mobile Recruiter] | |
ModuleBase.ReportProgress() [CLTDEPFE1] [1]% [Installing Mobile Recruiter] | |
ModuleBase.ReportProgress() [CLTDEPAPI11] [1]% [Installing Mobile Recruiter] | |
ModuleBase.ReportProgress() [CLTDEPFE1] [5]% [Invoking installer agent at net.tcp://cltdepfe1:8890/] | |
ModuleBase.ReportProgress() [CLTDEPAPI11] [5]% [Invoking installer agent at net.tcp://cltdepapi11:8890/] | |
ModuleBase.ReportProgress() [CLTDEPAPI10] [5]% [Invoking installer agent at net.tcp://cltdepapi10:8890/] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#region | |
using System; | |
using System.ComponentModel; | |
using System.ServiceModel; | |
using NLog; | |
#endregion | |
namespace Cmc.Installer.Agent.Client | |
{ | |
/// <summary> | |
/// This is the client library that wraps the InstallerAgentService.InstallerAgentServiceClient WCF service reference. | |
/// By default WCF will attempt to dispatch using an available SynchronizationContext. | |
/// The problem with this callback is the UI thread is already blocked in an outbound call. | |
/// For the call to dispatch we need to tell WCF not to use the SynchronizationContext. | |
/// </summary> | |
//[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)] | |
public sealed class InstallerAgentServiceClient : IInstallerAgentServiceClient, InstallerAgentService.IInstallerAgentServiceCallback, IDisposable | |
{ | |
private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); | |
private readonly InstallerAgentService.InstallerAgentServiceClient _client; // WCF client proxy | |
private readonly IInstallModule _installModule; | |
/// <summary> | |
/// Initializes a new instance of the <see cref="InstallerAgentServiceClient" /> class. | |
/// </summary> | |
/// <param name="module">The module.</param> | |
/// <param name="endpointAddress">The endpoint address.</param> | |
public InstallerAgentServiceClient(IInstallModule module, EndpointAddress endpointAddress) | |
{ | |
try | |
{ | |
// Each service client instance receives its own context | |
var instanceContext = new InstanceContext(this); | |
_client = new InstallerAgentService.InstallerAgentServiceClient(instanceContext, new NetTcpBinding(), | |
endpointAddress); | |
_installModule = module; | |
} | |
catch (Exception ex) | |
{ | |
Logger.Error(ex.Message); | |
throw; | |
} | |
} | |
/// <summary> | |
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. | |
/// </summary> | |
public void Dispose() | |
{ | |
Dispose(true); | |
//GC.SuppressFinalize(this); //TODO Is this safe? | |
} | |
/// <summary> | |
/// Called when [update progress]. | |
/// </summary> | |
/// <param name="progressPercentage">The progress.</param> | |
/// <exception cref="System.NotImplementedException"></exception> | |
public void OnUpdateProgress(int progressPercentage) | |
{ | |
//Logger.Trace("OnUpdateProgress = " + progressPercentage); | |
var args = new ProgressChangedEventArgs(progressPercentage, null); | |
Progress = progressPercentage; | |
_installModule.OnProgressChanged(this, args); | |
} | |
/// <summary> | |
/// Called when [install complete]. | |
/// </summary> | |
public void OnInstallComplete() | |
{ | |
Logger.Trace("InstallerAgentServiceClient.OnInstallComplete()"); | |
var handler = InstallCompleted; | |
if (handler != null) | |
{ | |
handler(this, EventArgs.Empty); | |
} | |
} | |
/// <summary> | |
/// Called when [uninstall complete]. | |
/// </summary> | |
/// <exception cref="System.NotImplementedException"></exception> | |
public void OnUninstallComplete() | |
{ | |
//_installModule.OnAfterUninstall(); | |
} | |
/// <summary> | |
/// Gets the progress. | |
/// </summary> | |
/// <value> | |
/// The progress. | |
/// </value> | |
public int Progress { get; set; } | |
/// <summary> | |
/// Installs the specified installer path. | |
/// </summary> | |
/// <param name="installerPath">The installer path.</param> | |
/// <param name="commandLine">The command line.</param> | |
public void Install(string installerPath, string commandLine) | |
{ | |
//TODO May need to introduce a delay to account for WCF service startup time | |
try | |
{ | |
// Invoke Cmc.Installer.Agent.InstallerAgentService::Install() via Net.Tcp | |
_client.Install(installerPath, commandLine); | |
} | |
catch (EndpointNotFoundException enfe) | |
{ | |
Logger.ErrorException("Endpoint not found: " + enfe.Message, enfe); | |
throw; | |
} | |
catch (ProtocolException pe) | |
{ | |
// Are you sure you're connecting to a Net.Tcp port and not a mex (http) port? | |
Logger.ErrorException(pe.Message, pe); | |
throw; | |
} | |
} | |
/// <summary> | |
/// Uninstalls the specified installer path. | |
/// </summary> | |
/// <param name="installerPath">The installer path.</param> | |
/// <exception cref="System.NotImplementedException"></exception> | |
public void Uninstall(string installerPath) | |
{ | |
// Invoke Cmc.Installer.Agent.InstallerAgentService::Uninstall() via Net.Tcp | |
_client.Uninstall(installerPath); | |
} | |
/// <summary> | |
/// Occurs when [progress changed]. | |
/// </summary> | |
public event ProgressChangedEventHandler ProgressChanged; | |
/// <summary> | |
/// Occurs when [install completed]. | |
/// </summary> | |
public event EventHandler InstallCompleted; | |
/// <summary> | |
/// Releases unmanaged and - optionally - managed resources. | |
/// </summary> | |
/// <param name="disposing"> | |
/// <c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only | |
/// unmanaged resources. | |
/// </param> | |
private void Dispose(bool disposing) | |
{ | |
if (disposing) | |
_client.Close(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#region | |
using System; | |
using System.ComponentModel.Composition; | |
using System.Diagnostics; | |
using System.ServiceModel; | |
using System.Threading.Tasks; | |
using Cmc.Installer.Agent.Client; | |
using Cmc.Installer.Infrastructure; | |
using Cmc.Installer.Modules.MobileRecruiter.Views; | |
using Microsoft.Practices.Prism.MefExtensions.Modularity; | |
using Microsoft.Practices.Prism.Regions; | |
#endregion | |
namespace Cmc.Installer.Modules.MobileRecruiter | |
{ | |
/// <summary> | |
/// Mobile Recruiter Module | |
/// </summary> | |
[ModuleExport(typeof (MobileRecruiterModule))] | |
public sealed class MobileRecruiterModule : ModuleBase, IDisposable | |
{ | |
[Import] public IRegionManager Region; | |
/// <summary> | |
/// The installer agent service client. Note: If this lived in ModuleBase | |
/// it would create a circular dependency with Cmc.Installer.Agent.Client | |
/// </summary> | |
private InstallerAgentServiceClient _installerAgentServiceClient; | |
/// <summary> | |
/// Gets the name of the module. | |
/// </summary> | |
/// <value> | |
/// The name of the module. | |
/// </value> | |
public override string ModuleName | |
{ | |
get { return "Mobile Recruiter"; } | |
} | |
/// <summary> | |
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. | |
/// </summary> | |
public void Dispose() | |
{ | |
_installerAgentServiceClient.Dispose(); | |
} | |
/// <summary> | |
/// Determines if module prerequisites are satisfied | |
/// </summary> | |
/// <param name="targetMachine"></param> | |
/// <returns></returns> | |
/// <exception cref="System.NotImplementedException"></exception> | |
public override bool PrerequisitesSatisfied(string targetMachine) | |
{ | |
throw new NotImplementedException(); | |
} | |
/// <summary> | |
/// Installs the specified target machine. | |
/// </summary> | |
/// <param name="targetMachine">The target machine.</param> | |
/// <param name="progress">The progress.</param> | |
/// <returns></returns> | |
public override async Task<int> Install(string targetMachine, IProgress<InstallProgress> progress) | |
{ | |
Progress = progress; | |
ReportProgress(progress, targetMachine, 1, "Installing " + ModuleName); | |
LoadSettings(); | |
var msi = Settings.MobileRecruiterModule.MSIs.MSI.Path.Value; | |
var msiArgs = Settings.MobileRecruiterModule.MSIs.MSI.CommandLine.Value; | |
//TODO make port configurable at runtime via app.config with fallback of 8890 or whatever | |
var uri = new Uri("net.tcp://" + targetMachine + ":8890"); | |
var endpointAddress = new EndpointAddress(uri); | |
ReportProgress(Progress, targetMachine, 5, "Invoking installer agent at " + uri); | |
_installerAgentServiceClient = new InstallerAgentServiceClient(this, endpointAddress); | |
// Bubble progress events back up to WPF Shell | |
_installerAgentServiceClient.ProgressChanged += (sender, args) => | |
{ | |
Debug.WriteLine("InstallerAgentServiceClient.ProgressChanged: {0}", args.ProgressPercentage); | |
ReportProgress(Progress, targetMachine, args.ProgressPercentage, args.UserState.ToString()); | |
}; | |
var ret = await _installerAgentServiceClient.Install(msi, msiArgs); | |
return ret; | |
} | |
/// <summary> | |
/// Uninstalls the specified target machine. | |
/// </summary> | |
/// <param name="targetMachine">The target machine.</param> | |
/// <param name="progress">The progress.</param> | |
/// <returns></returns> | |
/// <exception cref="System.NotImplementedException"></exception> | |
public override Task<int> Uninstall(string targetMachine, IProgress<InstallProgress> progress) | |
{ | |
throw new NotImplementedException(); | |
} | |
/// <summary> | |
/// Notifies the module that it has be initialized. | |
/// </summary> | |
public override void Initialize() | |
{ | |
Region.RegisterViewWithRegion(RegionNames.MainContentRegion, typeof (MobileRecruiterView)); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#region | |
using System; | |
using System.ComponentModel; | |
using System.Diagnostics; | |
using System.IO; | |
using System.Reflection; | |
using System.Threading.Tasks; | |
using Microsoft.Practices.Prism.Modularity; | |
#endregion | |
namespace Cmc.Installer | |
{ | |
public abstract class ModuleBase : IModule, IInstallModule | |
{ | |
protected IProgress<InstallProgress> Progress; | |
protected dynamic Settings; | |
private string _targetMachine; | |
public event ProgressChangedEventHandler ProgressChanged; | |
public event InstallCompletedEventHandler InstallCompleted; | |
/// <summary> | |
/// Gets the name of the module. | |
/// </summary> | |
/// <value> | |
/// The name of the module. | |
/// </value> | |
public abstract string ModuleName { get; } | |
/// <summary> | |
/// Determines if module prerequisites are satisfied | |
/// </summary> | |
/// <param name="targetMachine"></param> | |
/// <returns></returns> | |
public abstract bool PrerequisitesSatisfied(string targetMachine); | |
/// <summary> | |
/// Called when [progress changed]. | |
/// </summary> | |
/// <param name="sender">The sender.</param> | |
/// <param name="args">The <see cref="ProgressChangedEventArgs" /> instance containing the event data.</param> | |
public virtual void OnProgressChanged(object sender, ProgressChangedEventArgs args) | |
{ | |
ReportProgress(Progress, _targetMachine, args.ProgressPercentage); | |
} | |
/// <summary> | |
/// Loads the settings. | |
/// </summary> | |
/// <exception cref="System.IO.FileNotFoundException"></exception> | |
/// <exception cref="Cmc.Installer.ModuleSettingsNotFoundException"></exception> | |
public virtual void LoadSettings() | |
{ | |
var currentDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); | |
if (!File.Exists(currentDirectory + @"\settings.xml")) | |
{ | |
throw new FileNotFoundException(currentDirectory + @"\settings.xml"); | |
} | |
Settings = SettingsReader.LoadSettings(currentDirectory + @"\settings.xml"); | |
// Verify that settings.xml contains a <Modules><MobileRecruiterModule></MobileRecruiterModule></Modules> section | |
if (Settings.Modules == null || Settings.Modules.MobileRecruiterModule == null) | |
{ | |
throw new ModuleSettingsNotFoundException(); | |
} | |
} | |
/// <summary> | |
/// Installs the specified target machine. | |
/// </summary> | |
/// <param name="targetMachine">The target machine.</param> | |
/// <param name="progress">The progress.</param> | |
/// <returns></returns> | |
public abstract Task<int> Install(string targetMachine, IProgress<InstallProgress> progress); | |
/// <summary> | |
/// Uninstalls the specified target machine. | |
/// </summary> | |
/// <param name="targetMachine">The target machine.</param> | |
/// <param name="progress">The progress.</param> | |
/// <returns></returns> | |
public abstract Task<int> Uninstall(string targetMachine, IProgress<InstallProgress> progress); | |
/// <summary> | |
/// Notifies the module that it has be initialized. | |
/// </summary> | |
public abstract void Initialize(); | |
/// <summary> | |
/// Installs the asynchronous. | |
/// </summary> | |
/// <param name="targetMachine">The target machine.</param> | |
/// <param name="progress">The progress.</param> | |
/// <returns></returns> | |
public virtual Task<InstallCompletedResult> InstallAsync(string targetMachine, IProgress<InstallProgress> progress = null) | |
{ | |
var tcs = new TaskCompletionSource<InstallCompletedResult>(); | |
InstallCompletedEventHandler handler = null; | |
handler = (s, e) => | |
{ | |
InstallCompleted -= handler; | |
if (e.Exception != null) | |
tcs.TrySetException(e.Exception); | |
else | |
tcs.TrySetResult(e.Result); | |
}; | |
InstallCompleted += handler; | |
Install(targetMachine, progress); | |
return tcs.Task; | |
} | |
/// <summary> | |
/// Reports the progress. | |
/// </summary> | |
/// <param name="progress">The progress.</param> | |
/// <param name="machineName">Name of the machine.</param> | |
/// <param name="progressPercentage">The progress percentage.</param> | |
/// <param name="message">The message.</param> | |
protected void ReportProgress(IProgress<InstallProgress> progress, string machineName, int progressPercentage, | |
string message = "") | |
{ | |
if (progress == null) return; | |
Debug.WriteLine("ModuleBase.ReportProgress() [{0}] [{1}%] [{2}]", machineName, progressPercentage, | |
message); | |
progress.Report(new InstallProgress | |
{ | |
MachineName = machineName, | |
ProgressPercentage = progressPercentage, | |
Message = message | |
}); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment