воскресенье, 11 декабря 2016 г.

asp.net mvc - невалидные параметры действия - нюанс

обнаружил такую вещь. если есть действие:

public ActionResult MyAction (string name, int age)
{
}

если с клиента придет для ключа "age" нечисловое значение - вылетит исключение.

однако, если изменить действие так:


class PersonParams {
     pubic string name {get;set;};
     public int age{get;set;}
}
(кстати, поля фреймворком игнорируются, нужно объявлять именно свойства)

public ActionResult MyAction (PersonParams personParams)
{
}


 - в этом случае, если с клиента придет для ключа "age" нечисловое значение - действие будет выполняться, исключение не вылетит, свойство age будет иметь дефолтовое значение 0, а ModelState.IsValid будет иметь значение true

суббота, 26 ноября 2016 г.

наследование в JS - еще немного поразбирался

начал разбираться здесь

сейчас еще подумал еще на эту тему, и написал пример (он ниже).
там для эмуляции наследования используется только prototype. не используется object.create и прочие новомодные штучки, все "ближе к земле". синтаксис немного упростится, если использовать Object.Create (не понадобились бы функции типа A_Proto).
А еще недавно в JS появился синтаксис объявления классов, более-менее похожий на используемый в объектно-оринентированных языках, с использованием ключевого слова "class". однако, нет поддержки этого синтаксиса, например, в IE 11. то есть, на мой взгляд, использовать это пока рановато.


var A = function(initPropA, noConstructor){
 this.ConstructorA(initPropA);
};
var A_Proto = function(){
 this.propA = null; //для порядка
 this.ConstructorA = function(initPropA){
  console.log("ConstructorA");
  this.propA = initPropA;
 };
 this.fA = function(){
  console.log("fA");
 };
 this.virtF = function(param){
  console.log("virtFA: " + this.propA + "; " + param)
 };
}
A.prototype = new A_Proto();


var B = function(initPropB, initpropA){
 this.ConstructorB(initPropB, initpropA);
}

var B_Proto = function(){
 this.propB = null;
 this.ConstructorB = function(initPropB, initpropA){ //конструктор класса-потомка вызывает конструктор предка, а потом производит свою инициализацию
  this.ConstructorA(initpropA);
  console.log("ConstructorB");
  
  if (this.propA % 2 == 0)
   this.propA++;
  this.propB = initPropB;
 };
 
 this.fB = function(){
  console.log("fB");
 };
 
 this.ShowPropB = function(){
  console.log(this.propB);
 }
   
 this.virtF = function(param){
  console.log("virtFB: " + this.propB+ "; " + param);
  A.prototype.virtF.call(this, param); //вызов версии метода базового класса
 };
}
B_Proto.prototype = new A_Proto();
B.prototype = new B_Proto();


var C = function(){
 this.ConstructorC();
}

var C_Proto = function(){
 this.ConstructorC = function(){
  this.ConstructorB(123, 456);
  console.log("ConstructorC");
 }
 
 this.fC = function(){
  console.log("fC");
  this.ShowPropB();
 };
 
 this.virtF = function(param){
  console.log("virtFC: " + param);
  B.prototype.virtF.call(this, param); //вызов версии метода базового класса
 };
}
C_Proto.prototype = new B_Proto();
C.prototype = new C_Proto();

console.log("***A***");
var a = new A(222);
console.log(a.propA);
a.fA();
a.virtF("a_param");

console.log("***B***");
var b = new B(777, 222);
console.log(b.propA);
console.log(b.propB);
b.fA();
b.fB();
b.virtF("b_param");

console.log("***C***");
var c = new C();
console.log(c.propA);
console.log(c.propB);
c.fA();
c.fB();
c.fC();
c.virtF("c_param");
Аутпут:

***A***
inheritance.html
ConstructorA
inheritance.html
222
inheritance.html
fA
inheritance.html
virtFA: 222; a_param
inheritance.html
***B***
inheritance.html
ConstructorA
inheritance.html
ConstructorB
inheritance.html
223
inheritance.html
777
inheritance.html
fA
inheritance.html
fB
inheritance.html
virtFB: 777; b_param
inheritance.html
virtFA: 223; b_param
inheritance.html
***C***
inheritance.html
ConstructorA
inheritance.html
ConstructorB
inheritance.html
ConstructorC
inheritance.html
457
inheritance.html
123
inheritance.html
fA
inheritance.html
fB
inheritance.html
fC
inheritance.html
123
inheritance.html
virtFC: c_param
inheritance.html
virtFB: 123; c_param
inheritance.html
virtFA: 457; c_param

вторник, 22 ноября 2016 г.

Visual Studio 2013 закапризничала опять: ошибка HTTP 500.19

мое Asp.net-MVC-приложение хранится в git. И для удобства у меня есть несколько рабочих папок с разными ветками этого репозитория. и я достаточно свободно копирую и переименовываю эти папки.
Но сегодня - не знаю, связаны ли эти два факта, или нет - после очередного переименования/копирования папки и запуска приложения я увидел такой экран:

получается, IIS Express ищет web.config по старому пути папки (я переименовал папку kaspihelp2)

настройки отладки  меня были примерно такие (они стоят по дефолту при создании проекта, но настроенаа подпапка):
 
что я только не делал! даже компьютер перезагрузил! :)
по идее, следующим шагом была переустановка Студии (моему коллеге помогло в аналогичной ситуации).
Но в итоге проблема была устранена просто инкрементом номера порта :)
 
не забудьте ткнуть «Create Virtual Directory» (я не до конца разобрался, что это, но, вроде, не лишне)

среда, 9 ноября 2016 г.

Добавление глобального Html-хелпера


Есть проект Asp.net mvc (не знаю, как версию посмотреть, воздан в Visual Studio 2013)
Встала задача создать Html-хелпер, глобально доступный для всех cshtml-видов проекта
Написал класс вида:
namespace Aproject.Helpers
{
    public static class WebHelpers
    {
        public static string GetDateString(this HtmlHelper helper, DateTime date)
        {
            return date.ToLongDateString();
        }
    }
}
в cshtml-файле вида:
добавил сверху:
@using Aproject.Helpers
после этого смог использовать мой метод:
@Html.GetDateString(Model.Date)

но хотелось избавиться от необходимости перечислять в начале страницы все юзинги.
какое-то время ковырялся в гугле, в итоге выяснил:
нужно в Web.Config, который лежит в папке Views, в секцию
<pages pageBaseType="System.Web.Mvc.WebViewPage">
      <namespaces>
добавить ссылку на наше пространство имен.
Но и это еще не все! чтобы IntelliSence одуплился, нужно закрыть и открыть проект (я просто закрыл и переоткрыл вижуал-студию). Пока этого не сделаешь, всё, объявленное в этих пространствах имен, будет подчеркнуто красным.

воскресенье, 23 октября 2016 г.

git cherry pick

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

(с нюансами я не разбирался, пока просто это принял на вооружение)

среда, 19 октября 2016 г.

301-Permanent redirect

по поводу кодов редиректа вэб-сервера:

есть 2 кода редиректа: 301 (Moved permanently) и 302 (Found)

по идее, вэб-сервер возвращает эти коды, если запрошенный URL устарел, и вместо него должен использоваться новый (и этот новый прилагается к тексту ответа).
точнее, это верно для кода 301 (Moved permanently).
код 302 (Found) должен быть возвращен, если страница "перемещена временно", хотя, мне в голову не приходит, когда эта ситуация возможна.
так вот, как выснилось, код 301 - опасная хрень: однажды получив этот код, браузер запомнит , что при обращении к старому URL нужно вместо этого обращаться по такому-то новому адресу. и в следующий раз, если будет инициирован переход на старый адрес (например, он будет введен в адресную строку) - браузер сразу отправит запрос на новый адрес.
и это не вытравишь никакими очистками кеша (по крайней мере, на Хроме)

то есть, в случае чего, "перегадать" не получится (например, если окажется, что твой сайт содержал баг и редиректил не туда)

в отличие от 301, 302 к такому ужасу не приводит, браузер каждый раз запрашивает вэб-сервер по старому адресу, и переходит на новы только получив в очередной раз код 302.

мораль: я бы не касался 301-го кода даже двенадцациметровой палкой
но, с другой стороны, это может негативно сказаться на SEO (не изучал этот вопрос)

понедельник, 17 октября 2016 г.

учетка Microsoft закапризничала

внезапно получил сообщение, что у моей Visual Studio 2015 Community Edition истек 30-дневный триальный период. и хоть ты куда тыкай - не пускает в Студию!

в итоге с помощью гугла и экспериментов установил, что нужно залогиниться на outlook.com, разлогиниться и опять залогиниться. потом перелогиниться в Студии. после этого заработала

воскресенье, 16 октября 2016 г.

Dropbox - отморозок! история изменений файлов.

есть у меня один критичный файлик, и я озаботился тем, можно ли как-то сохранять его предыдущие версии, на случай, если я его сотру.
файлик лежит в дропбоксе.
и я обратил внимание на пункт "предыдущие версии" в контекстном меню. нажал - попал на страницу Dropbox, где перечислены куча последних версий этого файла (вот сколько я раз Ctrl+S нажимал - столько версий в дропбоксе хранится). не знаю, сколько он их всего хранит. это круто, черт побери!

четверг, 13 октября 2016 г.

Нюанс работы EntityFramework с валидационными атрибутами

может, кому-то пригодится: наткнулся на такую особенность: если навесить на сущность несколько валидационных атрибутов (потомки ValidationAtribute) одного класса - Entity Framework принимает во внимание только первый

среда, 14 сентября 2016 г.

настройки софта

создаю тут памятку для самого себя, как софт настраивать под мои предпочтения.

Notepad++ 
-решить проблему кодировки
-разное - автоопрееление обновления - молча обновляться
-auto-completion - выбрать function completion вместо function an word completion
-auto-completion - убрать галочки автовставки закрывающих скобок и кавычек, поставить галочку закрывающих тегов html/xml
-Backup - Remember current session for next launch - выключить
-плагин Compare - https://sourceforge.net/projects/npp-compare/

Firefox
-настройки tabmix - мышь - кнопки мыши - Ctrl+клик - закрытие вкладки
-настройки tabmix - мышь - кнопки мыши - убрать галочки "предотвращать перетаскивание...", "предотвращать изменение размера"
-настройки tabmix - события - новые вкладки - открывать открывать новые вкладки после текущей
-настройки tabmix - события - настройки вкладок - листать по ctrl-таб в порядке поcледнего просмотра


Windows 10
ввод пароля после сна:  Настроки - Учетные записи - Параметры входа - Требуется вход - "Каждый раз" 

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


Добавление русской проверки правописания в LibreOffice
http://extensions.libreoffice.org/extension-center/russian-dictionary-pack

качаем, запускем. предупреждение, что словари устарели - пофиг.

потом параметры - настройки языка - языки - языки документов по умолчанию - заападные: русский


четверг, 1 сентября 2016 г.

проблема с кодировкой в Notepad++

поправка: в новых версиях Notepad++ проблема отсутствует (7.5.9), но статью оставлю на случай, если понадобится задать шаблон вновьсоздаваемого файла
--------------
столкнулся с такой проблемой:
создаешь пустой текстовый файл средствами проводника Windows (контекстное меню - Создать - Текстовый документ),
открываешься его в notepad++ - он его открывает с кодировкой ANSI, не смотря на настройки, говорящие об обратном:



Если при этом напечатать там русских символов и сохранить - при следующем открытии частенько все или некоторые буквы выводятся в неверной кодировке.

однако, если напечатать английские буквы и/или некоторые базовые символы (а точнее, только символы, кодируемые в UTF-8 одним байтом), то после сохранения такой документ открывается в UTF-8. то есть, проблема у Notepad++ - с пустым файлом (я бы назвал это багом).

Чтобы устранить проблему, я изменил шаблон вновьсоздаваемого файла: теперь у меня текстовый файл создается сразу с одним символом - пробелом. и открывается в нужной кодировке.

как это сделать:
  • в реестре находим HKEY_CLASSES_ROOT\.txt\ShellNew
  • удаляем параметр "NullFile" , который говорит о том, что должен быть создан пустой файл
  • создаем параметр Data бинарного типа, вводим значение "20", что соответствует десятичному "32" и является символом пробела. Теперь в новом документе будет ставиться пробел


среда, 31 августа 2016 г.

наследование в JS - немного поразбирался

после этого поста еще доразбирался - можно тут посмотреть

есть дедовский способ наследования через прототипы:

у каждой функции есть свойство prototype. Смысл его - в том, что при вызове функции с ключевым словом new - создается объект, а функция выступает в качестве его конструктора (и может использовать указатель this). так вот, если у этого объекта запросить поле (в т.ч. , функцию), которое не было в нем инициализировано - это поле будет искаться в объекте, на который ссылается внутренний (недоступный программисту) указатель [[prototype]]. А указатель этот указывает на объект, который был в свойстве prototype функции-конструктора на момент вызова оператора new.
и можно в свойство prototype функции-конструктора вписать просто объект с полями.
а можно в качестве прототипа вписать созданный через new объект класса-предка.

следует заметить, что, даже если вызывается функция, являющаяся членом прототипа - в качестве this к ней приходит указатель на созданный через new объект, а не на объект, который лежит в [[prototype]].



function A(){

    this.Inc = function(){

        if (!this.Val)

            this.Val = 1;

        else

            this.Val++;

    }

}


function B(){

}


B.prototype = new A();



var a1 = new B();

var a2 = new B();


a1.Inc();

a2.Inc();

a1.Inc();


console.log(a1.Val);    //2

console.log(a2.Val);    //1
минус подхода - в том, что у родительского класса не может быть параметров конструктора


сейчас этот подход считается устаревшим. вместо него нужно использовать метод object.Create(его поддерживает даже IE9, вроде, так что можно уже использовать), который позволяет делать всякие навороты типа полей только для чтения и свойств с геттерами и сеттерами.
http://www.htmlgoodies.com/beyond/javascript/object.create-the-new-way-to-create-objects-in-javascript.html


но я не стал заморачиваться и изучать, думаю, пока и дедовского способа хватит

дополнение:
описанный выше способ наследования - прототипный.
а есть еще прием, который называется функциональным наследованием:


// Base object constructor function
function base(spec) {
    var that = {}; // Create an empty object
    that.name = spec.name; // Add it a "name" property
    return that; // Return the object
}

// Construct a child object, inheriting from "base"
function child(spec) {
    var that = base(spec); // Create the object through the "base" constructor
    that.sayHello = function() { // Augment that object
        return 'Hello, I\'m ' + that.name;
    };
    return that; // Return it
}

// Usage
var object = child({ name: 'a functional object' });
result.textContent = object.sayHello();


не используется ключевое слово this (говорят, с ним может быть гемор), можно использовать параметры конструктора... хороший способ!

http://julien.richard-foy.fr/blog/2011/10/30/functional-inheritance-vs-prototypal-inheritance/

суббота, 27 августа 2016 г.

Установка Visual Studio 2015 Community Edition

устанавливаю Visual Studio 2015 Community edition , англ. версию
Установка заканчивалась отчетом о множественных ошибках, что через загрузчик, что через ISO.
ошибки - схожи с описанными здесь:
http://stackoverflow.com/questions/33855177/multiple-errors-installing-visual-studio-2015-community-edition/33881460

много чего перепробовал, но, если не ошибаюсь, в итоге помогло решение, предложенное по этой ссылке. Но с нюансами.
1) нужно деинсталлировать vc redistributable 2015 (все, какие есть)
2) скачать редистрибьютабл  с сайта майкрософт и установить (и 32-, и 64-битную версии)
3) запустить установку студии в дефолтовом составе компонентов (папку назначения можно изменить)
4) у меня после этого опять вылезли ошибки инсталляции, но другие, и было предложено перезагрузить комп. перезагрузил, запустил инсталляцию опять (так же дефолтовую) - установка прошла успешно
5) запустил инсталлятор опять, выбрал Modify, изменил состав  компонентов, как мне надо - процесс прошел успешно (на самом деле, еще идет, но уже очень блихок к завершению)

ОС - Windows 8 со всеми обновлениями, 64 бита

среда, 6 июля 2016 г.

git rebase

альтернатива merge. плюсы: при слиянии не создается дополнительный коммит, как при merge.
минус: непонятно, на каком этапе ветки слились.

если используется ребейз - нужно, чтоб все члены команды знали, как с ним работать. иначе будет куча вопросов и "странных" мерджей

https://habrahabr.ru/post/161009/

Upd.: говорят, разрешение конфликтов геморное. и сами гитовцы не рекомендуют это использовать вместо мерджа. резюме: можно использовать просто как средство исправления помарок при коммитах, порождающих микромерджи

git staged

"staged" - статус файла, готового к коммиту.
если мы изменим файл - он еще не войдет в ближайший коммит. мы должны проиндексировать его (командой add как-то там). если после этой команды мы файл еще раз изменим, а потом закоммитим - в коммит попадет версия файла без этого последнего изменения

пятница, 22 апреля 2016 г.

asp.net: исключение папок из публикации для определенной платформы

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


открыть в ~блокноте файл проекта и вставить блок вида:
<PropertyGroup Condition="'$(Configuration)' == 'Secondary_Release'">
<ExcludeFoldersFromDeployment>thirdparty\ckfinder;thirdparty\qunit</ExcludeFoldersFromDeployment>
</PropertyGroup>


 перед первой существующей PropertyGroup 

 Secondary_Release - имя деплоймент-конфигурации; внутри ExcludeFoldersFromDeployment - список исключаемых папок относительно корня папки-цели деплоймента, через точку с запятой

среда, 2 марта 2016 г.

экспорт аудиозаметок из evernote

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

вложение экспортируется без расширения. приписываем ему расширение .acc

это - звуоквой формат, но у меня на компе он проигрываться отказался. так что, я его сконвертировал в mp3 с помощью http://media.io/

дополнение : если сэкспортилось с расширением arm - расширение .acc не прибавлять