1

This question probably has been asked multiple times, but none of their solution really helped.

I am using OneSignal to send push notifications to all connected clients. I implemented the code in a service and made it a Singleton.

What I want
My use case is that I want to send a notification to a user, and immediately send a different notification to another user.

Problem
It works only for the first request, after that, I keep getting this error:

System.InvalidOperationException: This operation cannot be performed after the request has been submitted.
   at System.Net.HttpWebRequest.InternalGetRequestStream()
   at System.Net.HttpWebRequest.GetRequestStream()
   at BingoAPI.Services.NotificationService.SendNotificationAsync(Byte[] buffer) in D:\Bingo\BingoAPI\Services\NotificationService.cs:line 74

Here is the implementation:

public NotificationService(IOptions<OneSignalNotificationSettigs> oneSignalSettings, IOptions<NotificationTemplates> notificationTemplates)
        {
            this.oneSignalSettings = oneSignalSettings;
            this.notificationTemplates = notificationTemplates;

            // request configuration
            request = WebRequest.Create(oneSignalSettings.Value.EndPoint) as HttpWebRequest;
            request.Headers.Add("authorization", oneSignalSettings.Value.Authorization);
            request.KeepAlive = true;
            request.Method = "POST";
            request.ContentType = "application/json; charset=utf-8";

        }

        private async Task SendNotificationAsync(byte[] buffer)
        {
            string responseContent = null;
            try
            {
                // here is the error
                var writer = await request.GetRequestStreamAsync();
                await writer.WriteAsync(buffer, 0, buffer.Length);
                writer.Close();

                var response = await request.GetResponseAsync() as HttpWebResponse;
                var reader = new StreamReader(response.GetResponseStream());
                responseContent = await reader.ReadToEndAsync();
            }
            catch (WebException ex)
            {
               // LOGGING
            }
        }

    }
Gicu Mironica
  • 585
  • 8
  • 22
  • I have to mention, I tried to add this service as Transient, and it worked. But, I don't think it is a long term solution because this has to be reinitialized for every request – Gicu Mironica Jun 04 '20 at 21:20
  • 1
    I know it is not a direct answer, but as you use asp net core I would suggest using a HttpClient through the IHttpClientFactory and use dependency injection. – Mono Jun 04 '20 at 21:40

2 Answers2

1

As far as I know, the Singleton means the application every subsequent request uses the same instance.

This means all the two request use the same HttpWebRequest.

Since your SendNotificationAsync is async method. If you call this method twice at same time. It will use the same HttpWebRequest(request) to send the request.

The error tells you that the first HttpWebRequest(request) is submitted and not executed complete, we couldn't submit HttpWebRequest(request) again.

In my opinion, you should register the service as Transient, since each we couldn't re-use the HttpWebRequest(request) .

Brando Zhang
  • 22,586
  • 6
  • 37
  • 65
1

I ended up using HttpClientFactory instead of HttpWebRequest although I could make it transient. But that does not look like a solution for me in the long term run because a lot of extra stuff has to be reinitialized with every request. And it's even less code.

public NotificationService(IOptions<OneSignalNotificationSettigs> oneSignalSettings, IOptions<NotificationTemplates> notificationTemplates,
                                   IHttpClientFactory clientFactory)
        {
            this.oneSignalSettings = oneSignalSettings;
            this.notificationTemplates = notificationTemplates;

            // request configuration
            httpClient = clientFactory.CreateClient();
            httpClient.DefaultRequestHeaders.Add("authorization", oneSignalSettings.Value.Authorization);
            request = new HttpRequestMessage(HttpMethod.Post, oneSignalSettings.Value.EndPoint);           
        }

        private async Task SerializeNotificationAsync(Object obj)
        {            
            var param = JsonConvert.SerializeObject(obj);
            var data = new StringContent(param, Encoding.UTF8, "application/json");
            await SendNotificationAsync(data);                                                
        }


        private async Task SendNotificationAsync(StringContent buffer)
        {            
            var response = await httpClient.PostAsync(request.RequestUri, buffer);

            if (!response.IsSuccessStatusCode)
            {
                // logg error

            }
        }
Gicu Mironica
  • 585
  • 8
  • 22