Пример #1
0
        private async Task<ConnectionDescriptor> EnsureConnectionAsync(ClientActionContext context, SessionMetadata sessionMetadata)
        {
            if (sessionMetadata.State == ProxyState.Open)
            {
                context.ActionResult = sessionMetadata.InitSessionResult;
                return sessionMetadata.ServerConnection;
            }

            if (sessionMetadata.State == ProxyState.Closed)
            {
                throw new ProxyClosedException();
            }

            using (await sessionMetadata.LockAsync())
            {
                // check connections tate again when under lock
                if (sessionMetadata.State == ProxyState.Open)
                {
                    context.ActionResult = sessionMetadata.InitSessionResult;
                    return sessionMetadata.ServerConnection;
                }

                if (sessionMetadata.State == ProxyState.Closed)
                {
                    throw new ProxyClosedException();
                }

                ClientActionContext initSessionContext = context;
                if (context.Action != sessionMetadata.Contract.InitSession.Action)
                {
                    // we are not initializaing proxy explicitely, so we need to check whether proxy has been initalized before
                    if (sessionMetadata.Contract.InitSession.HasParameters)
                    {
                        if (sessionMetadata.InitSessionParameters == null)
                        {
                            // we can not reuse initialization parameters, so throw 
                            throw new BoltClientException(
                                "Proxy need to be initialized before it can be used.",
                                ClientErrorCode.ProxyNotInitialized,
                                context.Action,
                                null);
                        }
                    }

                    // create init session context and reuse init parameters
                    initSessionContext = new ClientActionContext(
                        context.Proxy,
                        context.Contract,
                        sessionMetadata.Contract.InitSession.Action,
                        sessionMetadata.InitSessionParameters);
                }
                else if (sessionMetadata.Contract.InitSession.HasParameters)
                {
                    try
                    {
                        sessionMetadata.Contract.InitSession.ValidateParameters(initSessionContext.Parameters);
                    }
                    catch (Exception e)
                    {
                        // we can not reuse initialization parameters, so throw 
                        throw new BoltClientException(
                            $"Proxy is beeing initialized with invalid parameters. If session initialization has non empty parameters you should initialize it first by calling '{initSessionContext.Action.Name}' with proper parameters.",
                            ClientErrorCode.InvalidInitSessionParameters,
                            context.Action,
                            e);
                    }
                }

                try
                {
                    // execute whole pipeline
                    await Next(initSessionContext);

                    // extract connection and session id from response
                    string sessionId = ClientSessionHandler.GetSessionIdentifier(initSessionContext.Response);
                    if (sessionId == null)
                    {
                        throw new BoltServerException(
                            ServerErrorCode.SessionIdNotReceived,
                            sessionMetadata.Contract.InitSession.Action,
                            initSessionContext.Request?.RequestUri?.ToString());
                    }

                    if (initSessionContext.ServerConnection == null)
                    {
                        throw new BoltClientException(ClientErrorCode.ConnectionUnavailable, initSessionContext.Action);
                    }

                    sessionMetadata.InitSessionResult = initSessionContext.ActionResult;
                    sessionMetadata.InitSessionParameters = initSessionContext.Parameters;
                    sessionMetadata.SessionId = sessionId;
                    sessionMetadata.ServerConnection = initSessionContext.ServerConnection;
                    sessionMetadata.ChangeState(context.Proxy, ProxyState.Open);
                }
                catch (Exception e)
                {
                    Exception handled = HandleOpenConnectionError(initSessionContext, e, sessionMetadata);
                    if (handled == e)
                    {
                        throw;
                    }

                    if (handled != null)
                    {
                        throw handled;
                    }

                    throw;
                }
                finally
                {
                    // we should not dispose original context
                    if (context.Action != sessionMetadata.Contract.InitSession.Action)
                    {
                        initSessionContext.Dispose();
                    }
                }

                return sessionMetadata.ServerConnection;
            }
        }
Пример #2
0
        protected virtual Exception HandleOpenConnectionError(ClientActionContext context, Exception error, SessionMetadata session)
        {
            session.ClearSession();
            ErrorHandlingResult handlingResult = ErrorHandling.Handle(context, error);
            switch (handlingResult)
            {
                case ErrorHandlingResult.Close:
                    session.ChangeState(context.Proxy, ProxyState.Closed);
                    break;
                case ErrorHandlingResult.Recover:
                case ErrorHandlingResult.Rethrow:
                    session.ChangeState(context.Proxy, ProxyState.Ready);
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }

            return error;
        }
Пример #3
0
        private async Task <ConnectionDescriptor> EnsureConnectionAsync(ClientActionContext context, SessionMetadata sessionMetadata)
        {
            if (sessionMetadata.State == ProxyState.Open)
            {
                context.ActionResult = sessionMetadata.InitSessionResult;
                return(sessionMetadata.ServerConnection);
            }

            if (sessionMetadata.State == ProxyState.Closed)
            {
                throw new ProxyClosedException();
            }

            using (await sessionMetadata.LockAsync().ConfigureAwait(false))
            {
                // check connections tate again when under lock
                if (sessionMetadata.State == ProxyState.Open)
                {
                    context.ActionResult = sessionMetadata.InitSessionResult;
                    return(sessionMetadata.ServerConnection);
                }

                if (sessionMetadata.State == ProxyState.Closed)
                {
                    throw new ProxyClosedException();
                }

                ClientActionContext initSessionContext = context;
                if (context.Action.Action != sessionMetadata.Contract.InitSession.Action)
                {
                    // we are not initializaing proxy explicitely, so we need to check whether proxy has been initalized before
                    if (sessionMetadata.Contract.InitSession.HasParameters)
                    {
                        if (sessionMetadata.InitSessionParameters == null)
                        {
                            // we can not reuse initialization parameters, so throw
                            throw new BoltClientException(
                                      $"Action '{context.Action.Name}' on contract '{context.Contract.NormalizedName}' cannot be executed because proxy that is used for communication has not been initialized. Initialize the proxy first by explicitely calling '{initSessionContext.Action.Name}' action with proper parameters.",
                                      ClientErrorCode.InvalidInitSessionParameters,
                                      context.Action.Name);
                        }
                    }

                    // create init session context and reuse init parameters
                    initSessionContext = new ClientActionContext();
                    initSessionContext.Init(
                        context.Proxy,
                        context.Contract,
                        sessionMetadata.Contract.InitSession,
                        sessionMetadata.InitSessionParameters);
                }
                else if (sessionMetadata.Contract.InitSession.HasParameters)
                {
                    try
                    {
                        sessionMetadata.Contract.InitSession.ValidateParameters(initSessionContext.Parameters);
                    }
                    catch (Exception e)
                    {
                        // we can not reuse initialization parameters, so throw
                        throw new BoltClientException(
                                  $"Proxy initialization action '{context.Action.Name}' on contract '{context.Contract.NormalizedName}' cannot be executed because the provided parameters are invalid.",
                                  ClientErrorCode.InvalidInitSessionParameters,
                                  context.Action.Name,
                                  e);
                    }
                }

                try
                {
                    // execute whole pipeline
                    await Next(initSessionContext).ConfigureAwait(false);

                    // extract connection and session id from response
                    string sessionId = ClientSessionHandler.GetSessionIdentifier(initSessionContext.Response);
                    if (initSessionContext.ServerConnection == null)
                    {
                        throw new BoltClientException(ClientErrorCode.ConnectionUnavailable, initSessionContext.Action.Name);
                    }

                    sessionMetadata.InitSessionResult     = initSessionContext.ActionResult;
                    sessionMetadata.InitSessionParameters = initSessionContext.Parameters;
                    sessionMetadata.SessionId             = sessionId ?? throw new BoltServerException(
                                                                      ServerErrorCode.SessionIdNotReceived,
                                                                      sessionMetadata.Contract.InitSession.Action.Name,
                                                                      initSessionContext.Request?.RequestUri?.ToString());
                    sessionMetadata.ServerConnection = initSessionContext.ServerConnection;
                    sessionMetadata.ChangeState(context.Proxy, ProxyState.Open);
                }
                catch (Exception e)
                {
                    Exception handled = HandleOpenConnectionError(initSessionContext, e, sessionMetadata);
                    if (handled != null && handled != e)
                    {
                        throw handled;
                    }

                    throw;
                }
                finally
                {
                    // we should not dispose original context
                    if (context.Action.Action != sessionMetadata.Contract.InitSession.Action)
                    {
                        initSessionContext.Reset();
                    }
                }

                return(sessionMetadata.ServerConnection);
            }
        }
Пример #4
0
        public override async Task InvokeAsync(ClientActionContext context)
        {
            context.GetRequestOrThrow();

            // access or create session assigned to current proxy
            SessionMetadata session = _sessions.GetOrAdd(
                context.Proxy,
                proxy => new SessionMetadata(proxy.Contract.Session));

            if (session.State != ProxyState.Open)
            {
                // we need to open proxy
                await EnsureConnectionAsync(context, session).ConfigureAwait(false);
            }

            if (!UseDistributedSession)
            {
                // we stick to active connection otherwise new connection will be picked using PickConnectionMiddleware
                context.ServerConnection = session.ServerConnection;
            }

            if (context.Action.Action == session.Contract.InitSession.Action)
            {
                // at this point session is opened, assign initialization result just in case
                if (context.ActionResult == null)
                {
                    context.ActionResult = session.InitSessionResult;
                }
            }
            else if (context.Action.Action == session.Contract.DestroySession.Action)
            {
                if (context.Proxy.State == ProxyState.Closed)
                {
                    // no reason to continue in pipeline, proxy is already closed
                    session.ChangeState(context.Proxy, ProxyState.Closed);
                    context.ActionResult = session.DestroySessionResult;
                    return;
                }

                if (context.Proxy.State == ProxyState.Ready)
                {
                    // proxy was never initialized, ignore the rest of pipeline and close it
                    context.ActionResult = session.DestroySessionResult;
                    session.ChangeState(context.Proxy, ProxyState.Closed);
                    return;
                }

                if (session.RequiresDestroyParameters && context.Parameters == null)
                {
                    // we are trying to close proxy using IProxy.CloseAsync even when the destroy action requires actual parameters
                    throw new BoltClientException(
                              $"Destroing session requires parameters that were not provided for action '{context.Action.Name}'.",
                              ClientErrorCode.InvalidDestroySessionParameters,
                              context.Action.Name,
                              null);
                }

                try
                {
                    // execute destroy session and close proxy
                    ClientSessionHandler.EnsureSession(context.GetRequestOrThrow(), session.SessionId);
                    await Next(context).ConfigureAwait(false);
                }
                finally
                {
                    _sessions.TryRemove(context.Proxy, out session);
                    session.ClearSession();
                    session.ChangeState(context.Proxy, ProxyState.Closed);
                }
            }
            else
            {
                // prepare the request with session
                ClientSessionHandler.EnsureSession(context.GetRequestOrThrow(), session.SessionId);

                try
                {
                    // execute pipeline
                    await Next(context).ConfigureAwait(false);
                }
                catch (Exception e)
                {
                    Exception handled = HandleError(context, e, session);
                    if (e == handled)
                    {
                        // the handled error is same, so just rethrow
                        throw;
                    }

                    if (handled != null)
                    {
                        throw handled;
                    }
                }
            }
        }
Пример #5
0
        protected virtual Exception HandleOpenConnectionError(ClientActionContext context, Exception error, SessionMetadata session)
        {
            session.ClearSession();
            ErrorHandlingResult handlingResult = ErrorHandling.Handle(context, error);

            switch (handlingResult)
            {
            case ErrorHandlingResult.Close:
                session.ChangeState(context.Proxy, ProxyState.Closed);
                break;

            case ErrorHandlingResult.Recover:
            case ErrorHandlingResult.Rethrow:
                session.ChangeState(context.Proxy, ProxyState.Ready);
                break;

            default:
                throw new ArgumentOutOfRangeException($"The value of '{handlingResult}' is not supported", nameof(handlingResult));
            }

            return(error);
        }