WebAPI: версионирование на основе HTTP-заголовков

Допустим, что для различных версий API существуют разные контроллеры
Если необходимо делать выбор контроллера на основании заголовка, то для этого предлагается определить свою имплементацию интерфейса IHttpControllerSelector в ServicesContainer

Какой именно HTTP-заголовок необходимо использовать особо не важно, будь то Accept, или свой, например - X-Version (я выбираю Accept, исключительно из любопытства)

Легче всего реализовать IHttpControllerSelector - создать наследника DefaultHttpControllerSelector:

Swagger: внедрение произвольных http-заголовков

Если при необходимости использования web api через swagger необходимо отправлять кастомные http-заголовки, то это можно сделать очень просто
  1. открываем SwaggerConfig
  2. ищем метод, переданный в EnableSwaggerUi
  3. вызываем InjectJavaScript у объекта, типа SwaggerUiConfig (передаётся в качестве первого аргумента обработчика)
  4. В качестве параметров необходимо передать :
    1. сборку, содержащую js в качестве рекурса
    2. название ресурса

Swagger: переадресация help page на swagger

Немного ранее было описано, как установить и использовать Swagger для использования в качестве автодокументации к Web API

Многие привыкли к адресу документации по адресу help/, но swagger отдаёт доку, конечно же, по своему адресу swagger/ui/index

Первое что приходит в голову - сделать свой собственный RedirectHandler, но в сборке Swashbuckle.Core уже таковой имелся :)

Собственно редиректим старую урлу на новую путём добавления следующего кода в метод Register класса SwaggerConfig


Теперь по обращении к help/ будет редирект на swagger/ui/index

Web API: автодокументация (Help Page / Swagger)

Иногда очень удобно вместе с API иметь страницу показывающую реализованные в данный момент интерфейсы/методы и модели

При создании Web API проекта из VS 2015 в настоящий момент предлагается ASP.NET Web API Help Page, и работает решение практически из коробки
Необходимо лишь решить - нужны ли комментарии к методам и свойствам моделей

Но в ASP .NET Web API Help Page есть существенные недостатки:
  • методы можно посмотреть, но нельзя вызвать тут же
  • для генерации моделей для PATCH требовались дополнительные телодвижения, например через метод SetSampleForType, а хочется всё же - большей гибкости (создал метод/модель - пользователи тут же могут её увидеть)
  • Когда бизнес-логика и модели отделены от Web API (собственно контракты/модели в одной библиотеке, а модели в другой, web api - в третьей) help pages не даёт возможности указать несколько XML-документов. Как следствие - необходимо их смёржить, а после - указывать базовый
  • Слишком много телодвижений (переходов меж страницами)
  • Нельзя указать список возвращаемых HTTP-кодов
т.е. получается вроде бы как результат есть, но что-то не то

Swagger же лишён всех этих недостатков
Проявил себя в самом лучшем виде и уже несколько месяцев после начальной настройки под себя - мы его боле не трогали (проект немного специфичный, необходимо иметь возможность отправлять кастомные http-заголовки).

Потому я и выбрал Swagger, успешно подсадив на него всю команду и, как результат - множество вопросов отпадает, тестировать методы можно до реализации клиента (человеческие тесты), да и просто приятно пользоваться.

Тем не менее сначала рассмотрим краткую инструкцию о том, как создать ASP .NET API Help Page, а после - перейти на Swagger

ASP.NET Web API: Отмена долгих запросов

В случае, если метод контроллера обращается к стороннему ресурсу, то время его выполнения определённо зависит от множества обстоятельств: количество данных/ширина канала, время обработки запроса сторонним ресурсом, длина очереди к ресурсу и т.п.

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

Как вариант - заюзать на фронте nginx

А если допустимо - принимать CancellationToken и передавать его в долговыполняющиеся операции

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

ASP.NET MVC 6 Dependency Injection (внедрение зависимости)

Ниже будет слегка рассмотрена реализация dependency injection от ms в рамках базового шаблона ASP.NET MVC 6
Использованные классы написаны только для демонстрации и некоторые вещи не стоит делать в проде
Также для всего этого дела использованы некоторые фичи C# 6, just for fun
Извлечение реализации определённого интерфейса будет представлено в четырёх видах (хотя все они сводятся к одному, но при использовании сильно отличаются)

Итак, подробный разбор ниже

JavaScript без jQuery - несколько примеров

Не нужно использовать jQuery там, где вся его мощь ни к чему, т.к. многие вещи вполне спокойно делаются и без него

Ниже вы увидите примеры для следующих ситуаций:
  • Подписывание на окончание загрузки документа
  • Выборка элементов используя css-селекторы
  • Добавление/удаление подписчиков на события
  • Манипуляция с классами элемента
  • Работа с аттрибутами элементов
  • Управление контентом
  • Добавление/удаление элементов
  • Проход по DOM
  • Использование анимации
  • AJAX

remote: fatal: bad config value for 'pack.deltacachesize'

Заходите в серверный .gitconfig и прописываете примерно cледующее:

[core]
    packedGitLimit = 256m
    packedGitWindowSize = 32m

[pack]
    deltaCacheSize = 256m
    windowMemory = 256m

ASP.NET WebSocket

Ниже пример реализации WebSocket-сервера на ASP.NET via C#:
  1. Создаём новый пустой веб-сайт, в качестве фреймворка я выбрал 4.5.2
  2. Добавляем в корень файл CustomWS.ashx:

  3. Добавляем файл form.html

  4. И последний index.html
Короткое объяснение:
  1. Для обращения к веб-сокетам из JS необходимо использовать класс WebSocket, см. подробнее например здесь: https://learn.javascript.ru/websockets
  2. На серверной стороне сделан хендлер для обработки запроса, благодаря свойству context.IsWebSocketRequest можно понять, это запрос но открытие веб-сокета или нет
  3. Если запрос содержит начальное подтверждение AspNetWebSocket, то регистрируем обработчик через context.AcceptWebSocketRequest
  4. Ну а дальше см. код

Пример работы:

Ссылка на проект:

  1. web http://sansys-net-websockets.azurewebsites.net/
  2. исходники https://cloud.mail.ru/public/dacVwJuHUh8y/DemoWebSockets.zip
PS: 
  • текущий проект в ажуре допускает максимум 5 одновременных подключений, так что вы можете легко увидеть ошибки, лучше качайте исходники и смотрите локально, + можно попробовать всё ручками
  • код не является потокобезопасным для простоты

Яндекс карты: поиск по адресу, javascript

Если в упрощённом виде, то хочется что-то вроде этого:


Код на фидле: http://jsfiddle.net/SanSYS/k8bmxs0z/1/

или см. под катом ↓

Mi Band




Купил Mi Band, официальный сайт http://www.mi.com/my/miband/

Про него написано уже много, посему коротко:
  1. Официальное приложение не поддерживает русский
  2. Русифицированное приложение см. тут http://miui.su/miband
  3. Патч для включения возможности проброса уведомлений на Mi Band от других приложений https://github.com/KashaMalaga/XiaomiMiBand/releases (например: почтовые программы, whatsapp/viber, vk, да всё что генерит уведомления)

    С этим патчем легко словить вот такой эксепшн:
    No activada notificacion del sistema
    Это значит, что приложению необходимо дать права на чтение абсолютно всех уведомлений =)
    Использовалось устройство с Android 4.4.4:

    Внимание!
    1. даёте права на свой страх и риск)
    2. Если приложение из п.3 после переустановки падает, то следует удалить файл notificationappdb из корневой директории устройства. В этом поможет ES Проводник, с включенной опцией отображения скрытых файлов
Рекомендую к прочтению: 
  1. Обзор Mi Band от Xiaomi
  2. MIUI Russia — официальный фан сайт в России
  3. Bong II — обзор китайского фитнес-трекера  - Китайский аналог Mi Band
UPD 26.09.2015: после очередной успешной зарядки к устройству больше не удаётся подсоединиться. Увы, но оно отлично выдерживало и горячую воду, и сплав по реке... теперь жду, когда сядет окончательно, может реанимируется )

Generic Handler Url Routing / Маршрутизация хендлера

Допустим есть у нас хендлер, расположенный по пути /Handlers/DataHandler.ashx
Не суть важно что он делает (отдаёт капчу, футболку виртуальной команды, изменённую картинку и т.п.), важно то, что вам почему-то захотелось сделать так, чтобы хендер отрабатывал по ссылке вида /somehandler/{dataKey}

Итак, хендлер вот такой:



Первое что приходит на ум - прописать вот такой роутинг:



Но что поделать, вы словите
  1. System.Web.HttpException:
  2. Тип 'Handlers.DataHandler' не является производным от 'System.Web.UI.Page'.

т.к. в классе BuildManager в методе CreateInstanceFromVirtualPath написана проверка на базовый тип (стр. 12):



Решение очень простое

Как убрать расширение .aspx из адреса страницы

Текущая ситуация: есть сайт, на нём довольно много страниц, адреса которых заканчиваются на .aspx, что есть совсем плохо (/about.aspx, вместо /about)
Довольно просто избавиться от расширений в путях, заюзав FriendlyUrlSettings

В RouteConfig или любом другом классе, отвечающим за маршрутизацию (лишь бы не Global.asax) необходимо уведомить RouteCollection о необходимости использования FriendlyUrlSettings:




NAnt + YUI Compressor

Собираем некоторые проекты в TeamCity
Логика сборки написана в "скрипте" для NAnt
В одном из проектов есть много css и js
Необходимо их минимифицировать

Для этой цели попробовал YUI Compressor for NAnt
Плюсы:
  1. Компактность использования
Минусы:
  1. Не дружит с русскими символами 0_о
  2. Не обновлялся с 15 сентября 2010-го
Посему заюзал YUI Compressor как написано на странице:
java -jar yuicompressor-x.y.z.jar [options] [input file]

Пришлось , конечно, поставить яву, но результат вполне норм:

Что делает показанный выше таргет:

  1. Ходит по всем js/css в проекте
  2. На каждый файл вызывает yuicompressor-2.4.8.jar
  3. Собственно всё, как результат - все файлы минифицированы
PS: возможно будет полезна дополнительно страница с описанием функций, доступных в NAnt


cannot call methods on slider prior to initialization; attempted to call method 'option'

Возможно вы создали слайдер и не запомнили ссылку на него, а после этого пытаетесь установить значение слайдера вот так:


Рекомендую попробовать сохранить ссылку на созданный слайдер и обращаться уже через неё:

P.S.: В последних версиях jQueryUI/jQuery попробовал - проблемы не увидел, может стоит просто обновиться

IIS 401.3 Error do not have permission

Моя ситуация:
  1. К сожалению в в проекте под IIS есть виртуальное приложение, каталогом которого является расшаренная папка с другой машины (допустим \\AnotherServer\Folder\)
  2. При попытке обратиться к виртуальному приложению проекта получаем ошибку IIS 401.3 Error do not have permission
  3. Разрешилось просто:

Если дело происходит с локальной папкой, а не с расшареной, то, вероятно, нужно всего лишь дать доступ на чтение этой папки пользователю IUSR 

The server variable is not allowed to be set.

При использовании Application Request Routing и модуля RewriteModule словил вот такую ошибку:

The server variable "HTTP_ACCEPT_ENCODING" is not allowed to be set.

Возможно используется модуль Rewrite 2.0, не позволяющий обновлять серверные переменные на уровне сайта

Необходимо:

  1. Выбрать в IIS нужный сайт
  2. В правой панели найти и перейти в модуль URL Rewrite
  3. В панели действий (правая колонка IIS) выбрать View Server variables... (нужны привилегии администратора)
  4. Откроется список серверных переменных, и, если не видите нужной вам переменной - просто добавьте её
Если словилась просто ошибка 500.50 и вы не знаете, что за серверную переменную необходимо добавить - пропишите в customErrors (файл web.config) mode=Off, либо откройте сайт прямо на сервере (т.е. локально), при условии, что customErrors mode=RemoteOnly