Fixed blocking issue
authorpkanavos <pkanavos@gmail.com>
Wed, 26 Sep 2012 09:19:29 +0000 (12:19 +0300)
committerpkanavos <pkanavos@gmail.com>
Wed, 26 Sep 2012 09:23:54 +0000 (12:23 +0300)
trunk/Pithos.Client.WPF/Preferences/AddAccountViewModel.cs
trunk/Pithos.Client.WPF/Preferences/PreferencesView.xaml
trunk/Pithos.Client.WPF/Preferences/PreferencesViewModel.cs
trunk/Pithos.Client.WPF/SelectiveSynch/SelectiveSynchViewModel.cs
trunk/Pithos.Core/Agents/PollAgent.cs
trunk/Pithos.Core/Agents/SelectiveUris.cs
trunk/Pithos.Core/PithosMonitor.cs
trunk/Pithos.Network/CloudFilesClient.cs
trunk/Pithos.Network/ICloudClient.cs
trunk/Pithos.Network/WebExtensions.cs

index a39bd34..f4f43b1 100644 (file)
@@ -373,12 +373,9 @@ namespace Pithos.Client.WPF.Preferences
             try\r
             {\r
                 SetBusy("Validating Credentials", "");\r
-                var client = new CloudFilesClient(AccountName, Token) { AuthenticationUrl = CurrentServer,/*Proxy=Proxy */};                \r
-                await TaskEx.Run(() =>\r
-                                     {\r
-                                         client.Authenticate();\r
-                                         return client.ListContainers(AccountName);\r
-                                     }).ConfigureAwait(false);\r
+                var client = new CloudFilesClient(AccountName, Token) { AuthenticationUrl = CurrentServer,/*Proxy=Proxy */};\r
+                await client.Authenticate().ConfigureAwait(false);\r
+                await client.ListContainers(AccountName).ConfigureAwait(false);\r
                 HasValidCredentials = true;\r
                 ValidationMessage = "Credentials Validated";\r
             }\r
index d5fe64f..01031ff 100644 (file)
@@ -1,8 +1,6 @@
 <Window x:Class="Pithos.Client.WPF.Preferences.PreferencesView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
-        xmlns:cal="http://www.caliburnproject.org"
-        xmlns:extToolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit/extended"
         xmlns:Converters="clr-namespace:Pithos.Client.WPF.Converters"\r
         xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" x:Name="TheView"
         Title="Pithos+ Preferences" Height="436" Width="732" 
index 5ecba00..e19cd7d 100644 (file)
@@ -400,7 +400,7 @@ namespace Pithos.Client.WPF.Preferences
 \r
 \r
         readonly List<AccountSettings> _accountsToAdd=new List<AccountSettings>();\r
-       public void AddAccount()\r
+       public async void AddAccount()\r
        {\r
            var wizard = new AddAccountViewModel();\r
            if (_windowManager.ShowDialog(wizard) == true)\r
@@ -450,7 +450,7 @@ namespace Pithos.Client.WPF.Preferences
                                             AuthenticationUrl = newAccount.ServerUrl, UsePithos = true\r
                                         };\r
 \r
-                       InitializeSelectiveFolders(newAccount, client);\r
+                       await InitializeSelectiveFolders(newAccount, client);\r
 \r
                    \r
                        //TODO:Add the "pithos" container as a default selection                   \r
@@ -475,37 +475,41 @@ namespace Pithos.Client.WPF.Preferences
             \r
        }\r
 \r
-        private void InitializeSelectiveFolders(AccountSettings newAccount, CloudFilesClient client,int retries=3)\r
+        private async Task InitializeSelectiveFolders(AccountSettings newAccount, CloudFilesClient client,int retries=3)\r
         {\r
-            try\r
-            {\r
-                client.Authenticate();\r
-\r
-                var containers = client.ListContainers(newAccount.AccountName);\r
-                var containerUris = from container in containers\r
-                                    select String.Format(@"{0}/v1/{1}/{2}",\r
-                                                         newAccount.ServerUrl, newAccount.AccountName,\r
-                                                         container.Name);\r
-\r
-                newAccount.SelectiveFolders.AddRange(containerUris.ToArray());\r
-\r
-                var objectInfos = (from container in containers\r
-                                   from dir in client.ListObjects(newAccount.AccountName, container.Name)\r
-                                   where container.Name.ToString() != "trash"\r
-                                   select dir).ToList();\r
-                var tree = objectInfos.ToTree();\r
-\r
-                var selected = (from root in tree\r
-                                from child in root\r
-                                select child.Uri.ToString()).ToArray();\r
-                newAccount.SelectiveFolders.AddRange(selected);                \r
-            }\r
-            catch (WebException)\r
+            while(true)\r
             {\r
-                if (retries>0)\r
-                    InitializeSelectiveFolders(newAccount,client,retries-1);\r
-                else\r
-                    throw;\r
+                try\r
+                {\r
+                    await client.Authenticate().ConfigureAwait(false);\r
+\r
+                    var containers = await client.ListContainers(newAccount.AccountName).ConfigureAwait(false);\r
+                    var containerUris = from container in containers\r
+                                        select String.Format(@"{0}/v1/{1}/{2}",\r
+                                                             newAccount.ServerUrl, newAccount.AccountName,\r
+                                                             container.Name);\r
+\r
+                    newAccount.SelectiveFolders.AddRange(containerUris.ToArray());\r
+\r
+                    var objectInfos = (from container in containers\r
+                                       from dir in client.ListObjects(newAccount.AccountName, container.Name)\r
+                                       where container.Name.ToString() != "trash"\r
+                                       select dir).ToList();\r
+                    var tree = objectInfos.ToTree();\r
+\r
+                    var selected = (from root in tree\r
+                                    from child in root\r
+                                    select child.Uri.ToString()).ToArray();\r
+                    newAccount.SelectiveFolders.AddRange(selected);\r
+                    return;\r
+                }\r
+                catch (WebException)\r
+                {\r
+                    if (retries > 0)\r
+                        retries--;\r
+                    else\r
+                        throw;\r
+                }\r
             }\r
         }\r
 \r
index e6dff26..05eaec8 100644 (file)
@@ -94,21 +94,22 @@ namespace Pithos.Client.WPF.SelectiveSynch
             //_monitor = monitor;\r
             _events = events;\r
             _apiKey = apiKey;\r
-            //IsEnabled = account.SelectiveSyncEnabled;\r
+            //IsEnabled = account.SelectiveSyncEnabled;            \r
             TaskEx.Run(()=>LoadRootNode(forSelectiveActivation));\r
         }\r
 \r
-        private void LoadRootNode(bool forSelectiveActivation)\r
+        private async void LoadRootNode(bool forSelectiveActivation)\r
         {            \r
             //TODO: Check this\r
             var client = new CloudFilesClient(AccountName,_apiKey){AuthenticationUrl=Account.ServerUrl,UsePithos=true};\r
-            client.Authenticate();\r
+            await client.Authenticate().ConfigureAwait(false);\r
             \r
             //NEED to get the local folders here as well,\r
             // and combine them with the cloud folders\r
 \r
 \r
-            var dirs = from container in client.ListContainers(AccountName)  \r
+            var containerInfos = await client.ListContainers(AccountName).ConfigureAwait(false);\r
+            var dirs = from container in containerInfos  \r
                        where container.Name.ToUnescapedString() != "trash"\r
                        select new DirectoryRecord\r
                                   {\r
@@ -126,7 +127,7 @@ namespace Pithos.Client.WPF.SelectiveSynch
                              {\r
                                 DisplayName=account.name,\r
                                 Uri=client.StorageUrl.Combine("../"+ account.name),\r
-                                Directories=(from container in client.ListContainers(account.name)\r
+                                Directories=(from container in client.ListContainers(account.name).Result\r
                                             select new DirectoryRecord\r
                                                         {\r
                                                             DisplayName=container.Name.ToUnescapedString(),\r
index 240040a..c9c5773 100644 (file)
@@ -297,7 +297,8 @@ namespace Pithos.Core.Agents
                 var client = new CloudFilesClient(accountInfo);\r
 \r
                 //We don't need to check the trash container\r
-                var containers = client.ListContainers(accountInfo.UserName)\r
+                var allContainers=await client.ListContainers(accountInfo.UserName).ConfigureAwait(false);\r
+                var containers = allContainers\r
                     .Where(c=>c.Name.ToString()!="trash")\r
                     .ToList();\r
 \r
index facd42f..94b6ac2 100644 (file)
@@ -28,7 +28,7 @@ namespace Pithos.Core.Agents
             SelectivePaths = new ConcurrentDictionary<Uri, ConcurrentBag<string>>();\r
         }\r
 \r
-        readonly Dictionary<Uri, bool> _selectiveEnabled = new Dictionary<Uri, bool>();\r
+        readonly ConcurrentDictionary<Uri, bool> _selectiveEnabled = new ConcurrentDictionary<Uri, bool>();\r
 \r
 /*\r
         public void SetIsSelectiveEnabled(AccountInfo account,bool value)\r
index 5bc606b..ec51f4f 100644 (file)
@@ -227,12 +227,10 @@ namespace Pithos.Core
             }\r
             _cancellationSource = new CancellationTokenSource();\r
 \r
-            lock (this)\r
-            {\r
-                CloudClient = new CloudFilesClient(UserName, ApiKey)\r
-                                  {UsePithos = true, AuthenticationUrl = AuthenticationUrl};\r
-                _accountInfo = CloudClient.Authenticate();\r
-            }\r
+            CloudClient = new CloudFilesClient(UserName, ApiKey)\r
+                                {UsePithos = true, AuthenticationUrl = AuthenticationUrl};\r
+            \r
+            _accountInfo = await CloudClient.Authenticate().ConfigureAwait(false);\r
             _accountInfo.SiteUri = AuthenticationUrl;\r
             _accountInfo.AccountPath = RootPath;\r
 \r
index 22aeb0a..7680b3c 100644 (file)
@@ -68,7 +68,7 @@ namespace Pithos.Network
 {\r
 \r
     [Export(typeof(ICloudClient))]\r
-    public class CloudFilesClient:ICloudClient\r
+    public class CloudFilesClient:ICloudClient,IDisposable\r
     {\r
         private const string TOKEN_HEADER = "X-Auth-Token";\r
         private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);\r
@@ -93,6 +93,13 @@ namespace Pithos.Network
         private readonly string _emptyGuid = Guid.Empty.ToString();\r
         private readonly Uri _emptyUri = new Uri("",UriKind.Relative);\r
 \r
+        private HttpClientHandler _httpClientHandler = new HttpClientHandler\r
+                                                           {\r
+                                                               AllowAutoRedirect = true,\r
+                                                               AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,\r
+                                                               UseCookies = true,                                \r
+                                                           };\r
+\r
 \r
         public string Token\r
         {\r
@@ -216,7 +223,7 @@ namespace Pithos.Network
                 throw new WebException(String.Format("{0} with code {1} - {2}", message, statusCode, response.ReasonPhrase));\r
         }\r
 \r
-        public AccountInfo Authenticate()\r
+        public async Task<AccountInfo> Authenticate()\r
         {\r
             if (String.IsNullOrWhiteSpace(UserName))\r
                 throw new InvalidOperationException("UserName is empty");\r
@@ -235,14 +242,7 @@ namespace Pithos.Network
 \r
             var groups = new List<Group>();\r
 \r
-            var httpClientHandler = new HttpClientHandler\r
-            {\r
-                AllowAutoRedirect = true,\r
-                AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,\r
-                UseCookies = true,                                \r
-            };\r
-\r
-            using (var authClient = new HttpClient(httpClientHandler){ BaseAddress = new Uri(AuthenticationUrl),Timeout=TimeSpan.FromSeconds(30) })\r
+            using (var authClient = new HttpClient(_httpClientHandler,false){ BaseAddress = new Uri(AuthenticationUrl),Timeout=TimeSpan.FromSeconds(30) })\r
             //using (var authClient = new RestClient{BaseAddress=AuthenticationUrl})\r
             {                \r
                /* if (Proxy != null)\r
@@ -257,7 +257,7 @@ namespace Pithos.Network
                 string storageUrl;\r
                 string token;\r
                 \r
-                using (var response = authClient.GetAsyncWithRetries(new Uri(VersionPath, UriKind.Relative),3).Result) // .DownloadStringWithRetryRelative(new Uri(VersionPath, UriKind.Relative), 3);                    \r
+                using (var response = await authClient.GetAsyncWithRetries(new Uri(VersionPath, UriKind.Relative),3).ConfigureAwait(false)) // .DownloadStringWithRetryRelative(new Uri(VersionPath, UriKind.Relative), 3);                    \r
                 {\r
                     AssertStatusOK(response,"Authentication failed");\r
                 \r
@@ -292,14 +292,14 @@ namespace Pithos.Network
                 RootAddressUri = new Uri(rootUrl);\r
                 \r
 \r
-                _baseHttpClient = new HttpClient(httpClientHandler)\r
+                _baseHttpClient = new HttpClient(_httpClientHandler,false)\r
                 {\r
                     BaseAddress = StorageUrl,\r
                     Timeout = TimeSpan.FromSeconds(30)\r
                 };\r
                 _baseHttpClient.DefaultRequestHeaders.Add(TOKEN_HEADER, token);\r
 \r
-                _baseHttpClientNoTimeout = new HttpClient(httpClientHandler)\r
+                _baseHttpClientNoTimeout = new HttpClient(_httpClientHandler,false)\r
                 {\r
                     BaseAddress = StorageUrl,\r
                     Timeout = TimeSpan.FromMilliseconds(-1)\r
@@ -349,42 +349,58 @@ namespace Pithos.Network
             }\r
         }\r
 \r
-        public IList<ContainerInfo> ListContainers(string account)\r
+        public async Task<IList<ContainerInfo>> ListContainers(string account)\r
         {\r
 \r
             var targetUrl = GetTargetUrl(account);\r
-            var targetUri=new Uri(String.Format("{0}?format=json",targetUrl));\r
-            var result = GetStringAsync(targetUri, "List Containers failed").Result;\r
+            var targetUri = new Uri(String.Format("{0}?format=json", targetUrl));\r
+            var result = await GetStringAsync(targetUri, "List Containers failed").ConfigureAwait(false);\r
             if (String.IsNullOrWhiteSpace(result))\r
                 return new List<ContainerInfo>();\r
-            var infos = JsonConvert.DeserializeObject<IList<ContainerInfo>>(result);                \r
+            var infos = JsonConvert.DeserializeObject<IList<ContainerInfo>>(result);\r
             foreach (var info in infos)\r
             {\r
                 info.Account = account;\r
             }\r
             return infos;\r
-           /* using (var client = new RestClient(_baseClient))\r
-            {\r
-                if (!String.IsNullOrWhiteSpace(account))\r
-                    client.BaseAddress = GetAccountUrl(account);\r
-                \r
-                client.Parameters.Clear();\r
-                client.Parameters.Add("format", "json");\r
-                var content = client.DownloadStringWithRetryRelative(_emptyUri, 3);\r
-                client.AssertStatusOK("List Containers failed");\r
+        }\r
 \r
-                if (client.StatusCode == HttpStatusCode.NoContent)\r
-                    return new List<ContainerInfo>();\r
-                var infos = JsonConvert.DeserializeObject<IList<ContainerInfo>>(content);\r
+        //public IList<ContainerInfo> ListContainers(string account)\r
+        //{\r
+\r
+        //    var targetUrl = GetTargetUrl(account);\r
+        //    var targetUri=new Uri(String.Format("{0}?format=json",targetUrl));\r
+        //    var result = GetStringAsync(targetUri, "List Containers failed").Result;\r
+        //    if (String.IsNullOrWhiteSpace(result))\r
+        //        return new List<ContainerInfo>();\r
+        //    var infos = JsonConvert.DeserializeObject<IList<ContainerInfo>>(result);                \r
+        //    foreach (var info in infos)\r
+        //    {\r
+        //        info.Account = account;\r
+        //    }\r
+        //    return infos;\r
+        //   /* using (var client = new RestClient(_baseClient))\r
+        //    {\r
+        //        if (!String.IsNullOrWhiteSpace(account))\r
+        //            client.BaseAddress = GetAccountUrl(account);\r
                 \r
-                foreach (var info in infos)\r
-                {\r
-                    info.Account = account;\r
-                }\r
-                return infos;\r
-            }   */       \r
+        //        client.Parameters.Clear();\r
+        //        client.Parameters.Add("format", "json");\r
+        //        var content = client.DownloadStringWithRetryRelative(_emptyUri, 3);\r
+        //        client.AssertStatusOK("List Containers failed");\r
+\r
+        //        if (client.StatusCode == HttpStatusCode.NoContent)\r
+        //            return new List<ContainerInfo>();\r
+        //        var infos = JsonConvert.DeserializeObject<IList<ContainerInfo>>(content);\r
+                \r
+        //        foreach (var info in infos)\r
+        //        {\r
+        //            info.Account = account;\r
+        //        }\r
+        //        return infos;\r
+        //    }   */       \r
 \r
-        }\r
+        //}\r
 \r
         private string GetAccountUrl(string account)\r
         {\r
@@ -398,7 +414,7 @@ namespace Pithos.Network
                 if (Log.IsDebugEnabled) Log.DebugFormat("START");\r
 \r
                 var targetUri = new Uri(String.Format("{0}?format=json", RootAddressUri), UriKind.Absolute);\r
-                var content=GetStringAsync(targetUri, "ListSharingAccounts failed", since).Result;\r
+                var content=TaskEx.Run(async ()=>await GetStringAsync(targetUri, "ListSharingAccounts failed", since).ConfigureAwait(false)).Result;\r
 \r
                 //If the result is empty, return an empty list,\r
                 var infos = String.IsNullOrWhiteSpace(content)\r
@@ -456,9 +472,8 @@ namespace Pithos.Network
 \r
                 Func<ContainerInfo, string> getKey = c => String.Format("{0}\\{1}", c.Account, c.Name);\r
 \r
-                var accounts = ListSharingAccounts();\r
-                var containers = (from account in accounts\r
-                                 let conts = ListContainers(account.name)\r
+                var containers = (from account in ListSharingAccounts()\r
+                                 let conts = ListContainers(account.name).Result\r
                                  from container in conts\r
                                  select container).ToList();                \r
                 var items = from container in containers \r
@@ -848,7 +863,8 @@ namespace Pithos.Network
 \r
                 var containerUri = GetTargetUri(account).Combine(container);\r
                 var targetUri = new Uri(String.Format("{0}?format=json", containerUri), UriKind.Absolute);\r
-                var content = GetStringAsync(targetUri, "ListObjects failed", since).Result;\r
+\r
+                var content =TaskEx.Run(async ()=>await GetStringAsync(targetUri, "ListObjects failed", since).ConfigureAwait(false)).Result;\r
 \r
                 //304 will result in an empty string. Empty containers return an empty json array\r
                 if (String.IsNullOrWhiteSpace(content))\r
@@ -920,7 +936,7 @@ namespace Pithos.Network
 \r
                 var containerUri = GetTargetUri(account).Combine(container);\r
                 var targetUri = new Uri(String.Format("{0}?format=json&path={1}", containerUri,folder), UriKind.Absolute);\r
-                var content = GetStringAsync(targetUri, "ListObjects failed", since).Result;                \r
+                var content = TaskEx.Run(async ()=>await GetStringAsync(targetUri, "ListObjects failed", since).ConfigureAwait(false)).Result;                \r
 \r
                 //304 will result in an empty string. Empty containers return an empty json array\r
                 if (String.IsNullOrWhiteSpace(content))\r
@@ -2065,6 +2081,36 @@ namespace Pithos.Network
                 }\r
             }\r
         }\r
+\r
+        ~CloudFilesClient()\r
+        {\r
+            Dispose(false);\r
+        }\r
+\r
+        public void Dispose()\r
+        {\r
+            Dispose(true);\r
+            GC.SuppressFinalize(this);\r
+        }\r
+\r
+        protected virtual void Dispose(bool disposing)\r
+        {\r
+            if (disposing)\r
+            {\r
+                if (_httpClientHandler!=null)\r
+                    _httpClientHandler.Dispose();\r
+                if (_baseClient!=null)\r
+                    _baseClient.Dispose();\r
+                if(_baseHttpClient!=null)\r
+                    _baseHttpClient.Dispose();\r
+                if (_baseHttpClientNoTimeout!=null)\r
+                    _baseHttpClientNoTimeout.Dispose();\r
+            }\r
+            _httpClientHandler = null;\r
+            _baseClient = null;\r
+            _baseHttpClient = null;\r
+            _baseHttpClientNoTimeout = null;\r
+        }\r
     }\r
 \r
     public class ShareAccountInfo\r
index ebef1ee..526bfa5 100644 (file)
@@ -60,7 +60,7 @@ namespace Pithos.Network
         string Token { get; set; }\r
 \r
         bool UsePithos { get; set; }\r
-        AccountInfo Authenticate();\r
+        Task<AccountInfo> Authenticate();\r
         //WebProxy Proxy { get; set; }\r
         double DownloadPercentLimit { get; set; }\r
         double UploadPercentLimit { get; set; }\r
@@ -68,7 +68,7 @@ namespace Pithos.Network
 \r
         #region Container operations\r
 \r
-        IList<ContainerInfo> ListContainers(string account);\r
+        Task<IList<ContainerInfo>> ListContainers(string account);\r
         IList<ObjectInfo> ListObjects(string account, Uri container, DateTime? since = null);\r
         IList<ObjectInfo> ListObjects(string account, Uri container, Uri folder, DateTime? since = null);\r
         bool ContainerExists(string account, Uri container);\r
@@ -126,20 +126,20 @@ namespace Pithos.Network
 \r
         public bool UsePithos { get; set; }\r
 \r
-        public AccountInfo Authenticate()\r
+        public Task<AccountInfo> Authenticate()\r
         {\r
             Contract.Requires<ArgumentNullException>(!String.IsNullOrWhiteSpace(ApiKey), "ApiKey must be filled before calling Authenticate");\r
             Contract.Requires<ArgumentNullException>(!String.IsNullOrWhiteSpace(UserName), "UserName must be filled before calling Authenticate");\r
 \r
-            return default(AccountInfo);\r
+            return default(Task<AccountInfo>);\r
         }\r
 \r
-        public IList<ContainerInfo> ListContainers(string account)\r
+        public Task<IList<ContainerInfo>> ListContainers(string account)\r
         {\r
             Contract.Requires(!String.IsNullOrWhiteSpace(Token));\r
             Contract.Requires(StorageUrl!=null);            \r
 \r
-            return default(IList<ContainerInfo>);\r
+            return default(Task<IList<ContainerInfo>>);\r
         }\r
 \r
         public IList<ObjectInfo> ListSharedObjects(HashSet<string> knownContainers, DateTime? since)\r
index 5755144..5c55803 100644 (file)
@@ -122,7 +122,7 @@ namespace Pithos.Network
             {\r
                 try\r
                 {\r
-                    var result = await func();\r
+                    var result = await func().ConfigureAwait(false);\r
                     return result;\r
                 }\r
                 catch (Exception exc)\r
@@ -141,7 +141,7 @@ namespace Pithos.Network
                 HttpStatusCode.RedirectMethod,HttpStatusCode.NotModified,HttpStatusCode.TemporaryRedirect,HttpStatusCode.RedirectKeepVerb};\r
             while (retries > 0)\r
             {\r
-                var result = await func();\r
+                var result = await func().ConfigureAwait(false);\r
                 if (result.IsSuccessStatusCode || acceptedCodes.Contains(result.StatusCode))\r
                     return result;\r
                     \r
@@ -152,7 +152,7 @@ namespace Pithos.Network
                 if (result.StatusCode == HttpStatusCode.ServiceUnavailable)\r
                 {\r
                     Log.InfoFormat("[UNAVAILABLE] Waiting before retry: {0}",result.ReasonPhrase);\r
-                    await TaskEx.Delay(waitTime);\r
+                    await TaskEx.Delay(waitTime).ConfigureAwait(false);\r
                     //increase the timeout for repeated timeouts\r
                     if (waitTime<TimeSpan.FromSeconds(10))\r
                         waitTime = waitTime.Add(TimeSpan.FromSeconds(10));\r
@@ -173,12 +173,12 @@ namespace Pithos.Network
                 request.Headers.IfModifiedSince = since.Value;\r
             }\r
             //Func<Task<HttpResponseMessage>> call = () => _baseHttpClient.SendAsync(request);\r
-            using (var response = await client.SendAsyncWithRetries(request,3))\r
+            using (var response = await client.SendAsyncWithRetries(request,3).ConfigureAwait(false))\r
             {\r
                 if (response.StatusCode == HttpStatusCode.NoContent)\r
                     return String.Empty;\r
 \r
-                var content = await response.Content.ReadAsStringAsync();\r
+                var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);\r
                 return content;\r
             }\r
 \r
@@ -219,7 +219,17 @@ namespace Pithos.Network
             {\r
                 if (Log.IsDebugEnabled)\r
                     Log.DebugFormat("[REQUEST] {0}",message);\r
-                var result = await client.SendAsync(message,completionOption,cancellationToken);\r
+                HttpResponseMessage result;\r
+                try\r
+                {\r
+                    result = await client.SendAsync(message, completionOption, cancellationToken).ConfigureAwait(false);\r
+                }\r
+                catch (Exception exc)\r
+                {\r
+                    Log.FatalFormat("Unexpected error while sending:\n{0}\n{1}",message,exc);\r
+                    throw;\r
+                }\r
+                \r
                 if (result.IsSuccessStatusCode || acceptedCodes.Contains(result.StatusCode))\r
                 {\r
                     if (Log.IsDebugEnabled)\r
@@ -238,7 +248,7 @@ namespace Pithos.Network
                 {\r
                     \r
                     Log.WarnFormat("[UNAVAILABLE] Waiting before retrying [{0}]:[{1}] due to [{2}]",message.Method, message.RequestUri,result.ReasonPhrase);                    \r
-                    await TaskEx.Delay(waitTime);\r
+                    await TaskEx.Delay(waitTime).ConfigureAwait(false);\r
                     //increase the timeout for repeated timeouts\r
                     if (waitTime<TimeSpan.FromSeconds(10))\r
                         waitTime = waitTime.Add(TimeSpan.FromSeconds(10));\r