Постепенно, с изучением C# и .NET Framework, я начал писать различные Helper'ы, которые скрывали рутинный код за вызовом всего одного метода. После, это переросло в разработку полноценной библиотеки, которую я хочу вам представить. Данная библиотека написана полностью 'с нуля'.
Так что же такое xNet?
xNet — это библиотека классов для .NET Framework, которая включает в себя:
- Классы для работы с прокси-серверами: HTTP, Socks4(a), Socks5.
- Классы для работы с HTTP 1.0/1.1 протоколом: keep-alive, gzip, deflate, chunked, SSL, прокси и другое.
- Классы для работы с многопоточностью: многопоточный обход коллекции, асинхронные события и другое.
- Классы помощники, расширяющие возможности стандартных классов .NET Framework: FileHelper, DirectoryHelper, StringHelper, XmlHelper, BitHelper и другие.
Скачать библиотеку и документацию можно [ЗДЕСЬ]
В данной статье я напишу о работе только с сетевой частью библиотеки, так как она самая обширная и интересная. Перед прочтением, вы должны знать, что из себя представляет HTTP-протокол. Если вы этого не знаете, то обратитесь к списку ссылок в конце статьи.
Основа работы с HTTP-протоколом
Для отправки запросов используется класс HttpRequest. В нём можно устанавливать различные настройки: заголовки, время ожидания, нужно ли следовать переадресации, следует ли держать постоянное соединение и другие. Когда вы отправляете запрос, то он сначала принимает заголовки ответа с помощью объекта класса HttpResponse, а после возвращает ссылку на этот объект, чтобы вы могли загрузить тело сообщения. Загрузить тело сообщения можно с помощью одного из специальных методов.
Пример запроса:
using (var request = new HttpRequest())
{
// Отправляем запрос.
HttpResponse response = request.Get("habrahabr.ru");
// Принимаем тело сообщения в виде текста.
string content = response.ToText();
}
Оператор using используется для того, чтобы закрыть соединение с сервером, то есть, вызвать метод IDisposable.Dispose.
Получить ссылку на HttpResponse можно также с помощью свойства HttpRequest.Response.
Отправка простых запросов и загрузка тела сообщения
HttpRequest поддерживает 3 вида запросов: Get, Head и Post.
Пример GET-запроса:
using (var request = new HttpRequest())
{
var reqParams = new StringDictionary();
reqParams["param1"] = "val1";
reqParams["param2"] = "val2";
string content = request.Get("habrahabr.ru", reqParams).ToText();
}
Объект класса StringDictionary используется для передачи параметров запроса. В данном случае, это равносильно следующей записи:
Get("habrahabr.ru/?param1=val1¶m2=val2")
Пример POST-запроса:
using (var request = new HttpRequest())
{
var reqParams = new StringDictionary();
reqParams["login"] = "neo";
reqParams["password"] = "knockknock";
string content = request.Post(
"www.whitehouse.gov", reqParams).ToText();
}
Установить параметры POST-запроса можно четырьмя способами: с помощью объекта класса StringDictionary, с помощью обычной строки, с помощью массива байтов или с помощью объекта класса MultipartDataCollection.
Все параметры запроса автоматически кодируются для надёжной передачи HTTP-серверу. Но это не относится к параметрам POST-методов, отправляющих: string, byte[] и MultipartDataCollection. С помощью свойства HttpRequest.EnableAutoUrlEncode можно отключить автоматическое кодирование параметров POST-запросов.
Для загрузки тела сообщения, можно использовать один из трёх методов: ToText, ToBytes или ToFile. Если тело сообщения не нужно, то следует вызвать метод None.
Отправка Multipart/form данных
О Multipart/form данных. Для работы с ними используются два класса: класс MultipartDataElement представляет элемент Multipart данных, а класс MultipartDataCollection хранит эти элементы. В классе MultipartDataCollection есть уже заранее заготовленные методы, которые самостоятельно создают объекты класса MultipartDataElement и добавляют их в коллекцию.
Пример:
using (var request = new HttpRequest())
{
var multipartData = new MultipartDataCollection();
multipartData.AddData("login", "Bill Gates");
multipartData.AddData("password", "qwerthahaha");
multipartData.AddDataFile("file1", @"C:windows_9_alpha.rar", true);
string content = request.Post(
"www.microsoft.com", multipartData).ToText();
}
В одном из методов AddDataFile, есть параметр doPreLoading, который указывает, нужно ли использовать предварительную загрузку файла. Если использовать предварительную загрузку файла, то файл будет сразу загружен в память. Если файл имеет большой размер, либо нет необходимости, чтобы файл находился в памяти, то не используйте предварительную загрузку. В этом случае, файл будет загружаться блоками во время записи в поток.
Постоянные соединения
HttpRequest поддерживает постоянные соединения. Их можно отключить с помощью свойства HttpRequest.KeepAlive.
Пример:
using (var request = new HttpRequest())
{
request.Get("habrahabr.ru").None();
request.Get("habrahabr.ru").None();
request.Get("habrahabr.ru");
}
Все три запроса будут выполнены с помощью одного и того же соединения, но это только в том случае, если сервер не закроет соединение раньше. Обратите внимание — в последнем запросе я не вызываю метод None. Дело в том, что он загружает тело сообщения, чтобы следующий запрос мог корректно выполниться при использовании постоянного соединения, а так как это последний запрос, то не имеет смысла загружать тело сообщения, ведь соединение все равно будет закрыто.
Ещё немного о методе None. В случае если постоянное соединение не используется, то данный метод просто закрывает соединение. Если вы не вызовете данный метод, то он будет вызван автоматически при следующем запросе. Я рекомендую самим вызывать данный метод.
Имейте в виду, при работе с постоянными соединениями могут происходить отключения от сервера. Это может произойти по причине того, что на сервере достигнут предел запросов для одного соединения, либо вышло время ожидания следующего запроса. HttpRequest умеет обрабатывать такие ситуации, пробуя подключиться заново. Если подключиться не удастся, то он выдаст исключение.
Установка дополнительных заголовков и кукиксов
Установка дополнительных заголовков выполняется с помощью специального индексатора. Имейте в виду, некоторые заголовки можно задавать только с помощью специальных свойств. Их список можно найти в документации. Кукиксы задаются с помощью свойства HttpRequest.Cookies.
Пример:
using (var request = new HttpRequest())
{
request.Cookies = new CookieDictionary();
request.Cookies["hash"] = "yrttsumi";
request["X-Secret-Param1"] = "UFO";
request["X-Secret-Param2"] = "42";
request.Get("habrahabr.ru");
}
Список кукиксов может изменяться в зависимости от ответа сервера. Чтобы не допустить этого, нужно установить значение свойства CookieDictionary.IsLocked равным true.
Если вам нужно стереть все установленные заголовки, то используйте метод HttpRequest.ClearAllHeaders.
Соединение через прокси-сервер
xNet поддерживает работу со следующими типами прокси-серверов:
- HTTP — класс HttpProxyClient
- Socks4(a) — класс Socks4ProxyClient(a)
- Socks5 — класс Socks5ProxyClient
Все эти классы наследуют от класса ProxyClient.
Пример:
var proxyClient = HttpProxyClient.Parse("127.0.0.1:8080");
var tcpClient = proxyClient.CreateConnection("habrahabr.ru", 80);
// Далее работаем с соединением.
HttpRequest поддерживает работу через прокси-сервер. Для этого нужно задать свойство HttpRequest.Proxy.
Обработка ошибок
Если при работе с HTTP-протоколом произойдёт ошибка, то будет сгенерировано исключение HttpException, а если произойдёт ошибка при работе с прокси-сервером, то будет сгенерировано исключение ProxyException. Оба этих исключения наследуют от класса NetException.
Пример:
try
{
using (var request = new HttpRequest())
{
request.Proxy = Socks5ProxyClient.Parse("127.0.0.1:1080");
request.Get("habrahabr.ru");
}
}
catch (NetException ex)
{
Console.WriteLine(
"Произошла сетевая ошибка: " + ex.Message);
}
Дополнительные классы и интерфейсы
Класс HttpClient позволяет выполнять запросы с помощью вызова одного метода. При его использовании, автоматически задаётся случайный UserAgent и отключается постоянное соединение.
Класс HttpHelper предназначен для помощи в работе с HTTP-протоколом. У него есть несколько методов и все они предназначены для генерирования случайного UserAgent.
Класс ProxyHelper предназначен для помощи в работе с прокси. Там всего один метод, помогающий создавать прокси-клиент с нужными параметрами.
Класс WinInet позволяет взаимодействовать с настройками сети операционной системы Windows. С помощью него можно узнать, подключён ли компьютер к интернету или получить значение прокси-сервера Internet Explorer'а.
Класс HtmlHelper предназначен для помощи в работе с HTML. Пока там один метод, который заменяет в тексте HTML-сущности на представляющие их символы. Пример: &_quot;test&_quot; в «test»
Весьма простой интерфейс IHttpConnect, который содержит всего одно свойство — Request. Он может пригодиться в случае, если, допустим, класс использует HttpRequest для работы с HTTP-протоколом. Так как HttpRequest может содержать постоянное соединение и различные настройки, то его нужно будет постоянно передавать через параметры метода, что не очень удобно. Лучше всего для этого реализовать данный интерфейс и задать Request один раз через специальное свойство.
Ссылки на материалы по теме
Автор: EpicMan