пятница, 2 ноября 2012 г.

Как завершить процесс блокирующий порт

Недавно мне пришлось устанавливать Resin веб сервер на windows для сайта написанного на Java. Когда я запускал сервер с консоли я получал сообщения об ошибке, что порты, которые я настроил для сайтов заняты другими процессами. Почему заняты - не понятно.

Для того чтобы узнать, какие процессы используют порты можно воспользоваться командой NETSTAT с ключами -a -o:



Допустим вам нужен порт 2559 на 127.0.0.1. В данном примере он занят процессом 3788.

Для того, чтобы завершить процесс можно воспользоваться командой TASKKILL c ключами /PID для указания процесса и можно /F чтоб завергить его принудительно.
Например taskkill /f /pid 3788

Дополнение.
Если вы не хотите видеть весь список процессов netstat, вы можете перенаправить результат в канал и обработать командой FIND.

Например я хочу найти все процессы которые блокируют порты, начинающиеся с 49


 

воскресенье, 8 июля 2012 г.

Ограничиваем ввод только цифрами с помощью кастомного биндинга Knockout

Я уже писал как можно применить кастомный биндинг, чтоб прицепить jquery datepicker. Сегодня я покажу еще один пример.
Иногда возникает необходимость ограничить пользовательский ввод по какому-то критерию, например разрешить вводить только цифры или только текст без цифр, если это имя или город.
В данной статье я покажу как ограничить ввод только цифрами, но в дальнейшем можно будет развить эту тему и фильтровать на основе какого-нибудь дополнительного критерия.
Решение по фильтрации я не изобретал и взял первое попавшееся на stackoverflow. Его мы и будем использовать.

Начнем с написания кастомного биндинга.

 ko.bindingHandlers.inputFilter = {
        init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
            var filter = ko.utils.unwrapObservable(valueAccessor());

            if (filter == 'Numbers') {
                $(element).keydown(function (event) {
                    // Allow: backspace, delete, tab, escape, and enter
                    if (event.keyCode == 46 || event.keyCode == 8 || event.keyCode == 9 || event.keyCode == 27 || event.keyCode == 13 ||
                    // Allow: Ctrl+A
            (event.keyCode == 65 && event.ctrlKey === true) ||
                    // Allow: home, end, left, right
            (event.keyCode >= 35 && event.keyCode <= 39)) {
                        // let it happen, don't do anything
                        return;
                    }
                    else {
                        // Ensure that it is a number and stop the keypress
                        if (event.shiftKey || (event.keyCode < 48 || event.keyCode > 57) && (event.keyCode < 96 || event.keyCode > 105)) {
                            event.preventDefault();
                        }
                    }
                });
            }

        },
        update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
            // we don't need update.
        }
    };

function CarViewModel (){
   this.Age = ko.observable(10);
};

var car = new CarViewModel();
ko.applyBindings(car);

Ну и рабочий пример.


Тут ничего военного не появилось, все тот же init и update. В инит находится код, который я полностью скопировал с ответа на stackoverflow.
Если вы посмотрите на html, то увидите там строчку:

data-bind="value: Age, inputFilter: 'Numbers'

Это значит что мы хотим связать наш инпут со значением поля Age и добавляем наш кастомный биндинг с параметром Numbers.
Когда вызывается метод init мы получаем значение, которое передали в inputFilter, в данном случае это будет 'Numbers'. Это значение получается в данной строке

var filter = ko.utils.unwrapObservable(valueAccessor());

ну а дальше все ясно вроде, если это Number цепляем обработчик.
В данном случае, нам не нужен update, нам достаточно прицепить обработчик keydown один раз в init и все, потом он будет жить своей жизнью.

Помоему получилось красиво!

Что можно сделать лучше:
  • Код, который у меня находится в init можно вынести в плагин jquery или просто найти готовый плагин, ссылки на них есть в тоже же ответе.
  • Можно ввести в дело еще один параметр например Characters и фитровать только по буквам.
  • Можно пойти дальше и передавать допустимые символы, например !"№;%@ или еще лучше принимать шаблон. Я думаю изобретать парсер шаблона не придется, есть jquery плагины, досточно будет просто принять шаблон через custom binding.
Вопросы приветствуются.

среда, 4 июля 2012 г.

Генерация классов из XSD файлов с помощью Xsd2Code.

Недавно я интегрировался с веб сервисами компании Verizon. Общение с версисом происходило через XML с определенной структорой. В общем, запрос представлял из себя шапку (header) и сам запрос (body). Пример:

  
    *****
    ********
    **
    MISC
    XML
  
  
    
      ******
      
        HTC
      
    
  


В документации были только примеры XML запросов и ответов для каждого типа запроса, например активация линии, информация о немере, смена тарифного плана и тп. В основном сохранялся только тег request, а внутри него менялся контет.
Сначала я эти запросы формировал руками через XLinq и это было совсем не круто. Потом компания предоставила XSD файлы для каждого запроса и сказала, что мы можем использовать эти файлы для генерации XML запросов. До этого с XSD никогда не сталкивался и пока не нагуглил не знал как оно мне поможет.

В общем помогают эти файлы следующим образом:
1. Cначала с помощью одной из утилит XSD.exe от Microsoft или Xsd2Code на codeplex, можно сгенерить cs или vb файлы.
2. Код в этих файлах будет сгенерен с Xml аттрибутами, необхадимыми для формаирования правильного XML запроса. Чтоб сгенерить Xml, который я показал в примере, используется XmlSerializer.

Так в 2 шага можно сгенерировать валидный XML по XSD файлам.
Когда я дошел до генерации CS файлов из XSD, то выбора было не особо та и примеров как это делать тоже, в основном ссылки на xsd.exe с которым я так и не подружился.
В данной статье я хотел рассказать об утилите Xsd2Code.Чем она хороша ?
  1. Очень много настроек
  2. Интегрируется с студией
  3. Понимает теги xsd:include, которые ссылаются на другие xsd файлы.
  4. Не сложная в использовании
Как использовать ?

Для начала скачать и установить.

Дальше вызвав в консоли Xsd2Code.exe можно увидеть список доступных параметров

Usage: 

    Xsd2Code.exe  [Namespace] [Output file name] [Options]

Where:
                              - Path to an XSD file. Required
    [Namespace]                         - Generated code namespace. Optional. File name without extension if no value is specified
    [Output file name]                  - Name of the output (generated) file. Optional. 
    [Options]                           - Optional. See below for description

Options:
    /o[utput]                 - Name of the output (generated) file. 
                                          By default, name of the source file with extension .Designer.cs 
                                          (.Designer.vb or .Designer.cpp for VisualVasic and Visual C++ respectively)
    /n[s]                    - Generated code CLR namespace. Default: file name without extension
    /l[anguage]               - Generated code language (CS|VB|CPP). Default: CS
    /pl[atform]               - Generated code target platform (Net20|Net30|Net35|Silverlight20). Default: Net20
    /c[ollection]      - Collection base (Array|BindingList|List|ObservableCollection|DefinedType). Default: List
    /cu[customusings]    - Comma-separated of custom usings definition (E.g "Xsd2Code.Library,System.Xml.Linq")
    /sm                      - Serialize method name. Default: Serialize
    /dm                    - Deserialize method name. Default: Deserialize
    /lf[m]                - LoadFromFile method name. Default: LoadFromFile
    /sf[m]                  - SaveToFile methodname. Default: SaveToFile
    /is[+]                              - Include Serialize method
    /is-                                - Do not include Serialize method (default)
    /cl[+]                              - Include Clone method
    /cl-                                - Do not include Clone method (default)

Это не полный список, их раза в 2-3 больше, но нам все не надо.

Дальше генерим CS файл из XSD. Пример:
Xsd2Code.exe POSBizCheckStatus.xsd Ivanov.VerizonIntegration C:\POSBizCheckStatus.cs /pl Net35 /c Array /xa /is /sс
По порядку:
Xsd2Code.exe - путь к файлу или если вы находитесь в папке с утилитой, то просто название запускаемого файла утилиты.
POSBizCheckStatus.xsd - путь к xsd файлу или если он находится в папке с утилитой то просто нзвание файла. Вайжно!!! Лучше чтоб путь к xsd файлу не содержал пробелы, а то может не сработать
 Ivanov.VerizonIntegration - namespace в котором будет сгенерированый класс.
C:\POSBizCheckStatus.cs - путь и название cs файла в котором будет сгенереный класс по XSD схеме.
/pl Net35 - версия .NET для кода в данном случае 3.5
/c Array - как мы хотим видеть колекции, на выбоор несколько опций, в моем случае хочу чтоб колекции были как обычные массивы.
/xa - именно с этой опцией добавляются xml аттрибуты, которые помогу XmlSerializer'у правилно сгенерировать XML. Эту опцию можно отключить. Пример

    [GeneratedCode("Xsd2Code", "3.4.0.38968")]
    [Serializable]
    [DesignerCategory("code")]
    [XmlType(AnonymousType = true, Namespace = "http://pos.odc.vzwcorp.com")]
    public class miscResponseAccessoryList
    {
        private static XmlSerializer serializer;
        private miscResponseAccessoryListAccessoryInfo[] accessoryInfoField;
        private string countField;

        [XmlElement(DataType = "integer", Order = 0)]
        public string count
        {
            get { return countField; }
            set { countField = value; }
        }

        [XmlElement("accessoryInfo", Order = 1)]
        public miscResponseAccessoryListAccessoryInfo[] accessoryInfo
        {
            get { return accessoryInfoField; }
            set { accessoryInfoField = value; }
        }

/is - этот ключ добавляет в файл метод Serialize / Deserialize. Очень удобно, самому уже не надо писать.

 
public virtual string Serialize()
        {
            StreamReader streamReader = null;
            MemoryStream memoryStream = null;
            try
            {
                memoryStream = new MemoryStream();
                Serializer.Serialize(memoryStream, this);
                memoryStream.Seek(0, SeekOrigin.Begin);
                streamReader = new StreamReader(memoryStream);
                return streamReader.ReadToEnd();
            }
            finally
            {
                if ((streamReader != null))
                {
                    streamReader.Dispose();
                }
                if ((memoryStream != null))
                {
                    memoryStream.Dispose();
                }
            }
        }


/sc  - добавляет коментарии к свойствам.

Остальные ключи добавляются по мере необходимости. Есть настроки для WCF, Linq, DataBinding и тп.


Если у вас несколько XSD файлов и для них всех нужно сгенерить классы, например как у меня
















то можно использовать bat файл.

@echo off

set XsdPath="c:\Path\To\Xsd\Files"
set OutPath=%XsdPath%\Code
set ExePath="c:\Program Files (x86)\Xsd2Code\"
set Namespace=MyProject.Namespace
echo.Starting processing XSD files ...
for /f %%a IN ('dir %XsdPath%\*.xsd /a-d /b /s') do call:ProcessXsd %%a

echo.Finished processing XSD files ...
echo.&pause&
goto:eof

:ProcessXsd
%ExePath%\Xsd2Code %~1 %Namespace% %XsdPath%\Code\%~n1%.cs /pl Net35 /c Array /xa /is
echo.Processed %~n1
goto:eof

Нужно подставить значение XsdPath, OutPath, ExePath и Namespace. В моем случае я получил список файлов в папке Code.


















Это важно!
OutPath папка должна существовать, иначе провал.
XsdPath путь не должен содержать пробелов, иначе тоже пробвал

Пример использования в коде

logger.Info("Building XML for REASSIGN ACCOUNT request.");

            POSBizServices requestMessage = serviceRequestFactory.CreateReassignAccountRequest(request);

            logger.Info("Sending REASSIGN ACCOUNT request.");

            string requestXml = requestMessage.Serialize();
            string responseXml = SendRequest(requestXml);

            logger.Debug("REASSIGN ACCOUNT response: {0}.", responseXml);

            POSBizServices responseMessage;

            try
            {
                logger.Info("Deserializing XML response to POSBizServices as LINE STATUS response.");
                POSBizServices.Deserialize(responseXml, out responseMessage);
            }
            catch (Exception e)
            {
                logger.ErrorException("Error while deserializing LINE STATUS XML response to POSBizServices", e);
                throw;
            }

Пользуйтесь! Будут вопросы - отвечу.

понедельник, 23 января 2012 г.

Цепляем jQuery Datepicker c помощью кастомного биндинга на KnockoutJS

Как я говорил в предыдущей статье сегодня мы создадим свою "команду" ну или правильному custom binding (кастомный биндинг).
Что это такое ?
В knockout для того, чтобы с вашим элементом происходили какие-то махинации: скрыть, сделать неактивным, добавить стиль, присвоить значение и тп существуют команды, некоторые из которых вы уже видели в примерах - value, text, visible, ckecked, enable, options. Эти команды предопределены в фреймворке и предоставляют базовый и достаточный функционал для реализации ваших нужд.
Иногда бывают случаи когда код выглядит когда их вроде бы не хватает. Например, обавим в наши фильтры поддержку типа Date и когда пользователь выбрал поле, например Issue Date, установил курсор чтоб ввести значение, я хочу чтоб он не вводил его руками, а выбрал дату через jQuery datepicker. Естественно я хочу чтоб выбор даты срабатывал только для Date типа фильров, а для других Number и String оставался просто полем ввода.
Без своей кастомной команды, нам бы пришлось подписаться через subscribe на ColumnObj и смотреть при выборе поля из выпадающего списка его тип. Если это дата - применить datepicker, если нет - удалить datepicker. Если мы в будущем захотим добавить еще какую-то логику, то пойдут кастыли и будет все в куче. 
Тут нам как раз и поможет кастомный биндинг (команда). В итоге наш шаблон будет выглядеть так:
 
    <input data-bind="value: Value, datePicker: Type" type="text" />

Вся логика для выбора даты будет вынесена в команду datePicker. Собственно код:

ko.bindingHandlers.datePicker = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var type = ko.utils.unwrapObservable(valueAccessor());

        if (type == 'Date') {
            $(element).datepicker();
        }

    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var type = ko.utils.unwrapObservable(valueAccessor());

        if (type == 'Date') {
            $(element).datepicker();
        }
        else {
            $(element).datepicker("destroy");
        }
    }
}


Я не буду описывать все опции в деталях, о них выможете прочитать здесь.
Рассмотром, что и как.  Как мы видим для того чтобы создать команду, мы создаем объект с соответствующим называнием команды в ko.bindingHandlers. У нашего объекта должно быть две функции.

init - вызывается, когда knockout доходит до места в html, где установленна наша команда.
update - вызывается, когда изменится значение поля за которым мы следим с помощью нащей команды.
В нашем случае, data-bind="dataPicker: Type, value: Value" значит - следить за полем Type и если оно изменится вызвать команду datePicker. Она вызовится при инициализации и после последющих обновлений.
Что происходит в обработчиках?

valueAccessor() - возвращает поле, к которому привязана команд. Это всегда будет функция. т.к. все поля объявляются через ko.obsorvable или ko.computed и они возврашают функции.
ko.utils.unwrapObservable - это функция, которая вычисляет значение поля на такущий момент, когда вызывается эта строка.
Дальше, я думаю, все понятно. Параметры, которые передаютися в init и update очевидны, кроме allBindingsAccessor, но и пользоваться им вы врядли будете.

Ниже рабочий пример. Я добавил тип Date в Conditions, саму команду datePicker и поле Issue Date.

пятница, 13 января 2012 г.

Динамические фильтры на Javascript c помощью KnockoutJS

Сегодня я покажу практический пример, как можно применить KnockoutJS в реальном проекте и сделаем мы динамические фильтры для поиска задач, багов, тасков и тп по разработчику, названию таска и описанию. Возможно вы такие уже видели в TFS для генерации отчета или других системах, где можно добавлять любые фильтры и условия для поиска чего-либо. В итоге выглядит это так:



В конце мы добавим валидацию, чтоб нельзя было добавлять фильтр, если текущий пустой, а в следующей статье я напишу о том как можно писать плагины и свои команды в knockout и добавит фильтр по дате.

Приступим!

Сначала  определимся, что будет представлять из себя сам фильтр:


Column - колонка по кторой фильтруем или ищем
Condition - оператор для фильтра =, != и тп
Value - значение фильтра
Type - тип. Пока что у нас будет только String, Number потом расширим
NextFilterBinaryCondition - это условие с которым будет выполняться следующий фильтр "И", "ИЛИ". Например Developer = "Vitaly" and Issue = "write post" or Issue Description = "knockout".

Фильтры у нас будуте создаваться по названию поля по которому мы фильтруем. Колонки у нас хранятся как объекты. При создании фильтра мы сохраним название поля и найдем в списке объект колонку с помощью вспомогательной функции findFilterColumn и будем хранить обьъект колонка в поле ColumnObj. 
Если поле ColumnObj изменится, мы очищаем значение фильтра. Чтоб следить за изменениями поля ColumnObj мы подписуемся функцией subscribe.
Функцию-оброботчик, которыю мы передаем в subscribe, будет вызываться всегда, когда значение поля, на которое мы подписываемся, изменится.
Все поля, кроме ColumnObj, Condition, Value, NextFilterBinaryCondition  зависымые и значения мы не присваиваем им явно. Значения для этих полей пересчитываются при любом изменения одного из обычных полей. Это одна из прелестей knockout! Если смотреть сверху вниз то экосистема knockout будет вызывать обработчики в следующем порядке:
1. Присвоить значение в ColumnObj
2. Определеить поле Column как зависимое и попробовать просчитать.
3. Присвоить значение полю Condition.
4. Пересчитать Column
5. Присвоить значение полю NextFilterBinaryCondition.
6. Пересчитать Column.
7. Определеить поле Type как зависимое и просчитать.
8. Пересчитать Column.
9. Определеить поле AvailableConditions как зависимое и просчитать.
10. Пересчитать Type.
11. Пересчитать Column.
12. Установить значние поля Value и пересчитать Column, Type, AvailableConditions.

Все поля устанавливаются и пересчитываются по порядку в котором они были объявлены.

Теперь рассмотрит класс, который управляет всей бизнес логикой, хранит фильтры и он является и называется ViewModel

Объект Conditions содержит список типов фильтров и соответсвенно операций, условий, которые мы поодерживаем для этих типов данных. Также есть вспомогательная функция для поиска доступных условий по названию типа.

Например найти все доступные условия для фильтрации по типо 'Number'. Этой функцией мы будем пользоваться когда после выбора поля в первом списке, нам нужно будет отобразаить доступные условия во втором выпадающем списке.

Небольшое ТЗ. У нас должны выполнятся следующие требования:
- хранить фильтры
- добавлять фильтры
- удалять фильтры
- посылать все фильтры на сервер

При создании ViewModel мы передаем в него список колонок, которы объявлены выше. В конструкторе мы создаем массив фильтров и сразу добавляем один пустой фильтр. Если этого не сделать, то у нас на экране будет одна кнопка. Как только мы добавляем пустой фильтр, экосистема knockout трекает это, уведомляет всех подписчиков на изменения, если есть такие, и отображает пустой добавленные фильтр по шаблону и определенной для него бизнес логике.

Функция addFilter принимает объект фильтр, напротив которого мы клацнули "+", находит этот фильтр в списке уже существующих фильтров и добавляет после него новый пустой.
В данном случае у нас нет проверки, заполнены ли все фильтры или нет. Сейчас мы можем нажимать "+" бесконечно и у нас будет куча фильтров. Мы это исправим потом.

Функция removeFilter принимает объект фильтры который надо удалить, удаляет его из списка фильтров и если это был последний фильтр мы добавляем пустой. Зачем? Если мы этого не сделаем, то мы не сможем добавить фильтры, т.к. "+" отображается на строке с фильтром и без него у нас останется только кнопка submit.

Функция postFilters показывает сообщение с сериализованными фильтрами в JSON, которые надо послать на сервер для обработки. В knockout есть много утилитных функций о которых мы можете почитать подробней здесь.

Функция toJS, создает новый js объект, который не связан больше с knockout, это просто js объект. Все свойства в нем будут вычеслены с теми значениями, которые были на момент вызова функции toJS.

Когда мы сериализовали фильтры в js objects, то там будут поля, которые нам нужны и которые были нужны только для knockout, например ColumnObj, AvailableConditions. Эти поля не несут нам никакой информации на сервере, поэтому мы их смело удаляем и на сервер пойдет меньше данных. Функция toJSON сериализует js класс в JSON строку, которую мы и показываем.

Переходим к рассмотрению шаблона html:

Фильтры отображаются по шаблону в данном случае шаблон, это li и все что внутри него.
В предыдущих версия knockout обязательно надо было подключать jQuery Teample. В последней версии этого делать больше не нужно, теперь в фреймворке есть свой встроеный движок для шаблонов со своими плюшками. О всех новшествах новой версии 2.0 можно прочитать на блоге самого разработчика здесь.
Из нового  я использую переменную $root, которая ссылается на ViewModel класс. Если этого не сделать, то, например, поле columns будет искаться в классе Filter. Команда foreach пробегает по всем объектам коллекции filters и применяет шаблон для каждого объекта Filter. Шаблон выполняется с контекстом объекта, который передается в шаблон (Filter).
Переменная $data хранит ссылку на объект контекста (Filter в данном случае). Этой переменной я воспользовался, когда добавлял или удалял фильтр.
По умолчанию функции вызываются в контексте объекта в шаблоне (Filter), для этого в новой версии не нужно писать function () { ... }, есть более красиывый синтаксис например click: removeFilter($data). Но нам надо выполнять функции в контексте ViewModel поэтому мы пишем по старому, через function и выполняем функцию в контексте, котором нам надо.

Вроде бы все.

Теперь, как я говорил, добавим проверку. Если у нас хотя бы один фильтр без значения, то мы не будем добавлять новый.
Обновленный класс ViewModel выглядит теперь так:

а фильтр так:


и собственно результат:


В следующей статье я напишу как писать расширения для knockout и мы сделаем фильтр по дате. Если у нас поле будет с типом Date, то к нему будет автоматически применяться jQuery date picker.

Вопросы, коментарии преветсвуются!