In the following code:
[System.Diagnostics.CodeAnalysis.SuppressMessage("Await.Warning", "CS4014:Await.Warning")]
private async Task<bool> Refresh()
{
log.Info("Refreshing Token.");
Debug.WriteLine("Refreshing Token.");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(TOKEN_URL);
request.Method = "POST";
request.ContentType = "application/json; charset=UTF-8";
request.Headers.Add("Authorization", "basic " + authCode);
request.Accept = "application/json, text/javascript, */*; q=0.01";
request.ContentLength = payload.Length;
log.Debug(request.Headers["Authorization"]);
Debug.WriteLine(request.Headers["Authorization"]);
using (Stream writeStream = request.GetRequestStream())
{
await writeStream.WriteAsync(payload, 0, payload.Length);
}
lock (tokenLock)
{
Debug.WriteLine($"Write Lock enabled? {tokenLock.IsWriteLockHeld}");
tokenLock.EnterWriteLock();
Debug.WriteLine($"Write Lock enabled? {tokenLock.IsWriteLockHeld}");
}
try
{
string body;
using (HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync())
{
int numericStatusCode = (int)response.StatusCode;
Debug.WriteLine($"Response Code: {numericStatusCode}");
if (response.StatusCode != HttpStatusCode.OK)
{
log.Error($"!!!!! Request failed. Received HTTP {response.StatusCode}");
body = string.Empty;
}
else
{
string responseValue = string.Empty;
using (Stream responseStream = response.GetResponseStream())
{
if (responseStream != null)
{
using (StreamReader reader = new StreamReader(responseStream))
{
responseValue = await reader.ReadToEndAsync();
}
}
}
body = responseValue;
Debug.WriteLine($"Response Body = {body}");
log.Trace($"Response Body = {body}");
}
}
Debug.WriteLine($"Write Lock enabled? {tokenLock.IsWriteLockHeld}");
if (!string.IsNullOrEmpty(body))
{
_token = JsonConvert.DeserializeObject<AuthTokenInfo>(body, serializerSettings);
refreshUri = _token.RefreshTokenServerUri;
payload = Encoding.GetEncoding("utf-8").GetBytes(
JsonConvert.SerializeObject(new { grant_type = "refresh_token", _token.RefreshToken })
);
Debug.WriteLine($"Write Lock enabled? {tokenLock.IsWriteLockHeld}");
Debug.WriteLine($"Token Refreshed, Expires In = {_token.ExpiresIn}");
Debug.WriteLine($"Access Token = {_token.AccessToken}");
Debug.WriteLine($"New Token Refresh URI: {refreshUri}");
Debug.WriteLine($"New Refresh Token: {_token.RefreshToken}");
if (_token != null)
{
int refreshTime = 60 * 1000; // (Token.ExpiresIn.Value - (15 * 60)) * 1000;
log.Info($"Refreshing token in {refreshTime} milliseconds.");
Debug.WriteLine($"Refreshing token in {refreshTime} milliseconds.");
Task.Delay(refreshTime).ContinueWith(async (action) =>
{
log.Info("Refreshing token NOW.");
Debug.WriteLine("Refreshing token NOW.");
await Refresh();
});
Debug.WriteLine("Refresh scheduled.");
}
}
}
finally
{
lock(tokenLock)
{
Debug.WriteLine($"Write Lock enabled? {tokenLock.IsWriteLockHeld}");
tokenLock.ExitWriteLock();
Debug.WriteLine($"Write Lock enabled? {tokenLock.IsWriteLockHeld}");
}
}
return true;
}
When I execute this code, my debug output shows:
Refreshing Token.
Write Lock enabled? False
Write Lock enabled? True
Response Code: 200
Write Lock enabled? False
Write Lock enabled? False
Token Refreshed, Expires In = 3600
Refreshing token in 60000 milliseconds.
Refresh scheduled.
Write Lock enabled? False
Exception thrown: 'System.Threading.SynchronizationLockException' in System.Core.dll
Exception thrown: 'System.AggregateException' in mscorlib.dll
Exception thrown: 'System.TypeInitializationException' in InContactApi.dll
Exception thrown: 'System.TypeInitializationException' in mscorlib.dll
Exception thrown: 'System.AggregateException' in mscorlib.dll
An unhandled exception of type 'System.AggregateException' occurred in mscorlib.dll
One or more errors occurred.
Unhandled Exception: System.AggregateException: One or more errors occurred. ---> System.TypeInitializationException: The type initializer for 'InContact.Auth' threw an exception. ---> System.AggregateException: One or more errors occurred. ---> System.Threading.SynchronizationLockException: The write lock is being released without being held.
at System.Threading.ReaderWriterLockSlim.ExitWriteLock()
at InContact.AuthToken.<Refresh>d__12.MoveNext() in C:\Users\chill\source\repos\interactive_intelligence\InContactApi\InContactApi\Auth.cs:line 206
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
at System.Threading.Tasks.Task.Wait()
at InContact.AuthToken..ctor() in C:\Users\chill\source\repos\interactive_intelligence\InContactApi\InContactApi\Auth.cs:line 106
at InContact.Auth..cctor() in C:\Users\chill\source\repos\interactive_intelligence\InContactApi\InContactApi\Auth.cs:line 236
--- End of inner exception stack trace ---
at InContact.Auth.get_BaseURL()
at InContact.InContactApi.MakeRequestURL(String subURL, Dictionary`2 query, String callerName) in C:\Users\chill\source\repos\interactive_intelligence\InContactApi\InContactApi\InContactApi.cs:line 127
at InContact.InContactApi.<GetFolderListing>d__26.MoveNext() in C:\Users\chill\source\repos\interactive_intelligence\InContactApi\InContactApi\InContactApi.cs:line 607
--- 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 CallLogger.ICRecordings.<DirTraverse>d__8.MoveNext() in C:\Users\chill\source\repos\interactive_intelligence\CallLogger\CallLogger\ICRecordings.cs:line 73
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
at System.Threading.Tasks.Task`1.get_Result()
at CallLogger.Program.Main() in C:\Users\chill\source\repos\interactive_intelligence\CallLogger\CallLogger\Program.cs:line 32
The program '[34036] PhoneLogger.exe' has exited with code 0 (0x0).
I am not understanding how my write lock is unlocking partway through the code, with the only write unlock line I have being at the end in a finally block.
Can anyone shed some light on this for me, and/or suggest a better approach?
I am dealing with an OAuth system that has an access token that must be refreshed every hour (when I am finally done with it). I have implemented this Refresh method to accomplish the goal, and use a Task.Delay().ContinueWith() call to schedule the refresh to run automatically. I am using a ReadWriterLockSlim so that I can lock the reads from continuing while the refresh is happening. Otherwise I want them to work normally. I need them locked because once I request the new token from the server on the refresh, I can no longer use the old auth token.
Aleks Andreev, thank you.
So the solution is to not use ReadWriterLockSlim, but rather to install the Nito.AsyncEx NuGet module and then use the AsyncReadWriterLock from it. Because ReadWriterLockSlim does not work with async/await.
Related
I have a piece code written in an ASP Core 7 API, with EF Core 7, using MSSQL for the database. The below code is where the repository loads some data for the dashboard.
public async Task<ResponseResult<DashboardPendingBillsDto>> PendingBillDetails(CancellationToken token)
{
var venderInvoicelQuery = _context.Set<VendorInvoice>().AsQueryable();
var pendingBillsQuery = venderInvoicelQuery.Where(a => !a.IsBilled);
var today = DateTimeOffset.UtcNow;
var fourthDay = today.AddDays(-3);
var seventhDay = today.AddDays(-7);
var pendingBillsData = await pendingBillsQuery.Select(s => new
{
BetweenOneToFiveDays = pendingBillsQuery
.Where(a => fourthDay.Date < a.CreatedOn.Date && a.CreatedOn.Date <= today.Date).Count(),
BetweenSixToTenDays = pendingBillsQuery
.Where(a => seventhDay.Date < a.CreatedOn.Date && a.CreatedOn.Date <= fourthDay.Date).Count(),
AboveTenDays = pendingBillsQuery
.Where(a => a.CreatedOn.Date <= seventhDay.Date).Count()
}).FirstOrDefaultAsync(token);
var dashboardPendingBillsDto = new DashboardPendingBillsDto
{
BetweenZeroToThreeDays = pendingBillsData?.BetweenOneToFiveDays ?? 0,
BetweenFourToSevenDays = pendingBillsData?.BetweenSixToTenDays ?? 0,
AboveSevenDays = pendingBillsData?.AboveTenDays ?? 0,
};
return new ResponseResult<DashboardPendingBillsDto>(dashboardPendingBillsDto);
}
The above code returns the desired data as well as shown below
The problem is, if the HTTP request was cancelled, then the TaskCanceledException exception is thrown and it gives an error An error occurred using the connection to database 'test-db-12-jan-2023' on server 'DESKTOP-xxx. But i already passed the cancelation token into the FirstOrDefaultAsync(token) as such. it happens only if the http request was cancelled. Any help please.
update 29-jan-2023
I have a middle ware to handle exceptions globally and it is the first middle ware of the pipeline
And here is how the middleware handles the exceptions. i have only 2 exceptions here, TaskCanceledException and Exception
private Task ConvertException(HttpContext context, Exception exception)
{
var activityId = Activity.Current?.Id ?? "N/A";
_telemetry.TrackException(exception);
ErrorResponse errorResponse = new() { TraceId = activityId };
int httpStatusCode = StatusCodes.Status500InternalServerError;
context.Response.ContentType = "application/json";
var result = string.Empty;
switch (exception)
{
case TaskCanceledException:
//if client closes the connection
httpStatusCode = StatusCodes.Status200OK;
result = JsonConvert.SerializeObject(new ResponseResult<string>("Client closed the connecion"));
break;
case Exception:
httpStatusCode = StatusCodes.Status500InternalServerError;
errorResponse.Errors.Add(new KeyValuePair<string, IEnumerable<string>>(nameof(HttpStatusCode.InternalServerError), new[] { "Something went wrong, please try again" }));
result = JsonConvert.SerializeObject(errorResponse);
LogError(exception, activityId);
break;
}
context.Response.StatusCode = httpStatusCode;
return context.Response.WriteAsync(result);
}
Below is the exception message i get from the middleware
A task was cancelled
Below is the the stack trace from the exception which i can get from the middleware
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.<OpenInternalAsync>d__70.MoveNext()
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.<OpenInternalAsync>d__70.MoveNext()
at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.<OpenAsync>d__66.MoveNext()
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.<ExecuteReaderAsync>d__19.MoveNext()
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.<InitializeReaderAsync>d__21.MoveNext()
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.<ExecuteAsync>d__7`2.MoveNext()
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.<MoveNextAsync>d__20.MoveNext()
at System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable`1.ConfiguredValueTaskAwaiter.GetResult()
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.<SingleOrDefaultAsync>d__15`1.MoveNext()
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.<SingleOrDefaultAsync>d__15`1.MoveNext()
at VPMS.Persistence.Repositories.Dashboard.DashboardRepository.<PendingBillDetails>d__3.MoveNext() in C:\Projects\Legacy HealthCare - Vendor Payment Management System\VPMS\VPMS.Persistence\Repositories\DashboardRepository\DashboardRepository.cs:line 162
at VPMS.Application.DashBoard.Services.DashboardService.<GetPendingBillsAsync>d__3.MoveNext() in C:\Projects\Legacy HealthCare - Vendor Payment Management System\VPMS\VPMS.Application\DashBoard\Services\DashboardService.cs:line 25
at VPMS.Api.Controllers.Dashboard.DashboardController.<GetPendingBills>d__2.MoveNext() in C:\Projects\Legacy HealthCare - Vendor Payment Management System\VPMS\VPMS.Api\Controllers\DashBoardController.cs:line 30
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfActionResultExecutor.<Execute>d__0.MoveNext()
at System.Threading.Tasks.ValueTask`1.get_Result()
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<<InvokeActionMethodAsync>g__Logged|12_1>d.MoveNext()
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<<InvokeNextActionFilterAsync>g__Awaited|10_0>d.MoveNext()
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<<InvokeFilterPipelineAsync>g__Awaited|20_0>d.MoveNext()
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<<InvokeAsync>g__Logged|17_1>d.MoveNext()
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<<InvokeAsync>g__Logged|17_1>d.MoveNext()
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<<Invoke>g__AwaitRequestTask|6_0>d.MoveNext()
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.<Invoke>d__9.MoveNext()
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.<Invoke>d__6.MoveNext()
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.<Invoke>d__5.MoveNext()
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.<Invoke>d__4.MoveNext()
at VPMS.Api.Middleware.ExceptionHandlerMiddleware.<Invoke>d__3.MoveNext() in C:\Projects\Legacy HealthCare - Vendor Payment Management System\VPMS\VPMS.Api\Middleware\ExceptionHandlerMiddleware.cs:line 25
But i have serilogged configured and it gives an exception which does not hit the middle ware which is the real problem in here which is
An error occurred using the connection to database 'test-db-12-jan-2023' on server 'DESKTOP-xxx
The above error message is logged to the serilog but it never reaches the middleware and this is the exception i want to avoid. this is the problem here.
I'm using Azure Service Bus Topics with the AMQP protocol in the West Europe datacenter.
This is a schematic way of how the solution implented works:
private Microsoft.Azure.ServiceBus.SubscriptionClient CreateClient() {
string serviceBusConnectionString;
strin serviceBusTopicName;
string subscriptionName;
var subscriptionClient = new Microsoft.Azure.ServiceBus.SubscriptionClient(serviceBusConnectionString, serviceBusTopicName, subscriptionName) {
PrefetchCount = 0
};
return subscriptionClient;
}
public async Task<ISubscriptionClient> CreateSubscriptionClientAsync() {
//Some logic on the subscriptionClient, caching, creating a new one if it doesn't exists, etc.
return CreateClient()
}
private async Task CallbackAsync(Message msg, CancellationToken cancellationToken) {
//Do stuff with the Message
//when you're done Completethe message
}
public async Task<string> OpenAsync(CancellationToken cancellationToken) {
subscriptionClient = await CreateSubscriptionClientAsync().ConfigureAwait(false);
var messageHandlerOptions = new MessageHandlerOptions(ExceptionReceivedHandlerAsync) {
AutoComplete = false,
MaxAutoRenewDuration = TimeSpan.FromHours(8)
};
subscriptionClient.RegisterMessageHandler(CallbackAsync, messageHandlerOptions);
return string.Empty;
}
But last night I had couple of thousand exception like this one:
Exception: "System.InvalidOperationException: The AMQP object g2b-sessionXXXXXXXX is closing. Operation 'attach' cannot be performed.
at Microsoft.Azure.ServiceBus.Core.MessageReceiver.<OnReceiveAsync>d__86.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Azure.ServiceBus.Core.MessageReceiver.<>c__DisplayClass64_0.<<ReceiveAsync>b__0>d.MoveNext()
I'm using the Microsoft.Azure.ServiceBus v3.1.0.0,
On line I didn't find anything useful about this "Operation 'attach' cannot be performed".
On the message bus exception list page I didn't find any information about this specific problem. And in the status history site there is no reference about any outage involving Service Bus.
Did anyone experience this problem before?
What is causing the exception?
Do I need to implement any retry logic? How?
Any help is apreciated, thanks.
I am looking into an issue with some legacy code which is relaying a Http Request to another URL. It is an API Controller that reads the request and forwards it to another address asynchronously.
Very rarely, it throws a "Cannot access a disposed object" exception - full stack trace shown later in this question. It seems to be on the line where the HttpClient is calling the SendAsync method. I think it might be the ResponseHeadersRead option - I suspect it is happening when a large packet is being sent and it gets closed because it has just read the header and quit. Just thought I'd sanity check this with you all, for your thoughts. I'll change the option to be ResponseContentsRead option and see how that goes (but it can take a long time for the error to surface).
Here is the code:
using (var client = new HttpClient())
{
var request = BuildRelayHttpRequest(Request);
await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
}
private static HttpRequestMessage BuildRelayHttpRequest(HttpRequestMessage incomingRequest)
{
var forwardToUrl = new Uri(ConfigurationManager.AppSettings["ForwardFeedURL"]);
var relayRequest = new HttpRequestMessage(incomingRequest.Method, forwardToUrl);
if (incomingRequest.Method != HttpMethod.Get && incomingRequest.Content != null)
{
relayRequest.Content = incomingRequest.Content;
}
//Copies contents
relayRequest.Content = incomingRequest.Content;
return relayRequest;
}
And here is the exception:
System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Web.Http.WebHost.HttpControllerHandler+LazyStreamContent'.
at System.Net.Http.HttpContent.CheckDisposed()
at System.Net.Http.HttpContent.CopyToAsync(Stream stream, TransportContext context)
at System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult ar)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at CHO.Web.Services.ETrains.Controllers.ETrainsApiController.<CopyandForwardFeedAsyn>d__18.MoveNext() in \Controllers\MyAPIController.cs:line 289
Note, line 289 is the "await client.SendAsync" line of code
Odds are there is an error code being set by the server.
Follow your code with a response.EnsureSuccessStatusCode(); that is wrapped in a Try Catch block:
try
{
var request = BuildRelayHttpRequest(Request);
await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
// Handle success
}
catch (HttpRequestException)
{
// Handle failure
}
I am working with async operations with sockets (.Net 4 - VS 2010 SP1) and all seems to be working okay. However, after write and run an automated test, it pass green but displays an exception message:
---- UNHANDLED EXCEPTION ----
Thread Name: <No Name>
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.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Sockets.Socket'.
at System.Net.Sockets.Socket.EndAccept(IAsyncResult asyncResult)
at P2PNet.Listener.<ListenForConnections>b__0(IAsyncResult r) in C:\Users\lucas.ontivero\Documents\Visual Studio 2010\Projects\P2PNet\P2PNet\Listener.cs:line 76
at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endMethod, TaskCompletionSource`1 tcs)
--- End of inner exception stack trace ---
at System.Threading.Tasks.TaskExceptionHolder.Finalize()
---> (Inner Exception #0) System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Sockets.Socket'.
at System.Net.Sockets.Socket.EndAccept(IAsyncResult asyncResult)
at P2PNet.Listener.<ListenForConnections>b__0(IAsyncResult r) in C:\Users\lucas.ontivero\Documents\Visual Studio 2010\Projects\P2PNet\P2PNet\Listener.cs:line 76
at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endMethod, TaskCompletionSource`1 tcs)<---
I know what that exception means, it means the socket was closed before the EndAccept method was called. I have no problems with that, what I really don´t know is how to prevent that exception in an elegant way. This is my code:
private void ListenForConnections()
{
try
{
Task.Factory.FromAsync<Socket>(_listener.BeginAccept, _listener.EndAccept, _listener)
.ContinueWith(task =>
{
if (task.IsFaulted) return;
ListenForConnections();
var newSocket = task.Result;
RaiseClientConnectedEvent(new ConnectionEventArgs(newSocket));
}, TaskContinuationOptions.OnlyOnRanToCompletion);
}
catch (ObjectDisposedException)
{
}
I´ve tried with the line:
if (task.IsFaulted) return;
and also with:
.ContinueWith(task=>{}, TaskContinuation.OnlyOnFault);
But the exception is thrown anyway. Which is the way to prevent the exception?
Thank you!
Your line:
if (task.IsFaulted) return;
Is returning not faulted because you are checking the continuation task's status, not the preceding task. Change it to this:
private void ListenForConnections() {
Task<Socket> listentask = Task.Factory.FromAsync<Socket>(_listener.BeginAccept, _listener.EndAccept, _listener);
listentask.ContinueWith(task => {
if (listentask.IsFaulted) {
//observe exception
Exception exception = listentask.Exception;
return;
}
ListenForConnections();
var newSocket = listentask.Result;
RaiseClientConnectedEvent(new ConnectionEventArgs(newSocket));
});
//don't forget to start it
listentask.Start();
}
You need to observe the exception by reading the Exception property. Do that inside of your continuation.
I'm writing a background audio agent that plays music from an online stream and also periodically checks for updates in the track name and artist. I'm attempting to use an HttpWebRequest object to get the name and artist, but whenever I call HttpWebResponse trackResponse = (HttpWebResponse)trackRequest.EndGetResponse(result); the error below is thrown.
A first chance exception of type 'System.Net.WebException' occurred in System.Windows.dll
The stack trace for the WebException is the following:
at System.Net.Browser.AsyncHelper.BeginOnUI(SendOrPostCallback beginMethod, Object state)
at System.Net.Browser.ClientHttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at AudioPlaybackAgent.AudioPlayer.TrackCallback(IAsyncResult result)
at System.Net.Browser.ClientHttpWebRequest.<>c__DisplayClassa.<InvokeGetResponseCallback>b__8(Object state2)
at System.Threading.ThreadPool.WorkItem.WaitCallback_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadPool.WorkItem.doWork(Object o)
at System.Threading.Timer.ring()
Digging further into the trackRequest object, I find this:
ResponseStatusCode = 'trackRequest.ResponseStatusCode' threw an exception of type 'System.NullReferenceException'
and further into that, I find this:
at System.Net.HttpWebRequest.get_ResponseStatusCode()
at AudioPlaybackAgent.AudioPlayer.TrackCallback(IAsyncResult result)
at System.Net.Browser.ClientHttpWebRequest.<>c__DisplayClassa.<InvokeGetResponseCallback>b__8(Object state2)
at System.Threading.ThreadPool.WorkItem.WaitCallback_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadPool.WorkItem.doWork(Object o)
at System.Threading.Timer.ring()
Here is the code I am using. The TrackTimerTick function is called every 20 seconds by a Timer.
public static void TrackTimerTick(object state) {
try {
if (BackgroundAudioPlayer.Instance.PlayerState == PlayState.Playing) {
// Create a HttpWebrequest object to the desired URL.
HttpWebRequest trackRequest = (HttpWebRequest)HttpWebRequest.Create("<track/artist url");
// Start the asynchronous request.
IAsyncResult result = (IAsyncResult)trackRequest.BeginGetResponse(new AsyncCallback(TrackCallback), trackRequest);
}
} catch (WebException e) {
Debug.WriteLine(e.Message);
} catch (Exception e) {
Debug.WriteLine(e.Message);
}
}
public static void TrackCallback(IAsyncResult result) {
// State of request is asynchronous.
HttpWebRequest trackRequest = (HttpWebRequest)result.AsyncState;
HttpWebResponse trackResponse = (HttpWebResponse)trackRequest.EndGetResponse(result); // WebException thrown here
using (StreamReader httpwebStreamReader = new StreamReader(trackResponse.GetResponseStream())) {
string results = httpwebStreamReader.ReadToEnd();
XDocument trackXml = XDocument.Load(results);
string title = (from t in trackXml.Descendants("channel") select t.Element("title").Value).First<string>();
string artist = (from t in trackXml.Descendants("channel") select t.Element("artist").Value).First<string>();
if (BackgroundAudioPlayer.Instance.Track != null) {
AudioTrack track = BackgroundAudioPlayer.Instance.Track;
track.BeginEdit();
track.Title = title;
track.Artist = artist;
track.EndEdit();
}
}
trackResponse.Close();
}
Can anyone help me fix this problem? Thank you in advance.
The problem is that you call NotifyComplete() before the response is arrive. I don't understand fully what happens, but you initiate the request, you call NotifyComplete, the OS froze the agent's process, then the next time the agent wakes up the WebClient immediately throws an exception, probably by design.
So the solution is to don't call NotifyComplete until you got the response.
In my case I had to look at my project error log where normally exceptions are thrown and it was printing the message Unable to create an SSL/TLS secure channel. in System.Net.HttpWebRequest.GetResponse() and to solve this I added ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; before my request, but you can put it to be executed on your starter method or class. I think other think that you can do is to add the response in try and catch exception
try
{
var httpResponse = (HttpWebResponse)httpRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
Response response = new JavaScriptSerializer().Deserialize<Response>(result);
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
And here your response class
public class Response
{
public string value_02 { get; set; }
public string value_03 { get; set; }
public string value_04 { get; set; }
public string value_05 { get; set; }
public string value_05 { get; set; }
}
Fact that for me gave the exception
Exception thrown: 'System.Security.Authentication.AuthenticationException' in System.dll
Exception thrown: 'System.Security.Authentication.AuthenticationException' in System.dll
Exception thrown: 'System.Security.Authentication.AuthenticationException' in System.dll
Exception thrown: 'System.Security.Authentication.AuthenticationException' in System.dll
Exception thrown: 'System.Security.Authentication.AuthenticationException' in System.dll
Exception thrown: 'System.ObjectDisposedException' in System.dll
Exception thrown: 'System.Net.WebException' in System.dll
Exception thrown: 'System.Net.WebException' in System.dll
Exception thrown: 'System.NullReferenceException'
And I have added to solve my problem
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
Solved my problem