xNet — C# библиотека для работы с Web

Постепенно, с изучением C# и .NET Framework, я начал писать различные Helper'ы, которые скрывали рутинный код за вызовом всего одного метода. После это переросло в разработку полноценной библиотеки, которую я хочу вам представить. Данная библиотека написана полностью 'с нуля'.

Так что же такое xNet?


xNet — это библиотека классов для .NET Framework, которая включает в себя:
  • Классы для работы с прокси-серверами: HTTP, Socks4(a), Socks5, Chain.
  • Классы для работы с HTTP 1.0/1.1 протоколом: keep-alive, gzip, deflate, chunked, SSL, прокси и другое.


Скачать: releases
Исходники: github.com/X-rus/xNet

Статья была значительно переписана в связи с выходом новой версии библиотеки. Последнее обновление 12.09.2015

Основы


Для отправки запросов используется HttpRequest. В нём можно задать различные настройки: заголовки, время ожидания, нужно ли следовать переадресации, следует ли держать постоянное соединение и другие. Когда вы отправляете запрос, то он сначала принимает заголовки ответа с помощью HttpResponse, а после возвращает ссылку на этот объект, чтобы вы могли загрузить тело сообщения. Загрузить тело сообщения можно с помощью одного из специальных методов.

Пример запроса:
using (var request = new HttpRequest())
{
    request.UserAgent = Http.ChromeUserAgent();

    // Отправляем запрос.
    HttpResponse response = request.Get("habrahabr.ru");
    // Принимаем тело сообщения в виде строки.
    string content = response.ToString();
}

Оператор using используется для закрытия соединения с сервером. Тоже самое можно сделать вызвав метод HttpRequest.Close.

Получить ссылку на HttpResponse можно также с помощью свойства HttpRequest.Response. Возвращаемый HttpResponse не является уникальным. Для каждого HttpRequest существует только один HttpResponse (он используется повторно при каждом запросе).

Вот так выглядит данный запрос
GET / HTTP/1.1
Host: habrahabr.ru
Connection: keep-alive
Accept-Encoding: gzip,deflate
User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/24.0.1309.0 Safari/537.17


Отправка простых запросов и загрузка тела сообщения


Пример GET-запроса:
using (var request = new HttpRequest())
{
    var urlParams = new RequestParams();

    urlParams["param1"] = "val1";
    urlParams["param2"] = "val2";

    string content = request.Get("habrahabr.ru", urlParams).ToString();
}

RequestParams используется для установки параметров URL-адреса. В данном случае, это равносильно следующей записи:
Get("habrahabr.ru/?param1=val1&param2=val2")


Задать параметры URL-адреса можно с помощью метода HttpRequest.AddUrlParam. Эти параметры будут стёрты после первого же запроса.

Пример GET-запроса с временными параметрами URL-адреса:
using (var request = new HttpRequest())
{
    request.AddUrlParam("param1", "val1").AddUrlParam("param2", "val2");

    string content = request.Get("habrahabr.ru").ToString();
}


Пример POST-запроса:
using (var request = new HttpRequest())
{
    var reqParams = new RequestParams();

    reqParams["login"] = "neo";
    reqParams["password"] = "knockknock";

    string content = request.Post(
        "www.whitehouse.gov", reqParams).ToString();
}


Задать параметры запроса можно с помощью HttpRequest.AddParam. Эти параметры будут стёрты после первого же запроса.

Пример POST-запроса с временными параметрами:
using (var request = new HttpRequest())
{
    request.AddParam("login", "neo").AddParam("password", "knockknock");

    string content = request.Post("www.whitehouse.gov").ToString();
}


Также вы можете отправить строку, массив байтов, файл или любой объект наследующий от HttpContent.

Для загрузки тела сообщения используется один из пяти методов HttpResponse: ToString, ToBytes, ToFile, ToStream или ToMemoryStream. Если тело сообщения не нужно, то следует вызвать метод None.

Если вы хотите, чтобы параметры запроса кодировались, допустим, в 1251 кодировке, то нужно задать свойство HttpRequest.CharacterSet = Encoding.GetEncoding(1251)

Отправка Multipart/form данных


О Multipart/form данных. Для работы с ними используется класс MultipartContent.

Пример Multipart/form запроса:
using (var request = new HttpRequest())
{
    var multipartContent = new MultipartContent()
    {
        {new StringContent("Bill Gates"), "login"},
        {new StringContent("qwerthahaha"), "password"},
        {new FileContent(@"C:\windows_9_alpha.rar"), "file1", "1.rar"}
    };

    request.Post("www.microsoft.com", multipartContent).None();
}


Чтобы не создавать самим объект класса MultipartContent, можно использовать два специальных метода HttpRequest: AddField и AddFile. Эти параметры будут стёрты после первого же запроса.

Пример Multipart/form запроса с временными параметрами:
using (var request = new HttpRequest())
{
    request
        .AddField("login", "Bill Gates")
        .AddField("password", "qwerthahaha")
        .AddFile("file1", @"C:\windows_9_alpha.rar");

    request.Post("www.microsoft.com").None();
}


Постоянное соединение и переподключение


HttpRequest поддерживает постоянные соединения. Их можно отключить при помощи свойства HttpRequest.KeepAlive.

Пример:
using (var request = new HttpRequest("habrahabr.ru"))
{
    request.Get("/").None();
    request.Get("/feed").None();
    request.Get("/feed/posts");
}

Все три запроса будут выполнены с помощью одного и того же соединения, но это только в том случае, если сервер не закроет соединение раньше. Обратите внимание — в последнем запросе я не вызываю метод None. Дело в том, что он загружает тело сообщения, чтобы следующий запрос мог корректно выполниться при использовании постоянного соединения, а так как это последний запрос, то можно не загружать тело сообщения, ведь соединение все равно будет закрыто.

Ещё немного о методе None. В случае если постоянное соединение не используется, то данный метод просто закрывает соединение. Если вы не вызовете данный метод, то он будет вызван автоматически при следующем запросе. Я рекомендую самим вызывать данный метод.

Имейте в виду, при работе с постоянными соединениями могут происходить отключения от сервера. Это может произойти по причине того, что на сервере достигнут предел запросов для одного соединения, либо вышло время ожидания следующего запроса. HttpRequest умеет обрабатывать такие ситуации, пробуя подключиться заново (это поведение не связанно с Reconnect). Если подключиться не удастся, то он выдаст исключение. Для более тонкой настройки постоянных соединений можно использовать свойства KeepAliveTimeout и MaximumKeepAliveRequests.

Дополнительно вы можете управлять переподключениями при помощи свойств Reconnect, ReconnectLimit и ReconnectDelay. По умолчанию это поведение отключено. HttpRequest будет пробовать переподключиться в том случае, если произойдёт ошибка во время подключения к серверу, либо если произойдёт ошибка во время загрузки/отправки данных. Но переподключение не сработает, если ошибка произойдёт во время загрузки тела сообщения (в методе ToString(), например). Это поведение может пригодиться при работе с прокси или если у вас нестабильное соединение с интернетом.

Установка куки, заголовков и другого


Установка дополнительных заголовков выполняется с помощью специального индексатора. Имейте в виду, некоторые заголовки можно задавать только с помощью специальных свойств. Их список можно найти в документации. Заголовки заданные через индексатор отправляются во всех запросах. Если вам нужно установить временный заголовок для одного запроса, то используйте метод HttpRequest.AddHeader. Такие заголовки перекрывают заголовки заданные через индексатор.

Куки задаются с помощью свойства HttpRequest.Cookies. Куки могут изменяться в зависимости от ответа сервера. Чтобы не допустить этого, нужно установить значение свойства CookieDictionary.IsLocked равным true.

Пример:
using (var request = new HttpRequest("habrahabr.ru"))
{
    request.Cookies = new CookieDictionary()
    {
        {"hash", "yrttsumi"},
        {"super-hash", "df56ghd"}
    };

    request[HttpHeader.DNT] = "1";
    request["X-Secret-Param"] = "UFO";

    request.AddHeader("X-Tmp-Secret-Param", "42");
    request.AddHeader(HttpHeader.Referer, "http://site.com");

    request.Get("/");
}


У HttpRequest и у HttpResponse есть дополнительные методы для работы с куки и заголовками: ContainsHeader, EnumerateHeaders, ClearAllHeaders, ContainsCookie, ContainsRawCookie и другие.

Для отправки запросов нужно задать User-Agent. Его можно сгенерировать одним из методов Http: IEUserAgent, OperaUserAgent, ChromeUserAgent, FirefoxUserAgent или OperaMiniUserAgent.
И задать так:
request.UserAgent = Http.ChromeUserAgent();


Раньше существовал метод RandomUserAgent, но я его удалил, так как его использование может привести к некоторым проблемам. Допустим, сайт для Google Chrome выдаёт один контент, а для IE уже немного другой, или совсем другой. Поэтому, с осторожностью используйте User Agent'ты от различных браузеров.

У HttpRequest есть ещё много различных свойств, с помощью которых вы можете манипулировать отправляемыми заголовками. Смотрите документацию.

Соединение через прокси-сервер


xNet поддерживает работу со следующими типами прокси-серверов:
  • HTTP — класс HttpProxyClient
  • Socks4(a) — класс Socks4ProxyClient(a)
  • Socks5 — класс Socks5ProxyClient

Все эти классы наследуют от класса ProxyClient. Есть дополнительный класс ChainProxyClient, который позволяет создавать соединение через цепочку прокси-серверов.

Пример:
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 (HttpException ex)
{
    Console.WriteLine("Произошла ошибка при работе с HTTP-сервером: {0}", ex.Message);

    switch (ex.Status)
    {
        case HttpExceptionStatus.Other:
            Console.WriteLine("Неизвестная ошибка");
            break;

        case HttpExceptionStatus.ProtocolError:
            Console.WriteLine("Код состояния: {0}", (int)ex.HttpStatusCode);
            break;

        case HttpExceptionStatus.ConnectFailure:
            Console.WriteLine("Не удалось соединиться с HTTP-сервером.");
            break;

        case HttpExceptionStatus.SendFailure:
            Console.WriteLine("Не удалось отправить запрос HTTP-серверу.");
            break;

        case HttpExceptionStatus.ReceiveFailure:
            Console.WriteLine("Не удалось загрузить ответ от HTTP-сервера.");
            break;
    }
}


Дополнительные классы


Класс WinInet позволяет взаимодействовать с настройками сети операционной системы Windows. С помощью него можно узнать, подключён ли компьютер к интернету или получить значение прокси-сервера Internet Explorer'а.

Класс Html предназначен для помощи в работе с HTML и с другими текстовыми данными. В нём находится метод, который заменяет в тексте HTML-сущности на представляющие их символы. Пример: &_quot;test&_quot; в «test». Метод, который заменяет Unicode-сущности на представляющие их символы. Пример: \u2320 или \U044F. И методы для извлечения строк: Substring, LastSubstring, Substrings.

Ссылки по теме


Share post

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 42

    +2
    Как у вас с совместимостью с Mono? Или вопрос неуместен?
      +1
      Сложно сказать, ибо с Mono я не знаком. Если исключить класс WinInet, который вызывает функции WinAPI, то всё должно работать.
        +1
        А чего именно в .net не хватило что понадобился WinAPI?
          0
          Да, в общем-то, ничего особенного. Возможность узнать, подключён ли компьютер к интернету и возможность получить прокси-сервер IE.

          1. Можно попробовать самому подключиться к какому-нибудь ресурсу и узнать, есть ли подключение к интернету. Но я решил проще будет использовать именно WinAPI, да и это даёт побольше возможностей. Кто-то может предложить — NetworkInterface.GetIsNetworkAvailable, но это не то.

          2. В старых версиях я получал прокси IE так:
          WebRequest.DefaultWebProxy.GetProxy(new Uri("http://www.microsoft.com"))
          // Далее пару проверок.
          


          Мне этот способ не нравился и я использовал WinAPI, который, опять же, дал побольше возможностей.

          Когда я выложу исходники, можно будет от этого избавиться, если есть предложения.
      +3
      Хммм а почему бы вам не сделать отдельный репозиторий на гитхабе? К примеру я бы не стал использовать вашу библиотеку не посмотрев на реализацию того же HttpRequestа.
        0
        Посмотреть реализацию того или иного класса можно с помощью Reflector'а. А исходный код я могу потом выложить, если у кого-то будет желание его как-то развивать.
          +2
          Я бы не рискнул использовать подобную библиотеку без исходников в настоящем проекте. Если обнаружатся баги (а они наверняка обнаружатся), то возникнет очень неприятная зависимость от создателя библиотеки. Да и сами баги легче обнаружить, имея исходники.

          Поэтому, если вы действительно хотите поделиться своей библиотекой, то лучше выложить ее куда-нибудь (лучше на гитхаб или аналогичный сервис). Так и людям пользы будет и вы большую известность получите.
            +1
            Понимаете, в чём проблема. Вам не достаточно будет посмотреть исходники. Как вы определите, правильно ли я реализовал работу с HTTP-протоколом? Или с Socks5-протоколом? Вам для начала нужно будет проникнутся их описанием. После уже нужно будет изучить сам код, понять, почему я сделал или не сделал так. Это затратит слишком много времени, а библиотека для того и предназначена, чтобы ты её скачал и использовал, прочитав документацию.
              –1
              «Как вы определите, правильно ли я реализовал работу с HTTP-протоколом?»
              Элементарно. Посмотреть на ваши модульные тесты.
                +2
                А кто будет тестировать модульные тесты? Вдруг там неправильная проверка.
                0
                Я и не буду смотреть исходники, пока все будет работать как надо. А вот если что-то пойдет не так, то буду смотреть и отлаживать код.

                Если не хотите отдавать библиотеку в open source, то так и скажите. Я понимаю, что у вас могут быть другие планы, в этом нет ничего плохого. Но только не надо убеждать, что никому, кроме автора, исходники не нужны.
          +5
          Не знаю, насколько будет семантически правильно, но, может, стоит вместо ToText() использовать всем знакомый ToString()?
            +10
            Чем ваша библиотека лучше System.Net.Http?
              +3
              Я не работал с новой версией .NET, поэтому не могу объективно оценить, чем лучше/хуже. Первая версии библиотеки вышла ещё в начале 2011, когда этого не было.

              У меня есть поддержка Socks. В основном классе больше различных настроек. В общем, это всё, что я могу на данный момент привести в сравнение.
                +1
                Проблема в том, что анонсируете вы это сейчас, когда уже все есть. И зачем?
                  +3
                  Мне вот клиентскую часть пары сервисов приходится держать совместимой с .NET 2.0. Для поддержки того же LINQ приходится таскать за собой библиотечку, куда включены реализации нужных мне классов из Mono.
                    0
                    Такая ситуация (у меня кое-где была схожая) не отменяет того факта, что автор библиотеки должен понимать, что с переходом на такою-то версии фреймворка его библиотека теряет смысл.
                      0
                      LINQ кстати тянется на раз из .net35-ого… работает вполне себе.
                        0
                        А либы из дотнета разве лицензия позволяет распространять без установщика?
                      +1
                      Не всё: соксов нет, к сожалению.
                  +4
                  >>С помощью него можно узнать, подключён ли компьютер к интернету или получить значение прокси-сервера Internet Explorer'а.
                  Это можно получить и без api, через WebRequest.GetSystemWebProxy() и CredentialCache.DefaultCredentials;

                  >>Классы для работы с многопоточностью: многопоточный обход коллекции, асинхронные события и другое.
                  Все это есть в стандартном C# 4

                  Поэтому я присоединяюсь к вопросу lair: зачем нужна ваша библиотека и чем она лучше стандартных средств?
                    0
                    >> Это можно получить и без api, через WebRequest.GetSystemWebProxy() и CredentialCache.DefaultCredentials;
                    Мой класс завязан именно на моей библиотеки. Да и там его можно получить в виде строки, или задать.

                    >> Все это есть в стандартном C# 4
                    У меня другой принцип работы и больше возможностей.

                    Можете посмотреть документацию, там всё описано. Тогда, надеюсь, станет понятней.
                      0
                      У меня другой принцип работы и больше возможностей.

                      Например? Для многопоточного обхода коллекций.
                        0
                        Мой класс не использует пул потоков. Так что, его можно использовать в длительных операциях и устанавливать большое количество потоков.

                        В нём реализованы различные асинхронные события. Так что, его можно использовать в оконных приложениях.

                        [ЗДЕСЬ] можно узнать подробней и в документации.
                          +2
                          Мой класс не использует пул потоков.

                          В этом месте я хочу спросить три вещи.

                          Во-первых, знаете ли вы, что TPL позволяет использовать любой шедулер для задач, а не только на основе ThreadPool?
                          Во-вторых, что мешает использовать тредпул для длительных операций?
                          В-третьих, вы осознаете, какие накладные расходы возникают в вашей реализации? (если, конечно, вы не реализовали свой собственный пул потоков, а тогда в чем смысл)
                            0
                            Просто, насколько я знаю, ThreadPool используется другими классами для выполнения асинхронных операций. Да и он же предназначен для того, чтобы в нём можно было быстренько выполнить задачку и освободить поток. А если вам нужно выполнять несколько десятков длительных операций для, допустим, анализа данных, то будет нехорошо его забивать.

                            А что вы предлагаете? Как нужно его правильно реализовать? Или нужно его вообще удалить из библиотеки?
                              0
                              Просто, насколько я знаю, ThreadPool используется другими классами для выполнения асинхронных операций.

                              И что?

                              Да и он же предназначен для того, чтобы в нём можно было быстренько выполнить задачку и освободить поток.

                              Из чего вы делаете такие выводы?

                              А если вам нужно выполнять несколько десятков длительных операций для, допустим, анализа данных, то будет нехорошо его забивать.

                              И что в этом «нехорошего»? Не говоря уже о том, что не надо ставить (на обычном компьютере) несколько десятков длительных задач анализа данных, это не добавит производительности.

                              А что вы предлагаете? Как нужно его правильно реализовать? Или нужно его вообще удалить из библиотеки?

                              Я предлагаю пользоваться штатными средствами. TPL — прекрасная вещь, и писать свои велосипеды нужно только при наличии очень веских причин.

                              Я вам это говорю, помимо всего прочего, на основе собственного опыта, когда я сначала реализовал сложную многопоточную очередь для .net 3.5, а потом полностью ее выкинул в .net 4.
                        +2
                        >>Можете посмотреть документацию, там всё описано. Тогда, надеюсь, станет понятней.
                        Адекватного описания я у вас не нашел на сайте.

                        >>Мой класс завязан именно на моей библиотеке. Да и там его можно получить в виде строки, или задать.
                        В этом я не сомневаюсь, но объясните, зачем мне использовать вашу библиотеку, если я могу это сделать и без нее, тем более без прямого вызова системного апи, что еще и требует повышенных привилегий для приложения?

                        Что касается >>У меня другой принцип работы и больше возможностей. — сомневаюсь я что вы умнее целого Майкрасофт, а тем более вы говорите что не работали с новыми версиями платформы — как же вам знать что там меньше возможностей? А если даже и вы круче всего штата мелкомягких — ох уж я сомневаюсь что вы бы тогда брала фриланс заказы от 1000 рублей (пруф с вашего сайта).

                        Поймите, такие библиотеки имеют право жить, да я верю что они действительно помогают вам лично при решении задач когда вы клепаете ваши программы, но они совершенно не нужны обществу, ибо тот кто хочет решать подобные задачи и знает как это делать скорее всего сделает свою такую небольшую библиотеку, а чаще просто класс, а кто не умеет-не знает как — погуглит и найдет хотя бы более популярную сборку. Типовые задачи, которые вы обвернули можно решить не более затратно, но менее рискованно стандартными средствами .Net, а тащить закрытую чужую вилами писанную библиотеку (а не откажитесь ли вы завтра-послезавтра от ее поддержки и развития? что я тогда буду делать дальше?).
                          0
                          >> В этом я не сомневаюсь, но объясните, зачем мне использовать вашу библиотеку, если я могу это сделать и без нее, тем более без прямого вызова системного апи, что еще и требует повышенных привилегий для приложения?

                          Я не знаю, зачем вообще использовать библиотеку только для получения прокси-сервера IE. Это просто дополнительный класс для моей библиотеки, который упростит жизнь её пользователю.

                          >> сомневаюсь я что вы умнее целого Майкрасофт

                          Да и я не говорю, что умней их хоть они и своровали у меня идеи для .NET 4.5. У меня другой класс, для других целей. Да, он запускает задачу в потоках, но у него есть и другое. С ним можно работать в оконном приложение. Может кому пригодится, может нет.
                      0
                      Спасибо! То, что доктор прописал!
                        0
                        Автор, укажите, пожалуйста, по какой лицензии распространяется код? (нигде не нашёл)
                        И если можно, то, пожалуйста, сорц: без него многим будет юзать затруднительно. Потому что библиотека специфическая: большинство уже есть в .NET Framework и кому действительно надо переписывать реализацию хттп, тому определённо захочеттся что-либо дописать и тут.
                          0
                          Библиотека распространяется абсолютно свободно.

                          >> И если можно, то, пожалуйста, сорц
                          Хорошо, в ближайшем будущем залью на гитхаб.
                            0
                            Абсолютно свободно — это как? Укажите там, к примеру, CC0 (или BSD, или MIT), в таком случае.
                            Я к тому, что указать, что за лицензия — привычное дело, оно избавляет многих от кучи вопросов и непониманий (особенно когда будете выкладывать на гитхаб).
                            Если выложите — спасибо, возможно, пригодится.
                              0
                              New BSD License
                              Copyright © 2012, X-rus
                              All rights reserved.

                              Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

                              * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

                              * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

                              THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS «AS IS» AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                          0
                          Лично меня сразу напрягло обилие слов static и helper на диаграмме, а так же отсутствие интерфейсов. А вообще начинание хорошее, если отрефакторить и написать тесты.
                            +2
                            P.S. Для общего развития (начиная с .Net 1.1): WebClient, HttpRequest, HttpResponse. Да и вообще System.Net Namespace.

                            Правда, рекомендую ознакомиться с более свежими версиями.

                            P.P.S. Научиться программировать можно только программируя. Я бы рассматривал эту библиотеку как старт лично для автора, но ни в коем случае как нечто, что могут использовать другие люди.
                              0
                              P.P.S. Научиться программировать можно только программируя. Я бы рассматривал эту библиотеку как старт лично для автора, но ни в коем случае как нечто, что могут использовать другие люди.

                              Золотые слова!
                            –2
                            >> P.S. Для общего развития (начиная с .Net 1.1): WebClient, HttpRequest, HttpResponse. Да и вообще System.Net Namespace.

                            Спасибо, не знал о их существовании. Посмотрю на досуге.
                              0
                              Прошу прощения, не HttpRequest, HttpResponse, а HttpWebRequest, HttpWebResponse
                              0
                              Возможно ли интеграция с MVC платформой?
                                0
                                Моя сайт сделан на MVC платформе и там я использовал xNet (сетевую часть). Никаких проблем.
                                0
                                Хотелось бы видеть Вашу бибилиотеку в Nuget.

                                Only users with full accounts can post comments. Log in, please.