/// <summary> /// Adds a handler to an event of a server component. /// </summary> /// <param name="interfaceName">Name of the server component interface</param> /// <param name="correlation">Correlation information</param> /// <param name="uniqueName">Unique name of the server component instance (May left empty, if component isn´t registered with a unique name)</param> /// <param name="callContext">Call context data</param> public void AddEventHandler(string interfaceName, DelegateCorrelationInfo correlation, string uniqueName, LogicalCallContextData callContext) { if (string.IsNullOrEmpty(interfaceName)) throw new ArgumentException(LanguageResource.ArgumentException_InterfaceNameMissing, "interfaceName"); if (string.IsNullOrEmpty(uniqueName)) uniqueName = interfaceName; if (!_host.ComponentRegistry.ContainsKey(uniqueName)) throw new KeyNotFoundException(string.Format(LanguageResource.KeyNotFoundException_CannotFindComponentForInterface, interfaceName)); var details = new InvocationDetails() { InterfaceName = interfaceName, Registration = _host.ComponentRegistry[uniqueName], CallContextData = callContext }; Invoke_LoadCallContextData(details); Invoke_SetSession(details); Invoke_ResolveComponentInstance(details); var correlationSet = new List<DelegateCorrelationInfo> { correlation }; CreateClientServerWires(details.Type, details.Registration.EventStub, correlationSet, details.Registration.EventWirings); }
/// <summary> /// Bereitet den Aufrufkontext für die Übertragung vor. /// </summary> internal void PrepareCallContext(bool implicitTransactionTransfer) { // Transferobjekt für Kontextdaten erzeugen, die implizit übertragen werden sollen LogicalCallContextData data = new LogicalCallContextData(); // Sitzungsschlüssel im Transferobjekt ablegen data.Store.Add("sessionid", _sessionID); // Wenn eine Umgebungstransaktion aktiv ist die implizite Transaktionsübertragung eingeschaltet ist ... if (implicitTransactionTransfer && Transaction.Current != null) { // Umgebungstransaktion abrufen Transaction transaction = Transaction.Current; // Wenn die Transaktion noch aktiv ist ... if (transaction.TransactionInformation.Status == TransactionStatus.InDoubt || transaction.TransactionInformation.Status == TransactionStatus.Active) { // Transaktion im Transferobjekt ablegen data.Store.Add("transaction", transaction); } } // Transferobjekt in den Aufrufkontext einhängen CallContext.SetData("__ZyanContextData_" + _componentHostName, data); }
/// <summary> /// Called from client to send a heartbeat signal. /// </summary> /// <param name="sessionID">Client´s session key</param> /// <param name="callContext">Call context data</param> public void ReceiveClientHeartbeat(Guid sessionID, LogicalCallContextData callContext) { // validate server session var details = new InvocationDetails(); details.CallContextData = callContext; //Invoke_LoadCallContextData(details); Invoke_SetSession(details); // fire the heartbeat event OnClientHeartbeatReceived(new ClientHeartbeatEventArgs(DateTime.Now, sessionID)); }
/// <summary> /// Verlängert die Sitzung des Aufrufers und gibt die aktuelle Sitzungslebensdauer zurück. /// </summary> /// <returns>Sitzungslebensdauer (in Minuten)</returns> public int RenewSession() { // Kontextdaten aus dem Aufrufkontext lesen (Falls welche hinterlegt sind) LogicalCallContextData data = CallContext.GetData("__ZyanContextData_" + _host.Name) as LogicalCallContextData; // Wenn Kontextdaten übertragen wurden ... if (data != null) { // Wenn ein Sitzungsschlüssel übertragen wurde ... if (data.Store.ContainsKey("sessionid")) { // Sitzungsschlüssel lesen Guid sessionID = (Guid)data.Store["sessionid"]; // Wenn eine Sitzung mit dem angegebenen Schlüssel existiert ... if (_host.SessionManager.ExistSession(sessionID)) { // Sitzung abrufen ServerSession session = _host.SessionManager.GetSessionBySessionID(sessionID); // Sitzung verlängern session.Timestamp = DateTime.Now; // Aktuelle Sitzung im Threadspeicher ablegen ServerSession.CurrentSession = session; } else { // Ausnahme erzeugen InvalidSessionException ex = new InvalidSessionException(string.Format("Sitzungsschlüssel '{0}' ist ungültig! Bitte melden Sie sich erneut am Server an.", sessionID.ToString())); // Ausnahme werfen throw ex; } } } else { // Ausnahme erzeugen SecurityException ex = new SecurityException(LanguageResource.SecurityException_ContextInfoMissing); // Ausnahme werfen throw ex; } // Sitzungslebensdauer zurückgeben return(SessionAgeLimit); }
/// <summary> /// Prepares the .NET Remoting call context before a remote call. /// </summary> internal LogicalCallContextData PrepareCallContext(bool implicitTransactionTransfer) { LogicalCallContextData data = new LogicalCallContextData(); data.Store.Add("sessionid", _sessionID); if (implicitTransactionTransfer && Transaction.Current != null) { Transaction transaction = Transaction.Current; if (transaction.TransactionInformation.Status == TransactionStatus.InDoubt || transaction.TransactionInformation.Status == TransactionStatus.Active) { data.Store.Add("transaction", transaction); } } return(data); }
/// <summary> /// Prepares the .NET Remoting call context before a remote call. /// </summary> internal void PrepareCallContext(bool implicitTransactionTransfer) { LogicalCallContextData data = new LogicalCallContextData(); data.Store.Add("sessionid", _sessionID); if (implicitTransactionTransfer && Transaction.Current != null) { Transaction transaction = Transaction.Current; if (transaction.TransactionInformation.Status == TransactionStatus.InDoubt || transaction.TransactionInformation.Status == TransactionStatus.Active) { data.Store.Add("transaction", transaction); } } CallContext.SetData("__ZyanContextData_" + _componentHostName, data); }
/// <summary> /// Called from client to send a heartbeat signal. /// </summary> /// <param name="sessionID">Client´s session key</param> /// <param name="callContext">Call context data</param> public void ReceiveClientHeartbeat(Guid sessionID, LogicalCallContextData callContext) { // validate server session var details = new InvocationDetails(); details.CallContextData = callContext; //Invoke_LoadCallContextData(details); Invoke_SetSession(details); // fire the heartbeat event OnClientHeartbeatReceived(new ClientHeartbeatEventArgs(DateTime.Now, sessionID)); }
/// <summary> /// Processes remote method invocation. /// </summary> /// <param name="trackingID">Key for call tracking</param> /// <param name="interfaceName">Name of the component interface</param> /// <param name="delegateCorrelationSet">Correlation set for dynamic event and delegate wiring</param> /// <param name="methodName">Name of the invoked method</param> /// <param name="genericArguments">Generic arguments of the invoked method</param> /// <param name="paramTypes">Parameter types</param> /// <param name="callContext">Call context data</param> /// <param name="args">Parameter values</param> /// <returns>Return value</returns> public object Invoke(Guid trackingID, string interfaceName, List<DelegateCorrelationInfo> delegateCorrelationSet, string methodName, Type[] genericArguments, Type[] paramTypes, LogicalCallContextData callContext, params object[] args) { if (string.IsNullOrEmpty(interfaceName)) throw new ArgumentException(LanguageResource.ArgumentException_InterfaceNameMissing, "interfaceName"); if (string.IsNullOrEmpty(methodName)) throw new ArgumentException(LanguageResource.ArgumentException_MethodNameMissing, "methodName"); // Reset session variable (May point to wrong session, if threadpool thread is reused) ServerSession.CurrentSession = null; var details = new InvocationDetails() { TrackingID = trackingID, InterfaceName = interfaceName, DelegateCorrelationSet = delegateCorrelationSet, MethodName = methodName, GenericArguments = genericArguments, ParamTypes = paramTypes, Args = args, CallContextData = callContext }; var beforeInvokeOccured = false; try { //Invoke_LoadCallContextData(details); Invoke_SetSession(details); Invoke_SetTransaction(details); beforeInvokeOccured = true; ProcessBeforeInvoke(details); Invoke_CheckInterfaceName(details); Invoke_ConvertMethodArguments(details); Invoke_ResolveComponentInstance(details); Invoke_ObtainMethodMetadata(details); Invoke_InterceptDelegateParams(details); details.ReturnValue = details.MethodInfo.Invoke(details.Instance, details.Args, details.MethodInfo.IsOneWay()); Invoke_ApplyCustomSerializationOnReturnValue(details); } catch (Exception ex) { if (beforeInvokeOccured) Invoke_FireInvokeCanceledEvent(details, ex); else Invoke_FireInvokeRejectedEvent(details, ex); } finally { Invoke_CompleteTransactionScope(details); Invoke_CleanUp(details); } ProcessAfterInvoke(details); return details.ReturnValue; }
internal object SendRemoteMethodCallMessage(Guid trackingID, string uniqueName, List <DelegateCorrelationInfo> correlationSet, string methodName, Type[] genericArgs, Type[] paramTypes, object[] paramValues, LogicalCallContextData callContextData) { var rpcResponseMessage = _transportAdapter.SendRequest(new RequestMessage() { RequestType = RequestType.RemoteMethodCall, TrackingID = trackingID, Address = _serverUrl, DelegateCorrelationSet = correlationSet, GenericArguments = genericArgs, InterfaceName = uniqueName, MethodName = methodName, ParameterTypes = paramTypes, ParameterValues = paramValues, CallContext = callContextData }); return(rpcResponseMessage.ReturnValue); }
/// <summary> /// Removes a handler from an event of a server component. /// </summary> /// <param name="interfaceName">Name of the server component interface</param> /// <param name="correlation">Correlation information</param> /// <param name="uniqueName">Unique name of the server component instance (May left empty, if component isn´t registered with a unique name)</param> /// <param name="callContext">Call context data</param> public void RemoveEventHandler(string interfaceName, DelegateCorrelationInfo correlation, string uniqueName, LogicalCallContextData callContext) { if (string.IsNullOrEmpty(interfaceName)) { throw new ArgumentException(LanguageResource.ArgumentException_InterfaceNameMissing, "interfaceName"); } if (string.IsNullOrEmpty(uniqueName)) { uniqueName = interfaceName; } if (!_host.ComponentRegistry.ContainsKey(uniqueName)) { throw new KeyNotFoundException(string.Format(LanguageResource.KeyNotFoundException_CannotFindComponentForInterface, interfaceName)); } var details = new InvocationDetails() { InterfaceName = interfaceName, Registration = _host.ComponentRegistry[uniqueName], CallContextData = callContext }; Invoke_LoadCallContextData(details); Invoke_SetSession(details); Invoke_ResolveComponentInstance(details); var correlationSet = new List <DelegateCorrelationInfo> { correlation }; RemoveClientServerWires(details.Type, details.Registration.EventStub, correlationSet, details.Registration.EventWirings); }
/// <summary> /// Processes remote method invocation. /// </summary> /// <param name="trackingID">Key for call tracking</param> /// <param name="interfaceName">Name of the component interface</param> /// <param name="delegateCorrelationSet">Correlation set for dynamic event and delegate wiring</param> /// <param name="methodName">Name of the invoked method</param> /// <param name="genericArguments">Generic arguments of the invoked method</param> /// <param name="paramTypes">Parameter types</param> /// <param name="callContext">Call context data</param> /// <param name="args">Parameter values</param> /// <returns>Return value</returns> public object Invoke(Guid trackingID, string interfaceName, List <DelegateCorrelationInfo> delegateCorrelationSet, string methodName, Type[] genericArguments, Type[] paramTypes, LogicalCallContextData callContext, params object[] args) { if (string.IsNullOrEmpty(interfaceName)) { throw new ArgumentException(LanguageResource.ArgumentException_InterfaceNameMissing, "interfaceName"); } if (string.IsNullOrEmpty(methodName)) { throw new ArgumentException(LanguageResource.ArgumentException_MethodNameMissing, "methodName"); } // Reset session variable (May point to wrong session, if threadpool thread is reused) ServerSession.CurrentSession = null; var details = new InvocationDetails() { TrackingID = trackingID, InterfaceName = interfaceName, DelegateCorrelationSet = delegateCorrelationSet, MethodName = methodName, GenericArguments = genericArguments, ParamTypes = paramTypes, Args = args, CallContextData = callContext }; var beforeInvokeOccured = false; try { //Invoke_LoadCallContextData(details); Invoke_SetSession(details); Invoke_SetTransaction(details); beforeInvokeOccured = true; ProcessBeforeInvoke(details); Invoke_CheckInterfaceName(details); Invoke_ConvertMethodArguments(details); Invoke_ResolveComponentInstance(details); Invoke_ObtainMethodMetadata(details); Invoke_InterceptDelegateParams(details); details.ReturnValue = details.MethodInfo.Invoke(details.Instance, details.Args, details.MethodInfo.IsOneWay()); Invoke_ApplyCustomSerializationOnReturnValue(details); } catch (Exception ex) { if (beforeInvokeOccured) { Invoke_FireInvokeCanceledEvent(details, ex); } else { Invoke_FireInvokeRejectedEvent(details, ex); } } finally { Invoke_CompleteTransactionScope(details); Invoke_CleanUp(details); } ProcessAfterInvoke(details); return(details.ReturnValue); }
/// <summary> /// Ruft eine bestimmte Methode einer Komponente auf und übergibt die angegebene Nachricht als Parameter. /// Für jeden Aufruf wird temporär eine neue Instanz der Komponente erstellt. /// </summary> /// <param name="trackingID">Aufrufschlüssel zur Nachverfolgung</param> /// <param name="interfaceName">Name der Komponentenschnittstelle</param> /// <param name="delegateCorrelationSet">Korrelationssatz für die Verdrahtung bestimmter Delegaten oder Ereignisse mit entfernten Methoden</param> /// <param name="methodName">Methodenname</param> /// <param name="paramDefs">Parameter-Definitionen</param> /// <param name="args">Parameter</param> /// <returns>Rückgabewert</returns> public object Invoke(Guid trackingID, string interfaceName, List <DelegateCorrelationInfo> delegateCorrelationSet, string methodName, ParameterInfo[] paramDefs, params object[] args) { // Wenn kein Schnittstellenname angegeben wurde ... if (string.IsNullOrEmpty(interfaceName)) { // Ausnahme werfen throw new ArgumentException(LanguageResource.ArgumentException_InterfaceNameMissing, "interfaceName"); } // Wenn kein Methodenname angegben wurde ... if (string.IsNullOrEmpty(methodName)) { // Ausnahme werfen throw new ArgumentException(LanguageResource.ArgumentException_MethodNameMissing, "methodName"); } // Ggf. BeforeInvoke-Abos verarbeiten ProcessBeforeInvoke(trackingID, ref interfaceName, ref delegateCorrelationSet, ref methodName, ref args); // Wenn für den angegebenen Schnittstellennamen keine Komponente registriert ist ... if (!_host.ComponentRegistry.ContainsKey(interfaceName)) { // Ausnahme erzeugen KeyNotFoundException ex = new KeyNotFoundException(string.Format("Für die angegebene Schnittstelle '{0}' ist keine Komponente registiert.", interfaceName)); // InvokeCanceled-Ereignis feuern _host.OnInvokeCanceled(new InvokeCanceledEventArgs() { TrackingID = trackingID, CancelException = ex }); // Ausnahme werfen throw ex; } // Komponentenregistrierung abrufen ComponentRegistration registration = _host.ComponentRegistry[interfaceName]; // Komponenteninstanz erzeugen object instance = _host.GetComponentInstance(registration); // Implementierungstyp abrufen Type type = instance.GetType(); // Auflistung für Ereignisverdrahtungen Dictionary <Guid, Delegate> wiringList = null; // Wenn die Komponente SingleCallaktiviert ist ... if (registration.ActivationType == ActivationType.SingleCall) { // Auflistung für Ereignisverdrahtungen erzeugen wiringList = new Dictionary <Guid, Delegate>(); // Bei Bedarf Client- und Server-Komponente miteinander verdrahten CreateClientServerWires(type, instance, delegateCorrelationSet, wiringList); } // Transaktionsbereich TransactionScope scope = null; // Kontextdaten aus dem Aufrufkontext lesen (Falls welche hinterlegt sind) LogicalCallContextData data = CallContext.GetData("__ZyanContextData_" + _host.Name) as LogicalCallContextData; // Wenn Kontextdaten übertragen wurden ... if (data != null) { // Wenn ein Sitzungsschlüssel übertragen wurde ... if (data.Store.ContainsKey("sessionid")) { // Sitzungsschlüssel lesen Guid sessionID = (Guid)data.Store["sessionid"]; // Wenn eine Sitzung mit dem angegebenen Schlüssel existiert ... if (_host.SessionManager.ExistSession(sessionID)) { // Sitzung abrufen ServerSession session = _host.SessionManager.GetSessionBySessionID(sessionID); // Sitzung verlängern session.Timestamp = DateTime.Now; // Aktuelle Sitzung im Threadspeicher ablegen ServerSession.CurrentSession = session; } else { // Ausnahme erzeugen InvalidSessionException ex = new InvalidSessionException(string.Format("Sitzungsschlüssel '{0}' ist ungültig! Bitte melden Sie sich erneut am Server an.", sessionID.ToString())); // InvokeCanceled-Ereignis feuern _host.OnInvokeCanceled(new InvokeCanceledEventArgs() { TrackingID = trackingID, CancelException = ex }); // Ausnahme werfen throw ex; } } // Wenn eine Transaktion übertragen wurde ... if (data.Store.ContainsKey("transaction")) { // Transaktionsbereich erzeugen scope = new TransactionScope((Transaction)data.Store["transaction"]); } } else { // Ausnahme erzeugen SecurityException ex = new SecurityException(LanguageResource.SecurityException_ContextInfoMissing); // InvokeCanceled-Ereignis feuern _host.OnInvokeCanceled(new InvokeCanceledEventArgs() { TrackingID = trackingID, CancelException = ex }); // Ausnahme werfen throw ex; } // Rückgabewert object returnValue = null; // Typen-Array (zur Ermittlung der passenden Signatur) erzeugen Type[] types = new Type[paramDefs.Length]; // Auflistung der Indizes von Parametern, für die eine Delegatenverdrahtung notwendig ist Dictionary <int, DelegateInterceptor> delegateParamIndexes = new Dictionary <int, DelegateInterceptor>(); // Alle Parametertypen durchlaufen for (int i = 0; i < paramDefs.Length; i++) { // Typ in Array einfügen types[i] = paramDefs[i].ParameterType; // Versuchen den aktuellen Parameter in eine Delegaten-Abfangvorrichtung zu casten DelegateInterceptor delegateParamInterceptor = args[i] as DelegateInterceptor; // Wenn aktuelle Parameter eine Delegaten-Abfangvorrichtung ist ... if (delegateParamInterceptor != null) { // Parameter der Delegaten-Verdrahtungsliste zufügen delegateParamIndexes.Add(i, delegateParamInterceptor); } } // Ausnahme-Schalter bool exceptionThrown = false; try { // Metadaten der aufzurufenden Methode abrufen MethodInfo methodInfo = type.GetMethod(methodName, types); // Metadaten der Parameter abrufen ParameterInfo[] serverMethodParamDefs = methodInfo.GetParameters(); // Delegaten-Verdrahtungsliste durchlaufen foreach (int index in delegateParamIndexes.Keys) { // Abfangvorrichtung adressieren DelegateInterceptor delegateParamInterceptor = delegateParamIndexes[index]; // Metadaten des passenden Parameters der Serverkomponenten-Methode adressieren ParameterInfo serverMethodParamDef = serverMethodParamDefs[index]; // Dynamischen Draht erzeugen object dynamicWire = DynamicWireFactory.Instance.CreateDynamicWire(type, serverMethodParamDef.ParameterType, delegateParamInterceptor); // Typ des dynamischen Drahtes ermitteln Type dynamicWireType = dynamicWire.GetType(); // Dynamischen Draht mit Client-Fernsteuerung verdrahten dynamicWireType.GetProperty("Interceptor").SetValue(dynamicWire, delegateParamInterceptor, null); // Delegat zu dynamischem Draht erzeugen Delegate dynamicWireDelegate = Delegate.CreateDelegate(serverMethodParamDef.ParameterType, dynamicWire, dynamicWireType.GetMethod("In")); // Abfangvorrichtung durch dynamischen Draht austauschen args[index] = dynamicWireDelegate; } // Methode aufrufen returnValue = methodInfo.Invoke(instance, args); } catch (Exception ex) { // Ausnahme-Schalter setzen exceptionThrown = true; // InvokeCanceled-Ereignis feuern _host.OnInvokeCanceled(new InvokeCanceledEventArgs() { TrackingID = trackingID, CancelException = ex }); // Ausnahme weiterwerfen throw ex; } finally { // Wenn ein Transaktionsbereich existiert ... if (scope != null) { // Wenn keine Ausnahme aufgetreten ist ... if (!exceptionThrown) { // Transaktionsbereich abschließen scope.Complete(); } // Transaktionsbereich entsorgen scope.Dispose(); } // Wenn die Komponente SingleCallaktiviert ist ... if (registration.ActivationType == ActivationType.SingleCall) { // Verdrahtung aufheben RemoveClientServerWires(type, instance, delegateCorrelationSet, wiringList); } } // Ggf. AfterInvoke-Abos verarbeiten ProcessAfterInvoke(trackingID, ref interfaceName, ref delegateCorrelationSet, ref methodName, ref args, ref returnValue); // Rückgabewert zurückgeben return(returnValue); }