Я поддерживаю веб-API ASP.NET 2, работающий на .NET 4.6.1.
(Не упоминайте об окончании поддержки! Я много раз говорил им, чтобы они обновились. Горе моему несимпатичному боссу!!)
В этом приложении я думаю. использования HttpClient для доступа к другим веб-серверам.
Вот код, который я написал:
namespace myApps.Controllers.WebAPI
{
public class TempTestController : ApiController
{
private static HttpClient httpClient = new HttpClient();
[Route("AthorSiteContent")]
public IHttpActionResult getAthorSiteContent(string A_few_URLs)
{
var firstRequest = new System.Net.Http.HttpRequestMessage();
firstRequest.Method = System.Net.Http.HttpMethod.Head;
firstRequest.RequestUri = new Uri(A_few_URLs);
var firstResponse = httpClient.SendAsync(firstRequest).GetAwaiter().GetResult();
// check headers(host, status, Content-Type, Content-Length, etc...)
// If the content cannot be downloaded, the process ends here.
var secondRequest = new System.Net.Http.HttpRequestMessage();
secondRequest.Method = System.Net.Http.HttpMethod.Get;
secondRequest.RequestUri = new Uri(A_few_URLs);
var secondResponse = httpClient.SendAsync(secondRequest).GetAwaiter().GetResult();
var contentData = secondResponse.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult();
// Save contentData to a file
return new ResponseMessageResult(this.Request.CreateResponse(HttpStatusCode.NoContent));
}
}
}
Безопасен ли этот код? Не приведет ли это к исчерпанию сокетов?
Кроме того, я не использую HttpWebRequest, поскольку нашел информацию, которая
использование HttpWebRequest в ASP.NET может привести к исчерпанию сокетов.
обновление:
На основании полученного совета я изменил исходный код, добавив следующие функции:
- Удаление ненужных экземпляров и поддержка DNS обновления
- Используйте разные экземпляры HttpClient для каждого хоста
public class TempTestController : ApiController
{
//for multithreading
private static ConcurrentDictionary httpClientDics = new ConcurrentDictionary();
[Route("AthorSiteContent")]
public async Task getAthorSiteContent(string A_few_URLs)
{
//To delete unnecessary instances and deal with DNS updates.
var httpClientDicsKeys = new List(httpClientDics.Keys);
foreach (var key in httpClientDicsKeys)
{
if (httpClientDics[key].lastAccess < DateTime.Now.AddMinutes(-60))
{
httpClientDics[key].Dispose();
httpClientDics.TryRemove(key, out httpClientWrapper removeObject);
}
}
//Create an instance of HttpClient required to access BaseAddress if it does not already exist.
string baseAddress = httpClientWrapper.getBaseAddressFromURL(A_few_URLs);
if (!httpClientDicsKeys.Contains(baseAddress))
{
httpClientDics.TryAdd(baseAddress, new httpClientWrapper(A_few_URLs));
}
{
var firstRequest = new System.Net.Http.HttpRequestMessage();
firstRequest.Method = System.Net.Http.HttpMethod.Head;
firstRequest.RequestUri = new Uri(A_few_URLs);
var firstResponse = await httpClientDics[baseAddress].httpClient.SendAsync(firstRequest);
//check headers(host, status, Content-Type, Content-Length, etc...)
//If the content cannot be downloaded, the process ends here.
}
//If site cannot be accessed because DNS has been updated, lastAccess will not be changed.
httpClientDics[baseAddress].lastAccess = DateTime.Now;
{
var secondRequest = new System.Net.Http.HttpRequestMessage();
secondRequest.Method = System.Net.Http.HttpMethod.Get;
secondRequest.RequestUri = new Uri(A_few_URLs);
var secondResponse = await httpClientDics[baseAddress].httpClient.SendAsync(secondRequest);
var contentData = await secondResponse.Content.ReadAsByteArrayAsync();
//Save contentData to a file
}
return new ResponseMessageResult(this.Request.CreateResponse(HttpStatusCode.NoContent));
}
}
class httpClientWrapper : IDisposable
{
public HttpClient httpClient { get; set; }
public DateTime lastAccess { get; set; } = DateTime.Now;
public httpClientWrapper(string url)
{
this.httpClient = new HttpClient()
{
BaseAddress = new Uri(httpClientWrapper.getBaseAddressFromURL(url))
};
}
public static string getBaseAddressFromURL(string url)
{
var uri = new Uri(url);
return uri.GetLeftPart(UriPartial.Authority);
}
//Microsoft, this code is not COOL...
#region IDisposable Support
private bool disposedValue = false;
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
this.httpClient.Dispose();
}
this.httpClient = null;
disposedValue = true;
}
}
~httpClientWrapper()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
}
#endregion
}
Подробнее здесь: https://stackoverflow.com/questions/786 ... -web-api-2
Мобильная версия