// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. #region Using directives using System; using System.Management.Automation; using System.Globalization; #endregion namespace Microsoft.Management.Infrastructure.CimCmdlets { #region AsyncResultType /// /// /// Async result type /// /// public enum AsyncResultType { Result, Exception, Completion } #endregion #region CimResultContext /// /// Cim Result Context. /// internal class CimResultContext { /// /// Constructor. /// /// internal CimResultContext(object ErrorSource) { this.errorSource = ErrorSource; } /// /// ErrorSource property. /// internal object ErrorSource { get { return this.errorSource; } } private object errorSource; } #endregion #region AsyncResultEventArgsBase /// /// /// Base class of async result event argument /// /// internal abstract class AsyncResultEventArgsBase : EventArgs { /// /// Constructor. /// /// /// /// public AsyncResultEventArgsBase( CimSession session, IObservable observable, AsyncResultType resultType) { this.session = session; this.observable = observable; this.resultType = resultType; } /// /// Constructor. /// /// /// /// /// public AsyncResultEventArgsBase( CimSession session, IObservable observable, AsyncResultType resultType, CimResultContext cimResultContext) { this.session = session; this.observable = observable; this.resultType = resultType; this.context = cimResultContext; } public readonly CimSession session; public readonly IObservable observable; public readonly AsyncResultType resultType; // property ErrorSource public readonly CimResultContext context; } #endregion #region AsyncResult*Args /// /// /// operation successfully completed event argument /// /// internal class AsyncResultCompleteEventArgs : AsyncResultEventArgsBase { /// /// /// Constructor /// /// /// object. /// public AsyncResultCompleteEventArgs( CimSession session, IObservable observable) : base(session, observable, AsyncResultType.Completion) { } } /// /// /// async result argument with object /// /// internal class AsyncResultObjectEventArgs : AsyncResultEventArgsBase { /// /// Constructor. /// /// /// /// public AsyncResultObjectEventArgs( CimSession session, IObservable observable, object resultObject) : base(session, observable, AsyncResultType.Result) { this.resultObject = resultObject; } public readonly object resultObject; } /// /// /// operation completed with exception event argument /// /// internal class AsyncResultErrorEventArgs : AsyncResultEventArgsBase { /// /// Constructor. /// /// /// /// public AsyncResultErrorEventArgs( CimSession session, IObservable observable, Exception error) : base(session, observable, AsyncResultType.Exception) { this.error = error; } /// /// Constructor. /// /// /// /// /// public AsyncResultErrorEventArgs( CimSession session, IObservable observable, Exception error, CimResultContext cimResultContext) : base(session, observable, AsyncResultType.Exception, cimResultContext) { this.error = error; } public readonly Exception error; } #endregion #region CimResultObserver /// /// /// Observer to consume results from asynchronous operations, such as, /// EnumerateInstancesAsync operation of object. /// /// /// (See https://channel9.msdn.com/posts/J.Van.Gogh/Reactive-Extensions-API-in-depth-Contract/) /// for the IObserver/IObservable contact /// - the only possible sequence is OnNext* (OnCompleted|OnError)? /// - callbacks are serialized /// - Subscribe never throws /// /// /// object type internal class CimResultObserver : IObserver { /// /// Define delegate that handles new cmdlet action come from /// the operations related to the current CimSession object. /// /// CimSession object, which raised the event. /// Event args. public delegate void ResultEventHandler( object observer, AsyncResultEventArgsBase resultArgs); /// /// Define an Event based on the NewActionHandler. /// public event ResultEventHandler OnNewResult; /// /// Constructor. /// /// object that issued the operation. /// Operation that can be observed. public CimResultObserver(CimSession session, IObservable observable) { this.session = session; this.observable = observable; } /// /// Constructor. /// /// object that issued the operation. /// Operation that can be observed. public CimResultObserver(CimSession session, IObservable observable, CimResultContext cimResultContext) { this.session = session; this.observable = observable; this.context = cimResultContext; } /// /// /// Operation completed successfully /// /// public virtual void OnCompleted() { // callbacks should never throw any exception to // protocol layer, otherwise the client process will be // terminated because of unhandled exception, same with // OnNext, OnError try { AsyncResultCompleteEventArgs completeArgs = new AsyncResultCompleteEventArgs( this.session, this.observable); this.OnNewResult(this, completeArgs); } catch (Exception ex) { this.OnError(ex); DebugHelper.WriteLogEx("{0}", 0, ex); } } /// /// /// Operation completed with an error /// /// /// Error object. public virtual void OnError(Exception error) { try { AsyncResultErrorEventArgs errorArgs = new AsyncResultErrorEventArgs( this.session, this.observable, error, this.context); this.OnNewResult(this, errorArgs); } catch (Exception ex) { // !!ignore the exception DebugHelper.WriteLogEx("{0}", 0, ex); } } /// /// Deliver the result value. /// /// protected void OnNextCore(object value) { DebugHelper.WriteLogEx("value = {0}.", 1, value); try { AsyncResultObjectEventArgs resultArgs = new AsyncResultObjectEventArgs( this.session, this.observable, value); this.OnNewResult(this, resultArgs); } catch (Exception ex) { this.OnError(ex); DebugHelper.WriteLogEx("{0}", 0, ex); } } /// /// /// Operation got a new result object /// /// /// Result object. public virtual void OnNext(T value) { DebugHelper.WriteLogEx("value = {0}.", 1, value); // do not allow null value if (value == null) { return; } this.OnNextCore(value); } #region members /// /// Session object of the operation. /// protected CimSession CurrentSession { get { return session; } } private CimSession session; /// /// Async operation that can be observed. /// private IObservable observable; /// /// object used during delivering result. /// private CimResultContext context; #endregion } /// /// CimSubscriptionResultObserver class definition. /// internal class CimSubscriptionResultObserver : CimResultObserver { /// /// Constructor. /// /// /// public CimSubscriptionResultObserver(CimSession session, IObservable observable) : base(session, observable) { } /// /// Constructor. /// /// /// public CimSubscriptionResultObserver( CimSession session, IObservable observable, CimResultContext context) : base(session, observable, context) { } /// /// Override the OnNext method. /// /// public override void OnNext(CimSubscriptionResult value) { DebugHelper.WriteLogEx(); base.OnNextCore(value); } } /// /// CimMethodResultObserver class definition. /// internal class CimMethodResultObserver : CimResultObserver { /// /// Constructor. /// /// /// public CimMethodResultObserver(CimSession session, IObservable observable) : base(session, observable) { } /// /// Constructor. /// /// /// /// public CimMethodResultObserver( CimSession session, IObservable observable, CimResultContext context) : base(session, observable, context) { } /// /// Override the OnNext method. /// /// public override void OnNext(CimMethodResultBase value) { DebugHelper.WriteLogEx(); const string PSTypeCimMethodResult = @"Microsoft.Management.Infrastructure.CimMethodResult"; const string PSTypeCimMethodStreamedResult = @"Microsoft.Management.Infrastructure.CimMethodStreamedResult"; const string PSTypeCimMethodResultTemplate = @"{0}#{1}#{2}"; string resultObjectPSType = null; PSObject resultObject = null; CimMethodResult methodResult = value as CimMethodResult; if (methodResult != null) { resultObjectPSType = PSTypeCimMethodResult; resultObject = new PSObject(); foreach (CimMethodParameter param in methodResult.OutParameters) { resultObject.Properties.Add(new PSNoteProperty(param.Name, param.Value)); } } else { CimMethodStreamedResult methodStreamedResult = value as CimMethodStreamedResult; if (methodStreamedResult != null) { resultObjectPSType = PSTypeCimMethodStreamedResult; resultObject = new PSObject(); resultObject.Properties.Add(new PSNoteProperty(@"ParameterName", methodStreamedResult.ParameterName)); resultObject.Properties.Add(new PSNoteProperty(@"ItemType", methodStreamedResult.ItemType)); resultObject.Properties.Add(new PSNoteProperty(@"ItemValue", methodStreamedResult.ItemValue)); } } if (resultObject != null) { resultObject.Properties.Add(new PSNoteProperty(@"PSComputerName", this.CurrentSession.ComputerName)); resultObject.TypeNames.Insert(0, resultObjectPSType); resultObject.TypeNames.Insert(0, string.Format(CultureInfo.InvariantCulture, PSTypeCimMethodResultTemplate, resultObjectPSType, ClassName, MethodName)); base.OnNextCore(resultObject); } } /// /// Methodname. /// internal string MethodName { get; set; } /// /// Classname. /// internal string ClassName { get; set; } } /// /// IgnoreResultObserver class definition. /// internal class IgnoreResultObserver : CimResultObserver { /// /// Constructor. /// /// /// public IgnoreResultObserver(CimSession session, IObservable observable) : base(session, observable) { } /// /// Override the OnNext method. /// /// public override void OnNext(CimInstance value) { DebugHelper.WriteLogEx(); } } #endregion }