пятница, 10 января 2025 г.

FromQueryAttribute: неявное преобразование или неявные грабли?

В NetCore можно сделать контроллер и объявить в нем метод:

[ApiController]
public class PersonsController : ControllerBase {
 public EditModelApiDTO GetEditObjectModel(FromQuery(Name = PersonIdName)] int targetObjectId) { ...

Метод декларирует параметр с именем PersonIdName и в url нужно добавить для него значение: 
http://localhost:5555/api/Persons/GetEditObjectModel?PersonId=1

Дополнительно к такому варианту можно сделать вызов без явной передачи значения для этого параметра:
http://localhost:5555/api/Persons/GetEditObjectModel
В этом раскладе значением для аргумента targetObjectId будет '0': в url параметр с нужным именем не найден, значением считается 'null', оно неявно преобразуется в '0' и затем передается как значение для аргумента targetObjectId.

Так получилось, что в моем тестовом окружении '0' был именно тем значением, которое нужно было передать в запросе и приложение работало верно (т.е. "все работает", хотя клиентский код не передавал значение для PersonId).

При переходе на новое окружение мой код перестал работать правильно и появилась ошибка "данные не найдены": в новом окружении вообще не было данных для ключевого значения '0'. В этом смысле мне немного повезло и я сразу увидел хоть какое-то сообщение об ошибке: если бы были данные для ключевого значения '0', то мой код их бы и обработал без всяких сообщений и я бы наверняка не заметил неверную работу приложения, ведь по контексту вызова нужна обработка данных по другому ключевому значению.

Что бы сразу получать ошибку в этом раскладе мне нужно было добавить атрибут System.ComponentModel.DataAnnotations.RequiredAttribute:
public EditModelApiDTO GetEditObjectModel([Required, FromQuery(Name = PersonIdName)] int targetObjectId) { ...

В тексте новой ошибки есть указание на имя required параметра: "errors":{"personId":["The targetObjectId field is required."]}}

вторник, 10 декабря 2024 г.

Небольшой квест про запуск демки через docker compose

У меня настроена ежедневная сборка демки приложения и выкладывание демки на опубликованный сайт. Все стабильно работало полгода, но сегодня вместо моего сайта я увидел сообщение браузера "Hmmm… can't reach this page" - браузер не получил ответ от сервера.

Как так получилось?

среда, 13 ноября 2024 г.

Какие любопытные грабли случаются в работе с Docker образами: вроде тот docker образ, а оказывается что не тот

Очень хорошие пояснения есть в статье Docker performance on Azure Pipelines agents: несколько образов я собрал для внутреннего использования и они сделаны на основе mcr.microsoft.com/windows/servercore:ltsc2019 и mcr.microsoft.com/dotnet/framework/aspnet:4.8-windowsservercore-ltsc2019.

пятница, 1 ноября 2024 г.

Javascript: ниндзя-код в javascript с помощью "hoisting"

Декларация языка javascript позволяет сделать очень много комбинаций из разнообразных выражений и по мнению компилятора/интерпретатора все они будут вполне законны и будут выполняться без ошибок.

Некоторые из них хорошо описаны в статье Ниндзя-код, но пару дней назад мне попался не знакомый мне вариант, который заставил меня усомниться в моих знаниях javascript

Вот этот код (страничка в браузере):

<body>
<script>
window.myproj = {};
window.myproj.func1 = () => {
  alert(getFirstName());
}
</script>
<script>
window.myproj.func2 = () => {
  myproj.func1(
    getFirstName = () => { return "Alex"; },
  );
}
</script>
<script>
window.myproj.func2();
</script>
</body>

Можно ли по коду сказать что покажет в диалоге func2?
Я не смог.

четверг, 24 октября 2024 г.

Функции должны возвращать код ошибки (или "throw new Exception")

Например, функция должна сделать выделение строки в гриде:

   public CollectionView SelectRow(int index) {
    var gridElement = driver.FindElementWithWait(_xPath);
    var rowElements = gridElement.FindElements(By.CssSelector(".collection-row"));
    if(rowElements.Count > index)
      rowElements[index].Click();
    return this;
  }

четверг, 11 июля 2024 г.

Отрефакторить или написать с нуля?

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

let selection = null;
const func1 = (s, e) => {
  switch (e.command) {
    case 'paste': {
      destSelection = s.getSelection();
      sourceSelection = { ...selection };
      do {
        i = 0;
        do s.SetCellValue(destSelection.leftColumnIndex + (i++), destSelection.topRowIndex, s.getCellValue(sourceSelection.leftColumnIndex, sourceSelection.topRowIndex) ?? '');
        while (sourceSelection.rightColumnIndex > sourceSelection.leftColumnIndex++);
        destSelection.topRowIndex++; sourceSelection.leftColumnIndex = selection.leftColumnIndex;
      } while (sourceSelection.bottomRowIndex > sourceSelection.topRowIndex++);
    } break;
    case ...
  }
};

Добавлено много граблей в коде копирования значений между массивами.

понедельник, 18 апреля 2022 г.

Stripe в стартапе: какой вариант интеграции выбрать?

Stripe (https://stripe.com/) - это не только платежная система со своим апи, но и готовые UI элементы и готовый web интерфейс для работы с платежами. Можно сделать удобный/красивый/функциональный платежный сервис прямо на своем сайте и на все платежные сценарии (включая refund).