/// <summary> /// This .ctor is handy for message inspectors. /// Creates a substitute message for the original one with new values. /// Binding-specific context is cloned and headers/correlation data are cloned conditionaly /// </summary> public RequestAnyMsg(RequestMsg inspectedOriginal, TypeSpec contract, MethodSpec method, bool oneWay, Guid? instance, object[] args, bool cloneHeaders = true, bool cloneCorrelation = true) : base(inspectedOriginal, contract, method, oneWay, instance, cloneHeaders, cloneCorrelation) { m_Arguments = args; }
/// <summary> /// This .ctor is handy for message inspectors. /// Creates a substitute message for the original one with new values. /// Binding-specific context is cloned and headers/correlation data are cloned conditionaly /// </summary> protected RequestMsg(RequestMsg inspectedOriginal, MethodInfo method, Guid? instance, bool cloneHeaders = true, bool cloneCorrelation = true) : this(method, instance) { m_ServerTransport = inspectedOriginal.m_ServerTransport; CloneState(inspectedOriginal, cloneHeaders, cloneCorrelation); }
/// <summary> /// This .ctor is handy for message inspectors. /// Creates a substitute message for the original one with new values. /// Binding-specific context is cloned and headers/correlation data are cloned conditionaly /// </summary> protected RequestMsg(RequestMsg inspectedOriginal, MethodInfo method, Guid?instance, bool cloneHeaders = true, bool cloneCorrelation = true) : this(method, instance) { m_ServerTransport = inspectedOriginal.m_ServerTransport; CloneState(inspectedOriginal, cloneHeaders, cloneCorrelation); }
/// <summary> /// This .ctor is handy for message inspectors. /// Creates a substitute message for the original one with new values. /// Binding-specific context is cloned and headers/correlation data are cloned conditionaly /// </summary> protected RequestMsg(RequestMsg inspectedOriginal, TypeSpec contract, MethodSpec method, bool oneWay, Guid? instance, bool cloneHeaders = true, bool cloneCorrelation = true) : this(contract, method, oneWay, instance) { m_ServerTransport = inspectedOriginal.m_ServerTransport; CloneState(inspectedOriginal, cloneHeaders, cloneCorrelation); }
/// <summary> /// This .ctor is handy for message inspectors. /// Creates a substitute message for the original one with new values. /// Binding-specific context is cloned and headers/correlation data are cloned conditionaly /// </summary> public RequestAnyMsg(RequestMsg inspectedOriginal, MethodInfo method, Guid? instance, object[] args, bool cloneHeaders = true, bool cloneCorrelation = true) : base(inspectedOriginal, method, instance, cloneHeaders, cloneCorrelation) { m_Arguments = args; }
/// <summary> /// This .ctor is handy for message inspectors. /// Creates a substitute message for the original one with new values. /// Binding-specific context is cloned and headers/correlation data are cloned conditionaly /// </summary> protected RequestMsg(RequestMsg inspectedOriginal, TypeSpec contract, MethodSpec method, bool oneWay, Guid?instance, bool cloneHeaders = true, bool cloneCorrelation = true) : this(contract, method, oneWay, instance) { m_ServerTransport = inspectedOriginal.m_ServerTransport; CloneState(inspectedOriginal, cloneHeaders, cloneCorrelation); }
/// <summary> /// Handles request in the context of ServerHandler thread, replying back to result queue /// </summary> public void HandleRequestAsynchronously(RequestMsg request) { //todo In Future may supply Request.LongRunning to better predict thread allocation Task.Factory.StartNew( (r) => { var req = (RequestMsg)r; ResponseMsg response; try { response = HandleRequestSynchronously(req); } catch (Exception e1) { try { //call goes via Glue because there may be some global event handlers response = Glue.ServerHandleRequestFailure(req.RequestID, req.OneWay, e1, req.BindingSpecificContext); } catch(Exception e2) { this.WriteLog(LogSrc.Server, MessageType.Error, string.Format(StringConsts.GLUE_SERVER_HANDLER_ERROR + e2.ToMessageWithType()), from: "SrvrHndlr.HndlReqAsnly(ReqMsg:A)", exception: e2 ); return; } } if (!req.OneWay) try { req.ServerTransport.SendResponse(response); } catch(Exception error) { this.WriteLog(LogSrc.Server, MessageType.Error, string.Format(StringConsts.GLUE_SERVER_HANDLER_ERROR + error.ToMessageWithType()), from: "SrvrHndlr.HndlReqAsnly(ReqMsg:B)", exception: error ); } }, request); }
/// <summary> /// This .ctor is handy for message inspectors. /// Creates a substitute message for the original one with new values. /// Binding-specific context is cloned and headers/correlation data are cloned conditionaly /// </summary> public RequestAnyMsg(RequestMsg inspectedOriginal, TypeSpec contract, MethodSpec method, bool oneWay, Guid?instance, object[] args, bool cloneHeaders = true, bool cloneCorrelation = true) : base(inspectedOriginal, contract, method, oneWay, instance, cloneHeaders, cloneCorrelation) { m_Arguments = args; }
/// <summary> /// This .ctor is handy for message inspectors. /// Creates a substitute message for the original one with new values. /// Binding-specific context is cloned and headers/correlation data are cloned conditionaly /// </summary> public RequestAnyMsg(RequestMsg inspectedOriginal, MethodInfo method, Guid?instance, object[] args, bool cloneHeaders = true, bool cloneCorrelation = true) : base(inspectedOriginal, method, instance, cloneHeaders, cloneCorrelation) { m_Arguments = args; }
public ResponseMsg ServerHandleRequest(RequestMsg request) { return null; }
public void ClientDispatchedRequest(ClientEndPoint client, RequestMsg request, CallSlot callSlot) { }
}//class serverImplementer ------------------------------------------------------------------------------------------------------- private ResponseMsg inspectAndHandleRequest(RequestMsg request) { NFX.ApplicationModel.ExecutionContext.__SetThreadLevelContext(request, null, request.Session); //Glue level inspectors var inspectors = Glue.ServerMsgInspectors; for(var i=0; i<inspectors.Count; i++) { var insp = inspectors[i]; if (insp==null) continue; request = insp.ServerDispatchRequest(request.ServerTransport.ServerEndpoint, request); NFX.ApplicationModel.ExecutionContext.__SetThreadLevelContext(request, null, request.Session); } //Binding level inspectors inspectors = request.ServerTransport.Binding.ServerMsgInspectors; for(var i=0; i<inspectors.Count; i++) { var insp = inspectors[i]; if (insp==null) continue; request = insp.ServerDispatchRequest(request.ServerTransport.ServerEndpoint, request); NFX.ApplicationModel.ExecutionContext.__SetThreadLevelContext(request, null, request.Session); } //Endpoint level inspectors inspectors = request.ServerTransport.ServerEndpoint.MsgInspectors; for(var i=0; i<inspectors.Count; i++) { var insp = inspectors[i]; if (insp==null) continue; request = insp.ServerDispatchRequest(request.ServerTransport.ServerEndpoint, request); NFX.ApplicationModel.ExecutionContext.__SetThreadLevelContext(request, null, request.Session); } var response = handleRequest(request); NFX.ApplicationModel.ExecutionContext.__SetThreadLevelContext(request, response, request.Session); if (!request.OneWay && response!=null) { //Glue level inspectors inspectors = Glue.ServerMsgInspectors; for(var i=0; i<inspectors.Count; i++) { var insp = inspectors[i]; if (insp==null) continue; response = insp.ServerReturnResponse(request.ServerTransport.ServerEndpoint, request, response); NFX.ApplicationModel.ExecutionContext.__SetThreadLevelContext(request, response, request.Session); } //Binding level inspectors inspectors = request.ServerTransport.Binding.ServerMsgInspectors; for(var i=0; i<inspectors.Count; i++) { var insp = inspectors[i]; if (insp==null) continue; response = insp.ServerReturnResponse(request.ServerTransport.ServerEndpoint, request, response); NFX.ApplicationModel.ExecutionContext.__SetThreadLevelContext(request, response, request.Session); } //Endpoint level inspectors inspectors = request.ServerTransport.ServerEndpoint.MsgInspectors; for(var i=0; i<inspectors.Count; i++) { var insp = inspectors[i]; if (insp==null) continue; response = insp.ServerReturnResponse(request.ServerTransport.ServerEndpoint, request, response); NFX.ApplicationModel.ExecutionContext.__SetThreadLevelContext(request, response, request.Session); } return response; } return null; }
public RequestMsg ClientDispatchingRequest(ClientEndPoint client, RequestMsg request) { //Glue level inspectors foreach(var insp in ClientMsgInspectors.OrderedValues) request = insp.ClientDispatchCall(client, request); return request; }
private void interpretAuthenticationHeader(RequestMsg request) { if (!request.HasHeaders) return; var ah = request.Headers.FirstOrDefault(h => h is AuthenticationHeader) as AuthenticationHeader; if (ah == null) return; if (ah.Credentials==null && ah.Token.Data==null) return; User user; if (ah.Credentials!=null) user = App.SecurityManager.Authenticate(ah.Credentials); else user = App.SecurityManager.Authenticate(ah.Token); if (NFX.ApplicationModel.ExecutionContext.HasThreadContextSession) NFX.ApplicationModel.ExecutionContext.Session.User = user; else NFX.ApplicationModel.ExecutionContext.__SetThreadLevelSessionContext( App.Instance.MakeNewSessionInstance(Guid.NewGuid(), user) ); }
private object getServerInstance(serverImplementer server, RequestMsg request, out Guid? checkedOutID, out bool lockTaken) { object result = null; checkedOutID = null; lockTaken = false; if (server.InstanceMode == ServerInstanceMode.Singleton) { if (!m_SingletonInstances.TryGetValue(server.Implementation, out result)) lock(m_SingletonInstancesLock) { if (!m_SingletonInstances.TryGetValue(server.Implementation, out result)) { result = createInstance(server); var dict = new Dictionary<Type, object>( m_SingletonInstances ); dict[server.Implementation] = result; m_SingletonInstances = dict;//atomic } } } else if (server.InstanceMode == ServerInstanceMode.Stateful || server.InstanceMode == ServerInstanceMode.AutoConstructedStateful) { if (request.RemoteInstance.HasValue) { result = App.ObjectStore.CheckOut(request.RemoteInstance.Value); if (result==null || result.GetType()!=server.Implementation) throw new StatefulServerInstanceDoesNotExistException(StringConsts.GLUE_STATEFUL_SERVER_INSTANCE_DOES_NOT_EXIST_ERROR + server.Implementation.FullName); checkedOutID = request.RemoteInstance.Value; if (!server.ThreadSafe) { if (!Monitor.TryEnter(result, this.Glue.ServerInstanceLockTimeoutMs)) { App.ObjectStore.CheckIn(checkedOutID.Value);//check it back in because we could not lock it throw new StatefulServerInstanceLockTimeoutException(StringConsts.GLUE_STATEFUL_SERVER_INSTANCE_LOCK_TIMEOUT_ERROR + server.Implementation.FullName); } lockTaken = true; } } else result = createInstance(server);//no need to lock as instance is brand new } else // ServerInstanceMode.PerCall { result = createInstance(server); } return result; }
private ResponseMsg doWork(RequestMsg request) { var contract = request.Contract;//this throws when contract can't be found var server = getServerImplementer(request.ServerTransport.ServerEndpoint, contract);//throws when no implementor match found if (server.AuthenticationSupport) interpretAuthenticationHeader(request); //Authorizes user to the whole server contract and implementing class Security.Permission.AuthorizeAndGuardAction(server.Contract); Security.Permission.AuthorizeAndGuardAction(server.Implementation); serverImplementer.mapping mapped = server.SpecToMethodInfos(request.Method); Security.Permission.AuthorizeAndGuardAction(mapped.miContract); Security.Permission.AuthorizeAndGuardAction(mapped.miImplementation); Guid? checkedOutID; bool lockTaken; var instance = getServerInstance(server, request, out checkedOutID, out lockTaken); //throws when instance expired or cant be locked try { Guid? instanceID = null; bool isCtor = false; bool isDctor = false; if (server.InstanceMode == ServerInstanceMode.Stateful || server.InstanceMode == ServerInstanceMode.AutoConstructedStateful) { instanceID = request.RemoteInstance; isCtor = Attribute.IsDefined(mapped.miContract, typeof(ConstructorAttribute)); isDctor= Attribute.IsDefined(mapped.miContract, typeof(DestructorAttribute)); if (isCtor && isDctor) throw new ServerMethodInvocationException(StringConsts.GLUE_AMBIGUOUS_CTOR_DCTOR_DEFINITION_ERROR .Args( contract.FullName, request.MethodName)); if (server.InstanceMode != ServerInstanceMode.AutoConstructedStateful && !instanceID.HasValue && !isCtor) throw new ServerMethodInvocationException(StringConsts.GLUE_NO_SERVER_INSTANCE_ERROR .Args( contract.FullName, request.MethodName)); } //======================================================================================================== object result; try { var any = request as RequestAnyMsg; if (any!=null) result = mapped.miContract.Invoke(instance, any.Arguments); //do actual contract-implementing method work else { //call functor using typed RequestMsg derivative if (mapped.fBody==null) throw new ServerMethodInvocationException(StringConsts.GLUE_NO_ARGS_MARSHAL_LAMBDA_ERROR .Args( contract.FullName, request.MethodName)); result = mapped.fBody(instance, request); //do actual contract-implementing method work via Lambda } } catch(Exception bodyError) { Exception err = bodyError; if (err is TargetInvocationException)//unwrap the inner error which is wrapped by Invoke() if (err.InnerException!=null) err = err.InnerException; throw new ServerMethodInvocationException(StringConsts.GLUE_SERVER_CONTRACT_METHOD_INVOCATION_ERROR .Args(contract.FullName, request.MethodName, err.ToMessageWithType()), err); } //======================================================================================================== if (server.InstanceMode == ServerInstanceMode.Stateful || server.InstanceMode == ServerInstanceMode.AutoConstructedStateful) { if (isCtor || (server.InstanceMode == ServerInstanceMode.AutoConstructedStateful && !isDctor && !instanceID.HasValue)) { instanceID = Guid.NewGuid(); App.ObjectStore.CheckIn(instanceID.Value, instance, server.InstanceTimeoutMs); } else if (isDctor) { if (instanceID.HasValue) { App.ObjectStore.Delete(instanceID.Value); instanceID = null; checkedOutID = null; } } } if (request.OneWay) return null; var response = new ResponseMsg(request.RequestID, instanceID, result); response.__SetBindingSpecificContext(request); return response; } finally { if (lockTaken) Monitor.Exit(instance); if (checkedOutID.HasValue) App.ObjectStore.CheckIn(checkedOutID.Value, server.InstanceTimeoutMs); } }
private ResponseMsg handleRequest(RequestMsg request) { try { ServerCallContext.__SetThreadLevelContext(request); try { var response = doWork(request); var rhdr = ServerCallContext.GetResponseHeadersOrNull(); if (rhdr!=null && response!=null) response.Headers = rhdr; return response; } finally { ServerCallContext.__ResetThreadLevelContext(); } } catch(Exception error) { if (request.OneWay) { //because it is one-way, the caller will never know about it this.WriteLog(LogSrc.Server, MessageType.Error, string.Format(StringConsts.GLUE_SERVER_ONE_WAY_CALL_ERROR + error.ToMessageWithType()), from: "SrvrHndlr.handleRequest(ReqMsg)", exception: error ); return null; } else { var red = new RemoteExceptionData(error); var response = new ResponseMsg(request.RequestID, red); response.__SetBindingSpecificContext(request); return response; } } }
public RequestMsg ServerDispatchRequest(ServerEndPoint endpoint, RequestMsg request) { NFX.ApplicationModel.ExecutionContext.Application.Log.Write( new NFX.Log.Message{ Type=NFX.Log.MessageType.TraceA, From ="ServeInspector", Text="Received " + request.ServerTransport.StatBytesReceived.ToString() + " bytes"}); return request; }
public RequestMsg ClientDispatchCall(ClientEndPoint endpoint, RequestMsg request) { request.Headers.Add( new TextInfoHeader{ Text = "Moscow time is " + App.LocalizedTime.ToString(), Info = @"/\EH|/|H }|{|/|B!" }); return request; }
public void ClientDispatchedRequest(ClientEndPoint client, RequestMsg request, CallSlot callSlot) { if (client.Binding.OperationFlow == OperationFlow.Asynchronous) m_Calls.Put(callSlot); }
/// <summary> /// Handles request synchronously in the context of the calling thread. Returns NULL for one-way calls /// </summary> public ResponseMsg HandleRequestSynchronously(RequestMsg request) { try { return inspectAndHandleRequest(request); } catch(Exception error) //nothing may leak { if (request.OneWay) { //because it is one-way, the caller will never know about it this.WriteLog(LogSrc.Server, MessageType.Error, string.Format(StringConsts.GLUE_SERVER_ONE_WAY_CALL_ERROR + error.ToMessageWithType()), from: "SrvrHndlr.HandleRequestSynchronously(ReqMsg)", exception: error ); return null; } else { //call goes via Glue because there may be some global event handlers var response = Glue.ServerHandleRequestFailure(request.RequestID, request.OneWay, error, request.BindingSpecificContext); return response; } } finally { NFX.ApplicationModel.ExecutionContext.__SetThreadLevelContext(null, null, null); } }
public ResponseMsg ServerReturnResponse(ServerEndPoint endpoint, RequestMsg request, ResponseMsg response) { response.Headers.Add( new TextInfoHeader{ Text="Response generated at " + App.LocalizedTime.ToString(), Info = "Serve Node: " + endpoint.Node } ); return response; }
public void ServerDispatchRequest(RequestMsg request) { m_ServerHandler.HandleRequestAsynchronously(request); }
public RequestMsg ClientDispatchingRequest(ClientEndPoint client, RequestMsg request) { return request; }
public ResponseMsg ServerHandleRequest(RequestMsg request) { return m_ServerHandler.HandleRequestSynchronously(request); }
public void ServerDispatchRequest(RequestMsg request) { }
/// <summary> /// Internal framework-only method to bind thread-level context /// </summary> public static void __SetThreadLevelContext(RequestMsg request) { ts_Request = request; }
/// <summary> /// Dispatches a call into binding passing message through client inspectors on this endpoint /// </summary> protected CallSlot DispatchCall(RequestMsg request) { if (m_Headers.Count>0) request.Headers.AddRange(m_Headers); foreach(var insp in m_MsgInspectors.OrderedValues) request = insp.ClientDispatchCall(this, request); return Binding.DispatchCall(this, request); }
/// <summary> /// Internal framework-only method to clear thread-level context /// </summary> public static void __ResetThreadLevelContext() { ts_Request = null; ts_ResponseHeaders = null; }