/// <summary> /// Asynchronously gets an HTTP connection to an innovator instance (or proxy) at the given URL /// </summary> /// <param name="preferences">Object containing preferences for the connection</param> /// <param name="async">Whether or not to return the connection asynchronously. This is important /// as an HTTP request must be issued to determine the type of connection to create</param> /// <returns>A promise to return a connection object</returns> public static IPromise <IRemoteConnection> GetConnection(ConnectionPreferences preferences, bool async) { preferences = preferences ?? new ConnectionPreferences(); var url = preferences.Url; url = (url ?? "").TrimEnd('/'); if (url.EndsWith("Server/InnovatorServer.aspx", StringComparison.OrdinalIgnoreCase)) { url = url.Substring(0, url.Length - 21); } if (!url.EndsWith("/server", StringComparison.OrdinalIgnoreCase)) { url += "/Server"; } var configUrl = url + "/mapping.xml"; var service = preferences.HttpService ?? ConnectionPreferences.GetService(); Func <ServerMapping, IRemoteConnection> connFactory = m => { var uri = (m.Url ?? "").TrimEnd('/'); if (!uri.EndsWith("/server", StringComparison.OrdinalIgnoreCase)) { url += "/Server"; } switch (m.Type) { case ServerType.Proxy: throw new NotSupportedException(); default: return(ArasConn(service, uri, preferences)); } }; var result = new Promise <IRemoteConnection>(); var req = new HttpRequest { UserAgent = preferences.Headers.UserAgent }; req.SetHeader("Accept", "text/xml"); foreach (var header in preferences.Headers.NonUserAgentHeaders()) { req.SetHeader(header.Key, header.Value); } var trace = new LogData(4, "Innovator: Try to download mapping file", Factory.LogListener) { { "url", configUrl }, }; result.CancelTarget(service.GetPromise(new Uri(configUrl), async, trace, req) .Progress((p, m) => result.Notify(p, m)) .Done(r => { var data = r.AsString(); if (string.IsNullOrEmpty(data)) { result.Resolve(ArasConn(service, url, preferences)); } else { try { var servers = ServerMapping.FromXml(data).ToArray(); if (servers.Length < 1) { result.Resolve(ArasConn(service, url, preferences)); } else if (servers.Length == 1) { result.Resolve(connFactory(servers.Single())); } else { foreach (var server in servers) { server.Factory = connFactory; } result.Resolve(new MappedConnection(servers, preferences.AuthCallback)); } } catch (XmlException) { result.Resolve(ArasConn(service, url, preferences)); } } }).Fail(ex => { result.Resolve(ArasConn(service, url, preferences)); })).Always(trace.Dispose); if (preferences.Credentials != null) { IRemoteConnection conn = null; return(result .Continue(c => { conn = c; return c.Login(preferences.Credentials, async); }) .Convert(u => conn)); } return(result); }
private IPromise <ICredentials> DefaultAuthCallback(INetCredentials netCred, string endpoint, bool async) { var promise = new Promise <ICredentials>(); if (string.IsNullOrEmpty(endpoint)) { promise.Resolve(netCred); } else { var handler = new SyncClientHandler() { Credentials = netCred.Credentials, PreAuthenticate = true }; var http = new SyncHttpClient(handler); var endpointUri = new Uri(endpoint + "?db=" + netCred.Database); var trace = new LogData(4, "Innovator: Authenticate user via mapping", Factory.LogListener) { { "database", netCred.Database }, { "user_name", netCred.Credentials.GetCredential(endpointUri, null).UserName }, { "url", endpointUri }, }; http.GetPromise(endpointUri, async, trace) .Done(r => { var res = r.AsXml().DescendantsAndSelf("Result").FirstOrDefault(); var user = res.Element("user").Value; var pwd = res.Element("password").Value; if (pwd.IsNullOrWhiteSpace()) { promise.Reject(new ArgumentException("Failed to authenticate with Innovator server '" + endpoint + "'. Original error: " + user, "credentials")); } var needHash = !string.Equals(res.Element("hash").Value, "false", StringComparison.OrdinalIgnoreCase); if (needHash) { promise.Resolve(new ExplicitCredentials(netCred.Database, user, pwd)); } else { promise.Resolve(new ExplicitHashCredentials(netCred.Database, user, pwd)); } }).Fail(ex => { // Only hard fail for problems which aren't time outs and not found issues. var webEx = ex as HttpException; if (webEx != null && webEx.Response.StatusCode == HttpStatusCode.NotFound) { promise.Resolve(netCred); } else if (webEx != null && webEx.Response.StatusCode == HttpStatusCode.Unauthorized) { promise.Reject(ElementFactory.Local.ServerException("Invalid username or password")); } else if (webEx != null) { try { var result = ElementFactory.Local.FromXml(webEx.Response.AsStream); if (result.Exception != null) { promise.Reject(result.Exception); } else { promise.Reject(ex); } } catch (Exception) { promise.Reject(ex); } } else if (ex is TaskCanceledException) { promise.Resolve(netCred); } else { promise.Reject(ex); } }).Always(trace.Dispose); } return(promise); }
public override IPromise <Stream> Commit(bool async) { if (Status != UploadStatus.Pending) { return(_lastPromise); } Status = UploadStatus.Committed; // No transaction has been started if (_transactionId == null && !Files.Any(f => f.UploadPromise != null)) { _lastPromise = UploadAndApply(async); } else { var transactionId = default(string); _lastPromise = BeginTransaction(async) .Continue(t => { transactionId = t; return(Promises.All(Files .Select(f => f.UploadPromise ?? UploadFile(f, async)) .ToArray())); }) .Continue(l => { var aml = this.ToNormalizedAml(_conn.AmlContext.LocalizationContext); var content = new FormContent { { "XMLData", "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:i18n=\"http://www.aras.com/I18N\"><SOAP-ENV:Body><ApplyItem>" + aml + "</ApplyItem></SOAP-ENV:Body></SOAP-ENV:Envelope>" } }; var req = new HttpRequest() { Content = content }; _conn.SetDefaultHeaders(req.SetHeader); foreach (var ac in _conn.DefaultSettings) { ac.Invoke(req); } Settings?.Invoke(req); req.SetHeader("SOAPAction", "CommitTransaction"); req.SetHeader("VAULTID", Vault.Id); req.SetHeader("transactionid", transactionId); var trace = new LogData(4 , "Innovator: Execute vault query" , LogListener ?? Factory.LogListener , Parameters) { { "aras_url", _conn.MapClientUrl("../../Server") }, { "database", _conn.Database }, { "query", aml }, { "soap_action", "CommitTransaction" }, { "url", Vault.Url }, { "user_id", _conn.UserId }, { "vault_id", Vault.Id }, { "version", _conn.Version } }; return(Vault.HttpClient.PostPromise(new Uri(Vault.Url), async, req, trace).Always(trace.Dispose)); }) .Convert(r => r.AsStream); } return(_lastPromise); }
/// <summary> /// Uploads the files and applies the AML in a single transaction /// </summary> /// <param name="async">Whether to perform this action asynchronously</param> /// <returns>A promise to return an XML SOAP response as a <see cref="System.IO.Stream"/></returns> internal IPromise <Stream> UploadAndApply(string soapAction, string aml, IEnumerable <CommandFile> files, bool async) { return(_conn.FetchVersion(async).Continue(v => { return Vault.TransformUrl(_conn, async).Continue(u => { // Compile the headers and AML query into the appropriate content HttpRequest req; var content = new FormContent { { "XMLdata", "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:i18n=\"http://www.aras.com/I18N\"><SOAP-ENV:Body><ApplyItem>" + aml + "</ApplyItem></SOAP-ENV:Body></SOAP-ENV:Envelope>" } }; foreach (var file in files) { content.Add(file.AsContent(this, _conn.AmlContext.LocalizationContext, true).Single()); } content.Compression = _conn.Compression; if (_conn.Version >= new Version(12, 0, 9)) { req = GetUploadRequest12sp09(content, soapAction); } else { req = GetUploadRequestLegacy(content, soapAction); } foreach (var ac in _conn.DefaultSettings) { ac.Invoke(req); } Settings?.Invoke(req); req.Headers.TransferEncodingChunked = true; var trace = new LogData(4 , "Innovator: Execute query" , LogListener ?? Factory.LogListener , Parameters) { { "aras_url", _conn.MapClientUrl("../../Server") }, { "database", _conn.Database }, { "query", aml }, { "soap_action", soapAction }, { "url", Vault.Url }, { "user_id", _conn.UserId }, { "vault_id", Vault.Id }, { "version", _conn.Version } }; _conn.SetDefaultHeaders((name, value) => { if (string.Equals(name, "LOCALE", StringComparison.OrdinalIgnoreCase) || string.Equals(name, "TIMEZONE_NAME", StringComparison.OrdinalIgnoreCase)) { trace.Add(name.ToLowerInvariant(), value); } }); return Vault.HttpClient .PostPromise(new Uri(Vault.Url), async, req, trace) .Always(trace.Dispose) .Always(req.Dispose); }).Convert(r => r.AsStream); })); }