es
Feedback
.NET Разработчик

.NET Разработчик

Ir al canal en Telegram

Дневник сертифицированного .NET разработчика. Заметки, советы, новости из мира .NET и C#. Для связи: @SBenzenko Поддержать канал: - https://boosty.to/netdeveloperdiary - https://patreon.com/user?u=52551826 - https://pay.cloudtips.ru/p/70df3b3b

Mostrar más
6 723
Suscriptores
Sin datos24 horas
+87 días
+430 días
Archivo de publicaciones
. \nПри этом \n \nбудет работать. Обычно лучше избегать встроенного кода. Вынесите код JavaScript и CSS во внешние файлы.\n\nОднако, если нужно активировать встроенный контент, есть несколько вариантов:\n1. Атрибут nonce (одноразовый номер)\nСлучайный одноразовый токен (например, GUID), который добавляется в HTTP заголовок:\ndefault-src 'self'; style-src 'self' 'nonce-123456'; script-src 'self' 'nonce-123456'\nи во все элементы \n\n2. Хэш контента элемента\nНужно вычислить хеш SHA256, SHA384 или SHA512 контента элемента \nЕсли содержимое файла JavaScript не совпадает с хэшем, браузер откажется выполнить код.\n\nОкончание следует…\n\nИсточник: Кристиан Венц “Безопасность ASP.NET Core”. М.: ДМК Пресс, 2023. Глава 2.","datePublished":"2023-09-01T03:46:06Z","dateModified":"2023-09-01T03:46:06Z","author":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"publisher":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"commentCount":0,"interactionStatistic":[{"@type":"InteractionCounter","interactionType":"https://schema.org/ViewAction","userInteractionCount":1129},{"@type":"InteractionCounter","interactionType":"https://schema.org/LikeAction","userInteractionCount":6},{"@type":"InteractionCounter","interactionType":"https://schema.org/ShareAction","userInteractionCount":10}]}},{"@type":"ListItem","position":7,"item":{"@type":"SocialMediaPosting","@id":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2029","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2029","mainEntityOfPage":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2029","headline":"День 1674. #Безопасность Политика Безопасности Контента. Начало Политика безопасности контента (Content Secur…","articleBody":"День 1674. #Безопасность\nПолитика Безопасности Контента. Начало\nПолитика безопасности контента (Content Security Policy, CSP) представляет собой HTTP-заголовок Content-Security-Policy, который указывает браузерам, откуда загружать (и, в случае JavaScript, исполнять) контент, что может сделать почти невозможным осуществление межсайтового скриптинга. Значение заголовка состоит из директив и связанных значений.\n\nОсновная директива default-src предоставляет браузеру список всех действительных источников* или URI ресурсов.\n\n*Источник определяется как следующие три значения:\n- схема – http: или https:;\n- полностью определённое имя домена – www.example.com;\n- порт – по умолчанию 80 для HTTP или 443 для HTTPS (если используется порт по умолчанию, то обычно он не является частью значения источника).\nЕсли все три части различных источников идентичны, значит они совпадают. Например, у www.example.com и example.com разный источник, поскольку имена доменов не совпадают.\n\nКроме HTTP-заголовка можно использовать тег :\n\nОднако, это не очень удобно, когда значение директивы длинное. Кроме того, не будут работать некоторые функции CSP.\n\nCSP определяет большое количество директив для различных видов ресурсов:\n- base-uri – значения или пути, разрешенные для ;\n- child-src - фреймы и веб-воркеры,\n- connect-src - запросы HTTP и WebSocket,\n- font-src – шрифты,\n- form-action – значения для атрибута action элементов
;\n- img-src – изображения,\n- media-src - аудио- и видеофайлы,\n- object-src – плагины,\n- script-src - код JavaScript,\n- style-src - cтили CSS,\nи другие.\n\nСпециализированные директивы переопределяют значения default-src.\n\nВ заголовке директивы разделяются точкой с запятой, а их значения пробелами, например:\ndefault-src 'self'; style-src 'self' https://cdn.jsdelivr.net\n\nЗдесь мы разрешаем использовать ресурсы только из того же источника, что и сама страница ('self'), а также разрешаем получать стили из сети доставки контента (CDN). Заметьте, что для style-src также указано значение 'self', чтобы была возможность использовать локальные файлы стилей (т.к. style-src полностью перезаписывает значение default-src).\n\nДля указания источника есть следующие варианты:\n- сайт – https://example.com;\n- путь – https://example.com/assets/ (завершающий слеш обязателен для указания папки, а не файла с таким именем);\n- полный URI – https://example.com/assets/style.css;\n- подстановочный знак (*).\nРекомендуется использовать наиболее строгое указание источника, например, не разрешать все ресурсы из сети CDN.\n\nПродолжение следует…\n\nИсточник: Кристиан Венц “Безопасность ASP.NET Core”. М.: ДМК Пресс, 2023. Глава 2.","datePublished":"2023-08-31T06:01:18Z","dateModified":"2023-08-31T06:01:18Z","author":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"publisher":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"commentCount":5,"interactionStatistic":[{"@type":"InteractionCounter","interactionType":"https://schema.org/ViewAction","userInteractionCount":1056},{"@type":"InteractionCounter","interactionType":"https://schema.org/LikeAction","userInteractionCount":1},{"@type":"InteractionCounter","interactionType":"https://schema.org/ShareAction","userInteractionCount":12},{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":5}]}},{"@type":"ListItem","position":8,"item":{"@type":"SocialMediaPosting","@id":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2028","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2028","mainEntityOfPage":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2028","headline":"День 1673. #ЗаметкиНаПолях Отправляем Письма с Помощью FluentEmail В вашем приложении зарегистрировался новый…","articleBody":"День 1673. #ЗаметкиНаПолях\nОтправляем Письма с Помощью FluentEmail\nВ вашем приложении зарегистрировался новый пользователь? Код подтверждения должен быть отправлен на его email. Пользователь забыл пароль? Нужно отправить ему ссылку для сброса пароля. Сегодня приложения не могут существовать без отправки электронной почты. Поэтому нужно что-то легко и быстро настраиваемое для отправки электронных писем.\n\nFluentEmail — популярная библиотека с открытым исходным кодом для отправки email из приложений .NET. Он предоставляет fluent-интерфейс, т.е. мы можем легко создать сообщение, добавить получателей, установить тему и т. д., используя цепочку методов.\n\nСначала нужно добавить в проект NuGet-пакеты FluentEmail.Core и FluentEmail.Smtp. Теперь создать и отправить email очень просто:\nvar email = await Email\n .From(\"from@email.com\")\n .To(\"to@email.com\")\n .Subject(\"Hi\")\n .Body(\"Hello world!\")\n .SendAsync();\n\nЗаметьте, что From – единственный статический метод, поэтому в этом примере должен идти первым.\n\nДоступны наиболее распространённые методы:\n- .To(string emailAddress) — добавить получателей.\n- .SetFrom(string emailAddress) — изменить адрес отправителя.\n- .CC/BCC(string emailAddress) — добавление CC или BCC.\n- .Subject(string subject) — тема.\n- .Body(string body) — тело сообщения.\n- .Attach(Attachment attachment) — вложения.\n- .UsingTemplate(string template, T model, bool isHtml = true) — использовать шаблон (см. ниже).\n- .SendAsync() — отправить, используя настроенного отправителя (см. ниже).\n\nБолее правильным подходом будет настроить отправителя и шаблон в DI-контейнере:\nbuilder.Services\n .AddFluentEmail(\"from@email.com\")\n .AddRazorRenderer()\n .AddSmtpSender(…);\n\n- .AddFluentEmail() – настраивает FluentEmail с адресом отправителя по умолчанию.\n- AddSmtpSender() – настраивает провайдера отправителя SmtpSender. \n- AddRazorRenderer() – настраивает провайдера шаблонов RazorRenderer. \n\nИспользование Razor-шаблонов сообщений – одна из самых популярных функций FluentEmail. Чтобы её использовать, добавьте NuGet-пакет FluentEmail.Razor. RazorRenderer поддерживает любой код Razor. Используя шаблоны, вы можете заменить вызов .Body(…) в примере выше на один из следующих:\n- UsingTemplate(string template, T model) – использует шаблон из строки template (не очень удобно писать код Razor внутри простой строки, но подойдёт для простых шаблонов).\n- UsingTemplateFromFile(string fileName, T model) – позволяет указать путь к файлу шаблона – обычной странице .cshtml.\n\nFluentEmail позволяет вам подключить популярные провайдеры отправки email (или создать собственный, реализовав интерфейс ISender). Чтобы использовать отправителя, добавьте провайдера и настройте его в DI-контейнере. Доступны следующие основные провайдеры:\n- SMTP – стандартный клиент System.Net.Mail.SmtpClient\n- Mailgun\n- SendGrid\n- MimeKit\n\nНапример, добавить провайдера SendGrid можно, установив NuGet-пакет FluentEmail.SendGrid и вызвав:\nbuilder.Services\n .AddFluentEmail(\"from@email.com\")\n .AddRazorRenderer()\n .AddSendGridSender(\"apikey\");\n\nИсточники:\n- https://stefandjokic.tech/blog.html\n- https://lukelowrey.com/send-email-in-dotnet-core-with-fluent-email/","datePublished":"2023-08-30T05:36:30Z","dateModified":"2023-08-30T05:36:30Z","author":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"publisher":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"commentCount":0,"interactionStatistic":[{"@type":"InteractionCounter","interactionType":"https://schema.org/ViewAction","userInteractionCount":1053},{"@type":"InteractionCounter","interactionType":"https://schema.org/LikeAction","userInteractionCount":26},{"@type":"InteractionCounter","interactionType":"https://schema.org/ShareAction","userInteractionCount":27}]}},{"@type":"ListItem","position":9,"item":{"@type":"SocialMediaPosting","@id":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2027","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2027","mainEntityOfPage":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2027","headline":"День 1672. #ЗаметкиНаПолях Атрибуты From… в .NET Web API. Окончание Начало Атрибут ApiController Атрибут ApiC…","articleBody":"День 1672. #ЗаметкиНаПолях\nАтрибуты From… в .NET Web API. Окончание\nНачало\n\nАтрибут ApiController\nАтрибут ApiController добавляется к контроллеру, когда методы действия внутри него используются для обслуживания ответов API. Он настраивает функции и поведение методов действий контроллера для работы с API, облегчая жизнь разработчику, например, выдачу ответа HTTP 400, если ModelState недействителен, или выдачу деталей проблемы при ошибках.\n\n5. FromBody\nАтрибут FromBody используется для извлечения информации из тела запроса, когда тип контента в запросе указан как application/json, application/xml и т.п. Среда выполнения ASP.NET Core делегирует ответственность за чтение тела средству форматирования ввода (по умолчанию используется формат JSON). Для XML его можно добавить следующим образом:\nbuilder.Services.AddControllers()\n .AddXmlSerializerFormatters();\n\nЕсли контроллер имеет атрибут ApiController, необходимость в использовании атрибута FromBody отпадает.\n\nFromBody можно использовать только для одного параметра действия. После того как поток запроса прочитан средством форматирования ввода, он больше не доступен для повторного чтения для привязки других параметров через FromBody. Таким образом, если в теле JSON передается более одного значения, их необходимо добавить в один класс и использовать его в качестве типа для параметра действия. \n\nКогда FromBody применяется к параметру сложного типа, любые атрибуты источника привязки, применённые к его свойствам, игнорируются. Например, следующее действие Create указывает, что его параметр pet заполняется из тела:\npublic ActionResult Create([FromBody] Pet pet)\n\nКласс Pet указывает, что его свойство Breed заполняется из параметра строки запроса:\npublic class Pet\n{\n public string Name { get; set; };\n [FromQuery]\n public string Breed { get; set; };\n}\n\nЗдесь:\n- Атрибут FromQuery игнорируется.\n- Свойство Breed не заполняется из параметра строки запроса.\n\nСредства форматирования ввода читают только тело и не понимают атрибуты источника привязки. Если подходящее значение найдено в теле, это значение используется для заполнения свойства Breed.\n\n6. FromServices\nАтрибут FromServices не имеет ничего общего с HTTP-запросом. Вместо этого он позволяет использовать параметр метода действия для сопоставления с сервисом из контейнера внедрения зависимостей. Его цель — предоставить альтернативу внедрению через конструктор, когда вам нужен сервис только при вызове определённого метода.\n\nЕсли экземпляр типа не зарегистрирован в контейнере внедрения зависимостей, приложение выдаст исключение при попытке привязать параметр. Чтобы сделать параметр необязательным, используйте один из следующих подходов:\n- Сделайте параметр обнуляемым (в теле метода при обращении к параметру убедитесь, что он не null).\n- Установите значение по умолчанию для параметра.\n\nАтрибут FromServices также не требуется, если контроллер помечен атрибутом ApiController.\n\nИсточники:\n- https://www.roundthecode.com/dotnet-tutorials/fromquery-fromform-what-do-the-net-web-api-attributes-do\n- https://learn.microsoft.com/en-us/aspnet/core/mvc/models/model-binding","datePublished":"2023-08-29T05:52:42Z","dateModified":"2023-08-29T05:52:42Z","author":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"publisher":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"commentCount":0,"interactionStatistic":[{"@type":"InteractionCounter","interactionType":"https://schema.org/ViewAction","userInteractionCount":1019},{"@type":"InteractionCounter","interactionType":"https://schema.org/ShareAction","userInteractionCount":9}]}},{"@type":"ListItem","position":10,"item":{"@type":"SocialMediaPosting","@id":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2026","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2026","mainEntityOfPage":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2026","headline":"День 1671. #ЗаметкиНаПолях Атрибуты From… в .NET Web API. Начало Несмотря на то, что ASP.NET «из коробки» неп…","articleBody":"День 1671. #ЗаметкиНаПолях\nАтрибуты From… в .NET Web API. Начало\nНесмотря на то, что ASP.NET «из коробки» неплохо справляется с привязкой параметров методов действий контроллеров или свойств модели, мы можем детально контролировать, откуда мы хотим получить тот или иной параметр или свойство с помощью атрибутов [From<…>].\n\n1. FromQuery\nАтрибут FromQuery используется для получения параметра из строки запроса. Мы можем добавить атрибут FromQuery к параметру метода действия, и по умолчанию он будет сопоставлять имя параметра метода с соответствующим именем параметра строки запроса.\n\nВ примере ниже, если мы выполним запрос GET к /api/from-api/from-query?page=4, параметр page получит значение 4, и это значение будет возвращено как часть ответа:\n[ApiController]\n[Route(\"api/from-api\")]\npublic class FromApiController : Controller\n{\n [HttpGet(\"from-query\")]\n public IActionResult FromQuery([FromQuery] int page)\n {\n return Ok(new { page });\n }\n}\n\nМожно добавить необязательный параметр атрибута Name, если имя параметра метода действия отличается от имени в строке запроса:\npublic IActionResult FromQuery(\n [FromQuery(Name = \"p\")] int page)\nТогда /api/from-api/from-query?p=8 задаст параметру page значение 8.\n\n2. FromHeader\nАтрибут FromHeader сопоставляет параметр с соответствующим заголовком запроса на основе имени. Примером этого является использование аутентификации. Если мы используем аутентификацию JWT в веб-API, нам нужно добавить в запрос заголовок авторизации. Если мы хотим получить значение заголовка авторизации, мы можем добавить параметр метода authorization с атрибутом FromHeader.\npublic IActionResult FromHeader(\n [FromHeader] string authorization)\n{\n…\n}\nАналогично FromQuery, мы можем использовать необязательный параметр атрибута Name, если хотим, чтобы имя параметра метода отличалось от имени заголовка.\n\n3. FromForm\nАтрибут FromForm работает с запросами POST, если используется тип контента multipart/form-data или x-www-url-encoded. Точно так же, он сопоставит имя поля формы с именем параметра метода. Используя параметр атрибута Name, можно задать требуемое имя поля формы для сопоставления.\npublic IActionResult FromForm([FromForm] string name)\n{\n …\n} \n\n4. FromRoute\nFromRoute используется, если атрибут маршрута используется как часть действия. Добавив FromRoute к параметру действия, можно получить значение на основе имени атрибута маршрута. В следующем примере имеется атрибут маршрута с именем {category}. По умолчанию FromRoute сопоставит его атрибут с параметром метода действия category, что также можно переопределить с помощью параметра атрибута Name:\n[HttpGet(\"from-route/{category}\")]\npublic IActionResult FromRoute(\n [FromRoute(Name=\"category\")] string name)\n{\n …\n}\n\nОкончание следует…\n\nИсточник: https://www.roundthecode.com/dotnet-tutorials/fromquery-fromform-what-do-the-net-web-api-attributes-do","datePublished":"2023-08-28T05:44:24Z","dateModified":"2023-08-28T05:44:24Z","author":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"publisher":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"commentCount":0,"interactionStatistic":[{"@type":"InteractionCounter","interactionType":"https://schema.org/ViewAction","userInteractionCount":994},{"@type":"InteractionCounter","interactionType":"https://schema.org/ShareAction","userInteractionCount":12}]}},{"@type":"ListItem","position":11,"item":{"@type":"SocialMediaPosting","@id":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2025","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2025","mainEntityOfPage":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2025","headline":"День 1670. #ЗаметкиНаПолях Неожиданное Поведение Enum.TryParse Перечисления — это очень простые структуры, но…","articleBody":"День 1670. #ЗаметкиНаПолях\nНеожиданное Поведение Enum.TryParse\nПеречисления — это очень простые структуры, но некоторые функции, такие как Enum.TryParse, могут вести себя неожиданно. Сегодня рассмотрим, в чём дело, и как это исправить.\n\nEnum.TryParse «преобразует строковое представление имени или числового значения одной или нескольких перечислимых констант в эквивалентный перечислимый объект. Возвращаемое значение указывает, удалось ли преобразование».\n\nИтак, если у нас есть такое перечисление:\npublic enum Weekend\n{\n Saturday = 0,\n Sunday = 1\n}\n\nИ мы вызываем функцию:\nvar couldParse = \n Enum.TryParse(\"1\", out Weekend day);\n\nConsole.WriteLine($\"Удача: {couldParse}\");\nConsole.WriteLine($\"Значение: {day}\");\n\n//Вывод:\nУдача: True\nЗначение: Sunday\n\nПока всё нормально, но вот что интересно. Если вы укажете значение, которое не является частью перечисления, это всё равно будет работать:\nvar couldParse = \n Enum.TryParse(\"3\", out Weekend day);\n\n//Вывод:\nУдача: True\nЗначение: 3\n\nИ хотя «Значение: 3» может иметь смысл, так как вы также можете делать вещи, вроде\nvar myValue = (WeekendDay)3;\nкажется странным, что функция возвращает true и сообщает, что смогла без проблем преобразовать аргумент.\n\nЧто делать?\nИспользуйте Enum.IsDefined, чтобы проверить, находится ли данное значение в правильном диапазоне. С помощью Enum.IsDefined мы можем проверить, правильно ли значение для данного перечисления.\nvar couldParse = \n Enum.TryParse(\"3\", out Weekend day);\nif (couldParse \n && Enum.IsDefined(typeof(Weekend), day))\n{\n // Только здесь мы уверены в\n // корректности значения Weekend\n}\n\nИсточник: https://steven-giesel.com/blogPost/64d479f1-823f-4fc7-a56a-2b1ff06dcf72","datePublished":"2023-08-27T07:44:30Z","dateModified":"2023-08-27T07:44:30Z","author":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"publisher":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"commentCount":1,"interactionStatistic":[{"@type":"InteractionCounter","interactionType":"https://schema.org/ViewAction","userInteractionCount":1082},{"@type":"InteractionCounter","interactionType":"https://schema.org/ShareAction","userInteractionCount":21},{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":1}]}},{"@type":"ListItem","position":12,"item":{"@type":"SocialMediaPosting","@id":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2024","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2024","mainEntityOfPage":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2024","headline":"День 1669. Сертификат Microsoft. Доступ к Microsoft Learn Microsoft добавили возможность открывать и исследов…","articleBody":"День 1669.\nСертификат Microsoft. Доступ к Microsoft Learn\nMicrosoft добавили возможность открывать и исследовать портал Microsoft Learn во время сдачи сертификационных экзаменов. Этот ресурс будет доступен для всех ролевых и специализированных экзаменов на всех языках к середине сентября.\n\nВ повседневной жизни и работе нам часто нужно посмотреть что-то, что мы могли забыть или в чём мы не уверены. Теперь это возможно и при сдаче экзамена на сертификат Microsoft. В Microsoft расценивают портал, как вспомогательный ресурс, очень похожий на калькулятор. Поэтому предоставляют к нему доступ, однако время экзамена при этом не будет увеличено. Вопросы останутся прежними, они будут сконцентрированы на жизненных проблемах или сценариях, для решения которых требуется реальный опыт. В результате этот ресурс предназначен для ответов на вопросы, описывающих проблемы, для решения которых вам может потребоваться что-то поискать в Microsoft Learn. Использовать ресурс, чтобы ответить на все вопросы, не получится.\n\nВот некоторые детали:\n- У вас будет доступ ко всему домену Learn.microsoft.com, кроме секции вопросов и ответов и вашего профиля (вы не сможете войти в систему).\n- Время экзамена не будет добавлено. Таймер экзамена продолжит идти, пока вы будете искать в «Learn» необходимую вам информацию.\n- Ресурс будет доступен только для ролевых экзаменов, но не для экзаменов по основам.\n- Ресурс будет доступен на тех же языках, на которых доступен экзамен.\n\nЧтобы использовать Learn во время экзамена, нажмите на кнопку Microsoft Learn, доступную на экране вопросов экзамена. Microsoft Learn откроется в панели справа от экзаменационного вопроса. Вы можете перемещаться по веб-сайту, как обычно, и развернуть его на весь экран, если хотите. Вы можете открыть несколько вкладок сайта Microsoft Learn и переходить к различным частям сайта. Просмотр страниц ограничен доменом Microsoft Learn. Хотя сайт содержит ссылки на другие веб-страницы, такие как GitHub, при попытке перехода на другие домены в окне экзамена появится сообщение о том, что сайт недоступен.\n\nMicrosoft стремится улучшить общий процесс экзамена, чтобы каждый, кто хочет сдать сертификационный экзамен Microsoft, мог сделать это без каких-либо препятствий и продемонстрировать свой опыт для востребованных должностей.\n\nПоэтому, если вы хотели сдать сертификационный экзамен Microsoft, но не решались из-за боязни не вспомнить какие-нибудь детали, теперь этот барьер убран. По-моему, это отличное решение, особенно если готовиться к экзамену, используя сам портал Microsoft Learn, и хорошенько его изучить.\n\nИсточник: https://techcommunity.microsoft.com/t5/microsoft-learn-blog/introducing-a-new-resource-for-all-role-based-microsoft/ba-p/3500870","datePublished":"2023-08-26T06:21:51Z","dateModified":"2023-08-26T06:21:51Z","author":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"publisher":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"commentCount":5,"interactionStatistic":[{"@type":"InteractionCounter","interactionType":"https://schema.org/ViewAction","userInteractionCount":1172},{"@type":"InteractionCounter","interactionType":"https://schema.org/ShareAction","userInteractionCount":7},{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":5}]}},{"@type":"ListItem","position":13,"item":{"@type":"SocialMediaPosting","@id":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2023","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2023","mainEntityOfPage":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2023","headline":"День 1668. #ЗаметкиНаПолях Используем Секреты в Юнит-Тестах Хотя большинство юнит-тестов должны соответствова…","articleBody":"День 1668. #ЗаметкиНаПолях\nИспользуем Секреты в Юнит-Тестах\nХотя большинство юнит-тестов должны соответствовать характеристикам FIRST и быть «изолированными» путём имитации их зависимостей, бывают случаи, когда может быть полезно фактически подключиться к внешнему ресурсу, и использовать средство запуска модульных тестов для проверки вашего кода на «реальной» зависимости. По сути, такие тесты являются интеграционными, но не будем сейчас углубляться в терминологию.\n\nДопустим, вам нужна строка подключения к базе данных или другому внешнему ресурсу. Но вы не хотите включать её в код, поскольку все мы знаем, что секретам не место в системе контроля версий. Конечно, очевидным решением было бы получить доступ к строке подключения как к переменной среды, но Visual Studio Test Explorer (по крайней мере, насколько я могу судить) не предлагает простого способа установки переменных среды для запуска тестов. Существует файл .runsettings, но он страдает от точно такой же проблемы — в конечном итоге вам придётся добавить секреты в систему контроля версий.\n\nК счастью, функция пользовательских секретов .NET может помочь нам в этом. И хотя во многих статьях о ней предполагается, что вы используете ASP.NET Core, вы можете использовать пользовательские секреты .NET в любом типе проекта, включая тестовую сборку.\n\nВсё довольно просто. Сначала в командной строке в каталоге проекта модульного тестирования введите команду\ninit dotnet user-secrets\nЭто добавит GUID UserSecretsId в ваш файл .csproj.\n\nЗатем вы можете сохранить свой секрет с помощью команды user-secrets set, например:\ndotnet user-secrets set MyConnectionString \"my-connection-string\"\n\nЧтобы получить секретное значение в модульном тесте, просто используйте ConfigurationBuilder и вызовите AddUserSecrets, используя любой класс из вашей сборки в качестве аргумента типа. Затем вы сможете получить доступ к секретам по имени в экземпляре конфигурации и получите значение null, если секрет отсутствует.\nusing Microsoft.Extensions.Configuration;\n// ...\n\nvar config = new ConfigurationBuilder()\n .AddUserSecrets()\n .Build();\nvar connectionString = config[\"MyConnectionString\"];\n\nЗаметьте, что для этого вам понадобится установить NuGet-пакет Microsoft.Extensions.Configuration.UserSecrets.\n\nЕсли вы запускаете тесты в конвейере CI/CD, можно использовать переменные среды машины, на которой запущен конвейер. Просто добавьте вызов .AddEnvironmentVariables() в ConfigurationBuilder.\n\nИсточник: https://markheath.net/post/use-secrets-in-unit-tests","datePublished":"2023-08-25T05:38:07Z","dateModified":"2023-08-25T05:38:07Z","author":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"publisher":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"commentCount":0,"interactionStatistic":[{"@type":"InteractionCounter","interactionType":"https://schema.org/ViewAction","userInteractionCount":1170},{"@type":"InteractionCounter","interactionType":"https://schema.org/ShareAction","userInteractionCount":9}]}},{"@type":"ListItem","position":14,"item":{"@type":"SocialMediaPosting","@id":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2022","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2022","mainEntityOfPage":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2022","headline":".NET Разработчик","datePublished":"2023-08-24T18:41:36Z","dateModified":"2023-08-24T18:41:36Z","author":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"publisher":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"commentCount":6,"interactionStatistic":[{"@type":"InteractionCounter","interactionType":"https://schema.org/ViewAction","userInteractionCount":1101},{"@type":"InteractionCounter","interactionType":"https://schema.org/ShareAction","userInteractionCount":5},{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":6}]}},{"@type":"ListItem","position":15,"item":{"@type":"SocialMediaPosting","@id":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2021","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2021","mainEntityOfPage":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2021","headline":"День 1667. #ЗаметкиНаПолях #Debugging Отладка с Разных Точек Зрения Отладка — это процесс выявления основной…","articleBody":"День 1667. #ЗаметкиНаПолях #Debugging\nОтладка с Разных Точек Зрения\nОтладка — это процесс выявления основной причины ошибки и её исправления.\n\nПсихология\nДля многих разработчиков отладка - это стресс. Вместо того, чтобы относиться к этому как к решению задачи, она вызывает отрицание, взаимные обвинения, оправдания или даже апатию. Однако, признание, что отладка — это одна из форм решения проблем, - более эффективный подход.\n\nМышление\nКэрол Дуэк, известный психолог, представила концепции «мышления на рост» и «фиксированного мышления». Люди с мышлением на рост считают, что их способности и интеллект можно развить с помощью усилий, обучения и настойчивости. Люди с фиксированным мышлением считают, что их качества являются врождёнными и неизменными, что приводит к страху неудачи и нежеланию принимать вызовы. Дуэк подчёркивает важность воспитания мышления на рост для повышения устойчивости, обучения и личного развития.\n\nПрежде чем приступить к отладке, важно принять соответствующий образ мышления. Это влечёт за собой отказ от защиты своего эго, игнорирование любого давления проекта и обеспечение личного комфорта. Помните первое правило отладки: НЕ ПАНИКУЙТЕ.\n\nЭто возможность\nОтладку следует воспринимать как ценную возможность:\n- Лучше понять программу, над которой вы работаете.\n- Распознать типы ошибок, которые вы обычно совершаете.\n- Оценить качество вашего кода с точки зрения того, кто должен его читать и понимать.\n- Узнать, как вы подходите к решению проблем.\n\nПравильное отношение\nПри правильном отношении отладка может быть весёлой, как решение головоломки. Вот некоторые ключевые аспекты правильного отношения к эффективной отладке:\n- Любознательность: будьте готовы исследовать и понять основную причину проблемы.\n- Терпение: отладка может занять много времени. Будьте терпеливы и настойчивы.\n- Открытость к обучению: рассматривайте отладку как возможность учиться и улучшать свои навыки.\n- Смирение: признайте, что все совершают ошибки. Отладка — это поиск и исправление этих ошибок, а не отражение вашей ценности или интеллекта.\n- Системный подход: используйте системный подход для выявления и изоляции проблемы. Избегайте поспешных предположений и тщательно исследуйте код или систему.\n- Сотрудничество: не стесняйтесь обращаться за помощью.\n- Внимание к деталям: обратите внимание на мельчайшие детали, поскольку они часто могут содержать ключ к разгадке источника проблемы.\n- Оптимизм: вера в свою способность успешно решить проблему может помочь сохранить концентрацию и мотивацию.\n- Документация: отслеживайте процесс отладки, предпринятые шаги и решения. Эта документация может оказаться полезной для будущих справок и обучения.\n\nОтладка в два раза сложнее, чем написание кода. Следовательно, если вы пишете код максимально умно, вы по определению недостаточно умны, чтобы его отлаживать.\n Брайан В. Керниган\n\nЭто искусство\nОтладку можно рассматривать как форму искусства, поскольку она требует творческого и интуитивного подхода к решению сложных проблем с ПО. Опытный отладчик должен обладать терпением, вниманием к деталям и способностью мыслить нестандартно.\n\nПроцесс выявления и исправления ошибок часто включает изучение различных путей, использование различных стратегий, а иногда даже доверие своей интуиции. Подобно художнику, улучшающему свой шедевр, опытный отладчик оттачивает свое мастерство, извлекая уроки из каждой уникальной проблемы, с которой он сталкивается. Овладение искусством отладки может превратить программиста в виртуоза решения проблем, способного превратить хаос в коде в гармонию.\n\nИсточник: https://dev.to/rajasegar/debugging-from-different-viewpoints-46k0","datePublished":"2023-08-24T06:48:30Z","dateModified":"2023-08-24T06:48:30Z","author":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"publisher":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"commentCount":18,"interactionStatistic":[{"@type":"InteractionCounter","interactionType":"https://schema.org/ViewAction","userInteractionCount":1084},{"@type":"InteractionCounter","interactionType":"https://schema.org/ShareAction","userInteractionCount":9},{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":18}]}},{"@type":"ListItem","position":16,"item":{"@type":"SocialMediaPosting","@id":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2020","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2020","mainEntityOfPage":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2020","headline":"День 1666. #ВопросыНаСобеседовании Самые часто задаваемые вопросы на собеседовании по C# 21. Что такое слабые…","articleBody":"День 1666. #ВопросыНаСобеседовании\nСамые часто задаваемые вопросы на собеседовании по C#\n\n21. Что такое слабые ссылки и когда их использовать в C#?\nВ C# слабые ссылки — это ссылки на объекты, которые недостаточно надёжны, чтобы предотвратить сборку мусора для этих объектов. Они позволяют поддерживать ссылку на объект до тех пор, пока объект жив в памяти, но не препятствуя сборщику мусора (GC) освобождать объект при увеличении нагрузки на память. Со слабыми ссылками вы можете получить доступ к объекту, пока он всё ещё находится в памяти, но это не помешает GC удалить объект, если это необходимо.\n\nСлабые ссылки полезны в сценариях, когда вы хотите сохранить ссылку на большой объект для целей кэширования, но не хотите препятствовать его уничтожению при нехватке памяти. Это позволяет более эффективно управлять памятью, особенно при работе с большими наборами данных или кэшами в памяти.\n\nЧтобы использовать слабую ссылку в C#, создайте экземпляр класса WeakReference или WeakReference:\nWeakReference wr \n = new(new MyLargeObject());\n\nMyLargeObject lo;\nif (wr.TryGetTarget(out largeObject))\n{\n // объект всё ещё в памяти, используем его\n Console.WriteLine(\"Используем объект.\");\n}\nelse\n{\n // объект удалён сборщиком мусора\n Console.WriteLine(\"Объект удалён.\");\n largeObject = new MyLargeObject();\n}\n\nclass MyLargeObject\n{\n private byte[] _data = new byte[1000000];\n}\n\nВ этом примере, если GC решит освободить память, используемую экземпляром MyLargeObject, вызов weakReference.TryGetTarget возвратит значение false. В противном случае largeObject останется доступным через слабую ссылку.\n\nИсточник: https://dev.to/bytehide/20-senior-developer-c-interview-questions-and-answers-2023-3bjc","datePublished":"2023-08-23T05:13:57Z","dateModified":"2023-08-23T05:13:57Z","author":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"publisher":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"commentCount":0,"interactionStatistic":[{"@type":"InteractionCounter","interactionType":"https://schema.org/ViewAction","userInteractionCount":1127},{"@type":"InteractionCounter","interactionType":"https://schema.org/ShareAction","userInteractionCount":25}]}},{"@type":"ListItem","position":17,"item":{"@type":"SocialMediaPosting","@id":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2019","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2019","mainEntityOfPage":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2019","headline":"День 1665. #ЧтоНовенького Новый Интерфейс IHostedLifecycleService в .NET 8 Вчера я писал про конкурентный зап…","articleBody":"День 1665. #ЧтоНовенького\nНовый Интерфейс IHostedLifecycleService в .NET 8\nВчера я писал про конкурентный запуск и остановку hosted-сервисов в .NET 8, однако этим нововведения для размещённых сервисов не ограничиваются.\n\nВ пространство имён Microsoft.Extensions.Hosting добавлен интерфейс IHostedLifecycleService. Он наследуется от IHostedService, расширяя его методами для новых событий жизненного цикла, которые происходят до или после существующих методов StartAsync и StopAsync соответственно:\n- StartingAsync,\n- StartedAsync,\n- StoppingAsync,\n- StoppedAsync.\n\nМетод StartingAsync будет выполняться очень рано в жизненном цикле приложения, прежде чем StartAsync будет вызван для любого зарегистрированного размещённого сервиса. Это может использоваться для выполнения некоторых очень ранних проверок перед запуском приложения, таких как проверка критических требований или наличия зависимостей. Это позволит приложению потенциально завершаться сбоем при запуске до того, как какие-либо размещённые сервисы начнут выполнять свою основную рабочую нагрузку. Другие варианты использования включают «предварительный нагрев» и инициализацию синглтонов и других состояний, используемых приложением.\n\nStartedAsync будет вызываться в реализациях после завершения всех методов StartAsync для зарегистрированных размещённых сервисов. Его можно использовать для проверки состояния или условий приложения непосредственно перед пометкой приложения как успешно запущенного.\n\nStoppingAsync и StoppedAsync работают аналогично во время завершения работы приложения и предоставляют расширенные перехватчики для проверок до и после завершения работы.\n\nКроме того, в HostOptions добавлена новая опция StartupTimeout, позволяющая предоставить TimeSpan, который будет контролировать максимальное время, разрешённое для запуска всех размещённых сервисов. При установке в небесконечное (по умолчанию) значение токен отмены, передаваемый в события жизненного цикла запуска, будет отменяться по заданному тайм-ауту.\n\nИспользование интерфейса\nДовольно распространённая работа перед запуском приложения — инициализация БД. В таких средах, как CI, нам может потребоваться создавать фиктивную БД и заполнить её тестовыми данными. Одним из возможных вариантов решения является использование размещённых сервисов. В .NET 8, если сервисы запускаются конкурентно, может возникнуть проблема, когда один сервис зависит от результатов работы другого (например, от наличия инициализированной БД). Поэтому мы можем использовать IHostedLifecycleService, чтобы инициализировать базу до того, как она будет использована каким-либо другим сервисом:\npublic class ServiceA : IHostedService,\n IHostedLifecycleService\n{\n public Task StartingAsync(CancellationToken ct)\n {\n // инициализация БД\n return Task.CompletedTask;\n }\n\n // реализация других методов\n}\n \npublic class ServiceB : BackgroundService\n{\n protected override Task ExecuteAsync(\n CancellationToken stoppingToken)\n {\n // использование БД\n return Task.CompletedTask;\n }\n}\n\nЗдесь ServiceA реализует IHostedLifecycleService и инициализирует БД на самом раннем этапе жизненного цикла приложения, до любой из основных рабочих нагрузок. ServiceB, производный от BackgroundService, теперь может безопасно использовать БД, т.к. ExecuteAsync вызывается базовой реализацией StartAsync. Т.е. он не вызывается до тех пор, пока не будут завершены все методы StartingAsync для зарегистрированных сервисов. Также теперь не имеет значения, в каком порядке сервисы регистрируются в DI-контейнере:\nbuilder.Services.AddHostedService();\nbuilder.Services.AddHostedService();\n\nИсточник: https://www.stevejgordon.co.uk/introducing-the-new-ihostedlifecycleservice-interface-in-dotnet-8","datePublished":"2023-08-22T05:45:45Z","dateModified":"2023-08-22T05:45:45Z","author":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"publisher":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"commentCount":0,"interactionStatistic":[{"@type":"InteractionCounter","interactionType":"https://schema.org/ViewAction","userInteractionCount":987},{"@type":"InteractionCounter","interactionType":"https://schema.org/ShareAction","userInteractionCount":12}]}},{"@type":"ListItem","position":18,"item":{"@type":"SocialMediaPosting","@id":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2018","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2018","mainEntityOfPage":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2018","headline":"День 1664. #ЧтоНовенького Конкурентный Запуск и Остановка Hosted-Сервисов в .NET 8 Библиотека Microsoft.Exten…","articleBody":"День 1664. #ЧтоНовенького\nКонкурентный Запуск и Остановка Hosted-Сервисов в .NET 8\nБиблиотека Microsoft.Extensions.Hosting, используемая как в шаблоне проекта ASP.NET Core, так и в шаблоне Worker Service, обеспечивает возможность запуска долго работающего консольного приложения. В .NET 8 в ней появилась новая функциональность, влияющая на размещённые (hosted) сервисы.\n\nВ ASP.NET Core приложение запускает веб-сервер Kestrel и работает до тех пор, пока процесс не будет остановлен. Шаблон Worker Service идеально подходит для создания легковесных приложений обработки, которые работают постоянно. Например, это могут быть микросервисы, которые запрашивают сообщения из очереди и обрабатывают их.\n\nРазмещённые сервисы — это фоновые задачи, запускаемые хостом, которые выполняют работу приложения. Приложения могут определять один или несколько размещённых сервисов, регистрируя реализацию интерфейса IHostedService в DI-контейнере. Microsoft предоставляет общую реализацию этого интерфейса в абстрактном классе BackgroundService. Разработчики наследуют от этого класса и предоставляют реализацию абстрактного метода ExecuteAsync. Когда платформа размещения запускается, она запускает задачу, определённую в методе ExecuteAsync.\n\nДо .NET 8 код, который запускает и останавливает размещённые сервисы, делал это последовательно. Каждый IHostedService запускался последовательно через ожидание вызова StartAsync экземпляра. Т.е. каждая задача StartAsync должна была быть завершена до запуска следующей. Это не оказывало существенного влияния на большинство приложений, но это поведение по умолчанию всё же может вызывать проблемы. Несмотря на то, что внутри StartAsync рекомендуется выполнять небольшую работу, медленный размещённая сервис может задерживать запуск оставшейся части приложения.\n\nПри остановке приложений сервисы так же останавливались в обратном порядке через ожидание StopAsync. Это может быть более проблематичным, т.к. настроен тайм-аут (ShutdownTimeout), ограничивающий продолжительность корректного завершения работы. Т.е. тайм-аут должен учитывать время, необходимое для корректного закрытия всех размещённых сервисов. В некоторых ситуациях при сбросе текущих незавершённых работ это может привести к тому, что некоторые сервисы будут использовать большую часть тайм-аута.\n\nВ .NET 8 добавлены две новые опции, которые позволяют переключаться на параллельный запуск и/или остановку:\nvar host = Host.CreateDefaultBuilder(args)\n .ConfigureServices(svc =>\n {\n svc.Configure(o =>\n {\n o.ServicesStartConcurrently = true;\n o.ServicesStopConcurrently = true;\n });\n\n svc.AddHostedService();\n svc.AddHostedService();\n })\n .Build();\n\nВ примере выше регистрируются два размещённых сервиса, которые будут запускаться и останавливаться одновременно, не задерживая друг друга. Внутри .NET это достигается путём добавления всех сервисов в группу задач и ожидания завершения этой группы через Task.WhenAll. Для конкурентного останова это позволяет каждому размещённому сервису завершить свою работу в течение всего времени тайм-аута.\n\nСуществующее последовательное поведение остается по умолчанию. Как правило, переключение в параллельный режим считается безопасным для большинства приложений. Однако, если ваши размещённые сервисы напрямую зависят друг от друга каким-то образом, одновременный запуск или остановка могут вызвать ошибки в вашем приложении, поскольку вы не сможете полагаться на то, что необходимый сервис будет полностью запущен.\n\nИсточник: https://www.stevejgordon.co.uk/concurrent-hosted-service-start-and-stop-in-dotnet-8","datePublished":"2023-08-21T06:01:40Z","dateModified":"2023-08-21T06:01:40Z","author":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"publisher":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"commentCount":0,"interactionStatistic":[{"@type":"InteractionCounter","interactionType":"https://schema.org/ViewAction","userInteractionCount":1023},{"@type":"InteractionCounter","interactionType":"https://schema.org/ShareAction","userInteractionCount":17}]}},{"@type":"ListItem","position":19,"item":{"@type":"SocialMediaPosting","@id":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2017","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2017","mainEntityOfPage":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2017","headline":"День 1663. Результаты розыгрыша онлайн-билета на DotNext 2023 Победителя я определил простым рандомом из всех…","articleBody":"День 1663.\nРезультаты розыгрыша онлайн-билета на DotNext 2023\n\nПобедителя я определил простым рандомом из всех прокомментировавших исходный пост. Весь процесс в видео в первом комментарии.\n\nПобедил Stas Horoshavcev, поздравляю! В скором времени с вами свяжутся представители конференции и передадут билет.\n\nДля всех остальных промокод канала netdeveloper поможет купить билет «Для частных лиц» со скидкой. Также билет на конференцию вам может оплатить работодатель.\n\nЯ лично буду на конференции офлайн. Если тоже будете, можем пересечься.\n\nУзнать подробности о DotNext 2023, почитать программу и купить билеты можно на сайте.","datePublished":"2023-08-20T05:08:33Z","dateModified":"2023-08-20T05:08:33Z","author":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"publisher":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"commentCount":3,"interactionStatistic":[{"@type":"InteractionCounter","interactionType":"https://schema.org/ViewAction","userInteractionCount":1102},{"@type":"InteractionCounter","interactionType":"https://schema.org/ShareAction","userInteractionCount":4},{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":3}]}},{"@type":"ListItem","position":20,"item":{"@type":"SocialMediaPosting","@id":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2016","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2016","mainEntityOfPage":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary/posts/2016","headline":"День 1662. #Карьера Управляем Вверх: Руководство Разработчика по Карьерному Росту Управление «вверх» (Managin…","articleBody":"День 1662. #Карьера\nУправляем Вверх: Руководство Разработчика по Карьерному Росту\nУправление «вверх» (Managing up), по сути, является стратегией активной работы с вашим начальством для достижения общих целей. Речь идет о понимании ожиданий вашего руководителя, согласовании их с вашими целями и обеспечении того, чтобы вы оба слаженно работали над достижением общих побед. Для разработчиков это означает нечто большее, чем просто достижение целей спринта; это стремление продемонстрировать свою ценность и помочь вашему менеджеру добиться успеха в своей роли.\n\nПримеры управления вверх\n1. Прозрачная коммуникация: ваш менеджер поручил вам внедрить новую функцию, которая, по вашему мнению, может привести к потенциальным ошибкам. Вместо того, чтобы молча реализовывать её, обратитесь к нему, расскажите о потенциальных проблемах, возможно, даже предложив более эффективную альтернативу.\n\n2. Инициатива: вы обнаружили технический долг, который замедляет работу команды. Вместо того, чтобы ждать ежегодной проверки, чтобы обсудить его, назначьте встречу со своим руководителем, чтобы представить проблему и возможные решения.\n\n3. Цикл обратной связи: после завершения проекта попросите своего руководителя оставить отзыв, демонстрируя своё стремление расти и соответствовать ожиданиям команды.\n\nСоветы и рекомендации\n1. Поймите цели руководителя: узнайте, что движет вашим менеджером. Чего от него ожидает его начальство? Есть ли у него определённые KPI, которых нужно достичь? Поняв это, вы можете согласовать свой вклад, чтобы напрямую повлиять на его успех. В конце концов, какую бы роль вы ни занимали, ваша работа в основном состоит в том, чтобы ваш босс выглядел хорошо. Если у вас есть возможность взаимодействовать с людьми ещё на уровень выше, вы можете применить тот же принцип и к ним.\n\n2. Регулярно отчитывайтесь: не ждите плановых обзоров продуктивности. Организуйте короткие регулярные «проверки связи», чтобы обсудить прогресс, проблемы и получить отзыв. Это помогает в построении отношений доверия и прозрачности. Не заставляйте своего менеджера запрашивать у вас отчёты о статусе — еженедельно отправляйте электронное письмо с кратким изложением того, что вы сделали. Это отличный способ держать его в курсе, а также напоминать о вашем вкладе. Кроме того, такие регулярные отчёты очень пригодятся во время планового обзора продуктивности.\n\n3. Будьте ориентированы на решение: одно дело — определить проблему, а другое — предложить решение. При обсуждении проблем всегда старайтесь предлагать возможные решения, даже если это решения, которые вы не в состоянии реализовать. Это демонстрирует вашу инициативу и умение решать проблемы.\n\n4. Ищите обратную связь: покажите, что вы стремитесь расти и совершенствоваться. Регулярно запрашивайте обратную связь и действуйте в соответствии с ней. Если возможно, спросите об одной конкретной вещи, которую вы можете улучшить, а затем поработайте над ней. Если вы запросите слишком много отзывов, возможно, вы не сможете отреагировать на все и можете перегрузить своего руководителя.\n\n5. Управляйте ожиданиями: чётко сообщайте о сроках, потенциальных препятствиях и потребностях. Это помогает предотвратить любые неожиданности в последнюю минуту. Лучший способ превзойти ожидания — правильно их установить.\n\nПочему менеджеры тоже выигрывают\nМенеджеры получают огромную выгоду от управления вверх: прозрачную коммуникацию, упреждающие решения и члена команды, искренне заинтересованного в общем успехе. Это не только помогает в достижении командных целей, но и способствует созданию позитивной рабочей атмосферы, в которой выигрывают обе стороны.\n\nИсточник: https://ardalis.com/managing-up-developers-guide-career-advancement/","datePublished":"2023-08-19T05:47:50Z","dateModified":"2023-08-19T05:47:50Z","author":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"publisher":{"@type":"Organization","name":".NET Разработчик","url":"https://telemetr.io/es/channels/1282234011-netdeveloperdiary","image":"https://img.tlmtr.io/c/1oM7DJ/5319059513262845804?ty=x"},"commentCount":1,"interactionStatistic":[{"@type":"InteractionCounter","interactionType":"https://schema.org/ViewAction","userInteractionCount":1081},{"@type":"InteractionCounter","interactionType":"https://schema.org/ShareAction","userInteractionCount":9},{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":1}]}}]}
День 1679. #ЗаметкиНаПолях #Debugging Правила Отладки: Понимание Системы Решение проблем без подлинного их понимания может создать ненужные трудности и поставить под угрозу качество программы. Поэтому крайне важно тщательно понять систему, прежде чем пытаться её исправить. Чтобы добиться этого, триангулируйте дефект, протестировав сценарии, которые должны воспроизводить ошибку, и те, которые не должны воспроизводить её. Продолжайте этот процесс до тех пор, пока не поймете проблему достаточно хорошо, чтобы точно предсказать её возникновение в каждом случае. 1. Читайте документацию Понимание предполагаемого поведения системы, её конструкции, а иногда и обоснования её конструкции, очень важно. Когда отсутствует понимание какого-либо конкретного аспекта системы, это часто становится основной причиной проблем. Часто люди пытаются устранить проблемы, не вникая в документацию, просматривая её бегло и сосредотачиваясь только на тех разделах, которые они считают важными, непреднамеренно упуская из виду ключевую подсказку, скрытую в неисследованном разделе, которая могла бы раскрыть основную причину проблемы. Документация может казаться сложной из-за её размера, но важно в неё тщательно вникать. Часто функция, которая на первый взгляд кажется понятной, может вызывать неожиданные проблемы. Документация также часто содержит ценную информацию о проблемах, с которыми сталкивались другие. Предупреждения о типичных ошибках оказываются невероятно полезными, даже если вы считаете, что у вас необычная ошибка. Примеры кода могут помочь, но следует соблюдать осторожность. Они демонстрируют один из способов использования продукта, но могут не придерживаться передовых методов проектирования и не соответствовать реальным приложениям. Простое копирование кода без полного его понимания может привести к появлению ошибок в дальнейшем. 2. Знайте, что разумно При изучении системы крайне важно иметь чёткое представление о её типичном функционировании. Понимание стандартных операций позволяет эффективно выявлять отклонения или аномалии. Многим сложно выявить проблемы просто потому, что им не хватает фундаментального понимания того, как должна работать система. 3. Знайте дорожную карту Важно знать структуру системы. Когда определённые части системы считаются «черными ящиками», понимание того, как они должны взаимодействовать с другими компонентами, помогает определить, находится ли проблема внутри ящика или за его пределами. 4. Изучите свои инструменты Инструменты отладки предоставляют ценную информацию. Чтобы эффективно их использовать, важно освоить три аспекта: - выбор подходящего инструмента для задачи, - правильное его использование, - точная интерпретация результатов. Понимание ограничений инструментов не менее важно для обеспечения эффективных и успешных процессов отладки. 5. Изучайте подробности Избегайте предположений. Потратьте время на исследование и получение точной информации. Подробные детали были задокументированы либо вами, либо создателем библиотеки, API или платформы. Неразумно полагаться исключительно на свою память. Предположения могут вывести вас на ложный путь, где неверная информация может показаться верной, и вы упустите из виду важные проблемы. Вы можете столкнуться с запутанными данными или, что еще хуже, с ложно обнадёживающими данными. Берите пример с Эйнштейна, который никогда не трудился запоминать свой номер телефона. Он знал, что его всегда можно найти в телефонной книге. Источник: https://dev.to/rajasegar/debugging-rules-understand-the-system-ho5

День 1678. #ЧтоНовенького Превью Изображений в Visual Studio Любой разработчик часто работает с изображениями: локальными, размещёнными в Интернете или в общих сетевых ресурсах, либо существующими только в виде строк в кодировке Base64. В коде мы ссылаемся на них по-разному, но всегда как на строковые значения, которые не показывают нам, как выглядит изображение. Для Visual Studio теперь есть расширение Image Preview от Мэдса Кристенсена. Когда указатель мыши наводится на ссылку на изображение, появляется всплывающая подсказка, показывающая визуализированное изображение. Поддерживаются GIF, PNG, JPG, ICO и SVG в следующих случаях: - Абсолютный URL (http, https и ftp) - Относительный URL (./, ../ и /) - Путь к файлу (c:\, c:/, \ и /) - URI данных (data:image/png;base64,…) - URI пакета (pack://application:,,,/Images/MyImage.png) При относительной ссылке, например /file.png, расширение попытается разрешить его относительно корневой папки проекта или папки wwwroot в случае проектов ASP.NET. Источник

День 1677. #PostgresTips Советы по Postgres для Начинающих 7. Убедитесь, что контрольные суммы данных включены. Целостность данных является краеугольным камнем любой базы данных. Без уверенности в точности и согласованности данных даже самые совершенные структуры и алгоритмы БД станут бесполезными. Именно здесь контрольные суммы данных в Postgres играют решающую роль. Что это? В контексте БД контрольная сумма — это значение, полученное из суммы всех байтов в блоке данных. Если контрольные суммы данных включены, Postgres использует их для проверки целостности данных, хранящихся на диске. Когда данные записываются на диск, Postgres вычисляет и сохраняет значение контрольной суммы. Позже, когда эти данные считываются обратно в память, Postgres пересчитывает контрольную сумму и сравнивает её с сохранённым значением, чтобы убедиться, что данные не были повреждены. Почему это важно? Повреждение на уровне диска может быть вызвано различными факторами: от сбоев оборудования до ошибок ПО. Если включены контрольные суммы, Postgres может идентифицировать повреждённые данные до того, как это повлияет на ваше приложение или приведёт к более серьезным проблемам. Активация и накладные расходы Важно отметить, что контрольные суммы необходимо активировать во время создания кластера БД (initdb). Их невозможно включить для существующего кластера БД без дампа и восстановления данных или без использования специального инструмента pg_checksums (для этого потребуется некоторый опыт). Накладные расходы, связанные с контрольными суммами, относительно малы, особенно по сравнению с преимуществами обеспечения целостности данных. 8. Настройте автоочистку для частых запусков и более быстрого выполнения. Процесс автоочистки (autovacuum) в Postgres похож на бригаду уборщиков для БД. Он работает незаметно, очищая старые данные и освобождая место для новых данных, обеспечивая эффективность БД. Что это? Каждая операция INSERT, UPDATE или DELETE в Postgres создаёт новую версию строки (в случае DELETE помечает строку как удалённую). Со временем старые версии строк накапливаются, и их необходимо очищать. Autovacuum выполняет эту очистку, освобождая место для хранения и удаляя «мёртвые» строки. Он также отвечает за поддержание актуальности статистики таблиц и предотвращение инцидентов, связанных с переносом идентификаторов транзакций. Почему это важно? Без регулярной автоматической очистки БД может страдать от раздувания — неиспользуемого пространства, которое удерживает БД, что может замедлять запросы и тратить дисковое пространство. Другая проблема — устаревшая статистика, которая может приводить к неоптимальному выбору плана запроса и снижению производительности. Как настроить Настройка автоочистки сводится к тому, чтобы она запускалась чаще и быстрее выполняла свои задачи. По сути, настройку приходится вести в двух направлениях: - дать автоочистке больше мощности (больше рабочих процессов, большая квоту), т.к. по умолчанию разрешено только 3 рабочих процесса, и они довольно консервативно ограничиваются; - заставить её срабатывать чаще, т.к., опять же, по умолчанию она срабатывает только при значительных изменениях строк (10-20%); в OLTP базе данных желательно уменьшить этот показатель до 1% или даже ниже. Источник: https://postgres.ai/blog/20230722-10-postgres-tips-for-beginners

Гамма, Хелм, Влиссидес, ... #Quiz
Anonymous voting

День 1676. #Безопасность Политика Безопасности Контента. Окончание Начало Продолжение Отправка отчётов Часто полезно знать, когда политика CSP нарушается. Это означает, что либо вы не разрешили использование какого-либо источника, либо есть уязвимость, которая активно эксплуатируется. Директива report-uri заставит браузер отправлять POST-запрос на выбранную конечную точку при нарушении одной из политик:
default-src 'self'; style-src 'self' https://cdn.jsdelivr.net …; report-uri /csp-reports

Браузер отправит отчёт в формате JSON на эту конечную точку (которая также может находиться на другом домене) с информацией, какая политика была нарушена, какой файл (скрипт) её нарушил, в каком месте кода страницы он был вызван, и т.п. Существуют коммерческие системы, которые будут принимать ваши отчёты CSP и форматировать их в приятные UI представления (например, https://report-uri.com/). Стоит ли отправлять информацию о безопасности вашего сайта третьей стороне – решать вам. Однако, можно не дожидаться, пока в производственной среде что-то перестанет работать, прежде чем исправлять это. HTTP-заголовок Сontent-Security-Policy-Report-Only подойдёт для тестирования политик. В отличие от заголовка Content-Security-Policy, он не будет применять политики безопасности контента, а просто будет сообщать о найденных нарушениях политик на заданную конечную точку (если она задана в report-uri). При добавлении политик CSP к уже имеющемуся сайту полезно начать с использования заголовка Сontent-Security-Policy-Report-Only и политики, запрещающей всё. Для этого используется константа 'none':
default-src 'none'; form-action 'none'; report-uri /csp-reports

Затем, по мере получения отчётов либо вносите изменения в сайт, либо ослабляйте политики. Конечная цель – максимально строгая CSP, насколько это возможно при используемом вами стеке. Обязательно нужно отключить плагины и базовый URI:
object-src 'none'; base-uri 'none'

Также стоит рассмотреть возможность ограничения контента JavaScript только теми скриптами, для которых задан одноразовый токен:
script-src 'nonce-…'

Источник: Кристиан Венц “Безопасность ASP.NET Core”. М.: ДМК Пресс, 2023. Глава 2.

День 1675. #Безопасность Политика Безопасности Контента. Продолжение Начало Встроенный код Если существует директива CSP default-src или style-src, то встроенные стили перестают работать. Аналогично, при наличии default-src или script-src встроенный код JavaScript больше выполняться не будет. Это позволяет защититься от внедрения кода вида <script>/* вредоносный код */</script>. При этом <script src="script.js"></script> будет работать. Обычно лучше избегать встроенного кода. Вынесите код JavaScript и CSS во внешние файлы. Однако, если нужно активировать встроенный контент, есть несколько вариантов: 1. Атрибут nonce (одноразовый номер) Случайный одноразовый токен (например, GUID), который добавляется в HTTP заголовок: default-src 'self'; style-src 'self' 'nonce-123456'; script-src 'self' 'nonce-123456' и во все элементы <script> и <style>, где используются встроенный код:
<script nonce="123456'">…</script>

2. Хэш контента элемента Нужно вычислить хеш SHA256, SHA384 или SHA512 контента элемента <script> или <style>, включая разрывы строк и другие пробельные символы, и добавить в HTTP-заголовок значение 'sha<алгоритм>-<хэш>':
default-src 'self'; script-src 'self' 'sha256-nzw…='
Теперь эта политика явно разрешает встроенный код JavaScript, соответствующий хэшу. Использование хэша не распространяется на: - атрибуты обработчиков событий (например, onclick); - ссылки JavaScript: (<a href="JavaScript:…">); - атрибуты стилей (style="…"). Для активации этих функций, к значениям политики script-src или style-src надо добавить константу 'unsafe-hashes' (в дополнение к хэшам кода в этих атрибутах). Также перестанет работать динамическое выполнение кода (eval(), setInterval(), setTimeout() со строковыми аргументами и т.п.). Чтобы включить это, нужно добавить 'unsafe-eval'. 3. Значение 'unsafe-inline'. Разрешает исполнение встроенного кода (практически сводя на нет преимущества CSP). Проверка кода JavaScript с помощью Subresource Integrity (SRI) Если вы загружаете файл JavaScript со стороннего сервера, то можно проверить, что он не был подделан. Присвойте атрибуту integrity тега <script> хэш содержимого файла JavaScript:
<script src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="></script>
Если содержимое файла JavaScript не совпадает с хэшем, браузер откажется выполнить код. Окончание следует… Источник: Кристиан Венц “Безопасность ASP.NET Core”. М.: ДМК Пресс, 2023. Глава 2.

День 1674. #Безопасность Политика Безопасности Контента. Начало Политика безопасности контента (Content Security Policy, CSP) представляет собой HTTP-заголовок Content-Security-Policy, который указывает браузерам, откуда загружать (и, в случае JavaScript, исполнять) контент, что может сделать почти невозможным осуществление межсайтового скриптинга. Значение заголовка состоит из директив и связанных значений. Основная директива default-src предоставляет браузеру список всех действительных источников* или URI ресурсов. *Источник определяется как следующие три значения: - схема – http: или https:; - полностью определённое имя доменаwww.example.com; - порт – по умолчанию 80 для HTTP или 443 для HTTPS (если используется порт по умолчанию, то обычно он не является частью значения источника). Если все три части различных источников идентичны, значит они совпадают. Например, у www.example.com и example.com разный источник, поскольку имена доменов не совпадают. Кроме HTTP-заголовка можно использовать тег <meta>:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'">
Однако, это не очень удобно, когда значение директивы длинное. Кроме того, не будут работать некоторые функции CSP. CSP определяет большое количество директив для различных видов ресурсов: - base-uri – значения или пути, разрешенные для <base href="">; - child-src - фреймы и веб-воркеры, - connect-src - запросы HTTP и WebSocket, - font-src – шрифты, - form-action – значения для атрибута action элементов <form>; - img-src – изображения, - media-src - аудио- и видеофайлы, - object-src – плагины, - script-src - код JavaScript, - style-src - cтили CSS, и другие. Специализированные директивы переопределяют значения default-src. В заголовке директивы разделяются точкой с запятой, а их значения пробелами, например:
default-src 'self'; style-src 'self' https://cdn.jsdelivr.net

Здесь мы разрешаем использовать ресурсы только из того же источника, что и сама страница ('self'), а также разрешаем получать стили из сети доставки контента (CDN). Заметьте, что для style-src также указано значение 'self', чтобы была возможность использовать локальные файлы стилей (т.к. style-src полностью перезаписывает значение default-src). Для указания источника есть следующие варианты: - сайт – https://example.com; - путь – https://example.com/assets/ (завершающий слеш обязателен для указания папки, а не файла с таким именем); - полный URI – https://example.com/assets/style.css; - подстановочный знак (*). Рекомендуется использовать наиболее строгое указание источника, например, не разрешать все ресурсы из сети CDN. Продолжение следует… Источник: Кристиан Венц “Безопасность ASP.NET Core”. М.: ДМК Пресс, 2023. Глава 2.

День 1673. #ЗаметкиНаПолях Отправляем Письма с Помощью FluentEmail В вашем приложении зарегистрировался новый пользователь? Код подтверждения должен быть отправлен на его email. Пользователь забыл пароль? Нужно отправить ему ссылку для сброса пароля. Сегодня приложения не могут существовать без отправки электронной почты. Поэтому нужно что-то легко и быстро настраиваемое для отправки электронных писем. FluentEmail — популярная библиотека с открытым исходным кодом для отправки email из приложений .NET. Он предоставляет fluent-интерфейс, т.е. мы можем легко создать сообщение, добавить получателей, установить тему и т. д., используя цепочку методов. Сначала нужно добавить в проект NuGet-пакеты FluentEmail.Core и FluentEmail.Smtp. Теперь создать и отправить email очень просто:
var email = await Email
  .From("from@email.com")
  .To("to@email.com")
  .Subject("Hi")
  .Body("Hello world!")
  .SendAsync();

Заметьте, что From – единственный статический метод, поэтому в этом примере должен идти первым. Доступны наиболее распространённые методы: - .To(string emailAddress) — добавить получателей. - .SetFrom(string emailAddress) — изменить адрес отправителя. - .CC/BCC(string emailAddress) — добавление CC или BCC. - .Subject(string subject) — тема. - .Body(string body) — тело сообщения. - .Attach(Attachment attachment) — вложения. - .UsingTemplate(string template, T model, bool isHtml = true) — использовать шаблон (см. ниже). - .SendAsync() — отправить, используя настроенного отправителя (см. ниже). Более правильным подходом будет настроить отправителя и шаблон в DI-контейнере:
builder.Services
 .AddFluentEmail("from@email.com")
 .AddRazorRenderer()
 .AddSmtpSender(…);

- .AddFluentEmail() – настраивает FluentEmail с адресом отправителя по умолчанию. - AddSmtpSender() – настраивает провайдера отправителя SmtpSender. - AddRazorRenderer() – настраивает провайдера шаблонов RazorRenderer. Использование Razor-шаблонов сообщений – одна из самых популярных функций FluentEmail. Чтобы её использовать, добавьте NuGet-пакет FluentEmail.Razor. RazorRenderer поддерживает любой код Razor. Используя шаблоны, вы можете заменить вызов .Body(…) в примере выше на один из следующих: - UsingTemplate<T>(string template, T model) – использует шаблон из строки template (не очень удобно писать код Razor внутри простой строки, но подойдёт для простых шаблонов). - UsingTemplateFromFile<T>(string fileName, T model) – позволяет указать путь к файлу шаблона – обычной странице .cshtml. FluentEmail позволяет вам подключить популярные провайдеры отправки email (или создать собственный, реализовав интерфейс ISender). Чтобы использовать отправителя, добавьте провайдера и настройте его в DI-контейнере. Доступны следующие основные провайдеры: - SMTP – стандартный клиент System.Net.Mail.SmtpClient - Mailgun - SendGrid - MimeKit Например, добавить провайдера SendGrid можно, установив NuGet-пакет FluentEmail.SendGrid и вызвав:
builder.Services
 .AddFluentEmail("from@email.com")
 .AddRazorRenderer()
 .AddSendGridSender("apikey");

Источники: - https://stefandjokic.tech/blog.html - https://lukelowrey.com/send-email-in-dotnet-core-with-fluent-email/

День 1672. #ЗаметкиНаПолях Атрибуты From… в .NET Web API. Окончание Начало Атрибут ApiController Атрибут ApiController добавляется к контроллеру, когда методы действия внутри него используются для обслуживания ответов API. Он настраивает функции и поведение методов действий контроллера для работы с API, облегчая жизнь разработчику, например, выдачу ответа HTTP 400, если ModelState недействителен, или выдачу деталей проблемы при ошибках. 5. FromBody Атрибут FromBody используется для извлечения информации из тела запроса, когда тип контента в запросе указан как application/json, application/xml и т.п. Среда выполнения ASP.NET Core делегирует ответственность за чтение тела средству форматирования ввода (по умолчанию используется формат JSON). Для XML его можно добавить следующим образом:
builder.Services.AddControllers()
  .AddXmlSerializerFormatters();

Если контроллер имеет атрибут ApiController, необходимость в использовании атрибута FromBody отпадает. FromBody можно использовать только для одного параметра действия. После того как поток запроса прочитан средством форматирования ввода, он больше не доступен для повторного чтения для привязки других параметров через FromBody. Таким образом, если в теле JSON передается более одного значения, их необходимо добавить в один класс и использовать его в качестве типа для параметра действия. Когда FromBody применяется к параметру сложного типа, любые атрибуты источника привязки, применённые к его свойствам, игнорируются. Например, следующее действие Create указывает, что его параметр pet заполняется из тела:
public ActionResult<Pet> Create([FromBody] Pet pet)

Класс Pet указывает, что его свойство Breed заполняется из параметра строки запроса:
public class Pet
{
  public string Name { get; set; };
  [FromQuery]
  public string Breed { get; set; };
}

Здесь: - Атрибут FromQuery игнорируется. - Свойство Breed не заполняется из параметра строки запроса. Средства форматирования ввода читают только тело и не понимают атрибуты источника привязки. Если подходящее значение найдено в теле, это значение используется для заполнения свойства Breed. 6. FromServices Атрибут FromServices не имеет ничего общего с HTTP-запросом. Вместо этого он позволяет использовать параметр метода действия для сопоставления с сервисом из контейнера внедрения зависимостей. Его цель — предоставить альтернативу внедрению через конструктор, когда вам нужен сервис только при вызове определённого метода. Если экземпляр типа не зарегистрирован в контейнере внедрения зависимостей, приложение выдаст исключение при попытке привязать параметр. Чтобы сделать параметр необязательным, используйте один из следующих подходов: - Сделайте параметр обнуляемым (в теле метода при обращении к параметру убедитесь, что он не null). - Установите значение по умолчанию для параметра. Атрибут FromServices также не требуется, если контроллер помечен атрибутом ApiController. Источники: - https://www.roundthecode.com/dotnet-tutorials/fromquery-fromform-what-do-the-net-web-api-attributes-do - https://learn.microsoft.com/en-us/aspnet/core/mvc/models/model-binding

День 1671. #ЗаметкиНаПолях Атрибуты From… в .NET Web API. Начало Несмотря на то, что ASP.NET «из коробки» неплохо справляется с привязкой параметров методов действий контроллеров или свойств модели, мы можем детально контролировать, откуда мы хотим получить тот или иной параметр или свойство с помощью атрибутов [From<…>]. 1. FromQuery Атрибут FromQuery используется для получения параметра из строки запроса. Мы можем добавить атрибут FromQuery к параметру метода действия, и по умолчанию он будет сопоставлять имя параметра метода с соответствующим именем параметра строки запроса. В примере ниже, если мы выполним запрос GET к /api/from-api/from-query?page=4, параметр page получит значение 4, и это значение будет возвращено как часть ответа:
[ApiController]
[Route("api/from-api")]
public class FromApiController : Controller
{
  [HttpGet("from-query")]
  public IActionResult FromQuery([FromQuery] int page)
  {
    return Ok(new { page });
  }
}

Можно добавить необязательный параметр атрибута Name, если имя параметра метода действия отличается от имени в строке запроса:
public IActionResult FromQuery(
 [FromQuery(Name = "p")] int page)
Тогда /api/from-api/from-query?p=8 задаст параметру page значение 8. 2. FromHeader Атрибут FromHeader сопоставляет параметр с соответствующим заголовком запроса на основе имени. Примером этого является использование аутентификации. Если мы используем аутентификацию JWT в веб-API, нам нужно добавить в запрос заголовок авторизации. Если мы хотим получить значение заголовка авторизации, мы можем добавить параметр метода authorization с атрибутом FromHeader.
public IActionResult FromHeader(
 [FromHeader] string authorization)
{
…
}
Аналогично FromQuery, мы можем использовать необязательный параметр атрибута Name, если хотим, чтобы имя параметра метода отличалось от имени заголовка. 3. FromForm Атрибут FromForm работает с запросами POST, если используется тип контента multipart/form-data или x-www-url-encoded. Точно так же, он сопоставит имя поля формы с именем параметра метода. Используя параметр атрибута Name, можно задать требуемое имя поля формы для сопоставления.
public IActionResult FromForm([FromForm] string name)
{
 …
}    

4. FromRoute FromRoute используется, если атрибут маршрута используется как часть действия. Добавив FromRoute к параметру действия, можно получить значение на основе имени атрибута маршрута. В следующем примере имеется атрибут маршрута с именем {category}. По умолчанию FromRoute сопоставит его атрибут с параметром метода действия category, что также можно переопределить с помощью параметра атрибута Name:
[HttpGet("from-route/{category}")]
public IActionResult FromRoute(
 [FromRoute(Name="category")] string name)
{
 …
}

Окончание следует… Источник: https://www.roundthecode.com/dotnet-tutorials/fromquery-fromform-what-do-the-net-web-api-attributes-do

День 1670. #ЗаметкиНаПолях Неожиданное Поведение Enum.TryParse Перечисления — это очень простые структуры, но некоторые функции, такие как Enum.TryParse, могут вести себя неожиданно. Сегодня рассмотрим, в чём дело, и как это исправить. Enum.TryParse «преобразует строковое представление имени или числового значения одной или нескольких перечислимых констант в эквивалентный перечислимый объект. Возвращаемое значение указывает, удалось ли преобразование». Итак, если у нас есть такое перечисление:
public enum Weekend
{
  Saturday = 0,
  Sunday = 1
}

И мы вызываем функцию:
var couldParse = 
 Enum.TryParse("1", out Weekend day);

Console.WriteLine($"Удача: {couldParse}");
Console.WriteLine($"Значение: {day}");

//Вывод:
Удача: True
Значение: Sunday

Пока всё нормально, но вот что интересно. Если вы укажете значение, которое не является частью перечисления, это всё равно будет работать:
var couldParse = 
 Enum.TryParse("3", out Weekend day);

//Вывод:
Удача: True
Значение: 3

И хотя «Значение: 3» может иметь смысл, так как вы также можете делать вещи, вроде
var myValue = (WeekendDay)3;
кажется странным, что функция возвращает true и сообщает, что смогла без проблем преобразовать аргумент. Что делать? Используйте Enum.IsDefined, чтобы проверить, находится ли данное значение в правильном диапазоне. С помощью Enum.IsDefined мы можем проверить, правильно ли значение для данного перечисления.
var couldParse = 
 Enum.TryParse("3", out Weekend day);
if (couldParse 
 && Enum.IsDefined(typeof(Weekend), day))
{
  // Только здесь мы уверены в
  // корректности значения Weekend
}

Источник: https://steven-giesel.com/blogPost/64d479f1-823f-4fc7-a56a-2b1ff06dcf72

День 1669. Сертификат Microsoft. Доступ к Microsoft Learn Microsoft добавили возможность открывать и исследовать портал Microsoft Learn во время сдачи сертификационных экзаменов. Этот ресурс будет доступен для всех ролевых и специализированных экзаменов на всех языках к середине сентября. В повседневной жизни и работе нам часто нужно посмотреть что-то, что мы могли забыть или в чём мы не уверены. Теперь это возможно и при сдаче экзамена на сертификат Microsoft. В Microsoft расценивают портал, как вспомогательный ресурс, очень похожий на калькулятор. Поэтому предоставляют к нему доступ, однако время экзамена при этом не будет увеличено. Вопросы останутся прежними, они будут сконцентрированы на жизненных проблемах или сценариях, для решения которых требуется реальный опыт. В результате этот ресурс предназначен для ответов на вопросы, описывающих проблемы, для решения которых вам может потребоваться что-то поискать в Microsoft Learn. Использовать ресурс, чтобы ответить на все вопросы, не получится. Вот некоторые детали: - У вас будет доступ ко всему домену Learn.microsoft.com, кроме секции вопросов и ответов и вашего профиля (вы не сможете войти в систему). - Время экзамена не будет добавлено. Таймер экзамена продолжит идти, пока вы будете искать в «Learn» необходимую вам информацию. - Ресурс будет доступен только для ролевых экзаменов, но не для экзаменов по основам. - Ресурс будет доступен на тех же языках, на которых доступен экзамен. Чтобы использовать Learn во время экзамена, нажмите на кнопку Microsoft Learn, доступную на экране вопросов экзамена. Microsoft Learn откроется в панели справа от экзаменационного вопроса. Вы можете перемещаться по веб-сайту, как обычно, и развернуть его на весь экран, если хотите. Вы можете открыть несколько вкладок сайта Microsoft Learn и переходить к различным частям сайта. Просмотр страниц ограничен доменом Microsoft Learn. Хотя сайт содержит ссылки на другие веб-страницы, такие как GitHub, при попытке перехода на другие домены в окне экзамена появится сообщение о том, что сайт недоступен. Microsoft стремится улучшить общий процесс экзамена, чтобы каждый, кто хочет сдать сертификационный экзамен Microsoft, мог сделать это без каких-либо препятствий и продемонстрировать свой опыт для востребованных должностей. Поэтому, если вы хотели сдать сертификационный экзамен Microsoft, но не решались из-за боязни не вспомнить какие-нибудь детали, теперь этот барьер убран. По-моему, это отличное решение, особенно если готовиться к экзамену, используя сам портал Microsoft Learn, и хорошенько его изучить. Источник: https://techcommunity.microsoft.com/t5/microsoft-learn-blog/introducing-a-new-resource-for-all-role-based-microsoft/ba-p/3500870

День 1668. #ЗаметкиНаПолях Используем Секреты в Юнит-Тестах Хотя большинство юнит-тестов должны соответствовать характеристикам FIRST и быть «изолированными» путём имитации их зависимостей, бывают случаи, когда может быть полезно фактически подключиться к внешнему ресурсу, и использовать средство запуска модульных тестов для проверки вашего кода на «реальной» зависимости. По сути, такие тесты являются интеграционными, но не будем сейчас углубляться в терминологию. Допустим, вам нужна строка подключения к базе данных или другому внешнему ресурсу. Но вы не хотите включать её в код, поскольку все мы знаем, что секретам не место в системе контроля версий. Конечно, очевидным решением было бы получить доступ к строке подключения как к переменной среды, но Visual Studio Test Explorer (по крайней мере, насколько я могу судить) не предлагает простого способа установки переменных среды для запуска тестов. Существует файл .runsettings, но он страдает от точно такой же проблемы — в конечном итоге вам придётся добавить секреты в систему контроля версий. К счастью, функция пользовательских секретов .NET может помочь нам в этом. И хотя во многих статьях о ней предполагается, что вы используете ASP.NET Core, вы можете использовать пользовательские секреты .NET в любом типе проекта, включая тестовую сборку. Всё довольно просто. Сначала в командной строке в каталоге проекта модульного тестирования введите команду
init dotnet user-secrets
Это добавит GUID UserSecretsId в ваш файл .csproj. Затем вы можете сохранить свой секрет с помощью команды user-secrets set, например:
dotnet user-secrets set MyConnectionString "my-connection-string"

Чтобы получить секретное значение в модульном тесте, просто используйте ConfigurationBuilder и вызовите AddUserSecrets, используя любой класс из вашей сборки в качестве аргумента типа. Затем вы сможете получить доступ к секретам по имени в экземпляре конфигурации и получите значение null, если секрет отсутствует.
using Microsoft.Extensions.Configuration;
// ...

var config = new ConfigurationBuilder()
    .AddUserSecrets<MyUnitTests>()
    .Build();
var connectionString = config["MyConnectionString"];

Заметьте, что для этого вам понадобится установить NuGet-пакет Microsoft.Extensions.Configuration.UserSecrets. Если вы запускаете тесты в конвейере CI/CD, можно использовать переменные среды машины, на которой запущен конвейер. Просто добавьте вызов .AddEnvironmentVariables() в ConfigurationBuilder. Источник: https://markheath.net/post/use-secrets-in-unit-tests

Свойства A и B эквивалентны? public class MyClass { public int A { get; } = Random.Shared.Next(1000); public int B => Random.Shared.Next(1000); }
Anonymous voting

День 1667. #ЗаметкиНаПолях #Debugging Отладка с Разных Точек Зрения Отладка — это процесс выявления основной причины ошибки и её исправления. Психология Для многих разработчиков отладка - это стресс. Вместо того, чтобы относиться к этому как к решению задачи, она вызывает отрицание, взаимные обвинения, оправдания или даже апатию. Однако, признание, что отладка — это одна из форм решения проблем, - более эффективный подход. Мышление Кэрол Дуэк, известный психолог, представила концепции «мышления на рост» и «фиксированного мышления». Люди с мышлением на рост считают, что их способности и интеллект можно развить с помощью усилий, обучения и настойчивости. Люди с фиксированным мышлением считают, что их качества являются врождёнными и неизменными, что приводит к страху неудачи и нежеланию принимать вызовы. Дуэк подчёркивает важность воспитания мышления на рост для повышения устойчивости, обучения и личного развития. Прежде чем приступить к отладке, важно принять соответствующий образ мышления. Это влечёт за собой отказ от защиты своего эго, игнорирование любого давления проекта и обеспечение личного комфорта. Помните первое правило отладки: НЕ ПАНИКУЙТЕ. Это возможность Отладку следует воспринимать как ценную возможность: - Лучше понять программу, над которой вы работаете. - Распознать типы ошибок, которые вы обычно совершаете. - Оценить качество вашего кода с точки зрения того, кто должен его читать и понимать. - Узнать, как вы подходите к решению проблем. Правильное отношение При правильном отношении отладка может быть весёлой, как решение головоломки. Вот некоторые ключевые аспекты правильного отношения к эффективной отладке: - Любознательность: будьте готовы исследовать и понять основную причину проблемы. - Терпение: отладка может занять много времени. Будьте терпеливы и настойчивы. - Открытость к обучению: рассматривайте отладку как возможность учиться и улучшать свои навыки. - Смирение: признайте, что все совершают ошибки. Отладка — это поиск и исправление этих ошибок, а не отражение вашей ценности или интеллекта. - Системный подход: используйте системный подход для выявления и изоляции проблемы. Избегайте поспешных предположений и тщательно исследуйте код или систему. - Сотрудничество: не стесняйтесь обращаться за помощью. - Внимание к деталям: обратите внимание на мельчайшие детали, поскольку они часто могут содержать ключ к разгадке источника проблемы. - Оптимизм: вера в свою способность успешно решить проблему может помочь сохранить концентрацию и мотивацию. - Документация: отслеживайте процесс отладки, предпринятые шаги и решения. Эта документация может оказаться полезной для будущих справок и обучения. Отладка в два раза сложнее, чем написание кода. Следовательно, если вы пишете код максимально умно, вы по определению недостаточно умны, чтобы его отлаживать. Брайан В. Керниган Это искусство Отладку можно рассматривать как форму искусства, поскольку она требует творческого и интуитивного подхода к решению сложных проблем с ПО. Опытный отладчик должен обладать терпением, вниманием к деталям и способностью мыслить нестандартно. Процесс выявления и исправления ошибок часто включает изучение различных путей, использование различных стратегий, а иногда даже доверие своей интуиции. Подобно художнику, улучшающему свой шедевр, опытный отладчик оттачивает свое мастерство, извлекая уроки из каждой уникальной проблемы, с которой он сталкивается. Овладение искусством отладки может превратить программиста в виртуоза решения проблем, способного превратить хаос в коде в гармонию. Источник: https://dev.to/rajasegar/debugging-from-different-viewpoints-46k0

День 1666. #ВопросыНаСобеседовании Самые часто задаваемые вопросы на собеседовании по C# 21. Что такое слабые ссылки и когда их использовать в C#? В C# слабые ссылки — это ссылки на объекты, которые недостаточно надёжны, чтобы предотвратить сборку мусора для этих объектов. Они позволяют поддерживать ссылку на объект до тех пор, пока объект жив в памяти, но не препятствуя сборщику мусора (GC) освобождать объект при увеличении нагрузки на память. Со слабыми ссылками вы можете получить доступ к объекту, пока он всё ещё находится в памяти, но это не помешает GC удалить объект, если это необходимо. Слабые ссылки полезны в сценариях, когда вы хотите сохранить ссылку на большой объект для целей кэширования, но не хотите препятствовать его уничтожению при нехватке памяти. Это позволяет более эффективно управлять памятью, особенно при работе с большими наборами данных или кэшами в памяти. Чтобы использовать слабую ссылку в C#, создайте экземпляр класса WeakReference или WeakReference<T>:
WeakReference<MyLargeObject> wr 
 = new(new MyLargeObject());

MyLargeObject lo;
if (wr.TryGetTarget(out largeObject))
{
  // объект всё ещё в памяти, используем его
  Console.WriteLine("Используем объект.");
}
else
{
  // объект удалён сборщиком мусора
  Console.WriteLine("Объект удалён.");
  largeObject = new MyLargeObject();
}

class MyLargeObject
{
  private byte[] _data = new byte[1000000];
}

В этом примере, если GC решит освободить память, используемую экземпляром MyLargeObject, вызов weakReference.TryGetTarget возвратит значение false. В противном случае largeObject останется доступным через слабую ссылку. Источник: https://dev.to/bytehide/20-senior-developer-c-interview-questions-and-answers-2023-3bjc

День 1665. #ЧтоНовенького Новый Интерфейс IHostedLifecycleService в .NET 8 Вчера я писал про конкурентный запуск и остановку hosted-сервисов в .NET 8, однако этим нововведения для размещённых сервисов не ограничиваются. В пространство имён Microsoft.Extensions.Hosting добавлен интерфейс IHostedLifecycleService. Он наследуется от IHostedService, расширяя его методами для новых событий жизненного цикла, которые происходят до или после существующих методов StartAsync и StopAsync соответственно: - StartingAsync, - StartedAsync, - StoppingAsync, - StoppedAsync. Метод StartingAsync будет выполняться очень рано в жизненном цикле приложения, прежде чем StartAsync будет вызван для любого зарегистрированного размещённого сервиса. Это может использоваться для выполнения некоторых очень ранних проверок перед запуском приложения, таких как проверка критических требований или наличия зависимостей. Это позволит приложению потенциально завершаться сбоем при запуске до того, как какие-либо размещённые сервисы начнут выполнять свою основную рабочую нагрузку. Другие варианты использования включают «предварительный нагрев» и инициализацию синглтонов и других состояний, используемых приложением. StartedAsync будет вызываться в реализациях после завершения всех методов StartAsync для зарегистрированных размещённых сервисов. Его можно использовать для проверки состояния или условий приложения непосредственно перед пометкой приложения как успешно запущенного. StoppingAsync и StoppedAsync работают аналогично во время завершения работы приложения и предоставляют расширенные перехватчики для проверок до и после завершения работы. Кроме того, в HostOptions добавлена новая опция StartupTimeout, позволяющая предоставить TimeSpan, который будет контролировать максимальное время, разрешённое для запуска всех размещённых сервисов. При установке в небесконечное (по умолчанию) значение токен отмены, передаваемый в события жизненного цикла запуска, будет отменяться по заданному тайм-ауту. Использование интерфейса Довольно распространённая работа перед запуском приложения — инициализация БД. В таких средах, как CI, нам может потребоваться создавать фиктивную БД и заполнить её тестовыми данными. Одним из возможных вариантов решения является использование размещённых сервисов. В .NET 8, если сервисы запускаются конкурентно, может возникнуть проблема, когда один сервис зависит от результатов работы другого (например, от наличия инициализированной БД). Поэтому мы можем использовать IHostedLifecycleService, чтобы инициализировать базу до того, как она будет использована каким-либо другим сервисом:
public class ServiceA : IHostedService,
 IHostedLifecycleService
{
  public Task StartingAsync(CancellationToken ct)
  {
    // инициализация БД
    return Task.CompletedTask;
  }

  // реализация других методов
}
  
public class ServiceB : BackgroundService
{
  protected override Task ExecuteAsync(
   CancellationToken stoppingToken)
  {
    // использование БД
    return Task.CompletedTask;
  }
}

Здесь ServiceA реализует IHostedLifecycleService и инициализирует БД на самом раннем этапе жизненного цикла приложения, до любой из основных рабочих нагрузок. ServiceB, производный от BackgroundService, теперь может безопасно использовать БД, т.к. ExecuteAsync вызывается базовой реализацией StartAsync. Т.е. он не вызывается до тех пор, пока не будут завершены все методы StartingAsync для зарегистрированных сервисов. Также теперь не имеет значения, в каком порядке сервисы регистрируются в DI-контейнере:
builder.Services.AddHostedService<ServiceB>();
builder.Services.AddHostedService<ServiceA>();

Источник: https://www.stevejgordon.co.uk/introducing-the-new-ihostedlifecycleservice-interface-in-dotnet-8

День 1664. #ЧтоНовенького Конкурентный Запуск и Остановка Hosted-Сервисов в .NET 8 Библиотека Microsoft.Extensions.Hosting, используемая как в шаблоне проекта ASP.NET Core, так и в шаблоне Worker Service, обеспечивает возможность запуска долго работающего консольного приложения. В .NET 8 в ней появилась новая функциональность, влияющая на размещённые (hosted) сервисы. В ASP.NET Core приложение запускает веб-сервер Kestrel и работает до тех пор, пока процесс не будет остановлен. Шаблон Worker Service идеально подходит для создания легковесных приложений обработки, которые работают постоянно. Например, это могут быть микросервисы, которые запрашивают сообщения из очереди и обрабатывают их. Размещённые сервисы — это фоновые задачи, запускаемые хостом, которые выполняют работу приложения. Приложения могут определять один или несколько размещённых сервисов, регистрируя реализацию интерфейса IHostedService в DI-контейнере. Microsoft предоставляет общую реализацию этого интерфейса в абстрактном классе BackgroundService. Разработчики наследуют от этого класса и предоставляют реализацию абстрактного метода ExecuteAsync. Когда платформа размещения запускается, она запускает задачу, определённую в методе ExecuteAsync. До .NET 8 код, который запускает и останавливает размещённые сервисы, делал это последовательно. Каждый IHostedService запускался последовательно через ожидание вызова StartAsync экземпляра. Т.е. каждая задача StartAsync должна была быть завершена до запуска следующей. Это не оказывало существенного влияния на большинство приложений, но это поведение по умолчанию всё же может вызывать проблемы. Несмотря на то, что внутри StartAsync рекомендуется выполнять небольшую работу, медленный размещённая сервис может задерживать запуск оставшейся части приложения. При остановке приложений сервисы так же останавливались в обратном порядке через ожидание StopAsync. Это может быть более проблематичным, т.к. настроен тайм-аут (ShutdownTimeout), ограничивающий продолжительность корректного завершения работы. Т.е. тайм-аут должен учитывать время, необходимое для корректного закрытия всех размещённых сервисов. В некоторых ситуациях при сбросе текущих незавершённых работ это может привести к тому, что некоторые сервисы будут использовать большую часть тайм-аута. В .NET 8 добавлены две новые опции, которые позволяют переключаться на параллельный запуск и/или остановку:
var host = Host.CreateDefaultBuilder(args)
 .ConfigureServices(svc =>
 {
   svc.Configure<HostOptions>(o =>
   {
     o.ServicesStartConcurrently = true;
     o.ServicesStopConcurrently = true;
   });

   svc.AddHostedService<WorkerOne>();
   svc.AddHostedService<WorkerTwo>();
 })
 .Build();

В примере выше регистрируются два размещённых сервиса, которые будут запускаться и останавливаться одновременно, не задерживая друг друга. Внутри .NET это достигается путём добавления всех сервисов в группу задач и ожидания завершения этой группы через Task.WhenAll. Для конкурентного останова это позволяет каждому размещённому сервису завершить свою работу в течение всего времени тайм-аута. Существующее последовательное поведение остается по умолчанию. Как правило, переключение в параллельный режим считается безопасным для большинства приложений. Однако, если ваши размещённые сервисы напрямую зависят друг от друга каким-то образом, одновременный запуск или остановка могут вызвать ошибки в вашем приложении, поскольку вы не сможете полагаться на то, что необходимый сервис будет полностью запущен. Источник: https://www.stevejgordon.co.uk/concurrent-hosted-service-start-and-stop-in-dotnet-8

День 1663. Результаты розыгрыша онлайн-билета на DotNext 2023 Победителя я определил простым рандомом из всех прокомментирова
День 1663. Результаты розыгрыша онлайн-билета на DotNext 2023 Победителя я определил простым рандомом из всех прокомментировавших исходный пост. Весь процесс в видео в первом комментарии. Победил Stas Horoshavcev, поздравляю! В скором времени с вами свяжутся представители конференции и передадут билет. Для всех остальных промокод канала netdeveloper поможет купить билет «Для частных лиц» со скидкой. Также билет на конференцию вам может оплатить работодатель. Я лично буду на конференции офлайн. Если тоже будете, можем пересечься. Узнать подробности о DotNext 2023, почитать программу и купить билеты можно на сайте.

День 1662. #Карьера Управляем Вверх: Руководство Разработчика по Карьерному Росту Управление «вверх» (Managing up), по сути, является стратегией активной работы с вашим начальством для достижения общих целей. Речь идет о понимании ожиданий вашего руководителя, согласовании их с вашими целями и обеспечении того, чтобы вы оба слаженно работали над достижением общих побед. Для разработчиков это означает нечто большее, чем просто достижение целей спринта; это стремление продемонстрировать свою ценность и помочь вашему менеджеру добиться успеха в своей роли. Примеры управления вверх 1. Прозрачная коммуникация: ваш менеджер поручил вам внедрить новую функцию, которая, по вашему мнению, может привести к потенциальным ошибкам. Вместо того, чтобы молча реализовывать её, обратитесь к нему, расскажите о потенциальных проблемах, возможно, даже предложив более эффективную альтернативу. 2. Инициатива: вы обнаружили технический долг, который замедляет работу команды. Вместо того, чтобы ждать ежегодной проверки, чтобы обсудить его, назначьте встречу со своим руководителем, чтобы представить проблему и возможные решения. 3. Цикл обратной связи: после завершения проекта попросите своего руководителя оставить отзыв, демонстрируя своё стремление расти и соответствовать ожиданиям команды. Советы и рекомендации 1. Поймите цели руководителя: узнайте, что движет вашим менеджером. Чего от него ожидает его начальство? Есть ли у него определённые KPI, которых нужно достичь? Поняв это, вы можете согласовать свой вклад, чтобы напрямую повлиять на его успех. В конце концов, какую бы роль вы ни занимали, ваша работа в основном состоит в том, чтобы ваш босс выглядел хорошо. Если у вас есть возможность взаимодействовать с людьми ещё на уровень выше, вы можете применить тот же принцип и к ним. 2. Регулярно отчитывайтесь: не ждите плановых обзоров продуктивности. Организуйте короткие регулярные «проверки связи», чтобы обсудить прогресс, проблемы и получить отзыв. Это помогает в построении отношений доверия и прозрачности. Не заставляйте своего менеджера запрашивать у вас отчёты о статусе — еженедельно отправляйте электронное письмо с кратким изложением того, что вы сделали. Это отличный способ держать его в курсе, а также напоминать о вашем вкладе. Кроме того, такие регулярные отчёты очень пригодятся во время планового обзора продуктивности. 3. Будьте ориентированы на решение: одно дело — определить проблему, а другое — предложить решение. При обсуждении проблем всегда старайтесь предлагать возможные решения, даже если это решения, которые вы не в состоянии реализовать. Это демонстрирует вашу инициативу и умение решать проблемы. 4. Ищите обратную связь: покажите, что вы стремитесь расти и совершенствоваться. Регулярно запрашивайте обратную связь и действуйте в соответствии с ней. Если возможно, спросите об одной конкретной вещи, которую вы можете улучшить, а затем поработайте над ней. Если вы запросите слишком много отзывов, возможно, вы не сможете отреагировать на все и можете перегрузить своего руководителя. 5. Управляйте ожиданиями: чётко сообщайте о сроках, потенциальных препятствиях и потребностях. Это помогает предотвратить любые неожиданности в последнюю минуту. Лучший способ превзойти ожидания — правильно их установить. Почему менеджеры тоже выигрывают Менеджеры получают огромную выгоду от управления вверх: прозрачную коммуникацию, упреждающие решения и члена команды, искренне заинтересованного в общем успехе. Это не только помогает в достижении командных целей, но и способствует созданию позитивной рабочей атмосферы, в которой выигрывают обе стороны. Источник: https://ardalis.com/managing-up-developers-guide-career-advancement/