К основному контенту

Сообщения

Сообщения за февраль, 2012

C# и API ВКонтакте. Обращение к адресу API-сервиса путем создания HTTP-запроса (POST)

В статье  C# POST. Отправляем запросы на адрес стороннего сервера  я рассказал про метод, с помощью которого можно работать с различным API, принимающими POST запрос и возвращающими ответ в виде json или xml. Сегодня я хочу написать, как я применял этот метод при работе с API  ВКонтакте. Для примера возьму задачу получения через API списка групп, в которых состоит пользователь. В первую очередь необходимо зарегистристрировать наш сайт как приложение ВКонтакте. Заходим по ссылке  http://vk.com/editapp?act=create&site=1  и подключаем наш сайт. Дальше задача  делится на две подзадачи, а именно: авторизация пользователя и обращение к API для получения списка групп. Для авторизации мы пользователю предлагаем перейти по следующей ссылке: http://api.vkontakte.ru/oauth/authorize? response_type=code&redirect_uri={0} &client_id={1} &scope={2} &display=page , redirect_uri - адрес страницы нашего сайта, куда будет возвращен пользователь после авторизации Вконтак

C# POST. Отправляем запросы на адрес стороннего сервера.

В ходе работы очень часто сталкиваюсь с различными внешними API, которые принимают на вход данные, отправленные через POST запрос, и возвращают результат в виде xml или json. Ниже привожу свой метод отправляющий данные на адрес стороннего сервера через POST: postedData - данные, отправляемые на сервер, postUrl - адрес, по которому мы обращаемся public static HttpWebResponse PostMethod(string postedData, string postUrl) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(postUrl); request.Method = "POST"; request.Credentials = CredentialCache.DefaultCredentials; UTF8Encoding encoding = new UTF8Encoding(); var bytes = encoding.GetBytes(postedData); request.ContentType = "application/x-www-form-urlencoded"; request.ContentLength = bytes.Length; using (var newStream = request.GetRequestStream()) { newStream.Write(bytes, 0, bytes.Length); newStream.Close(); } return (HttpWebResponse)request.GetResponse(); } Метод возвращает ответ

Зависимость кеша от изменений в базе данных. CacheDependency на примере нашего проекта.

В предыдущей записи в блоге  я писал, что в  своем проекте мы используем CacheDependency для  динамического обновления кеша в зависимости от изменений в базе данных. Теперь пишу об этом более подробно. Итак, CacheDependency позволяет нам устанавливать зависимость между объектом в кеше и строкой в базе данных. Как только строка меняется, обнуляется кеш, идет новый запрос в базу, а в кеш записывается новое значение.Таким образом, мы имеем всегда актуальные данные. При этом данные закешированы, и обновляются только при необходимости. Так как в своем проекте мы используем SQL Server 2008, то для мониторинга изменений мы будем использовать Service Broker. Включается он в базе следующим образом: ALTER DATABASE [База данных] SET ENABLE_BROKER Тут есть одна сложность. Включить брокер можно только в том случае, если база находится в режиме SINGLE_USER. То есть для рабочего проекта придется отключать пользователей. Следующим шагом является программное создание зависимостей кеша.

Выполнение метода асинхронно в отдельном потоке в MVC. BackgroundWorker и Thread.

В своем проекте используем CacheDependency для динамического обновления кеша в зависимости от изменений в базе данных. При первом запуске устанавливаются зависимости: объект в кеше  - строка в базе данных. Если значения в строке таблицы базы данных меняются, то меняется кеш сбрасывается и данные запрашиваются для данной строки повторно. В работе возникла следующая проблема. Если объектов > 500, то первый запуск выполняется долго. Как оказалось, установка зависимостей для каждого объекта со строками базы данных занимает большое количество времени (10-ки секунд), так как для каждого объекта выполняется запрос в базу данных по ключу. А чем больше объектов, тем больше запросов. Чтобы решить эту проблему, я предложил записывать объекты в кеш асинхронно в отдельном потоке. Алгоритм следующий: считываем объекты из базы, отображаем их пользователям и параллельно запускаем процесс записи объектов в кеш. Пользователь видит данные сразу и не ждет пока они добавятся в кеш. Сначала мы хот

Отображение сustomErrors страниц в случае ошибок 400, 404, 500 в MVC

В одном из предыдущих постов я писал о том, как фиксировать ошибки в MVC Сегодня я расскажу как отображать user friendly страницы, если возникли ошибки 400, 404, 500 или любые другие страницы ошибок. Предыстория вопроса. В asp.net данный вопрос решался просто. Достаточно было в файле web.config указать секцию: <customErrors defaultRedirect="~/500.aspx" mode="RemoteOnly"> <error redirect="404.aspx" statusСode="404"/> <error redirect="500.aspx" statusСode="500"/> </customErrors > Либо прописать страницы для отображения ошибок в IIS. В случае с MVC дело обстоит иначе. Так как MVC использует свою схему для маршрутизации, то для подключения страниц отображения ошибок нужно сделать следующее. Во-первых, создадим контроллер, который будет отвечать за отображение наших ошибок пользователю. public class ErrorController : Controller { //id - код ошибки  public ActionResult StatusCode(int id

Событие Page_PreInit в разрезе MasterPage

Страница  asp.net  во время выполнения проходит так называемый жизненный цикл, который состоит из различных событий. Первое из событий в жизненном цикле является событие PreInit. Если мы хотим, чтобы часть кода выполнялась на странице раньше других блоков перед инициализацией элементов на странице, то этот код необходимо поместить в конструкцию: protected void Page_PreInit(object sender, EventArgs e) { //Наш код } Это верно для одной страницы asp.net. А если мы хотим дублировать это событие для всех страниц нашего сайта? Писать для каждой страницы данный код? Не наш метод=) Посмотрим, есть ли решение. Первое, что пришло в голову - это добавить наш Page_PreInit в MasterPage (шаблон для всех страниц сайта), но, как оказалось, в классе MasterPage нет поддержки  метода Page_PreInit и, соответственно, написать Page_PreInit в MasterPage мы не можем. Решение было следующим: В папке App_Code был создан файл BasePage.cs со следующим кодом: //класс BasePage, наследуется от класса

Ошибка авторизации TFS после добавления библиотек через NuGet.

Ошибка, с которой я столкнулся, скорее всего возможна только в корпоративной сети, где политики безопасности устанавливаются администратором. После подключения к проекту библиотек через NuGet в VisualStudio 2010, отключался доступ к TFS (система контроля версий). При попытке работы с TFS после подключения библиотек появлялась следующая ошибка: TF30063: You are not authorized to access [TfsServer].The remote server returned an error: (401) Unauthorized. Самым простым решением был перезапуск VS, но со временем эта ошибка стала раздражать все больше и больше. Оказалось, что во всем виноват наш любимый InternetExplorer. Корпоративные политики безопасности каким-то образом ограничивали доступ к TFS. Решение как всегда было очень простым: Добавить адрес TFS-сервера в список доверенных узлов в настройках безопасности InternetExplorer. После совершения данного действия ошибка более не появлялась.

Изменение размера картинок на c#. Проблемы с качеством итогового изображения.

Сегодня расскажу о схеме работы с картинками, которая используется сейчас у меня на работе. Картинки хранятся в базе в максимальном разрешении. Для вывода на сайте картинка  в зависимости от страницы или блока сжимается до нужного в пикселях размера. Размер пикселей передается в параметрах запроса. На итоговое изображение накладывается watermark, затем картинка кешируется и при повторном обращении уже берется из кеша. В момент отправки клиенту картинке присваивается уникальный Etag и параметры кеширования в браузере. То есть при повторном обращении браузер уже не запрашивает картинку, а берет из дискового кеша. Недавно мы столкнулись с такой проблемой: при изменении gif картинки, качество ее заметно ухудшалось и те решения, которые успешно работали c jpeg, с gif картинками не давали результатов. Решение оказалось достаточно простым. После изменения размера для gif картинок нужно устанавливать: ImageFormat  format = ImageFormat.Png; context.Response.ContentType = "image/pn

CLR процедуры. Проблемой с XML-сериализацией.

Работая с CLR процедурами столкнулся со следующей проблемой: при попытке сериализовать в объект ответ от Web-сервиса с помощью XmlSerializer я получал следующую ошибку на SQL-сервере: Cannot load dynamically generated serialization assembly. Как оказалось, для CLR процедуры, использующей Xml-сериализацию, необходимо создавать отдельную сборку сериализации и загружать эту сборку в SQL-сервер. Чтобы создать сборку сериализации, нужно выполнить следующие шаги: 1. В VS выполнить Build проекта, в котором мы создаем  CLR процедуры. 2. С помощью приложения sgen.exe  создать сборку сериализации. Для этого выполнить в командной строке следующий код: [Путь до приложения  sgen.exe]>sgen.exe /force [Путь до проекта с  CLR процедурами] / SqlServerProject.dll В моем случае: [Путь до приложения  sgen.exe] == C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin; SqlServerProject.dll - это имя сборки моего проекта с CLR процедурами. В папке со сборкой проекта появ

Моя первая CLR процедура

Недавно мне пришлось решать следующую задачу: объединить данные, полученные из Web API с результатами sql запроса, а готовый результирующий сет использовать в sql-процедуре. Для решения этой задачи я обратился к CLR процедурам. CLR процедуры - это хранимые  процедуры, выполняемые на SQL-сервере, но написанные на языке C#. CLR процедуры компилируются в отдельную dll и добавляются в SQL-сервер. Чтобы написать свою первую CLR процедуру, я создал новый проект и назвал его SqlServerProject. В качестве шаблона выбрал CLR Database Project. При создании проекта появилось диалоговое окно с просьбой привязать базу данных. Я указал базу данных, где планировал разворачивать CLR процедуру. Для CLR процедуры необходимо указать уровень доступа. Существует три варианта доступа: Safe, External, Unsafe. Подробное об ограничениях доступа можно почитать здесь.  Для своего проекта я выбрал External, так как для моей процедуры требуется доступ в интернет. В проекте я создал файл с именем St

Оптимизация контента. Сжатие и объединение файлов css и js с помощью библиотеки Combres. Часть II.

Сегодня в продолжение темы про оптимизацию пишу про библиотеку Combres. Итак, Combres  - это библиотека для объединения файлов стилей и скриптов, и сжатия итогового файла. Подключается эта библиотека через менеджер NuGet: После добавления библиотеки в файле web.config появятся необходимые ссылки на библиотеку. А в папке  App_Data появится файл combres.xml  В этом файле и происходят все необходимые настройки. Ниже приведу пример файла: <? xml   version = " 1.0 "   encoding = " utf-8 "  ?> < combres   xmlns = ' urn:combres ' >     < filters >         < filter   type = " Combres.Filters.FixUrlsInCssFilter, Combres "  />     </ filters >     < resourceSets   url = " ~/combres.axd "                    defaultDuration = " 30 "                    defaultVersion = " auto "                    defaultDebugEnabled = " false "                    defaultIgnorePipelineWhe

Оптимизация контента. Сжатие и объединение файлов css и js с помощью библиотеки Combres. Часть I.

Итак, сегодня поговорим об оптимизации пользовательского контента.  Если вы хотите сделать легковесный сайт, который будет мгоновенно  загружаться в браузере пользователя, то придется выполнить немало пунктов. Некоторые из них я перечислю ниже: Сжатие пользовательского контента. Согласитесь, передать по сети 10 Кб намного быстрее чем 50Кб. Сжатые файлы обрабатывает браузер на стороне пользователя. Самый распространенный способ для сжатия контента -  Gzip.  Gzip поддерживает большинство браузеров, но не все (сразу вспоминается наш любимый ie 6). Подключить сжатие можно разными способами. Напишу об этом отдельно.   Объединение мелких файлов в один большой. Это относится как к файлам стилей, скриптов, так  и к картинкам. Браузер загружает файлы в несколько потоков, но если файлов много, то пока не загрузится первая часть и не освободятся новые потоки, следующие файлы загружены не будут. Плюс нужно учесть время на открытие и закрытие нового соединения и т.п. мелочи. Так вот для объе