I'm stressing a service I'm writing that uses a WebSocket taken from AcceptWebSocketAsync. The code I'm using to send messages through the WebSocket is this:
static bool
SendMessage(WebSocket webSocket, WebSocketMessage message, byte[] buffer, CancellationToken cancellationToken)
{
try {
var endOfMessage = false;
do {
using(var timeout = new CancellationTokenSource(webSocketsTimeout))
using(var lcts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeout.Token)) {
var count = message.Content.Read(buffer, 0, buffer.Length);
endOfMessage = count < buffer.Length;
// ReSharper disable once MethodSupportsCancellation
webSocket
.SendAsync(new ArraySegment<byte>(buffer, 0, count), message.Type, endOfMessage, lcts.Token)
.Wait() // SendAsync should be canceled using the Token.
;
}
} while(endOfMessage == false);
return true;
}
catch(Exception e) {
TraceConnectionError(e);
return false;
}
finally {
message.Dispose();
}
}
My problem is that under "stress" (I'm opening and closing 6 connections every 30 seconds until the system fails), I'm getting:
Unhandled Exception: System.AggregateException: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread. ---> System.Net.HttpListenerException: An operation was attempted on a nonexistent network connection
at System.Net.WebSockets.WebSocketHttpListenerDuplexStream.WriteAsyncFast(HttpListenerAsyncEventArgs eventArgs)
at System.Net.WebSockets.WebSocketHttpListenerDuplexStream.<MultipleWriteAsyncCore>d__38.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Net.WebSockets.WebSocketBase.<SendFrameAsync>d__48.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
at System.Net.WebSockets.WebSocketBase.WebSocketOperation.<Process>d__19.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Net.WebSockets.WebSocketBase.<SendAsyncCore>d__47.MoveNext()
--- End of inner exception stack trace ---
at System.Threading.Tasks.TaskExceptionHolder.Finalize()
Shouldn't the Wait() I'm using be enough to "observe" the Task exception?
The problem was a race condition in .NET framework code.
I've reported the bug here.
As a workaround, I keep a list of used WebSockets which I regularly check for State != Open and then call this code:
public static class WebSocketXs
{
readonly static Assembly assembly = typeof(WebSocket).Assembly;
readonly static FieldInfo m_InnerStream = assembly.GetType("System.Net.WebSockets.WebSocketBase").GetField(nameof(m_InnerStream), BindingFlags.NonPublic | BindingFlags.Instance);
readonly static FieldInfo m_ReadTaskCompletionSource = assembly.GetType("System.Net.WebSockets.WebSocketHttpListenerDuplexStream").GetField(nameof(m_ReadTaskCompletionSource), BindingFlags.NonPublic | BindingFlags.Instance);
readonly static FieldInfo m_WriteTaskCompletionSource = assembly.GetType("System.Net.WebSockets.WebSocketHttpListenerDuplexStream").GetField(nameof(m_WriteTaskCompletionSource), BindingFlags.NonPublic | BindingFlags.Instance);
readonly static FieldInfo[] completionSourceFields = {m_ReadTaskCompletionSource, m_WriteTaskCompletionSource };
/// <summary>
/// This fixes a race that happens when a <see cref="WebSocket"/> fails and aborts after failure.
/// The <see cref="completionSourceFields"/> have an Exception that is not observed as the <see cref="WebSocket.Abort()"/>
/// done to WebSocketBase <see cref="m_InnerStream"/> is just <see cref="TaskCompletionSource{TResult}.TrySetCanceled()"/> which
/// does nothing with the completion source <see cref="Task.Exception"/>.
/// That in turn raises a <see cref="TaskScheduler.UnobservedTaskException"/>.
/// </summary>
public static void
CleanUpAndDispose(this WebSocket ws)
{
foreach(var completionSourceField in completionSourceFields) {
m_InnerStream
.GetValue(ws)
.Maybe(completionSourceField.GetValue)
.Maybe(s => s as TaskCompletionSource<object>)?
.Task
.Exception
.Maybe(_ => {}) // We just need to observe any exception.
;
}
ws.Dispose();
}
}
Related
I have the following Code:
System.Threading.Tasks.Task appointmentEndTask = App.ArdaBusinessLogic.AppointmentEnd(_appointment);
System.Threading.Tasks.Task appointmentEndCompletedTask = appointmentEndTask.ContinueWith(
async task =>
{
_appointmentDetailPage.IsDirty = true;
await App.MasterNavigationPage.Navigation.PopModalAsync();
},
System.Threading.CancellationToken.None,
System.Threading.Tasks.TaskContinuationOptions.OnlyOnRanToCompletion,
System.Threading.Tasks.TaskScheduler.FromCurrentSynchronizationContext());
System.Threading.Tasks.Task appointmentEndFaultedTask = appointmentEndTask.ContinueWith(
async task =>
{
await App.MasterNavigationPage.Navigation.PopModalAsync();
await App.ShowErrorPageAsync(task.Exception);
},
System.Threading.CancellationToken.None,
System.Threading.Tasks.TaskContinuationOptions.OnlyOnFaulted,
System.Threading.Tasks.TaskScheduler.FromCurrentSynchronizationContext());
So if the "AppointmentEnd"-Task completes the current Modal-Page should be closed. From time to time (not always!) i get the following error in my crash logs. Linenumber 139 is "await App.MasterNavigationPage.Navigation.PopModalAsync()" after "_appointmentDetailPage.IsDirty = true" in this case.
Xamarin caused by: android.runtime.JavaProxyThrowable:
System.AggregateException: A Task's exception(s) were not observed
either by Waiting on the Task or accessing its Exception property. As
a result, the unobserved exception was rethrown by the finalizer
thread. ---System.ArgumentOutOfRangeException: Index was out of
range. Must be non-negative and less than the size of the collection.
Parameter name: index at
System.Collections.Generic.List`1[T].get_Item (System.Int32 index)
[0x00009] in
/Users/builder/jenkins/workspace/xamarin-android-d15-9/xamarin-android/external/mono/external/corefx/src/Common/src/CoreLib/System/Collections/Generic/List.cs:180
at Xamarin.Forms.Application+NavigationImpl+<OnPopModal>d__2.MoveNext
() [0x00022] in D:\a\1\s\Xamarin.Forms.Core\Application.cs:381
--- End of stack trace from previous location where exception was thrown --- at
CPM.Arda.Mobile.Freelancer.Ui.Pages.Appointment.Complete+<<confirmButton_Clicked>b__5_0>d.MoveNext
() [0x0007d] in
D:\ProjekteTFVC\ArdaMobileFreelancer\SourceCode\Ui\1.0\Pages\Appointment\Complete.xaml.cs:139
--- End of inner exception stack trace ---
---(Inner Exception #0) System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the
collection. Parameter name: index at
System.Collections.Generic.List`1[T].get_Item (System.Int32 index)
[0x00009] in
/Users/builder/jenkins/workspace/xamarin-android-d15-9/xamarin-android/external/mono/external/corefx/src/Common/src/CoreLib/System/Collections/Generic/List.cs:180
at Xamarin.Forms.Application+NavigationImpl+<OnPopModal>d__2.MoveNext
() [0x00022] in D:\a\1\s\Xamarin.Forms.Core\Application.cs:381
--- End of stack trace from previous location where exception was thrown --- at
CPM.Arda.Mobile.Freelancer.Ui.Pages.Appointment.Complete+<<confirmButton_Clicked>b__5_0>d.MoveNext
() [0x0007d] in
D:\ProjekteTFVC\ArdaMobileFreelancer\SourceCode\Ui\1.0\Pages\Appointment\Complete.xaml.cs:139
Unfortunately, I do not understand how it can come to this error. Can you help me?
First, why are you using such a complicated syntax instead of taking advantage of async await?
public async void EndAppointement()
{
try
{
await App.ArdaBusinessLogic.AppointmentEnd(_appointment);
_appointmentDetailPage.IsDirty = true;
await App.MasterNavigationPage.Navigation.PopModalAsync();
}
catch (Exception exception)
{
await App.MasterNavigationPage.Navigation.PopModalAsync();
await App.ShowErrorPageAsync(exception);
}
}
Second, looking at XF source code:
protected override async Task<Page> OnPopModal(bool animated)
{
Page modal = ModalStack[ModalStack.Count - 1];
if (_owner.OnModalPopping(modal))
{
_owner.OnPopCanceled();
return null;
}
Page result = await base.OnPopModal(animated);
result.Parent = null;
_owner.OnModalPopped(result);
return result;
}
It seems that your modal stack is messed up: meaning you are trying to pop pages that are not on the stack. Are you sure you're on a modal page? Maybe use PopAsync instead of PopModalAsync.
I am new to azure. I am trying to create ResourceGroup then trying to deploy a VM. But I am getting exception during accessing resourcegroups.
I am following MSDN example given here: https://learn.microsoft.com/en-us/azure/virtual-machines/windows/csharp-template
I tried different subscription but no luck. Couldn't find any pointers online for this issue or I might have missed. If you could help me please let me know.
Thanks.
//AppId,Key,TenetId are correct
var credentials = SdkContext.AzureCredentialsFactory
.FromServicePrincipal(ApplicationID, Key, TenetID,
new AzureEnvironment()
{
AuthenticationEndpoint = #"https://login.windows.net/",
ManagementEndpoint = #"https://management.core.windows.net/",
ResourceManagerEndpoint = #"https://management.azure.com/",
GraphEndpoint = #"https://graph.windows.net/",
});
var azure = Azure
.Configure()
.WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic)
.Authenticate(credentials)
.WithSubscription(AzureProperties.SubscriptionId);
var groupName = "MyresourceGroup1";
var location = Region.USWest;
//Exception comes at here.
var resourceGroup = azure.ResourceGroups.Define(groupName)
.WithRegion(location)
.Create();
//Exception details.
System.ArgumentNullException
HResult=0x80004003
Message=Value cannot be null.
Parameter name: value
Source=mscorlib
StackTrace:
at System.String.EndsWith(String value, StringComparison comparisonType)
at Microsoft.Azure.Management.ResourceManager.Fluent.Authentication.AzureCredentials.<ProcessHttpRequestAsync>d__24.MoveNext()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
at Microsoft.Azure.Management.ResourceManager.Fluent.ResourceGroupsOperations.<CreateOrUpdateWithHttpMessagesAsync>d__6.MoveNext()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Azure.Management.ResourceManager.Fluent.ResourceGroupImpl.<CreateResourceAsync>d__26.MoveNext()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Azure.Management.ResourceManager.Fluent.Core.ResourceActions.Creatable`4.<Microsoft-Azure-Management-ResourceManager-Fluent-Core-ResourceActions-IResourceCreator<IResourceT>-CreateResourceAsync>d__15.MoveNext()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Azure.Management.ResourceManager.Fluent.Core.DAG.CreatorTaskItem`1.<ExecuteAsync>d__6.MoveNext()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Azure.Management.ResourceManager.Fluent.Core.DAG.TaskGroupBase`1.<ExecuteNodeTaskAsync>d__14.MoveNext()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Azure.Management.ResourceManager.Fluent.Core.Extensions.Synchronize[TResult](Func`1 function)
at Microsoft.Azure.Management.ResourceManager.Fluent.Core.ResourceActions.Creatable`4.Create()
at pvt_CreateVM.AzureVMManager.CreateVM()
at pvt_CreateVM.Program.Main(String[] args)
I think code is currently failing because you haven't set any value for KeyVaultSuffix property for AzureEnvrionment that you have initialized.
It's a guess looking at the error info you have shared but I say this after looking at the relevant source code for Azure Management Libraries for .NET
(on a side note it's awesome that anyone can do that.. here is a link)
public async override Task ProcessHttpRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var adSettings = new ActiveDirectoryServiceSettings
{
AuthenticationEndpoint = new Uri(Environment.AuthenticationEndpoint),
TokenAudience = new Uri(Environment.ManagementEndpoint),
ValidateAuthority = true
};
string url = request.RequestUri.ToString();
if (url.StartsWith(Environment.GraphEndpoint, StringComparison.OrdinalIgnoreCase))
{
adSettings.TokenAudience = new Uri(Environment.GraphEndpoint);
}
string host = request.RequestUri.Host;
// I guess this is where your code is failing currently.
if (host.EndsWith(Environment.KeyVaultSuffix, StringComparison.OrdinalIgnoreCase))
{
How to fix
Unless there is a good reason, I would not initialize AzureEnvironment object and instead use the values already available, as that would make sure all required properties have correct values.
Example: AzureEnvironment.AzureGlobalCloud. Look here for all possible values
Change this code where you initialize AzureEnvironment
var credentials = SdkContext.AzureCredentialsFactory
.FromServicePrincipal(ApplicationID, Key, TenetID,
new AzureEnvironment()
{
AuthenticationEndpoint = #"https://login.windows.net/",
ManagementEndpoint = #"https://management.core.windows.net/",
ResourceManagerEndpoint = #"https://management.azure.com/",
GraphEndpoint = #"https://graph.windows.net/",
});
To this code
var credentials = SdkContext.AzureCredentialsFactory
.FromServicePrincipal(clientId,
clientSecret,
tenantId,
AzureEnvironment.AzureGlobalCloud);
In case you have some reason that none of the available environment values are good enough, then make sure you initialize all required properties for AzureEnvironment
I am trying to get the links from VSO for workitems, and the code seems to work fine when called from a single thread, but throws exceptions when called from a parallel for each loop.
I initalize my vso client object in my class's constructor:
vso = new WorkItemReporting(Config.VSTSAccessToken);
Then later in a method:
Parallel.ForEach(msrcAbBugsToProcess, new ParallelOptions { MaxDegreeOfParallelism = 10 }, bugId =>
{
var workItemLinks = vso.GetWorkItemSourceCodeLinks(bugId);
});
witclient below is a WorkItemTrackingHttpClient which is in a different class (WorkItemReporting) and calls the API. It is this call that fails.
public List<string> GetWorkItemSourceCodeLinks(int bugId)
{
var workItemSourceCodeLinks = new List<string>();
var workItem = _witClient.GetWorkItemAsync(bugId, null, null, WorkItemExpand.Relations).Result;
if (workItem?.Relations != null)
{
var validSourceCodeLinkTypes = new List<string> { "ArtifactLink", "Hyperlink" };
foreach (var relation in workItem.Relations)
{
if (validSourceCodeLinkTypes.Contains(relation.Rel))
{
workItemSourceCodeLinks.Add(relation.Url);
}
}
}
}
This works fine if I don't use the Parallel.ForEach and I get the needed data from the API. When I do, I get this exception 50% of the time:
Object reference not set to an instance of an object.
at System.Security.Cryptography.X509Certificates.X509CertificateCollection.GetHashCode()
at System.Net.HttpWebRequest.GetConnectionGroupLine()
at System.Net.HttpWebRequest.SubmitRequest(ServicePoint servicePoint)
at System.Net.HttpWebRequest.BeginGetResponse(AsyncCallback callback, Object state)
at System.Net.Http.HttpClientHandler.StartGettingResponse(RequestState state)
at System.Net.Http.HttpClientHandler.StartRequest(Object obj)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
at Microsoft.VisualStudio.Services.Common.VssHttpMessageHandler.<SendAsync>d__17.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.VisualStudio.Services.Common.VssHttpRetryMessageHandler.<SendAsync>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.VisualStudio.Services.WebApi.VssHttpClientBase.<SendAsync>d__48.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.VisualStudio.Services.WebApi.VssHttpClientBase.<SendAsync>d__45`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.VisualStudio.Services.WebApi.VssHttpClientBase.<SendAsync>d__27`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.VisualStudio.Services.WebApi.VssHttpClientBase.<SendAsync>d__26`1.MoveNext()
Is there something I'm doing wrong?
A solution is to create WorkItemReporting inside Parallel.ForEach:
Parallel.ForEach(msrcAbBugsToProcess, new ParallelOptions { MaxDegreeOfParallelism = 10 }, bugId =>
{
var vso = new WorkItemReporting(Config.VSTSAccessToken);
var workItemLinks = vso.GetWorkItemSourceCodeLinks(bugId);
});
You need to lock access to the external resource by doing something like the following.
As per comment #AlexSikilinda _witClient must not be thread safe.
For what your doing though, just because you can create multiple threads doesn't means you should, i would get timings, on what your doing with and without the parallel processing in your code,
Keep in mind if you use non thread safe external resources, and locks then it maybe just as slow as running in a normal for loop. You need to test both scenario's.
Add an object outside your methods to allow access to the lock object from every thread, this will help manage the access to the non thread safe class.
vso = new WorkItemReporting(Config.VSTSAccessToken);
private readonly object _witLock = new object();
In the following you DON'T want to put the lock around the entire methods contents as i have, otherwise you are definitely wasting your time using the Parallel for this piece of code.
Based on what your doing thought this should stop the exceptions.
You need refactor the code so that only the call to _witClient is within the lock. So just declare the workItem variable outside the lock with it proper type, and then only wrap the call to workItem = _witClient.GetWorkItemAsync(bugId, null, null, WorkItemExpand.Relations).Result; in your lock code.
public List<string> GetWorkItemSourceCodeLinks(int bugId)
{
var workItemSourceCodeLinks = new List<string>();
lock (_witLock)
{
var workItem = _witClient.GetWorkItemAsync(bugId, null, null, WorkItemExpand.Relations).Result;
if (workItem?.Relations != null)
{
var validSourceCodeLinkTypes = new List<string> { "ArtifactLink", "Hyperlink" };
foreach (var relation in workItem.Relations)
{
if (validSourceCodeLinkTypes.Contains(relation.Rel))
{
workItemSourceCodeLinks.Add(relation.Url);
}
}
}
}
}
Good Luck
Problem occurs only on my client machine. I ran my application on 4 machines without reproduction success.
I would like to ask on advice and help in debug the following exception while using Flurl library:
What may cause this exception to run only on specific machine ?
System.TypeInitializationException: The type initializer for 'Module.Performance.PriceProviders.YahooClientFactory' threw an exception. ---> System.AggregateException: One or more errors occurred. ---> System.NullReferenceException: Object reference not set to an instance of an object.
at Flurl.Http.FlurlClient.ReadResponseCookies(HttpResponseMessage response)
at Flurl.Http.FlurlClient.d__28.MoveNext()
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task1.GetResultCore(Boolean waitCompletionNotification)
at System.Threading.Tasks.Task1.get_Result()
at Module.Performance.PriceProviders.YahooClientFactory..cctor()
--- End of inner exception stack trace ---
at Module.Performance.PriceProviders.YahooClientFactory.get_GetYahooClient()
at Module.Performance.PriceProviders.YahooFlurlClient.d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Module.Performance.PriceProviders.YahooStockPriceProvider.d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Module.Performance.PriceProviders.PriceProviderBase.d__3.MoveNext()
Code beneath the exception looks like:
YahooClientFactory is singletone factor to optimize the request time. Factory is often called by other async task (higher layer)
public static class YahooClientFactory
{
public static IFlurlClient GetYahooClient => YahooClientInstance;
public static string Crumb { get; }
private static readonly IFlurlClient YahooClientInstance;
private const string CookieUrl = "https://finance.yahoo.com";
private static string userAgent = "User-Agent";
private static string headerString =
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36";
private const string CrumbUrl = "https://query1.finance.yahoo.com/v1/test/getcrumb";
private static int MaxRetryCount = 5;
static YahooClientFactory()
{
YahooClientInstance = new FlurlClient()
.WithHeader(userAgent, headerString)
.EnableCookies()
.WithUrl($"{CookieUrl}?{GetRandomString(8)}");
for (int i = 0; i < MaxRetryCount; i++)
{
YahooClientInstance
.GetAsync(CancellationToken.None)
.Result
.EnsureSuccessStatusCode();
if (YahooClientInstance.Cookies?.Count > 0)
{
break;
}
if (i == MaxRetryCount)
{
throw new Exception("Reached maximum number of retries when connecting to yahoo client.");
}
Thread.Sleep(100);
}
Crumb = YahooClientInstance
.WithUrl(CrumbUrl)
.GetAsync(CancellationToken.None)
.ReceiveString()
.Result;
}
public static string GetRandomString(int length)
{
const string Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
return string.Join("", Enumerable.Range(0, length).Select(i => Chars[new Random().Next(Chars.Length)]));
}
}
It looks like you've encountered a known bug where Flurl attempts to read cookies after a failed request without checking for a null response. This is fixed for Flurl.Http 2.0. Please upgrade to the latest prerelease and report back whether that resolves your issue.
I have a C# project with a service reference against a web service.
I have the following code, first to trigger a method at the service request:
private void Button_Click(object sender, RoutedEventArgs e)
{
App.service.getFileCompleted += service_getFileCompleted;
App.service.getFileAsync(App.user, App.document);
}
And the service_getFileCompleted is supposed to retrieve a byte[], put it into a file and then open that file with the default application:
async void service_getFileCompleted(object sender, BackendReference.getFileCompletedEventArgs e)
{
string tmp = "temp." + e.Result.type;
StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder;
StorageFile localFile = await local.CreateFileAsync(tmp, CreationCollisionOption.ReplaceExisting);
using (Stream writeStream = await localFile.OpenStreamForWriteAsync())
{
writeStream.Seek(0, SeekOrigin.End);
await writeStream.WriteAsync(e.Result.fileData, 0, e.Result.fileData.Length);
}
await Windows.System.Launcher.LaunchFileAsync(localFile);
}
}
First time the apps starts, and the button is triggered it works like a charm. However, when pressing the button the second time the row
Stream writeStream = await localFile.OpenStreamForWriteAsync()
casts an System.UnauthorizedAccessException.
More exactly:
System.UnauthorizedAccessException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.IO.WindowsRuntimeStorageExtensions.d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.IO.WindowsRuntimeStorageExtensions.d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at archive.DocumentDetail.d__0.MoveNext()} System.Exception {System.UnauthorizedAccessException}
Why is this so?
Thanks