/// <summary> /// Performs a POST Logout request, ending the current session. /// </summary> public async Task LogoutAsync() { if (Cookies == null) { return; } try { await ServiceLayerRoot.AppendPathSegment("Logout").WithCookies(Cookies).PostAsync(); _loginResponse = new SLLoginResponse(); _lastRequest = default; Cookies = null; } catch (FlurlHttpException ex) { try { if (ex.Call.HttpResponseMessage == null) { throw; } var response = await ex.GetResponseJsonAsync <SLResponseError>(); throw new SLException(response.Error.Message.Value, response.Error, ex); } catch { throw ex; } } }
/// <summary> /// Initializes a new instance of the <see cref="SLConnection"/> class. /// Only one instance per company/user should be used in the application. /// </summary> /// <param name="serviceLayerRoot"> /// The Service Layer root URI. The expected format is https://[server]:[port]/b1s/[version] /// </param> /// <param name="companyDB"> /// The Company database (schema) to connect to. /// </param> /// <param name="userName"> /// The SAP user to be used for the Service Layer authentication. /// </param> /// <param name="password"> /// The password for the provided user. /// </param> /// <param name="language"> /// The language code to be used. Specify a code if you want error messages in some specific language other than English. /// A GET request to the UserLanguages resource will return all available languages and their respective codes. /// </param> /// <param name="numberOfAttempts"> /// The number of attempts for each request in case of an HTTP response code of 401, 500, 502, 503 or 504. /// If the response code is 401 (Unauthorized), a login request will be performed before the new attempt. /// </param> public SLConnection(Uri serviceLayerRoot, string companyDB, string userName, string password, int?language = null, int numberOfAttempts = 3) { if (string.IsNullOrWhiteSpace(companyDB)) { throw new ArgumentException("companyDB can not be empty."); } if (string.IsNullOrWhiteSpace(userName)) { throw new ArgumentException("userName can not be empty."); } if (string.IsNullOrWhiteSpace(password)) { throw new ArgumentException("password can not be empty."); } ServiceLayerRoot = serviceLayerRoot; CompanyDB = companyDB; UserName = userName; Password = password; Language = language; NumberOfAttempts = numberOfAttempts; LoginResponse = new SLLoginResponse(); }
/// <summary> /// Performs the POST Login request to the Service Layer. /// </summary> /// <param name="forceLogin"> /// Whether the login request should be forced even if the current session has not expired. /// </param> /// <param name="expectReturn"> /// Wheter the login information should be returned. /// </param> private async Task <SLLoginResponse> ExecuteLoginAsync(bool forceLogin = false, bool expectReturn = false) { // Prevents multiple login requests in a multi-threaded scenario await _semaphoreSlim.WaitAsync(); try { if (forceLogin) { _lastRequest = default; } // Session still valid, no need to login again if (DateTime.Now.Subtract(_lastRequest).TotalMinutes < _loginResponse.SessionTimeout) { return(expectReturn ? LoginResponse : null); } var loginResponse = await ServiceLayerRoot .AppendPathSegment("Login") .WithCookies(out var cookieJar) .PostJsonAsync(new { CompanyDB, UserName, Password, Language }) .ReceiveJson <SLLoginResponse>(); Cookies = cookieJar; _loginResponse = loginResponse; _loginResponse.LastLogin = DateTime.Now; return(expectReturn ? LoginResponse : null); } catch (FlurlHttpException ex) { try { if (ex.Call.HttpResponseMessage == null) { throw; } var response = await ex.GetResponseJsonAsync <SLResponseError>(); throw new SLException(response.Error.Message.Value, response.Error, ex); } catch { throw ex; } } finally { _semaphoreSlim.Release(); } }