/// <summary> /// Crea una nuova istanza della classe ProcessingServiceMonitor usando i parametri specificati /// per la configurazione di un proxy interno. /// </summary> /// <param name="bindingConfig">La configurazione del proxy interno.</param> /// <param name="remoteUri">L'uri del servizio di elaborazione.</param> /// <remarks> /// La configurazione del proxy interno è posticipata e viene pertanto eseguita non appena sarà /// richiesta la prima comunicazione col servizio di elaborazione. /// </remarks> public ProcessingServiceMonitor(Binding bindingConfig, Uri remoteUri) { m_BindingConfig = bindingConfig; m_RemoteUri = remoteUri; m_InternalProxy = null; m_MonitorClosed = false; }
/// <summary> /// Determina l'avvio della procedura che permette di inviare il task specificato al servizio di elaborazione, /// di verificarne periodicamente il completamento e di eseguire alla fine il download dei relativi risultati /// eventualmente prodotti. /// </summary> /// <remarks> /// Prima di invocare questo metodo, è necessario utilizzare il metodo SetTaskData per poter impostare i dati /// relativi al task da elaborare. /// Inoltre, questo metodo non dovrebbe essere invocato sul thread della UI, in quanto la verifica periodica /// del completamento dell'elaborazione blocca tale thread per l'intervallo di polling specificato. /// </remarks> public void Start() { if (m_Proxy == null) { try { RaiseTaskExecutionProgress(TaskRequestState.InitializingProxy, null); m_Proxy = new ProcessingServiceClient(m_Binding, m_Endpoint); m_Proxy.Open(); RaiseTaskExecutionProgress(TaskRequestState.ProxyInitialized, null); RaiseTaskExecutionProgress(TaskRequestState.SendingRequest, null); m_TaskRequestId = m_Proxy.SubmitData(m_TaskData); RaiseTaskExecutionProgress(TaskRequestState.RequestSent, null); bool completed = false; while (!completed) { m_PollingWaitHandle.WaitOne(m_PollingInterval); TaskState ts = m_Proxy.GetState(m_TaskRequestId); switch (ts) { case TaskState.Completed: RaiseTaskExecutionProgress(TaskRequestState.DownloadingResults, null); m_TaskResults = m_Proxy.GetResults(m_TaskRequestId); RaiseTaskExecutionProgress(TaskRequestState.ResultsDownloaded, null); RaiseTaskExecutionCompleted(false, null, m_TaskResults); completed = true; break; case TaskState.None: completed = true; break; default: completed = false; break; } } RaiseTaskExecutionProgress(TaskRequestState.DisposingProxy, null); m_Proxy.Close(); RaiseTaskExecutionProgress(TaskRequestState.ProxyDisposed, null); } catch (Exception ex) { HandleError(ex); } } }
/// <summary> /// Istanzia un nuovo oggetto della classe TaskExecution con i parametri specificati. /// </summary> /// <param name="serviceUri">indirizzo del servizio di elaborazione del task</param> /// <param name="pollingInterval">tempo di attesa nella verifica di completamento del task</param> /// <exception cref="UriFormatException"> /// Se si specifica un URI non valido come indirizzo del servizio di elaborazione. /// </exception> /// <exception cref="ArgumentNullException"> /// Se si specifica il valore null come indirizzo del servizio di elaborazione. /// </exception> public TaskExecution(string serviceUri, TimeSpan pollingInterval) { m_PollingInterval = pollingInterval; m_PollingWaitHandle = new ManualResetEvent(false); m_Binding = new BasicHttpBinding(); m_Endpoint = new EndpointAddress(serviceUri); m_Proxy = null; m_CommunicationErrorsMapping = new Dictionary<Type, TaskExecutionState>() { { typeof(TimeoutException), TaskExecutionState.TimeoutError }, { typeof(EndpointNotFoundException), TaskExecutionState.ServiceNotFoundError }, { typeof(CommunicationException), TaskExecutionState.CommunicationError } }; m_TaskRequestId = string.Empty; m_TaskData = new TaskData() { Name = string.Empty, Contents = string.Empty }; m_TaskResults = null; }
/// <summary> /// Istanzia un nuovo oggetto della classe TaskExecution con i parametri specificati. /// </summary> /// <param name="serviceUri">indirizzo del servizio di elaborazione del task</param> /// <param name="pollingInterval">tempo di attesa nella verifica di completamento del task</param> /// <exception cref="UriFormatException"> /// Se si specifica un URI non valido come indirizzo del servizio di elaborazione. /// </exception> /// <exception cref="ArgumentNullException"> /// Se si specifica il valore null come indirizzo del servizio di elaborazione. /// </exception> public TaskExecution(string serviceUri, TimeSpan pollingInterval) { m_PollingInterval = pollingInterval; m_PollingWaitHandle = new ManualResetEvent(false); m_Binding = new BasicHttpBinding(); m_Endpoint = new EndpointAddress(serviceUri); m_Proxy = null; m_CommunicationErrorsMapping = new Dictionary <Type, TaskRequestState>() { { typeof(TimeoutException), TaskRequestState.TimeoutError }, { typeof(EndpointNotFoundException), TaskRequestState.ServiceNotFoundError }, { typeof(CommunicationException), TaskRequestState.CommunicationError } }; m_TaskRequestId = string.Empty; m_TaskData = new TaskData() { Name = string.Empty, Contents = string.Empty }; m_TaskResults = null; }
/// <summary> /// Permette di gestire un errore verificatosi durante la procedura e restituisce true se è stata gestita, /// altrimenti false se non è stato necessario gestirlo poiché di fatto non è avvenuta alcun errore. /// </summary> /// <param name="error">l'eccezione che ha provocato l'errore</param> private void HandleError(Exception error) { if (error != null) { TaskRequestState state; if (m_CommunicationErrorsMapping.TryGetValue(error.GetType(), out state)) { RaiseTaskExecutionProgress(state, error); m_Proxy.Abort(); RaiseTaskExecutionProgress(TaskRequestState.ProxyDisposed, error); m_Proxy = null; } else { if (error is FaultException <ServiceFault> ) { RaiseTaskExecutionProgress(TaskRequestState.OperationError, error); RaiseTaskExecutionProgress(TaskRequestState.DisposingProxy, error); m_Proxy.Close(); } else { RaiseTaskExecutionProgress(TaskRequestState.UnknownError, error); m_Proxy.Abort(); RaiseTaskExecutionProgress(TaskRequestState.ProxyDisposed, error); m_Proxy = null; } } RaiseTaskExecutionCompleted(false, error, null); } }
/// <summary> /// Permette di gestire un errore verificatosi durante la procedura e restituisce true se è stata gestita, /// altrimenti false se non è stato necessario gestirlo poiché di fatto non è avvenuta alcun errore. /// </summary> /// <param name="error">l'eccezione che ha provocato l'errore</param> private void HandleError(Exception error) { if (error != null) { TaskExecutionState state; if (m_CommunicationErrorsMapping.TryGetValue(error.GetType(), out state)) { RaiseTaskExecutionProgress(state, error); m_Proxy.Abort(); RaiseTaskExecutionProgress(TaskExecutionState.ProxyDisposed, error); m_Proxy = null; } else { if (error is FaultException<ServiceFault>) { RaiseTaskExecutionProgress(TaskExecutionState.OperationError, error); RaiseTaskExecutionProgress(TaskExecutionState.DisposingProxy, error); m_Proxy.Close(); } else { RaiseTaskExecutionProgress(TaskExecutionState.UnknownError, error); m_Proxy.Abort(); RaiseTaskExecutionProgress(TaskExecutionState.ProxyDisposed, error); m_Proxy = null; } } RaiseTaskExecutionCompleted(false, error, null); } }
/// <summary> /// Determina l'avvio della procedura che permette di inviare il task specificato al servizio di elaborazione, /// di verificarne periodicamente il completamento e di eseguire alla fine il download dei relativi risultati /// eventualmente prodotti. /// </summary> /// <remarks> /// Prima di invocare questo metodo, è necessario utilizzare il metodo SetTaskData per poter impostare i dati /// relativi al task da elaborare. /// Inoltre, questo metodo non dovrebbe essere invocato sul thread della UI, in quanto la verifica periodica /// del completamento dell'elaborazione blocca tale thread per l'intervallo di polling specificato. /// </remarks> public void Start() { if (m_Proxy == null) { try { RaiseTaskExecutionProgress(TaskExecutionState.InitializingProxy, null); m_Proxy = new ProcessingServiceClient(m_Binding, m_Endpoint); m_Proxy.Open(); RaiseTaskExecutionProgress(TaskExecutionState.ProxyInitialized, null); RaiseTaskExecutionProgress(TaskExecutionState.SendingRequest, null); m_TaskRequestId = m_Proxy.SubmitData(m_TaskData); RaiseTaskExecutionProgress(TaskExecutionState.RequestSent, null); bool completed = false; while (!completed) { m_PollingWaitHandle.WaitOne(m_PollingInterval); TaskState ts = m_Proxy.GetState(m_TaskRequestId); switch (ts) { case TaskState.Completed: RaiseTaskExecutionProgress(TaskExecutionState.DownloadingResults, null); m_TaskResults = m_Proxy.GetResults(m_TaskRequestId); RaiseTaskExecutionProgress(TaskExecutionState.ResultsDownloaded, null); completed = true; break; case TaskState.None: completed = true; break; default: completed = false; break; } } RaiseTaskExecutionProgress(TaskExecutionState.DisposingProxy, null); m_Proxy.Close(); RaiseTaskExecutionProgress(TaskExecutionState.ProxyDisposed, null); RaiseTaskExecutionCompleted(false, null, m_TaskResults); } catch (Exception ex) { HandleError(ex); } } }
/// <summary> /// Questo metodo viene automaticamente invocato nel momento in cui il proxy completa la chiusura del canale /// di comunicazione e permette di rimuovere la registrazione degli eventi associati al proxy e di riportare /// quest'ultimo al valore null. /// </summary> /// <param name="sender">l'oggetto che ha generato l'evento</param> /// <param name="args">informazioni aggiuntive sull'evento</param> private void Proxy_CloseCompleted(object sender, AsyncCompletedEventArgs args) { if (HandleCancellationIfRequired(args.Cancelled)) return; if (HandleErrorIfRequired(args.Error)) return; RaiseTaskExecutionProgress(TaskExecutionState.ProxyDisposed, null); UnregisterProxyEvents(); m_Proxy = null; }
/// <summary> /// Permette di gestire un errore verificatosi durante la procedura e restituisce true se è stata gestita, /// altrimenti false se non è stato necessario gestirlo poiché di fatto non è avvenuta alcun errore. /// </summary> /// <param name="error">l'eccezione che ha provocato l'errore</param> /// <returns>true se l'eventuale errore è stata gestito, altrimenti false</returns> private bool HandleErrorIfRequired(Exception error) { if (error != null) { TaskExecutionState state; if (m_CommunicationErrorsMapping.TryGetValue(error.GetType(), out state)) { RaiseTaskExecutionProgress(state, error); m_Proxy.Abort(); RaiseTaskExecutionProgress(TaskExecutionState.ProxyDisposed, error); UnregisterProxyEvents(); m_Proxy = null; } else { if (error is FaultException<ServiceFault>) { RaiseTaskExecutionProgress(TaskExecutionState.OperationError, error); BeginCloseProxy(); } else { RaiseTaskExecutionProgress(TaskExecutionState.UnknownError, error); m_Proxy.Abort(); RaiseTaskExecutionProgress(TaskExecutionState.ProxyDisposed, error); UnregisterProxyEvents(); m_Proxy = null; } } RaiseTaskExecutionCompleted(false, error, null); return true; } return false; }
/// <summary> /// Inizia la configurazione del proxy per la comunicazione col servizio di elaborazione. /// </summary> private void BeginOpenProxy() { RaiseTaskExecutionProgress(TaskExecutionState.InitializingProxy, null); m_Proxy = new ProcessingServiceClient(m_Binding, m_Endpoint); m_Proxy.OpenCompleted += new EventHandler<AsyncCompletedEventArgs>(Proxy_OpenCompleted); m_Proxy.CloseCompleted += new EventHandler<AsyncCompletedEventArgs>(Proxy_CloseCompleted); m_Proxy.SubmitDataCompleted += new EventHandler<SubmitDataCompletedEventArgs>(Proxy_SubmitDataCompleted); m_Proxy.GetStateCompleted += new EventHandler<GetStateCompletedEventArgs>(Proxy_GetStateCompleted); m_Proxy.GetResultsCompleted += new EventHandler<GetResultsCompletedEventArgs>(Proxy_GetResultsCompleted); m_Proxy.OpenAsync(); }
/// <summary> /// Rilascia le risorse utilizzate per la comunicazione col server di elaborazione. /// </summary> public void Close() { lock (m_SyncLock) { if (m_InternalProxy != null) { try { m_InternalProxy.Close(); } catch { if (m_InternalProxy.State == CommunicationState.Faulted) { m_InternalProxy.Abort(); } } finally { m_InternalProxy = null; m_MonitorClosed = true; } } } }
/// <summary> /// Interroga il servizio di elaborazione remota specificato al momento della creazione di questo oggetto /// al fine di ricevere le eventuali risorse di calcolo messe a disposizione da tale servizio e l'istante /// di ricezione della risposta da parte del servizio stesso. Se non si verifica nessun errore durante la /// comunicazione col servizio, questo metodo restituisce true; in caso contratio restituisce false. /// </summary> /// <param name="resources">L'elenco risorse eventualmente disponibili sul server di elaborazione.</param> /// <param name="detection">L'istante di più recente rilevazione del server di elaborazione.</param> /// <returns>true se non si verifica nessun errore durante la comunicazione; in caso contrario false.</returns> public bool TryGetResources(out IEnumerable<TaskPerformerInfo> resources, out DateTime detection) { lock (m_SyncLock) { if (m_MonitorClosed || m_BindingConfig == null || m_RemoteUri == null) { resources = default(IEnumerable<TaskPerformerInfo>); detection = default(DateTime); return false; } try { if (m_InternalProxy == null) { m_InternalProxy = new ProcessingServiceClient(m_BindingConfig, new EndpointAddress(m_RemoteUri)); m_InternalProxy.Open(); } string[] resourcesList = m_InternalProxy.QueryForEnabledResources(); detection = DateTime.Now; HashSet<TaskPerformerInfo> resourceSet = new HashSet<TaskPerformerInfo>(); foreach (var resourceItem in resourcesList) resourceSet.Add(new TaskPerformerInfo(resourceItem)); resources = resourceSet; return true; } catch { if (m_InternalProxy != null) { if (m_InternalProxy.State == CommunicationState.Faulted) { m_InternalProxy.Abort(); m_InternalProxy = null; } } resources = default(IEnumerable<TaskPerformerInfo>); detection = default(DateTime); return false; } } }