/// <summary> /// Send a <paramref name="request "/>on the specified <paramref name="connector"/> /// and await a response /// </summary> public IGraphable SendReceive(ISendReceiveConnector connector, IGraphable request) { // Ensure the connector is open if (!connector.IsOpen()) { connector.Open(); } // Send the request ISendResult sendResult = connector.Send(request); // Was the send successful? if (sendResult.Code != ResultCode.Accepted && sendResult.Code != ResultCode.AcceptedNonConformant) { return(null); } // Await the response IReceiveResult receiveResult = connector.Receive(sendResult); // Debug information #if DEBUG foreach (var itm in receiveResult.Details) { Trace.WriteLine(String.Format("{0}: {1} @ {2}", itm.Type, itm.Message, itm.Location)); } #endif // Structure return(receiveResult.Structure); }
/// <summary> /// Finishes an asynchronous send operation and retreive the result of the send. /// </summary> /// <param name="asyncResult">The instance of the callback pointer.</param> /// <returns>The result of the send operation.</returns> /// <example cref="BeginSend(MARC.Everest.Interfaces.IGraphable,AsyncCallback,object)"> /// </example> public ISendResult EndSend(IAsyncResult asyncResult) { //TODO: This should block until completed. if (!asyncResult.IsCompleted) { return(null); } else { ISendResult result = asyncResults[asyncResult]; lock (asyncResults) { asyncResults.Remove(asyncResult); } return(result); } }
/// <summary> /// Begin an asynchronous receive event. /// </summary> /// <param name="correlate">The result of the send method.</param> /// <param name="callback">A callback.</param> /// <param name="state">User state.</param> public IAsyncResult BeginReceive(ISendResult correlate, AsyncCallback callback, object state) { // Formatter check if (!IsOpen()) { throw new ConnectorException(ConnectorException.MSG_INVALID_STATE, ConnectorException.ReasonType.NotOpen); } // Create the work that will perform the operations Worker w = new Worker(); w.Formatter = (IXmlStructureFormatter)Formatter; #if WINDOWS_PHONE w.Actions = this.m_actions; #else w.WcfConfiguration = wcfConfiguration; #endif w.MessageVersion = wcfClient.Endpoint.Binding.MessageVersion; Message data = null; if (!results.TryGetValue(correlate, out data)) { return(null); } // The asynchronous result, used to correlate results when EndReceive is called IAsyncResult result = new ReceiveResultAsyncResult(state, new AutoResetEvent(false)); // Work w.Completed += new WaitCallback(delegate(object sender) { lock (asyncResults) asyncResults.Add(result, (sender as Worker).ReceiveResult); (result.AsyncWaitHandle as AutoResetEvent).Set(); }); ThreadPool.QueueUserWorkItem(w.WorkReceive, data); return(result); }
/// <summary> /// Receive the result from the connector. /// </summary> /// <param name="correlate">The send result. Used to correlate the response with the request.</param> /// <returns>The receive result.</returns> /// <remarks>Performs a blocking receive operation. If you use this method after a BeginSend() /// this method will block and wait for a response.</remarks> public IReceiveResult Receive(ISendResult correlate) { // Receive the result from the connector if (!IsOpen()) { throw new ConnectorException(ConnectorException.MSG_INVALID_STATE, ConnectorException.ReasonType.NotOpen); } // wait for a message Message responseMessage = null; DateTime startTime = DateTime.Now; while (!results.TryGetValue(correlate, out responseMessage) && DateTime.Now.Subtract(startTime).CompareTo(wcfClient.Endpoint.Binding.ReceiveTimeout) == -1) { //TODO: Should use a WaitHandle Thread.Sleep(100); } if (responseMessage == null) { throw new TimeoutException("Receive() operation did not complete in specified amount of time"); } // process the message Worker w = new Worker(); w.Formatter = (IXmlStructureFormatter)Formatter; #if WINDOWS_PHONE w.Actions = this.m_actions; #else w.WcfConfiguration = wcfConfiguration; #endif w.WorkReceive(responseMessage); return(w.ReceiveResult); }
/// <summary> /// Begin an asynchronous receive event. /// </summary> /// <param name="correlate">The result of the send method.</param> /// <param name="callback">A callback.</param> /// <param name="state">User state.</param> public IAsyncResult BeginReceive(ISendResult correlate, AsyncCallback callback, object state) { // Formatter check if (!IsOpen()) throw new ConnectorException(ConnectorException.MSG_INVALID_STATE, ConnectorException.ReasonType.NotOpen); // Create the work that will perform the operations Worker w = new Worker(); w.Formatter = (IXmlStructureFormatter)Formatter; #if WINDOWS_PHONE w.Actions = this.m_actions; #else w.WcfConfiguration = wcfConfiguration; #endif w.MessageVersion = wcfClient.Endpoint.Binding.MessageVersion; Message data = null; if (!results.TryGetValue(correlate, out data)) return null; // The asynchronous result, used to correlate results when EndReceive is called IAsyncResult result = new ReceiveResultAsyncResult(state, new AutoResetEvent(false)); // Work w.Completed += new WaitCallback(delegate(object sender) { lock (asyncResults) asyncResults.Add(result, (sender as Worker).ReceiveResult); (result.AsyncWaitHandle as AutoResetEvent).Set(); }); ThreadPool.QueueUserWorkItem(w.WorkReceive, data); return result; }
/// <summary> /// Receive the result from the connector. /// </summary> /// <param name="correlate">The send result. Used to correlate the response with the request.</param> /// <returns>The receive result.</returns> /// <remarks>Performs a blocking receive operation. If you use this method after a BeginSend() /// this method will block and wait for a response.</remarks> public IReceiveResult Receive(ISendResult correlate) { // Receive the result from the connector if (!IsOpen()) throw new ConnectorException(ConnectorException.MSG_INVALID_STATE, ConnectorException.ReasonType.NotOpen); // wait for a message Message responseMessage = null; DateTime startTime = DateTime.Now; while (!results.TryGetValue(correlate, out responseMessage) && DateTime.Now.Subtract(startTime).CompareTo(wcfClient.Endpoint.Binding.ReceiveTimeout) == -1) //TODO: Should use a WaitHandle Thread.Sleep(100); if (responseMessage == null) throw new TimeoutException("Receive() operation did not complete in specified amount of time"); // process the message Worker w = new Worker(); w.Formatter = (IXmlStructureFormatter)Formatter; #if WINDOWS_PHONE w.Actions = this.m_actions; #else w.WcfConfiguration = wcfConfiguration; #endif w.WorkReceive(responseMessage); return w.ReceiveResult; }
public void Work(object state) { // Prepare stream Stream s = null; FileSendResult result = new FileSendResult(); IGraphable data = (IGraphable)state; IFormatterGraphResult fResult = null; try { // Graph the object. //We graph to a memory stream and transfer to a file stream on success because //the state of the stream is unknown if the result code is not accepted. This //could cause a process which is listening to new files to read an invalid or //non-conformant message from the publish service. In this model, we graph, //verify and finally commit. MemoryStream ms = new MemoryStream(); fResult = Formatter.Graph(ms, data); result.Code = fResult.Code; result.Details = fResult.Details; // Did the operation succeed? if (result.Code == ResultCode.Accepted || result.Code == ResultCode.AcceptedNonConformant) { //TODO: Should transfer in chunks instead of all at once. s = System.IO.File.Create(TargetFile); ms.WriteTo(s); ms.Close(); } } catch (MessageValidationException e) { result.Code = ResultCode.Rejected; List <IResultDetail> dtl = new List <IResultDetail>(new IResultDetail[] { new FileResultDetail(ResultDetailType.Error, e.Message, TargetFile, e) }); dtl.AddRange(fResult.Details ?? new IResultDetail[0]); result.Details = dtl.ToArray(); } catch (FormatException e) { result.Code = ResultCode.Rejected; result.Details = new IResultDetail[] { new FileResultDetail(ResultDetailType.Error, e.Message, TargetFile, e) }; } catch (DirectoryNotFoundException e) { result.Code = ResultCode.NotAvailable; result.Details = new IResultDetail[] { new FileResultDetail(ResultDetailType.Error, e.Message, TargetFile, e) }; } catch (IOException e) { result.Code = ResultCode.Error; result.Details = new IResultDetail[] { new FileResultDetail(ResultDetailType.Error, e.Message, TargetFile, e) }; } catch (Exception e) { result.Code = ResultCode.Error; result.Details = new IResultDetail[] { new FileResultDetail(ResultDetailType.Error, e.Message, TargetFile, e) }; } finally { if (s != null) { s.Close(); } if (result.Code != ResultCode.Accepted) { System.IO.File.Delete(TargetFile); } } this.Result = result; // Fire completed event if (Completed != null) { Completed(this); } }
public void Work(object state) { // Prepare stream Stream s = null; FileSendResult result = new FileSendResult(); IGraphable data = (IGraphable)state; IFormatterGraphResult fResult = null; try { // Graph the object. //We graph to a memory stream and transfer to a file stream on success because //the state of the stream is unknown if the result code is not accepted. This //could cause a process which is listening to new files to read an invalid or //non-conformant message from the publish service. In this model, we graph, //verify and finally commit. MemoryStream ms = new MemoryStream(); fResult = Formatter.Graph(ms, data); result.Code = fResult.Code; result.Details = fResult.Details; // Did the operation succeed? if (result.Code == ResultCode.Accepted || result.Code == ResultCode.AcceptedNonConformant) { //TODO: Should transfer in chunks instead of all at once. s = System.IO.File.Create(TargetFile); ms.WriteTo(s); ms.Close(); } } catch (MessageValidationException e) { result.Code = ResultCode.Rejected; List<IResultDetail> dtl = new List<IResultDetail>(new IResultDetail[] { new FileResultDetail(ResultDetailType.Error, e.Message, TargetFile, e) }); dtl.AddRange(fResult.Details ?? new IResultDetail[0]); result.Details = dtl.ToArray(); } catch (FormatException e) { result.Code = ResultCode.Rejected; result.Details = new IResultDetail[] { new FileResultDetail(ResultDetailType.Error, e.Message, TargetFile, e) }; } catch (DirectoryNotFoundException e) { result.Code = ResultCode.NotAvailable; result.Details = new IResultDetail[] { new FileResultDetail(ResultDetailType.Error, e.Message, TargetFile, e) }; } catch (IOException e) { result.Code = ResultCode.Error; result.Details = new IResultDetail[] { new FileResultDetail(ResultDetailType.Error, e.Message, TargetFile, e) }; } catch (Exception e) { result.Code = ResultCode.Error; result.Details = new IResultDetail[] { new FileResultDetail(ResultDetailType.Error, e.Message, TargetFile, e) }; } finally { if (s != null) s.Close(); if (result.Code != ResultCode.Accepted) System.IO.File.Delete(TargetFile); } this.Result = result; // Fire completed event if (Completed != null) Completed(this); }
/// <summary> /// Fired whenever a message is available for processing /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void connector_MessageAvailable(object sender, UnsolicitedDataEventArgs e) { // Audit service IAuditorService auditService = Context.GetService(typeof(IAuditorService)) as IAuditorService; #region Setup Audit AuditData audit = new AuditData( DateTime.Now, ActionType.Execute, OutcomeIndicator.Success, EventIdentifierType.ApplicationActivity, new AuditCode("GEN", null) ); audit.Actors.Add(new AuditActorData() { NetworkAccessPointId = Environment.MachineName, NetworkAccessPointType = NetworkAccessPointType.MachineName, UserIdentifier = String.Format("{0}\\{1}", Environment.UserDomainName, Environment.UserName) }); audit.Actors.Add(new AuditActorData() { UserIsRequestor = true, NetworkAccessPointId = e.SolicitorEndpoint.ToString(), NetworkAccessPointType = NetworkAccessPointType.IPAddress, UserIdentifier = e.SolicitorEndpoint.ToString() }); audit.AuditableObjects.Add(new AuditableObject() { IDTypeCode = AuditableObjectIdType.Uri, LifecycleType = AuditableObjectLifecycle.Access, Role = AuditableObjectRole.DataRepository, ObjectId = e.ReceiveEndpoint.ToString(), Type = AuditableObjectType.SystemObject }); #endregion try { // Find a receiver capable of processing this var wcfConnector = (sender as IListenWaitConnector); IReceiveResult rcvResult = wcfConnector.Receive(); // get the persistence service from the context IMessagePersistenceService persistenceService = Context.GetService(typeof(IMessagePersistenceService)) as IMessagePersistenceService; // Were we able to process the message Assembly messageTypeAssembly = null; if (rcvResult.Structure != null) { messageTypeAssembly = rcvResult.Structure.GetType().Assembly; } // Find the configuration section that handles the specified revision var curRevision = m_configuration.Revisions.Find(o => o.Listeners.Exists(l => l.ConnectionString == wcfConnector.ConnectionString)); if (curRevision == null) { Trace.TraceError("This service does not seem to have support for the version of message being used"); throw new UninterpretableMessageException("This service doesn't support this standard", rcvResult); } // Do we have a handler for this message interaction? Cast as an interaction // and attempt to find the handler configuration IInteraction interactionStructure = rcvResult.Structure as IInteraction; MessageHandlerConfiguration receiverConfig = null; if (interactionStructure != null && interactionStructure.InteractionId != null && !String.IsNullOrEmpty(interactionStructure.InteractionId.Extension)) { receiverConfig = curRevision.MessageHandlers.Find(o => o.Interactions.Exists(i => i.Id == interactionStructure.InteractionId.Extension)); } else { Trace.TraceWarning("Interaction is missing InteractionId attribute! Assuming default"); // Set interaction id var intId = interactionStructure.GetType().GetMethod("GetInteractionId", BindingFlags.Static | BindingFlags.Public); if (intId == null) { throw new InvalidOperationException("Cannot find the GetInteractionId method, cannot determine interaction"); } interactionStructure.InteractionId = intId.Invoke(null, null) as II; } // Message identifier missing? if (interactionStructure.Id == null) { interactionStructure.Id = Guid.NewGuid(); Trace.TraceWarning("Interaction is missing id. Generated token {0}...", interactionStructure.Id.Root); } IEverestMessageReceiver currentHandler = null, defaultHandler = null; var defaultHandlerConfig = curRevision.MessageHandlers.Find(o => o.Interactions.Exists(i => i.Id == "*")); receiverConfig = receiverConfig ?? defaultHandlerConfig; // find a handler // Receiver configuration if (receiverConfig == null) { throw new InvalidOperationException("Cannot find appropriate handler this message"); } else { var messageState = Core.Services.MessageState.New; IInteraction response = null; InteractionConfiguration interactionConfig = receiverConfig.Interactions.Find(o => o.Id == interactionStructure.InteractionId.Extension); if (interactionConfig != null && interactionConfig.Disclosure) { persistenceService = null; } // check with persistence if (persistenceService != null) { messageState = persistenceService.GetMessageState(String.Format(curRevision.MessageIdentifierFormat, interactionStructure.Id.Root, interactionStructure.Id.Extension)); } switch (messageState) { case Core.Services.MessageState.New: // Persist the message if (persistenceService != null) { MemoryStream ms = new MemoryStream(); try { WriteMessageToStream(sender as IFormattedConnector, interactionStructure, ms); persistenceService.PersistMessage(String.Format(curRevision.MessageIdentifierFormat, interactionStructure.Id.Root, interactionStructure.Id.Extension), ms); } finally { ms.Dispose(); } } currentHandler = receiverConfig.Handler; defaultHandler = defaultHandlerConfig.Handler; response = currentHandler.HandleMessageReceived(sender, e, rcvResult) as IInteraction; if (persistenceService != null) { MemoryStream ms = new MemoryStream(); try { WriteMessageToStream(sender as IFormattedConnector, response, ms); persistenceService.PersistResultMessage(String.Format(curRevision.MessageIdentifierFormat, response.Id.Root, response.Id.Extension), String.Format(curRevision.MessageIdentifierFormat, interactionStructure.Id.Root, interactionStructure.Id.Extension), ms); } finally { ms.Dispose(); } } break; case Core.Services.MessageState.Complete: var rms = persistenceService.GetMessageResponseMessage(String.Format(curRevision.MessageIdentifierFormat, interactionStructure.Id.Root, interactionStructure.Id.Extension)); var parseResult = (sender as IFormattedConnector).Formatter.Parse(rms); response = parseResult.Structure as IInteraction; break; case Core.Services.MessageState.Active: throw new ApplicationException("Message is already being processed"); } // Send back IListenWaitRespondConnector ilwConnector = sender as IListenWaitRespondConnector; if (ilwConnector == null) // no need to send something back { auditService.SendAudit(audit); return; } else { // Invalid message delegate var invalidMessageDelegate = new EventHandler <MessageEventArgs>(delegate(object sndr, MessageEventArgs mea) { audit.Outcome = OutcomeIndicator.MinorFail; InvalidMessageResult res = new InvalidMessageResult() { Code = mea.Code, Details = mea.Details, Structure = rcvResult.Structure }; if (defaultHandler != null) { mea.Alternate = response; } Trace.TraceWarning("Returning a default message because Everest was unable to serialize the response correctly. Error was {0}", mea.Code); Trace.Indent(); foreach (IResultDetail dtl in mea.Details) { Trace.TraceWarning("{0} : {1} : {2}", dtl.Type, dtl.Message, dtl.Location); } Trace.Unindent(); mea.Alternate = response; }); ilwConnector.InvalidResponse += invalidMessageDelegate; try { // Create headers var wcfResult = rcvResult as WcfReceiveResult; if (wcfResult != null && wcfResult.Headers != null) { var rcvrInfo = receiverConfig.Interactions.Find(o => o.Id == interactionStructure.InteractionId.Extension); if (rcvrInfo != null) { wcfResult.ResponseHeaders = CreateResponseHeaders(rcvrInfo.ResponseHeaders, wcfResult.Headers.MessageVersion); } if (wcfResult.ResponseHeaders != null) { wcfResult.ResponseHeaders.RelatesTo = wcfResult.Headers.MessageId; } } ISendResult sndResult = ilwConnector.Send(response, rcvResult); if (sndResult.Code != ResultCode.Accepted && sndResult.Code != ResultCode.AcceptedNonConformant) { Trace.TraceError("Cannot send response back to the solicitor : {0}", sndResult.Code); Trace.Indent(); foreach (IResultDetail dtl in sndResult.Details ?? new IResultDetail[0]) { Trace.TraceError("{0}: {1} : {2}", dtl.Type, dtl.Message, dtl.Location); } Trace.Unindent(); } } finally { if (auditService != null) { auditService.SendAudit(audit); } // Remove the invalid message delegate ilwConnector.InvalidResponse -= invalidMessageDelegate; } } } } catch (System.Exception ex) { #region Audit Failure audit.Outcome = OutcomeIndicator.EpicFail; if (auditService != null) { auditService.SendAudit(audit); } #endregion Trace.TraceError(ex.ToString()); throw; } }