public void InvocationDetailsObtainPublicMethodInfo() { var foo = new InvocationDetails { Type = typeof(Service), InterfaceType = typeof(IService), MethodName = "Foo", ParamTypes = new Type[0], GenericArguments = new Type[0] }; Assert.IsTrue(foo.FindMethodInfo()); Assert.IsNotNull(foo.MethodInfo); Assert.AreEqual(foo.MethodName, foo.MethodInfo.Name); }
public void InvocationDetailsObtainPrivateMethodInfo() { var bar = new InvocationDetails { Type = typeof(Service), InterfaceType = typeof(IService), MethodName = "Bar", ParamTypes = new Type[0], GenericArguments = new Type[0] }; Assert.IsTrue(bar.FindMethodInfo()); Assert.IsNotNull(bar.MethodInfo); Assert.AreNotEqual(bar.MethodName, bar.MethodInfo.Name); }
/// <summary> /// Sets the session for the current worker thread. /// </summary> /// <param name="details">Invocation details</param> private void Invoke_SetSession(InvocationDetails details) { // validate session var sessionID = details.CallContextData.Store.ContainsKey("sessionid") ? (Guid)details.CallContextData.Store["sessionid"] : Guid.Empty; if (!_host.SessionManager.ExistSession(sessionID)) { throw new InvalidSessionException(string.Format(LanguageResource.InvalidSessionException_SessionIDInvalid, sessionID)); } // double-check to avoid race condition var session = _host.SessionManager.GetSessionBySessionID(sessionID); if (session == null) { throw new InvalidSessionException(string.Format(LanguageResource.InvalidSessionException_SessionIDInvalid, sessionID)); } // set current session details.Session = session; details.Session.Timestamp = DateTime.Now; details.Session.ClientAddress = GetCallingClientIPAddress(); _host.SessionManager.SetCurrentSession(details.Session); }
/// <summary> /// Fires the InvokeRejected event. /// </summary> /// <param name="details">Invocation details</param> /// <param name="ex">Exception</param> private void Invoke_FireInvokeRejectedEvent(InvocationDetails details, Exception ex) { details.ExceptionThrown = true; var args = new InvokeCanceledEventArgs { TrackingID = details.TrackingID, CancelException = ex }; _host.OnInvokeRejected(args); throw args.CancelException.PreserveStackTrace() ?? new InvokeCanceledException(); }
/// <summary> /// Converts method arguments, if needed. /// <remarks> /// Conversion is needed when Types configured for custom serialization or arguments are delegates. /// </remarks> /// </summary> /// <param name="details">Invocation details</param> private void Invoke_ConvertMethodArguments(InvocationDetails details) { details.DelegateParamIndexes = new Dictionary<int, DelegateInterceptor>(); for (int i = 0; i < details.ParamTypes.Length; i++) { var delegateParamInterceptor = details.Args[i] as DelegateInterceptor; if (delegateParamInterceptor != null) { details.DelegateParamIndexes.Add(i, delegateParamInterceptor); continue; } var container = details.Args[i] as CustomSerializationContainer; if (container != null) { var serializationHandler = _host.SerializationHandling[container.HandledType]; if (serializationHandler == null) { var ex = new KeyNotFoundException(string.Format(LanguageResource.KeyNotFoundException_SerializationHandlerNotFound, container.HandledType.FullName)); _host.OnInvokeCanceled(new InvokeCanceledEventArgs() { TrackingID = details.TrackingID, CancelException = ex }); throw ex; } details.Args[i] = serializationHandler.Deserialize(container.DataType, container.Data); } } }
/// <summary> /// Sets the remote subscription counter. /// </summary> /// <param name="details">The details.</param> private void Invoke_SetRemoteSubscriptionCounter(InvocationDetails details) { if (details.CallContextData.Store != null && ServerSession.CurrentSession != null) { details.CallContextData.Store["subscriptions"] = ServerSession.CurrentSession.RemoteSubscriptionCounter; } }
/// <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> /// Processes AfterInvoke event subscriptions (if there any). /// </summary> /// <param name="details">Invocation details</param> private void ProcessAfterInvoke(InvocationDetails details) { if (_host.HasAfterInvokeSubscriptions()) { AfterInvokeEventArgs afterInvokeArgs = new AfterInvokeEventArgs() { TrackingID = details.TrackingID, InterfaceName = details.InterfaceName, DelegateCorrelationSet = details.DelegateCorrelationSet, MethodName = details.MethodName, Arguments = details.Args, ReturnValue = details.ReturnValue }; _host.OnAfterInvoke(afterInvokeArgs); } }
/// <summary> /// Sets the session for the current worker thread. /// </summary> /// <param name="details">Invocation details</param> private void Invoke_SetSession(InvocationDetails details) { // validate session var sessionID = details.CallContextData.Store.ContainsKey("sessionid") ? (Guid)details.CallContextData.Store["sessionid"] : Guid.Empty; if (!_host.SessionManager.ExistSession(sessionID)) { throw new InvalidSessionException(string.Format(LanguageResource.InvalidSessionException_SessionIDInvalid, sessionID.ToString())); } // set current session details.Session = _host.SessionManager.GetSessionBySessionID(sessionID); details.Session.Timestamp = DateTime.Now; ServerSession.CurrentSession = details.Session; PutClientAddressToCurrentSession(); }
/// <summary> /// Obtains metadata of the invoked method via reflection. /// </summary> /// <param name="details">Invocation details</param> private void Invoke_ObtainMethodMetadata(InvocationDetails details) { details.MethodInfo = details.Type.GetMethod(details.MethodName, details.GenericArguments, details.ParamTypes); if (details.MethodInfo == null) { var methodSignature = MessageHelpers.GetMethodSignature(details.Type, details.MethodName, details.ParamTypes); var exceptionMessage = String.Format(LanguageResource.MissingMethodException_MethodNotFound, methodSignature); throw new MissingMethodException(exceptionMessage); } }
/// <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; }
public void InvocationDetailsUnknownMethod() { var baz = new InvocationDetails { Type = typeof(Service), InterfaceType = typeof(IService), MethodName = "Baz", ParamTypes = new Type[0], GenericArguments = new Type[0] }; Assert.IsFalse(baz.FindMethodInfo()); Assert.IsNull(baz.MethodInfo); }
/// <summary> /// Adds remote handlers to events of a server component. /// </summary> /// <param name="interfaceName">Name of the server component interface.</param> /// <param name="correlationSet">Correlation information.</param> /// <param name="uniqueName">Unique name of the server component instance (may be left empty, if component isn't registered with a unique name).</param> public void AddEventHandlers(string interfaceName, IEnumerable<DelegateCorrelationInfo> correlationSet, string uniqueName) { if (string.IsNullOrEmpty(interfaceName)) throw new ArgumentException(LanguageResource.ArgumentException_InterfaceNameMissing, "interfaceName"); if (string.IsNullOrEmpty(uniqueName)) uniqueName = interfaceName; if (!_host.ComponentCatalog.IsRegistered(uniqueName)) throw new KeyNotFoundException(string.Format(LanguageResource.KeyNotFoundException_CannotFindComponentForInterface, interfaceName)); var details = new InvocationDetails() { InterfaceName = interfaceName, Registration = _host.ComponentCatalog.GetRegistration(uniqueName) }; Invoke_LoadCallContextData(details); Invoke_SetSession(details); Invoke_ResolveComponentInstance(details); CreateClientServerWires(details.Type, details.Registration.EventStub, correlationSet, details.Registration.EventWirings); Invoke_CleanUp(details); }
/// <summary> /// Intercepts delegate parameters. /// </summary> /// <param name="details">Invocation details</param> private void Invoke_InterceptDelegateParams(InvocationDetails details) { var serverMethodParamDefs = details.MethodInfo.GetParameters(); foreach (int index in details.DelegateParamIndexes.Keys) { var delegateParamInterceptor = details.DelegateParamIndexes[index]; var serverMethodParamDef = serverMethodParamDefs[index]; var dynamicWire = DynamicWireFactory.CreateDynamicWire(details.Type, serverMethodParamDef.ParameterType); dynamicWire.Interceptor = delegateParamInterceptor; details.Args[index] = dynamicWire.InDelegate; } }
/// <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> /// Loads data from the logical call context. /// </summary> /// <param name="details">Invocation details</param> private void Invoke_LoadCallContextData(InvocationDetails details) { // check for logical context data details.CallContextData = CallContext.GetData("__ZyanContextData_" + _host.Name) as LogicalCallContextData; if (details.CallContextData == null) { throw new SecurityException(LanguageResource.SecurityException_ContextInfoMissing); } }
/// <summary> /// Applies custom serialization on return value (if configured). /// </summary> /// <param name="details">Invocation details</param> private void Invoke_ApplyCustomSerializationOnReturnValue(InvocationDetails details) { if (details.ReturnValue != null) { Type returnValueType = details.ReturnValue.GetType(); Type handledType; ISerializationHandler handler; _host.SerializationHandling.FindMatchingSerializationHandler(returnValueType, out handledType, out handler); if (handler != null) { byte[] raw = handler.Serialize(details.ReturnValue); details.ReturnValue = new CustomSerializationContainer(handledType, returnValueType, raw); } } }
/// <summary> /// Resolves the component instance to be invoked. /// </summary> /// <param name="details">Invocation details</param> private void Invoke_ResolveComponentInstance(InvocationDetails details) { // Skip resolving registration, if already done if (details.Registration == null) details.Registration = _host.ComponentRegistry[details.InterfaceName]; // get component instance details.Instance = _host.GetComponentInstance(details.Registration); details.Type = details.Instance.GetType(); }
/// <summary> /// Checks if the provided interface name belongs to a registered component. /// </summary> /// <param name="details">Invocation details</param> private void Invoke_CheckInterfaceName(InvocationDetails details) { // look up the component registration info if (!_host.ComponentRegistry.ContainsKey(details.InterfaceName)) throw new KeyNotFoundException(string.Format(LanguageResource.KeyNotFoundException_CannotFindComponentForInterface, details.InterfaceName)); }
/// <summary> /// Sets a transaction for the current worker thread, if provided. /// </summary> /// <param name="details">Invocation details</param> private void Invoke_SetTransaction(InvocationDetails details) { // transfer implicit transaction var transaction = details.CallContextData.Store.ContainsKey("transaction") ? (Transaction)details.CallContextData.Store["transaction"] : null; if (transaction != null) details.Scope = new TransactionScope(transaction); }
/// <summary> /// Cleans up event handlers and component instance (if needed). /// </summary> /// <param name="details">Invocation details</param> private void Invoke_CleanUp(InvocationDetails details) { if (details.Instance != null && details.Registration != null && details.Registration.ActivationType == ActivationType.SingleCall) { _host.ComponentCatalog.CleanUpComponentInstance(details.Registration, details.Instance); } }
/// <summary> /// Processes BeforeInvoke event subscriptions (if there any). /// </summary> /// <param name="details">Invocation details</param> private void ProcessBeforeInvoke(InvocationDetails details) { if (_host.HasBeforeInvokeSubscriptions()) { BeforeInvokeEventArgs cancelArgs = new BeforeInvokeEventArgs() { TrackingID = details.TrackingID, InterfaceName = details.InterfaceName, DelegateCorrelationSet = details.DelegateCorrelationSet, MethodName = details.MethodName, Arguments = details.Args, Cancel = false }; _host.OnBeforeInvoke(cancelArgs); if (cancelArgs.Cancel) { if (cancelArgs.CancelException == null) cancelArgs.CancelException = new InvokeCanceledException(); throw cancelArgs.CancelException.PreserveStackTrace(); } details.InterfaceName = cancelArgs.InterfaceName; details.DelegateCorrelationSet = cancelArgs.DelegateCorrelationSet; details.MethodName = cancelArgs.MethodName; details.Args = cancelArgs.Arguments; } }
/// <summary> /// Completes the transaction scope, if no exception occured. /// </summary> /// <param name="details">Invocation details</param> private void Invoke_CompleteTransactionScope(InvocationDetails details) { if (details.Scope != null) { if (!details.ExceptionThrown) details.Scope.Complete(); details.Scope.Dispose(); } }
/// <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="args">Parameter values</param> /// <returns>Return value</returns> public object Invoke(Guid trackingID, string interfaceName, List <DelegateCorrelationInfo> delegateCorrelationSet, string methodName, Type[] genericArguments, Type[] paramTypes, 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) _host.SessionManager.SetCurrentSession(null); var details = new InvocationDetails() { TrackingID = trackingID, InterfaceName = interfaceName, DelegateCorrelationSet = delegateCorrelationSet, MethodName = methodName, GenericArguments = genericArguments, ParamTypes = paramTypes, Args = args }; 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_SetRemoteSubscriptionCounter(details); Invoke_CleanUp(details); } ProcessAfterInvoke(details); return(details.ReturnValue); }
/// <summary> /// Fires the InvokeRejected event. /// </summary> /// <param name="details">Invocation details</param> /// <param name="ex">Exception</param> private void Invoke_FireInvokeRejectedEvent(InvocationDetails details, Exception ex) { details.ExceptionThrown = true; var args = new InvokeCanceledEventArgs { TrackingID = details.TrackingID, InterfaceName = details.InterfaceName, DelegateCorrelationSet = details.DelegateCorrelationSet, MethodName = details.MethodName, Arguments = details.Args, CancelException = ex }; _host.OnInvokeRejected(args); throw args.CancelException.PreserveStackTrace() ?? new InvokeCanceledException(); }