checking Internet connection with HttpClient - c#

I am having difficulties to understand on how the bellow code could handle occasional internet connection loss. Ideally I would like to pause the app, once the connection is lost, and resume when it is up again. Is there any guideline on how to do it?
HttpClientHandler clientHandler = new HttpClientHandler();
clientHandler.UseDefaultCredentials = true;
HttpClient client = new HttpClient(clientHandler) { MaxResponseContentBufferSize = 1000000 };
HttpResponseMessage response = await client.GetAsync(Url, ct);

The following example is not a direct solution, but it is an example I built to show how to return "pre-canned" content to requests whilst offline and then return back online when connectivity is restored. If you can get what I'm doing here, building what you want should be fairly easy.
[Fact]
public async Task Getting_a_response_when_offline()
{
var offlineHandler = new OfflineHandler(new HttpClientHandler(), new Uri("http://oak:1001/status"));
offlineHandler.AddOfflineResponse(new Uri("http://oak:1001/ServerNotRunning"),
new HttpResponseMessage(HttpStatusCode.NonAuthoritativeInformation)
{
Content = new StringContent("Here's an old copy of the information while we are offline.")
});
var httpClient = new HttpClient(offlineHandler);
var retry = true;
while (retry)
{
var response = await httpClient.GetAsync(new Uri("http://oak:1001/ServerNotRunning"));
if (response.StatusCode == HttpStatusCode.OK) retry = false;
Thread.Sleep(10000);
}
}
public class OfflineHandler : DelegatingHandler
{
private readonly Uri _statusMonitorUri;
private readonly Dictionary<Uri, HttpResponseMessage> _offlineResponses = new Dictionary<Uri, HttpResponseMessage>();
private bool _isOffline = false;
private Timer _timer;
public OfflineHandler(HttpMessageHandler innerHandler, Uri statusMonitorUri)
{
_statusMonitorUri = statusMonitorUri;
InnerHandler = innerHandler;
}
public void AddOfflineResponse(Uri uri, HttpResponseMessage response)
{
_offlineResponses.Add(uri,response);
}
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (_isOffline == true) return OfflineResponse(request);
try
{
var response = await base.SendAsync(request, cancellationToken);
if (response.StatusCode == HttpStatusCode.ServiceUnavailable || response.StatusCode == HttpStatusCode.BadGateway)
{
MonitorOfflineState();
return OfflineResponse(request);
}
return response;
}
catch (WebException ex)
{
MonitorOfflineState();
return OfflineResponse(request);
}
}
private void MonitorOfflineState()
{
_isOffline = true;
_timer = new Timer( async state =>
{
var request = new HttpRequestMessage() {RequestUri = _statusMonitorUri};
try
{
var response = await base.SendAsync(request, new CancellationToken());
if (response.StatusCode == HttpStatusCode.OK)
{
_isOffline = false;
_timer.Dispose();
}
}
catch
{
}
}, null, new TimeSpan(0,0,0),new TimeSpan(0,1,0));
}
private HttpResponseMessage OfflineResponse(HttpRequestMessage request)
{
if (_offlineResponses.ContainsKey(request.RequestUri))
{
return _offlineResponses[request.RequestUri];
}
return new HttpResponseMessage(HttpStatusCode.ServiceUnavailable);
}
}
}

Related

.Net Core - Docker Linux memory usage keeps increasing

I am bit frustrated now what's wrong with my code, and I hope you guys can help me with it, so here are the things I have tried.
so I tried making the HttpClient static, and I tried using the IHttpClientFactory.CreateClient() and I even added this on my .csproj
<ServerGarbageCollection>false</ServerGarbageCollection>
Here is the sample code that I have been doing
public class TestController : BaseController
{
private static HttpClient _httpClient = new();
public TestController()
{
}
[HttpGet("bills")]
public async Task<IActionResult> GetBillsPresentment([FromQuery] GetBillPresentmentQuery query)
{
if (!query.AccountNumber.Contains("-"))
query.AccountNumber = FormatAccountNumber(query.AccountNumber);
var billDetails = await GetBillDetail(query.AccountNumber);
if (billDetails == null)
throw new ProviderProcessException(ProviderErrorCode.INVALID_ACCOUNT_NUMBER);
return Ok(new BillPresentmentVm
{
User = new CustomerDto
{
CustomerName = billDetails.Name
},
Billing = new BillingDto
{
AccountNumber = query.AccountNumber,
DueDate = DateTime.Parse(billDetails.LastReadDate).AddMonths(1),
Outstanding = !string.IsNullOrEmpty(billDetails.Arrears) ? decimal.Parse(billDetails.Arrears) : null
}
});
}
private async Task<ResponseModel> GetBillDetail(string accountNumber)
{
try
{
var payload = new { accno = accountNumber };
string json = JsonConvert.SerializeObject(payload);
var buffer = System.Text.Encoding.UTF8.GetBytes(json);
using var byteContent = new ByteArrayContent(buffer);
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = await _httpClient.PostAsync("https://test.com", byteContent);
if (!response.IsSuccessStatusCode)
throw new ProviderProcessException(ProviderErrorCode.BILLING_CYCLE_UNAVAILABLE);
var result = await response.Content.ReadAsStringAsync();
if (result == "Accno not found!") return null;
var data = JsonConvert.DeserializeObject<ResponseModel>(result);
return data;
}
catch (Exception)
{
throw new ProviderProcessException(ProviderErrorCode.BILLING_CYCLE_UNAVAILABLE);
}
}
private static string FormatAccountNumber(string accountNumber)
{
return string.Format("{0:#######-########}", Convert.ToInt64(accountNumber));
}
}
And here's the docker memory usage
The memory usage keeps increasing after a request. Can someone explains me why it is not decreasing?
Thank you very much in advance
I solve this issue using IHttpClientFactory instead of HttpClient.
https://learn.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests
I use some thing like this and it works fine on large amount of requests per second and it use memory in normal way .
namespace BehsaLoyalty.ApiClient
{
public class ApiRepo : IApiRepo
{
private readonly IHttpClientFactory _HttpClientFactory;
public ApiRepo (IHttpClientFactory httpClientFactory)
{
_HttpClientFactory = httpClientFactory;
}
public async Task<ResponseModel> PostMyObject(Myobject model, CancellationToken cancellationToken)
{
HttpClient httpClient = _HttpClientFactory.CreateClient("ApiDestinationURI");
using HttpRequestMessage request = new(HttpMethod.Post, "/blah/blah");
request.Content = new StringContent(JsonSerializer.Serialize(model));
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
HttpResponseMessage response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseContentRead, cancellationToken);
response.EnsureSuccessStatusCode();
string createdContent = await response.Content.ReadAsStringAsync();
ResponseModel ResponseReturn = JsonSerializer.Deserialize<ResponseModel>(createdContent);
return ResponseReturn;
}
}
}

Xamarin - Delegating Handler failing with System.Threading.Tasks.TaskCanceledException: A task was canceled

On my Xamarin Forms project I'm trying to logout when the token is no longer valid and it returns 401 response.
For that I'm trying to use a DelegatingHandler but it will stop at SendAsync method without giving any errors.
Here is the DelegatingHandler class
public class HttpDelegatingHandler : DelegatingHandler
{
public HttpDelegatingHandler(HttpMessageHandler innerHandler) : base(innerHandler)
{
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// before request
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
// after request
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
await Logout();
}
return response;
}
private async Task Logout()
{
CurrentPropertiesService.Logout();
CurrentPropertiesService.RemoveCart();
await Shell.Current.GoToAsync($"//main");
}
And here is my class AzureApiService where GetAsync stops the application
public class AzureApiService
{
HttpClient httpClient;
public AzureApiService()
{
#if DEBUG
var httpHandler = new HttpDelegatingHandler(new HttpClientHandler());
#else
var httpHandler = HttpDelegatingHandler(new HttpClientHandler());
#endif
httpClient = new HttpClient(httpHandler);
httpClient.Timeout = TimeSpan.FromSeconds(15);
httpClient.MaxResponseContentBufferSize = 256000;
}
public async Task<string> LoginAsync(string url, AuthUser data)
{
var user = await HttpLoginPostAsync(url, data);
if (user != null)
{
//Save data on constants
CurrentPropertiesService.SaveUser(user);
return user.Token;
}
else
{
return string.Empty;
}
}
// Generic Get Method
public async Task<T> HttpGetAsync<T>(string url, string token)
{
T result = default(T);
try
{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = await httpClient.GetAsync(url);
HttpContent content = response.Content;
var jsonResponse = await content.ReadAsStringAsync();
result = JsonConvert.DeserializeObject<T>(jsonResponse);
}
catch (Exception ex)
{
OnError(ex.ToString());
}
return result;
}
Please help I don't know where the issue is. Thanks.

How to know the retry iteration number in retryPolicy.excute()

I am getting an error "The request message was already sent. Cannot send the same request message multiple times" for multiple retries of the same request. So, as far as I know, I need to recreate a new HttpRequestMessage for the second retry. Is there a way to know the retry iteration number in the retryPolicy.Execute() sothat I can clone the HttpRequestMessage for second retry empty?
using Polly;
using Polly.Retry;
namespace RetryLogic {
public class HttpFactory
{
private static readonly TimeSpan defaultTimeoutInMinutes = TimeSpan.FromMinutes(5);
private static readonly RetryPolicy<HttpResponseMessage> retryPolicy;
private static readonly HttpClient client;
static HttpFactory()
{
retryPolicy = Policy
.Handle<Exception>()
.OrResult<HttpResponseMessage>(resp => resp.StatusCode == HttpStatusCode.GatewayTimeout
|| resp.StatusCode == HttpStatusCode.ServiceUnavailable
|| resp.StatusCode == (HttpStatusCode)550)
.WaitAndRetry(1, GetRetryDelay);
var handler = new HttpClientHandler
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
client = new HttpClient(handler)
{
Timeout = defaultTimeoutInMinutes
};
}
public static HttpRequestMessage CreateRequest(HttpMethod method, string pathAndQuery, NameValueCollection headers, Stream requestBody)
{
HttpRequestMessage request = new HttpRequestMessage(method, pathAndQuery);
if (requestBody != null)
{
request.Content = new StreamContent(requestBody);
request.Headers.TransferEncodingChunked = true;
}
return AddRequestHeaders(request, headers);
}
public static HttpResponseMessage MakeRequest(HttpRequestMessage request, ILoggerFactory factory, List<HttpOptions> httpOptions = null)
{
return retryPolicy.Execute(() =>
{
// How to know the retry iteration count here?
HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead;
if (httpOptions != null)
{
foreach (HttpOptions httpOption in httpOptions)
{
switch (httpOption)
{
case HttpOptions.SkipReadingResponseContent:
completionOption = HttpCompletionOption.ResponseHeadersRead;
break;
case HttpOptions.TransferChunkEncodedRequest:
client.DefaultRequestHeaders.TransferEncodingChunked = true;
break;
}
}
}
HttpResponseMessage response = client.SendAsync(request, completionOption).Result;
return response;
});
}
}
public enum HttpOptions
{
SkipReadingResponseContent,
TransferChunkEncodedRequest
} }
Retry Polly is not providing any inbuilt functionality to know the iteration number.
int iterationNumber = 0;
policy.Execute(() => {
iterationNumber++;
// ...
} );

A method was called at an unexpected time from IHttpFilter.SendRequestAsync

I'm developing an UWP app that calls a web service. For that I use a HttpClient object from Windows.Web.Http namespace and I pass a IHttpFilter object to its constructor. This filter is responsible for the authentication process. I based my solution following this link and the authentication logic is based on this
I don't know what I'm doing wrong but I got this exception: A method was called at an unexpected time. (Exception from HRESULT: 0x8000000E)
The scenario that I'm testing is when the token is invalid despite it is assumed it is valid. In this case the (now > TokenManager.Token.ExpiresOn) condition is false, then an authorization header is added (with an invalid token), then a request is sent, then the http response code and www-authenticate header is inspected and if it is neccessary, a new access token must be requested by means of refresh token in order to do a retry. It is when I reach this line when the exception is thrown (the second time): response = await InnerFilter.SendRequestAsync(request).AsTask(cancellationToken, progress);
I have no idea what I'm doing wrong. I have seen another questions where people got this error and usually it's because they try to get the task's result without waiting for the task's completion but I'm using the await keyword in all asynchronous methods.
public class AuthFilter : HttpFilter
{
public override IAsyncOperationWithProgress<HttpResponseMessage, HttpProgress> SendRequestAsync(HttpRequestMessage request)
{
return AsyncInfo.Run<HttpResponseMessage, HttpProgress>(async (cancellationToken, progress) =>
{
var retry = true;
if (TokenManager.TokenExists)
{
var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
if (now > TokenManager.Token.ExpiresOn)
{
retry = false;
await RefreshTokenAsync();
}
request.Headers.Authorization = new HttpCredentialsHeaderValue(TokenManager.Token.TokenType, TokenManager.Token.AccessToken);
}
HttpResponseMessage response = await InnerFilter.SendRequestAsync(request).AsTask(cancellationToken, progress);
cancellationToken.ThrowIfCancellationRequested();
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
var authHeader = response.Headers.WwwAuthenticate.SingleOrDefault(x => x.Scheme == "Bearer");
if (authHeader != null)
{
var challenge = ParseChallenge(authHeader.Parameters);
if (challenge.Error == "token_expired" && retry)
{
var success = await RefreshTokenAsync();
if (success)
{
request.Headers.Authorization = new HttpCredentialsHeaderValue(TokenManager.Token.TokenType, TokenManager.Token.AccessToken);
response = await InnerFilter.SendRequestAsync(request).AsTask(cancellationToken, progress);
}
}
}
}
return response;
});
}
private async Task<bool> RefreshTokenAsync()
{
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Accept.Add(new HttpMediaTypeWithQualityHeaderValue("application/json"));
var content = new HttpStringContent(JsonConvert.SerializeObject(new { RefreshToken = TokenManager.Token.RefreshToken }), UnicodeEncoding.Utf8, "application/json");
var response = await httpClient.PostAsync(SettingsService.Instance.WebApiUri.Append("api/login/refresh-token"), content);
if (response.IsSuccessStatusCode)
TokenManager.Token = JsonConvert.DeserializeObject<Token>(await response.Content.ReadAsStringAsync());
return response.IsSuccessStatusCode;
}
}
private (string Realm, string Error, string ErrorDescription) ParseChallenge(IEnumerable<HttpNameValueHeaderValue> input)
{
var realm = input.SingleOrDefault(x => x.Name == "realm")?.Value ?? string.Empty;
var error = input.SingleOrDefault(x => x.Name == "error")?.Value ?? string.Empty;
var errorDescription = input.SingleOrDefault(x => x.Name == "error_description")?.Value ?? string.Empty;
return (realm, error, errorDescription);
}
public override void Dispose()
{
InnerFilter.Dispose();
GC.SuppressFinalize(this);
}
}
public abstract class HttpFilter : IHttpFilter
{
public IHttpFilter InnerFilter { get; set; }
public HttpFilter()
{
InnerFilter = new HttpBaseProtocolFilter();
}
public abstract IAsyncOperationWithProgress<HttpResponseMessage, HttpProgress> SendRequestAsync(HttpRequestMessage request);
public abstract void Dispose();
}
EDIT:
According to these links (link, link), it seems to be that I cannot send the same request twice. But I need to re-send the same request but with different authentication header. How can I achieve that?
Ok, after struggling with this for a long time, I ended up doing this:
public override IAsyncOperationWithProgress<HttpResponseMessage, HttpProgress> SendRequestAsync(HttpRequestMessage request)
{
return AsyncInfo.Run<HttpResponseMessage, HttpProgress>(async (cancellationToken, progress) =>
{
var retry = true;
if (TokenManager.TokenExists)
{
var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
if (now > TokenManager.Token.ExpiresOn)
{
retry = false;
await RefreshTokenAsync();
}
request.Headers.Authorization = new HttpCredentialsHeaderValue(TokenManager.Token.TokenType, TokenManager.Token.AccessToken);
}
HttpResponseMessage response = await InnerFilter.SendRequestAsync(request).AsTask(cancellationToken, progress);
cancellationToken.ThrowIfCancellationRequested();
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
var authHeader = response.Headers.WwwAuthenticate.SingleOrDefault(x => x.Scheme == "Bearer");
if (authHeader != null)
{
var challenge = ParseChallenge(authHeader.Parameters);
if (challenge.Error == "token_expired" && retry)
{
var secondRequest = request.Clone();
var success = await RefreshTokenAsync();
if (success)
{
secondRequest.Headers.Authorization = new HttpCredentialsHeaderValue(TokenManager.Token.TokenType, TokenManager.Token.AccessToken);
response = await InnerFilter.SendRequestAsync(secondRequest).AsTask(cancellationToken, progress);
}
}
}
}
return response;
});
}
public static HttpRequestMessage Clone(this HttpRequestMessage request)
{
var clone = new HttpRequestMessage(request.Method, request.RequestUri)
{
Content = request.Content
};
foreach (KeyValuePair<string, object> prop in request.Properties.ToList())
{
clone.Properties.Add(prop);
}
foreach (KeyValuePair<string, string> header in request.Headers.ToList())
{
clone.Headers.Add(header.Key, header.Value);
}
return clone;
}
Because I needed to re-send the request, I made a second request cloning the first one.

HttpClient.SendAsync doesn't use DelegatingHandler when testing

We have a few classes in our C# project that make calls out to 3rd party APIs. We're using HttpClient objects for the calls. We've set up our classes where we do these calls to accept an HttpClient so that when testing, we can use a custom/fake DelegatingHandler with the client.
We've set up our classes like this:
public class CallingService : ApiService
{
private readonly ISomeOtherService _someOtherService;
public CallingService (ILogger logger,
IConfigurationManager configurationManager,
ISomeOtherService someOtherService) : base(logger, configurationManager)
{
_someOtherService = someOtherService;
}
public CallingService (ILogger logger,
HttpClient client,
IConfigurationManager configurationManager,
ISomeOtherService someOtherService) : base(logger, configurationManager, client)
{
_someOtherService = someOtherService;
}
private async Task<XmlNodeList> TransmitToApi(string xml_string)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12;
//..
string type = "application/xml";
var content = new StreamContent(new MemoryStream(Encoding.ASCII.GetBytes(xml_string)));
var targetUri = new Uri(ConfigurationManager.GetAppSetting("ApiUrl"));
var message = new HttpRequestMessage
{
RequestUri = targetUri ,
Method = HttpMethod.Post,
Content = content
};
message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
message.Content.Headers.Add("Content-Type", type);
message.Headers.Add("someHeader", someData);
HttpResponseMessage response = null;
try
{
// Define the cancellation token.
CancellationTokenSource source = new CancellationTokenSource();
CancellationToken token = source.Token;
response = await Client.SendAsync(message, token);
}
catch (Exception ex)
{
throw ex;
}
//...
return someData;
}
The base ApiService class defines a generic HttpClient object if one is not provided.
We're currently using SendAsync so we can define the message headers. (We have more headers than are listed here.)
The test defines the DelegatingHandler like this:
public class FakeResponseHandler : DelegatingHandler
{
private readonly Dictionary<Uri, HttpResponseMessage> _fakeResponses = new Dictionary<Uri, HttpResponseMessage>();
public void AddFakeResponse(Uri uri, HttpResponseMessage responseMessage, string content = "", bool asXml = false)
{
if (!string.IsNullOrWhiteSpace(content))
{
if (asXml)
{
responseMessage.Content = new StringContent(content, Encoding.UTF8, "application/xml");
}
else
{
responseMessage.Content = new StringContent(content, Encoding.UTF8, "application/json");
}
}
_fakeResponses.Add(uri, responseMessage);
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (_fakeResponses.ContainsKey(request.RequestUri))
{
return _fakeResponses[request.RequestUri];
}
return new HttpResponseMessage(HttpStatusCode.NotFound) { RequestMessage = request };
}
}
And then:
[Fact]
public async Task ItWillDoStuffAndCallApi()
{
using (var mock = AutoMock.GetLoose())
{
mock.Mock<IConfigurationManager>()
.Setup(cm => cm.GetAppSetting("ApiUrl"))
.Returns("http://example.org/test/");
string testReturnData = GetFileContents("IntegrationTests.SampleData.SampleApiResponseXML.txt");
FakeResponseHandler fakeResponseHandler = new FakeResponseHandler();
fakeResponseHandler.AddFakeResponse(new Uri("http://example.org/test/"),
new HttpResponseMessage(HttpStatusCode.OK),
testReturnData,
true);
//HttpClient httpClient = new HttpClient(fakeResponseHandler);
HttpClient httpClient = HttpClientFactory.Create(fakeResponseHandler);
mock.Provide(httpClient);
var ourService = new CallingService();
ourService.TransmitToApi(someXmlString);
}
}
When we run the test, we receive the message:
Handler did not return a response message.
And we never seem to get into DelegatingHandler.SendAsync method.
We have other classes calling APIs using HttpClient.PostAsync or GetAsync, and these do call the DelegatingHandler.SendAsync method and work as expected.
We've tried:
HttpClient httpClient = new HttpClient(fakeResponseHandler);
and
HttpClient httpClient = HttpClientFactory.Create(fakeResponseHandler);
We've also tried Client.SendAsync with and without the cancellation token.
Why is this not working?
Should we re-write this to use PostAsync?
I'd need to see the implementation of HttpClientFactory.Create and what Client.SendAsync actually does internally but nevertheless I was able to use the sample code you provide and fill in the blanks where I could to get the following to work:
public class FakeResponseHandler : DelegatingHandler
{
private readonly Dictionary<Uri, HttpResponseMessage> _fakeResponses = new Dictionary<Uri, HttpResponseMessage>();
public void AddFakeResponse(Uri uri, HttpResponseMessage responseMessage, string content = "", bool asXml = false)
{
if (!string.IsNullOrWhiteSpace(content))
{
if (asXml)
{
responseMessage.Content = new StringContent(content, Encoding.UTF8, "application/xml");
}
else
{
responseMessage.Content = new StringContent(content, Encoding.UTF8, "application/json");
}
}
_fakeResponses.Add(uri, responseMessage);
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var emptyContent = string.Empty;
if (request.Content.Headers.ContentType.MediaType == "application/xml")
emptyContent = "<empty />";
return Task.FromResult(_fakeResponses.ContainsKey(request.RequestUri) ?
_fakeResponses[request.RequestUri] :
new HttpResponseMessage(HttpStatusCode.NotFound)
{
RequestMessage = request,
Content = new StringContent(emptyContent)
});
}
}
Just to make things clean use Task.FromResult to return a task in SendAsync and also provide an empty content to avoid null reference exceptions.
public class CallingService
{
private readonly HttpClient _httpClient;
private readonly IConfigurationManager _configurationManager;
public CallingService(HttpClient httpClient,
IConfigurationManager configurationManager)
{
_httpClient = httpClient;
_configurationManager = configurationManager;
}
public async Task<XmlNodeList> TransmitToApi(string xml_string)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12;
//..
string type = "application/xml";
var content = new StreamContent(new MemoryStream(Encoding.ASCII.GetBytes(xml_string)));
var targetUri = new Uri(_configurationManager.GetAppSetting("ApiUrl"));
var message = new HttpRequestMessage
{
RequestUri = targetUri,
Method = HttpMethod.Post,
Content = content
};
message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
message.Content.Headers.Add("Content-Type", type);
string somedata;
try
{
// Define the cancellation token.
CancellationTokenSource source = new CancellationTokenSource();
CancellationToken token = source.Token;
var response = await _httpClient.SendAsync(message, token);
somedata = await response.Content.ReadAsStringAsync();
}
catch (Exception ex)
{
throw ex;
}
//...
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(somedata);
return xmlDoc.SelectNodes("*");
}
}
And then the test passes the instance of HttpClient to CallingService:
[TestMethod]
public async Task TestMethod1()
{
const string content = #"<root><test>1243</test></root>";
const string httpExample = "http://example.org/test/";
var configurationManager = new Mock<IConfigurationManager>();
configurationManager
.Setup(cm => cm.GetAppSetting("ApiUrl"))
.Returns(httpExample);
var fakeResponseHandler = new FakeResponseHandler();
fakeResponseHandler.AddFakeResponse(new Uri(httpExample),
new HttpResponseMessage(HttpStatusCode.OK), content, true);
using (var httpClient = new HttpClient(fakeResponseHandler))
{
var ourService = new CallingService(httpClient, configurationManager.Object);
var result = await ourService.TransmitToApi(content);
Assert.AreEqual(content, result.Item(0)?.OuterXml);
}
}
This all works so if I had to guess - the issue would be somewhere in your HttpClientFacotry.
Hope that helps!! Cheers, :)

Categories

Resources