Exception Details: System.Web.HttpException: A potentially dangerous Request.Path value was detected from the client (:)

Ошибка:
«Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Web.HttpException: A potentially dangerous Request.Path value was detected from the client (:).

Решение:

1. Добавить параметр в раздел system.webServer:

<security>
<requestFiltering allowDoubleEscaping="true" />
</security>

2. Добавить параметр в раздел configuration

<system.web>
<pages validateRequest="false" />
<httpRuntime requestPathInvalidCharacters="" />
</system.web>

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

Источник: http://www.koderline.ru/expert/programming/article-problemy-bezopasnosti-pri-rabote-s-1s-cherez-iis/

APDEX: Замеры производительности

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

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

Добавляем в серверный модуль

#Область ОценкаПроизводительности
Функция ОП_СодержитСвойство(Переменная, ИмяСвойства)
	// Инициализируем структуру для теста с ключом (значение переменной "ИмяСвойства") и значением NULL
	СтруктураПроверка = Новый Структура;
	СтруктураПроверка.Вставить(ИмяСвойства, NULL);
	// Заполняем созданную структуру из переданного значения переменной
	ЗаполнитьЗначенияСвойств(СтруктураПроверка, Переменная);
	// Если значение для свойства структуры осталось NULL, то искомое свойство не найдено, и наоборот.
	Если СтруктураПроверка[ИмяСвойства] = NULL Тогда
		Возврат Ложь;
	Иначе
		Возврат Истина;
	КонецЕсли;
КонецФункции
 
Процедура ОП_НачатьЗамерФорма(Форма) Экспорт
	Если НЕ ОП_СодержитСвойство(Форма, "ИМС_ЗамерПроизводительности") Тогда
		ОписаниеТипа = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(14, 0, ДопустимыйЗнак.Неотрицательный));
		Реквизиты = Новый Массив;
		Реквизиты.Добавить(Новый РеквизитФормы("ИМС_ЗамерПроизводительности", ОписаниеТипа));
		Форма.ИзменитьРеквизиты(Реквизиты);
	КонецЕсли;
 
	Форма.ИМС_ЗамерПроизводительности = ОценкаПроизводительности.НачатьЗамерВремени();
КонецПроцедуры
 
Процедура ОП_ЗавершитьЗамерФорма(Форма, Операция = ".Открытие") Экспорт
	Объект = Форма.РеквизитФормыВЗначение("Объект");
 
	ИмяОбъекта = Объект.Метаданные().Имя;
	ОценкаПроизводительности.ЗакончитьЗамерВремени("Имс:"+ИмяОбъекта+Операция,Форма.ИМС_ЗамерПроизводительности);
КонецПроцедуры
 
#КонецОбласти

Дальше, добавляем новое расширение конфигурации. В расширение добавляем требуемые формы документов и на форме:

 
&НаСервере
Процедура ОП_ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	РУ.ОП_НачатьЗамерФорма(ЭтаФорма);
КонецПроцедуры
 
 
&НаКлиенте
Процедура ОП_ПриОткрытии(Отказ)
	ОП_ПриОткрытииНаСервере();
КонецПроцедуры
 
 
&НаСервере
Процедура ОП_ПриОткрытииНаСервере()
	РУ.ОП_ЗавершитьЗамерФорма(ЭтаФорма);
КонецПроцедуры
 
 
&НаСервере
Процедура ОП_ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
	Если ПараметрыЗаписи.РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
		РУ.ОП_НачатьЗамерФорма(ЭтаФорма);
	КонецЕсли;
КонецПроцедуры
 
 
&НаСервере
Процедура ОП_ПослеЗаписиНаСервере(ТекущийОбъект, ПараметрыЗаписи)
	Если ПараметрыЗаписи.РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
		РУ.ОП_ЗавершитьЗамерФорма(ЭтаФорма,".Проведение");
	КонецЕсли;
КонецПроцедуры

Главное, не забыть снять флаг “Безопасный режим” с расширения. Замеры производительности в безопасном режиме не работают.

Публикация календарей 1С Документооборота в формате ICS

Календари в формате ICS для Документооборота или интеграция документооборота с Outlook.
При внедрени мероприятий в документообороте, всегда вставал вопрос: а в Outlook календарь можно импортировать? Стандартный документооборот не позволяет этого. Пришлось сделать расширение реализующее календарь в виде http сервиса.

Тестировался на Документооборот 8 КОРП, редакция 2.1 (2.1.9.3) и 1С:Предприятие 8.3 (8.3.8.2197)

По аналогии можно сделать и для других платформ.

Путь к календарям: http[s]://{веб-сервер 1С}/{Имя базы}/hs/ical?room={Имя помещения (переговорной)}

Календарь ICS

Динамические роли в Документообороте 1С через Автоподстановки

Меня всегда удивляло что в 1С Документообороте не работает автоматическая подстановка ролей по объектам адресации. Небольшая доработка и вуаля – теперь работает.

В модуле ШаблоныБизнесПроцессовПереопределяемый

// Возвращает список пользовательских функций для автоподстановки исполнителей в шаблонах бизнес-процессов
// Параметры:
//	ИменаПредметовДляФункций - массив - массив имен предметов для функций автоподстановки
//
Функция ПолучитьСписокДоступныхФункций(ИменаПредметовДляФункций) Экспорт
 
	ДоступныеФункции = Новый СписокЗначений;
	//ДоступныеФункции.Добавить("ШаблоныБизнесПроцессовПереопределяемый.&lt;ИмяФункции&gt;(Объект)", "&lt;Представление функции&gt;");
	rudm_ДобавитьАвтоподстановки(ДоступныеФункции);
 
        Возврат ДоступныеФункции;
 
КонецФункции
 
 
Процедура rudm_ДобавитьАвтоподстановки(ДоступныеФункции)
	ДоступныеФункции.Добавить("ШаблоныБизнесПроцессовПереопределяемый.rudm_ПолучитьРеквизитПредметаБизнесПроцесса((Объект)", "Ответственный за предмет");
 
	Выборка = Справочники.РолиИсполнителей.Выбрать();
	Пока Выборка.Следующий() Цикл
		Если Выборка.ИспользуетсяСОбъектамиАдресации И Выборка.ИспользуетсяБезОбъектовАдресации Тогда
			ДоступныеФункции.Добавить("ШаблоныБизнесПроцессовПереопределяемый.rudm_РольСбъектамиАдресации(Объект,"""+Выборка.Код+""")", Выборка.Наименование);
		КонецЕсли;
	КонецЦикла;
КонецПроцедуры
 
Функция rudm_ПредметОтветственный(БизнесПроцессОбъект) Экспорт
	Возврат rudm_ПолучитьРеквизитПредметаБизнесПроцесса(БизнесПроцессОбъект, "Ответственный");
КонецФункции
 
Функция rudm_ПолучитьОбъектАдресации(БизнесПроцессОбъект, ТипОбъектаАдресации) Экспорт
	Если ТипОбъектаАдресации = ПланыВидовХарактеристик.ОбъектыАдресацииЗадач.Организация Тогда
		возврат ШаблоныБизнесПроцессовПереопределяемый.ПолучитьРеквизитПредметаБизнесПроцесса(БизнесПроцессОбъект, "Организация");
	ИначеЕсли ТипОбъектаАдресации = ПланыВидовХарактеристик.ОбъектыАдресацииЗадач.Контрагент Тогда
		возврат ШаблоныБизнесПроцессовПереопределяемый.ПолучитьРеквизитПредметаБизнесПроцесса(БизнесПроцессОбъект, "Контрагент");
	ИначеЕсли ТипОбъектаАдресации = ПланыВидовХарактеристик.ОбъектыАдресацииЗадач.Подразделение Тогда
		возврат ШаблоныБизнесПроцессовПереопределяемый.ПолучитьРеквизитПредметаБизнесПроцесса(БизнесПроцессОбъект, "Подразделение");
	ИначеЕсли ТипОбъектаАдресации = ПланыВидовХарактеристик.ОбъектыАдресацииЗадач.Проект Тогда
		возврат ШаблоныБизнесПроцессовПереопределяемый.ПолучитьРеквизитПредметаБизнесПроцесса(БизнесПроцессОбъект, "Проект");
	КонецЕсли;
 
	Возврат Неопределено;
КонецФункции
 
Функция rudm_ПолучитьПолнуюРоль(Роль, ОсновнойОбъектАдресации, ДополнительныйОбъектАдресации) Экспорт
 
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ ПЕРВЫЕ 1
		|	ПолныеРоли.Ссылка  ПолнаяРоль
		|ИЗ
		|	Справочник.ПолныеРоли КАК ПолныеРоли
		|ГДЕ
		|	ПолныеРоли.Владелец = &amp;РольИсполнителя
		|	И ПолныеРоли.ОсновнойОбъектАдресации = &amp;ОсновнойОбъектАдресации
		|	И ПолныеРоли.ДополнительныйОбъектАдресации = &amp;ДополнительныйОбъектАдресации";
 
	Запрос.УстановитьПараметр("ДополнительныйОбъектАдресации", ДополнительныйОбъектАдресации);
	Запрос.УстановитьПараметр("ОсновнойОбъектАдресации", ОсновнойОбъектАдресации);
	Запрос.УстановитьПараметр("РольИсполнителя", Роль);
 
	РезультатЗапроса = Запрос.Выполнить();
 
	ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
 
	Если ВыборкаДетальныеЗаписи.Следующий() Тогда
		Возврат  ВыборкаДетальныеЗаписи.ПолнаяРоль;
	Иначе
		//Если не найдена роль с объектами адресации, ищем роль без них
		Запрос.УстановитьПараметр("ДополнительныйОбъектАдресации", Неопределено);
		Запрос.УстановитьПараметр("ОсновнойОбъектАдресации", Неопределено);
		Запрос.УстановитьПараметр("РольИсполнителя", Роль);
		РезультатЗапроса = Запрос.Выполнить();
		ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
		Если ВыборкаДетальныеЗаписи.Следующий() Тогда
			Возврат  ВыборкаДетальныеЗаписи.ПолнаяРоль;
		КонецЕсли;
	КонецЕсли;
 
	Возврат Неопределено;
КонецФункции // ()	
 
 
Функция rudm_РольСбъектамиАдресации(БизнесПроцессОбъект, КодРоли) Экспорт
	Роль = Справочники.РолиИсполнителей.НайтиПоКоду(КодРоли);
 
	ОсновнойОбъектАдресации = rudm_ПолучитьОбъектАдресации(БизнесПроцессОбъект, Роль.ТипыОсновногоОбъектаАдресации);
	ДополнительныйОбъектАдресации = rudm_ПолучитьОбъектАдресации(БизнесПроцессОбъект, Роль.ТипыДополнительногоОбъектаАдресации);  
 
	СтруктураАдресации = Новый Структура;
	СтруктураАдресации.Вставить("РольИсполнителя", rudm_ПолучитьПолнуюРоль(Роль, ОсновнойОбъектАдресации, ДополнительныйОбъектАдресации));	
 
	СтруктураАдресации.Вставить("ОсновнойОбъектАдресации", ОсновнойОбъектАдресации);
	СтруктураАдресации.Вставить("ДополнительныйОбъектАдресации", ДополнительныйОбъектАдресации);  
 
	Возврат СтруктураАдресации;
 
КонецФункции
 
 
Функция rudm_ПолучитьРеквизитПредметаБизнесПроцесса(БизнесПроцессОбъект, НазваниеРеквизита) Экспорт
 
	Если БизнесПроцессОбъект.Предметы.Количество() &gt; 0 Тогда
		Предмет = БизнесПроцессОбъект.Предметы[0].Предмет;
		Попытка	
			Возврат Предмет[НазваниеРеквизита];
		Исключение
		КонецПопытки;	
	КонецЕсли;
	Возврат  Неопределено;
КонецФункции

Custom segue

Промучился вечер с настраиваемыми Segue. На новое окно переходило, а обратно – никак. Возвращаешь стандартный Segue – все работает. Фишка оказалась в порядке вызова функции present.

Изначальный вариант выглядел так:

class FlipSegue: UIStoryboardSegue {
 
    override func perform() {
        let fromViewController = self.source
        let toViewController = self.destination
 
        UIView.transition(from: fromViewController.view, to: toViewController.view, duration: 0.5, options: .transitionFlipFromLeft ) {
            fromViewController.present(toViewController, animated: false, completion: nil)
        }
    }
}

а правильный так:

class FlipSegue: UIStoryboardSegue {
 
    override func perform() {
        let fromViewController = self.source
        let toViewController = self.destination
 
        fromViewController.present(toViewController, animated: false, completion: nil)
        UIView.transition(from: fromViewController.view, to: toViewController.view, duration: 0.5, options: .transitionFlipFromLeft )
    }
}

притом unwind segue должно быть таким:

class UnFlipSegue: UIStoryboardSegue {
    override func perform() {
        let fromViewController = self.source
        let toViewController = self.destination
 
 
        UIView.transition(from: fromViewController.view, to: toViewController.view, duration: 0.5, options: .transitionFlipFromRight) { _ in
            fromViewController.dismiss(animated: false, completion: nil )
        }
    }
 
}

Интересная статистика

Divination под Android делит установки, практически поровну, между 4, 5 и 6 версией. Установок на 7-й версии – мизер.

А вот Apple, статистику распределения по версиям, не дает. Зато дает распределение между планшетом и телефоном 10% к 90%. На Android, распределение между телефонами и планшетами, аналогичное.

Сравнивать доходность между двумя платформами пока нельзя, слишком разное количество установок. Но вот доход на тысячу показов у iOS версии в 10 раз больше чем у Android.

Реклама

Рекламный сервис Apple iAD приказал долго жить.  Это сподвигло меня перейти на Google Admob и теперь я могу сравнить эти две рекламные площадки.

  1. Интеграция iAD в приложение намного проще. Для Admob надо не только подключить сам фреймворк, но и добавить в проект кучу фреймворков от которых он зависит. iAD вытащил на форму и забыл, а для Admob надо еще прописать запрос на получение рекламы.
  2. По возможности кастомизации лидирует Admob. Ему можно указать ключевые слова, местоположение, пол, возраст…  Учитывает ли данные пользователя и местоположение iAD – не знаю. Но ключевые слова он точно не учитывал, а жаль.
  3. Доходы iAD и Admob давали сопоставимые. Правда сравнивать можно только первые месяцы размещения рекламы. Под конец использования iAD сильно “сдулся”. А Admob еще не так долго эксплуатировался, что бы делать какие-то выводы.

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

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

Получить целые числа языком запросов 1С

Интересная задачка с собеседования – получить средствами языка запросов числа от -500 до 500. Само решение тривиально, но для него нужно получить перечень чисел от 0 до… ну хотя бы до 500. А это уже интереснее. Одно из возможных решений приведено ниже. Продолжая подставляя степени двойки можно получить очень длинную последовательность целых чисел.

ВЫБРАТЬ
0 КАК Числа
ПОМЕСТИТЬ Шаг0
 
ОБЪЕДИНИТЬ ВСЕ
 
ВЫБРАТЬ
1
;
 
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Лево.Числа * 2 + Право.Числа КАК Числа
ПОМЕСТИТЬ Шаг2
ИЗ
Шаг0 КАК Лево,
Шаг0 КАК Право
;
 
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Лево.Числа * 4 + Право.Числа КАК Числа
ПОМЕСТИТЬ Шаг4
ИЗ
Шаг2 КАК Лево,
Шаг2 КАК Право
;
 
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Лево.Числа * 8 + Право.Числа КАК Числа
ПОМЕСТИТЬ Шаг8
ИЗ
Шаг4 КАК Лево,
Шаг4 КАК Право
;
 
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Лево.Числа * 16 + Право.Числа КАК Числа
ПОМЕСТИТЬ Шаг16
ИЗ
Шаг8 КАК Лево,
Шаг8 КАК Право
;
 
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Лево.Числа * 32 + Право.Числа КАК Числа
ИЗ
Шаг16 КАК Лево,
Шаг16 КАК Право