четверг, 18 ноября 2021 г.

.NET Ошибка: Не удалось создать защищенный канал ssl/tls на Windows Server 2008 R2 / 2012 R2(The request was aborted: Could not create SSL/TLS secure channel) TLS 1.2

Ситуация: 

С недавних пор наши приложения на .net 4.5 в функционал которых, кроме прочего, входит загрузка страниц с сайтов. Перестали работать на серверах Windows Werver 2008 R2 и Windows Server 2012 R2

Ошибка

Не удалось создать защищенный канал ssl/tls
или она же на английском
The request was aborted: Could not create SSL/TLS secure channel

Причем эти же приложения работали нормально на машинах разработчиков на Windows 10.


Разбор ситуации. Что не помогло

Сразу скажу - много форумов читали, много советов перепробовали - нам
не помогли такие действия:

игры с настройкой протокола в приложении

ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(AlwaysGoodCertificate);

ServicePointManager.Expect100Continue = true;

ServicePointManager.DefaultConnectionLimit = 9999;

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

игры с переходом на более свежий фреймворк: 

пробовали и .NET 4.6.1 и .NET 4.7.2


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

Вот советы, которые нам не помогли

Disable SSL fallback and use only TLS for outbound connections in .NET? (Poodle mitigation)
https://stackoverflow.com/questions/26389899/disable-ssl-fallback-and-use-only-tls-for-outbound-connections-in-net-poodle

How to specify SSL protocol to use for WebClient class
https://stackoverflow.com/questions/30491716/how-to-specify-ssl-protocol-to-use-for-webclient-class

.Net WebClient: Could not create SSL/TLS secure channel
https://www.aspsnippets.com/Articles/Net-WebClient-Could-not-create-SSLTLS-secure-channel.aspx

Запрос был прерван: Не удалось создать защищенный канал SSL/TLS
https://answer-id.com/ru/74496884

Запрос был прерван: не удалось создать безопасный канал SSL / TLS
https://qastack.ru/programming/2859790/the-request-was-aborted-could-not-create-ssl-tls-secure-channel

Не удалось создать защищенный канал SSL/TLS только на сервере Windows Server 2012
https://coderoad.ru/59975964/%D0%9D%D0%B5-%D1%83%D0%B4%D0%B0%D0%BB%D0%BE%D1%81%D1%8C-%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D1%82%D1%8C-%D0%B7%D0%B0%D1%89%D0%B8%D1%89%D0%B5%D0%BD%D0%BD%D1%8B%D0%B9-%D0%BA%D0%B0%D0%BD%D0%B0%D0%BB-SSL-TLS-%D1%82%D0%BE%D0%BB%D1%8C%D0%BA%D0%BE-%D0%BD%D0%B0-%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80%D0%B5-Windows-Server


How to enable TLS 1.2 on the site servers and remote site systems
https://docs.microsoft.com/en-us/mem/configmgr/core/plan-design/security/enable-tls-1-2-server

How to enable TLS 1.2 on clients
https://docs.microsoft.com/en-us/mem/configmgr/core/plan-design/security/enable-tls-1-2-client


Разбор ситуации 2: Варианты решения

Продолжили наши разбирательства, и, думаем, нашли причину ошибки и
2 возможных варианта решения:

Наиболее вероятная причина ошибки

Старые операционки не поддерживают новые наборы шифрования протокола TLS 1.2

Суть наших умозаключений 

похоже, что проблема в наборах шифрования (Cipher Suites)

попытался их внимательнее поразбирать с помощью статьи
https://docs.microsoft.com/en-us/answers/questions/227738/windows-server-2012-r2-tls-12-cipher-suites.html

не помогло.

Продолжили разбирательство

Вот Cipher Suites для разных операционных систем
https://docs.microsoft.com/en-us/windows/win32/secauthn/cipher-suites-in-schannel

по наводкам из статьи установил

IISCrypto
https://www.nartac.com/Products/IISCrypto

Увидел: на локальной машине есть такой набор 
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

он же используется и на веб сайте с которого хотим загружать страницы

это я посмотрел через сайт
https://www.ssllabs.com/ssltest/analyze.html

Вот раздел с наборами шифрования

Cipher Suites
# TLS 1.3 (server has no preference)
TLS_AES_128_GCM_SHA256 (0x1301)   ECDH x25519 (eq. 3072 bits RSA)   FS128
TLS_CHACHA20_POLY1305_SHA256 (0x1303)   ECDH x25519 (eq. 3072 bits RSA)   FS256
TLS_AES_256_GCM_SHA384 (0x1302)   ECDH x25519 (eq. 3072 bits RSA)   FS256
# TLS 1.2 (suites in server-preferred order)
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)   ECDH x25519 (eq. 3072 bits RSA)   FS256
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca8)   ECDH x25519 (eq. 3072 bits RSA)   FS256
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)   ECDH x25519 (eq. 3072 bits RSA)   FS128


но, к сожалению, наборы не поддерживается в виндовс сервер 2012
https://docs.microsoft.com/en-us/windows/win32/secauthn/tls-cipher-suites-in-windows-8-1

и тем более в Windows Server 2008
https://docs.microsoft.com/en-us/windows/win32/secauthn/tls-cipher-suites-in-windows-7

а поддерживается только в Windows 10 (Windows Server 2016+)
https://docs.microsoft.com/en-us/windows/win32/secauthn/tls-cipher-suites-in-windows-10-v1607


Поизучали возможность обновления этих пакетов

How to Update Your Windows Server Cipher Suite for Better Security
https://www.howtogeek.com/221080/how-to-update-your-windows-server-cipher-suite-for-better-security/

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

Вот более подробный разбор этой темы
Windows Server 2012 R2 TLS 1.2 Cipher Suites
https://docs.microsoft.com/en-us/answers/questions/227738/windows-server-2012-r2-tls-12-cipher-suites.html

вроде бы неудача...
но, в форумах часто проскальзывает что "хром работает, а .NET Framework приложения - нет". Причина в том, что баузер хром использует свои пакеты шифрования а не полагается ОС.
Мы зацепились за эту идею.

В одном из проектов мы использовали компонент - внедренный браузер на Chromium

пакет в Nuget: CefSharp.Winforms, CefSharp.Common.

Попробовали загрузить страницу через этот механизм - работает!

Решения

то есть у вас есть 2 варианта решения

1. переход на свежий Windows Server 2016

2. использование пакета CefSharp но предупреждаю, он увеличивает размер приложения (в нашем случае на 100+ МБ)

Выбор за вами :)

Если нужны будут детальные инструкции по CefSharp -напишите в комментах: сделаю отдельную статью.

Материалы по теме

Как узнать версию TLS на сайте
https://ru.wikihow.com/%D1%83%D0%B7%D0%BD%D0%B0%D1%82%D1%8C-%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D1%8E-TLS-%D0%BD%D0%B0-%D1%81%D0%B0%D0%B9%D1%82%D0%B5

Страница для анализа SSL на нужном сайте(домене)
https://www.ssllabs.com/ssltest/analyze.html

How to Update Your Windows Server Cipher Suite for Better Security
https://www.howtogeek.com/221080/how-to-update-your-windows-server-cipher-suite-for-better-security/

Cipher Suites in TLS/SSL (Schannel SSP)
https://docs.microsoft.com/en-us/windows/win32/secauthn/cipher-suites-in-schannel

Demystifying Schannel
https://techcommunity.microsoft.com/t5/core-infrastructure-and-security/demystifying-schannel/ba-p/259233


 





  

суббота, 12 декабря 2020 г.

Разбор архитектуры, применение паттернов проектирования и рефакторинг по работающему проекту

Преимущества рефакторинга по живой системе по сравнению с рефакторингом по "книжным задачам"

1. не надо вникать в чужую предметную область - работаешь в своей.

2. не надо выдумывать тестовое окружение. Берем состояние кода на текущий момент времени и разбираем его. Код написан предшественниками, коллегами или даже самим программистом, но стихийно и/или давно.

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

4. Код всегда с тобой в исходном коде проекта. Всегда можно подсмотреть, если забыл, как были сделаны те или иные вещи.


Недостатки

Есть риск внесения ошибок. Поэтому рефакторинг я предпочитаю делать маленькими шагами и с повышенным вниманием к тестам.

вторник, 6 октября 2020 г.

ASP.NET MVC: одинаковый IP адрес клиента (Request.UserHostAddress) после настройки переадресации с HTTP на HTTPS

Ситуация и проблема 

Есть приложение ASP.NET MVC. В приложении записывааются IP адреса клиентов для статистики через 

Request.UserHostAddress

В какой то момент понадобилась переадресация с http на https, которая была сделана через рерайт в веб-конфиге. И значение Request.UserHostAddress стало показывать всегда один и тот же адрес (адрес сервера хостинга).

Решение

Использовать поле 

Request.Headers["X-Forwarded-For"] 

в нем, в моем случае, через запятую были 2 IP-адреса. Взяли из них первый.

Код получился примерно такой

var IPv4Address = "";

var headerValueXForwerdedFor = request.Headers["X-Forwarded-For"];

if (string.IsNullOrWhiteSpace(headerValueXForwerdedFor))

{

  IPv4Address = request?.UserHostAddress;

}

else

{

  var XForwardedForIpAddress = headerValueXForwerdedFor;

  var commaindex = headerValueXForwerdedFor.IndexOf(',');

  if (commaindex > 0)

  {

  XForwardedForIpAddress = headerValueXForwerdedFor.Substring(0, commaindex);

  }  

   IPv4Address = XForwardedForIpAddress;

 }


Что помогло: 

статья со StackOwerflow

https://stackoverflow.com/questions/15297620/request-userhostaddress-return-ip-address-of-load-balancer

суббота, 12 сентября 2020 г.

Курсы программирования для детей

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

Есть онлайн и оффлайн форматы

Курсы по таким языкам и технологиям

  • C#
  • C/C++
  • Code
  • HTML, CSS
  • Java
  • JavaScript
  • Python
  • Scratch
  • Unity

четверг, 23 апреля 2020 г.

Установка 2-х SSL сертификатов на 2-х сайтах на одном Windows Server

Задача

Нужно установить 2 SSL - сертификата на одном сервере (Windows Server)

Решение

В IIS/сайт/Привязки сайта
нужно установить галочку "требовать обозначение имени сервера"



Решение взял из статьи
https://qna.habr.com/q/434575

воскресенье, 12 апреля 2020 г.

C# Как убрать порт по умолчанию при генерации адреса с помощью UriBuilder

Проблема


есть такой код по преобраpованию ссылки

var uriBuilder = new UriBuilder(absoluteUri);
//(код модифицирующий url с помощью механизмов UriBuilder)
...
uriBuilder.ToString()

uriBuilder.ToString() генерирует ссылку с явным указанием порта, даже если порта во входной строке не было

Пример
вход: https://a.b.com/test
выход:https://a.b.com:443/test

Что помогло

Статья
How to remove the port number from a url string
https://stackoverflow.com/questions/2819336/how-to-remove-the-port-number-from-a-url-string

Решение

написал такой вспомогательный метод

private static string GetUriBuilderAsStringWithoutDefaultPort(UriBuilder uriBuilder)
        {
            if (uriBuilder.Uri.IsDefaultPort) uriBuilder.Port = -1;
            return uriBuilder.ToString();
        }

и теперь вместо UriBuilder.ToString() вызваю GetUriBuilderAsStringWithoutDefaultPort(uriBuilder)


C# пример SEO оформления страниц сайта с пейджингом (с учетом рекомендаций Google)

Задача


Оформить дружелюбно для поиска Google страницы сайта с пейджингом

Теория

На английском
SEO Guide to Google Webmaster Recommendations for Pagination
https://moz.com/blog/seo-guide-to-google-webmaster-recommendations-for-pagination

На русском
Постраничная верстка rel=«next|prev»
https://habr.com/ru/post/128746/

Сухая выжимка.
Для страниц каталога , которые реализованы в виде пейджинга рекомендуется прописывать в заголовке страницы

<link rel="prev" href="http://www.example.com/article?story=abc&page=2" /> <link rel="next" href="http://www.example.com/article?story=abc&page=4" />


причем   link rel="prev" не нужен на первой странице, а
link rel="next" не нужен на последней

Решение на C#

public static class UtilsSeo
    {
        private const string pageParamName = "page";

        public static string FindUrlPagePrev(
            string url,
            int? pageNumber,
            int pageSize,
            int itemTotalCount
        )
        {
            var pageNumberStrongDefined = GetStrongDefinedPageNumber(pageNumber);

            if (pageNumberStrongDefined <= 1) return null;

            if (pageNumberStrongDefined > GetMaxPageNumber(pageSize, itemTotalCount)) return null;

            return devuaUtils2014.Urls.UrlParamAddOrChange(url, pageParamName, (pageNumberStrongDefined - 1).ToString());
        }

        private static int GetStrongDefinedPageNumber(int? pageNumber)
        {
            var pageNumberStrongDefined = pageNumber ?? 0;
            if (pageNumberStrongDefined <= 0) pageNumberStrongDefined = 1;
            return pageNumberStrongDefined;
        }

        public static bool IsLastPage(
            int? pageNumber,
            int pageSize,
            int itemTotalCount
            )
        {
           return GetStrongDefinedPageNumber(pageNumber) >= GetMaxPageNumber(pageSize, itemTotalCount);
        }

        private static double GetMaxPageNumber(int pageSize, int itemTotalCount)
        {
            return Math.Ceiling( (double)itemTotalCount / (double)pageSize );
        }

        public static string FindUrlPageNext(
            string url,
            int? pageNumber,
            int pageSize,
            int itemTotalCount
        )
        {
            if (IsLastPage(pageNumber, pageSize, itemTotalCount)) return null;

            var pageNumberStrongDefined = GetStrongDefinedPageNumber(pageNumber);
            
            return devuaUtils2014.Urls.UrlParamAddOrChange(url, pageParamName,
                (pageNumberStrongDefined + 1).ToString());
        }

    }

Утилиты

namespace devuaUtils2014
{
    public static class Urls
    {
        public static string UrlParamRemove(string absoluteUri, string paramName)
        {
            var uriBuilder = new UriBuilder(absoluteUri);
            var query = HttpUtility.ParseQueryString(uriBuilder.Query);
            query.Remove(paramName);
            uriBuilder.Query = query.ToString();
            return GetUriBuilderAsStringWithoutDefaultPort(uriBuilder);
        }

        private static string GetUriBuilderAsStringWithoutDefaultPort(UriBuilder uriBuilder)
        {
            if (uriBuilder.Uri.IsDefaultPort)
            {
                uriBuilder.Port = -1;
            }
            return uriBuilder.ToString();
        }

        public static string UrlParamChange(string absoluteUri, string paramName, string paramValue)
        {
            var uriBuilder = new UriBuilder(absoluteUri);
            var query = HttpUtility.ParseQueryString(uriBuilder.Query);
            query[paramName] = paramValue;
            uriBuilder.Query = query.ToString();
            
            return GetUriBuilderAsStringWithoutDefaultPort(uriBuilder);
        }


        public static string UrlParamAdd(string absoluteUri, string paramName, string paramValue)
        {
            var uriBuilder = new UriBuilder(absoluteUri);
            var query = HttpUtility.ParseQueryString(uriBuilder.Query);
            query.Add(paramName,paramValue); //[paramName] = paramValue;
            uriBuilder.Query = query.ToString();
            
            return GetUriBuilderAsStringWithoutDefaultPort(uriBuilder);
        }

        public static string UrlParamAddOrChange(string absoluteUri, string paramName, string paramValue)
        {
            var uriBuilder = new UriBuilder(absoluteUri);
            var query = HttpUtility.ParseQueryString(uriBuilder.Query);
            var res = "";
            if (string.IsNullOrEmpty(query[paramName]))
            {
                res = UrlParamAdd(absoluteUri, paramName, paramValue);
            }
            else
            {
                res = UrlParamChange(absoluteUri, paramName, paramValue);
            } 
            return res;
        }
    }
}

Пример
https://childcourse.com.ua/course?page=2

четверг, 5 сентября 2019 г.

Visual Studio 2019 и TFS: пропала команда New Team Project

Окружение

Visual Studio 2019, Team Foundation Services 2015

Ситуация

Из студии (из раздела командной работы) пропала команда New Team Project

Исследование

Помогла статья
https://stackoverflow.com/questions/57501950/there-is-no-menu-to-create-new-team-project-on-visual-studio-2019

В ней сказано что это проблема взаимодействия 19-й студии и TFS 2015 и TFS 2017.

Что сделал:

Создал командный проект в Visual Studio 2017

суббота, 12 января 2019 г.

TFS Удаление Workspace

Задача: удалить устаревший Workspace в Team Foundation Server 2015

Помог пост
https://stackoverflow.com/questions/28298771/how-to-remove-tfs-workspace-mapping-for-another-user

Установил программу Team Foundation Sidekicks 2015
http://www.attrice.info/cm/tfs/
 и согласно инструкциям поста удалил устаревший Workspace

суббота, 29 декабря 2018 г.

ASP.NET MVC Ошибка при загрузке fontawesome-webfont.woff2 ERR_ABORTED 404 (Not Found)


Проблема: 

анализирую загрузку веб страницы (сайт на ASP.NET MVC) через средства разработчика Chrome

наблюдаю ошибку загрузки одного ресурса,

GET https://(сайт)/Content/themes/SbAdmin2/font-awesome-4.7.0/fonts/fontawesome-webfont.woff2?v=4.7.0 net::ERR_ABORTED 404 (Not Found)

причем, проверю по ftp: файл в директории есть

Погуглил:
если вкратце, то ошибка появляется из-за того что настройки веб-сервера не воспринимают расширение .woff2 как статический контент.

Нужно помочь в єтом веб серверу.

Делается через web.config. Нужно добавить несколько строк в разделе system.webServer / staticContent

Добавленные строки выделил

 <system.webServer>
    <staticContent>
      <clientCache cacheControlCustom="public" cacheControlMode="UseMaxAge" cacheControlMaxAge="365.00:00:00" />
  <remove fileExtension=".woff" />
      <remove fileExtension=".woff2" />
      <mimeMap fileExtension=".woff" mimeType="application/x-font-woff" />
      <mimeMap fileExtension=".woff2" mimeType="application/font-woff2" />
    </staticContent>



Материалы по теме
HTTP 404 Not Found Error with .woff or .woff2 Font Files
https://hotcakescommerce.zendesk.com/hc/en-us/articles/210926903-HTTP-404-Not-Found-Error-with-woff-or-woff2-Font-Files


How to solve glyphicons-halflings-regular.woff2 Err_Aborted issue in ASP.Net MVC 5
https://stackoverflow.com/questions/46508793/how-to-solve-glyphicons-halflings-regular-woff2-err-aborted-issue-in-asp-net-mvc

суббота, 22 декабря 2018 г.

IIS - парсинг логов и их визуализация

Задача: парсить и представлять в табличном виде логи IIS (определить, кто создает самую большую нагрузку на сайт)

Окружение: IIS 8.5 на Windows Server 2012

Что первое: нагуглил статью
Вертим логи как хотим ? анализ журналов в системах Windows
https://habr.com/company/pc-administrator/blog/351594/


По итогам
1. Установил LogParser 2.2
https://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=24659

2. Установил Log Parser Studio
https://gallery.technet.microsoft.com/Log-Parser-Studio-cd458765


Дальше оказалось не так уж сложно, если знакомы с SQL-запросами
Часть запросов предустановлены в Log Parser Studio

Также помогла статья
поля IIS логов
https://stackify.com/how-to-interpret-iis-logs/


По итогу определил самые нагружающие сайт IP-адреса (неудивительно что ими оказались IP-адреса гугл0бота) и проанализировал обращения к сайту

Помогли такие заготовки запросов

ip-адреса по количеству запросов
select c-ip, cs(User-Agent),count(c-ip) as requestcount from '[LOGFILEPATH]'
where cs-uri-stem like '%/%' 

group by c-ip, cs(User-Agent) order by count(c-ip) desc

запросы от определенных IP-адресов
select * from '[LOGFILEPATH]'
where c-ip like '66.249.64.%' and date ='2018-12-22' and time > '10:15:00' order by date, time



См. также
Log Parser Studio and IIS Advanced Logging
https://blogs.technet.microsoft.com/karywa/2013/06/28/log-parser-studio-and-iis-advanced-logging/

получение информации по IP адресу
https://2ip.ru/whois/
https://ru.infobyip.com/

четверг, 20 декабря 2018 г.

Ошибки "500 - Internal server error" и "Service Unavailable" с Url Rewrite (переопределение URL) на IIS 8.5 (Windows Server 2012)

Окружение: Windows Server 2012, IIS 8.5

Ситуация: переношу на сервер веб-приложение на технологии ASP.NET MVC

Ошибка 1:
500 - Internal server error


начинаю разбираться. оказывается в web.config была секция переопределния url

<rewrite>
...
</rewrite>

Закомментировал эту секцию, сайт заработал.

статьи по теме
Url Rewrite in IIS 7.5 causes Internal server error
https://stackoverflow.com/questions/3332923/url-rewrite-in-iis-7-5-causes-internal-server-error

URL Rewriter causing a "500 Internal Server Error"
https://forums.asp.net/t/1669041.aspx?URL+Rewriter+causing+a+500+Internal+Server+Error+


Ок. Но ведь нужно настроить переопределение URL
в статьях нашел подсказку: нужно установить Модуль перопределение Url-адресов

Что советуют:
устанавливать по ссылке
https://www.iis.net/downloads/microsoft/url-rewrite
или через Web Platform Installer

проделал оба варианта:

Получаю

Ошибка 2
Service Unavailable

Начинаю разбираться

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

Иду дальше
Управление компьютером
  Ветка в дереве: Служебные проргаммы / Просмотр событий / Журналы Windows / Приложение

Вижу такую ошибку
Не удалось загрузить модуль библиотеки DLL C:\Windows\system32\inetsrv\rewrite.dll.  Данные представляют собой код ошибки.

гуглю

Troubleshooting IIS AppPool crashes (status 503) after Windows 10 Anniversary Update
https://orcharddojo.net/blog/troubleshooting-iis-apppool-crashes-status-503-after-windows-10-anniversary-update

Windows 8.1 / Windows 10 breaks my ASP.NET / IIS : “Service unavailable”
https://stackoverflow.com/questions/18714709/windows-8-1-windows-10-breaks-my-asp-net-iis-service-unavailable/32186719#32186719

IIS UrlRewrite is not working for IIS 8
https://stackoverflow.com/questions/14607390/iis-urlrewrite-is-not-working-for-iis-8

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

Что же помогло? помог странный вариант: установка более старой версии модуля url rewrite (для iis 7) по ссылке

https://www.microsoft.com/ru-ru/download/details.aspx?id=7435






пятница, 9 ноября 2018 г.

EF.Core, Db First Подход. Scaffolding Lazy Loading

Ситуация. Делаю проект на .Net Core + Entity Framework Core
Использую DB First подход.

Хочу использовать Lazy Loading (По привычке работы с EF 6)

Проблема: стандартный скаффлодинг (через Scaffold-DbContext) не добавляет признака virtual у моделей-таблиц БД что необходимо для Lazy Loading-а.

При попытке запуска получаю ошибку

InvalidOperationException: Navigation property '(PropertyName)' on entity type '(EntityName)' is not virtual. UseLazyLoadingProxies requires all entity types to be public, unsealed, have virtual navigation properties, and have a public or protected constructor.

Как решил вопрос
перешел на скаффолдинг с использованием EF Core Power Tools

Установка:
Visual Studio -> меню Tools/Extensions And Updates

ищем EF Core Power Tools
устанавливаем

Далее скаффолдинг производим через конекстное меню проекта
пункт
EF Core Power Tools/Reverse Engineer

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

public MyDbContext(DbContextOptions<MyDbContext> options)
            : base(options)
        {
        }


Далее, самый важный момент
собственно добавление поддержки Lazy Loading

при скаффолдинге через EF Core Power Tools нужно включить опцию
Customize code using Handlebars Templates



После этого в папке проекта появятся папкf CodeTemplates с подпапками


Чтобы добавить поддержку Lazy Loading в сгенерированный код, измените шаблон Properties.hbs в CSharpEntityType / Partials следующим образом:


{{spaces 8}}public virtual ICollection<{{nav-property-type}}> {{nav-property-name}} { get; set; }
{{spaces 8}}public virtual {{nav-property-type}} {{nav-property-name}} { get; set; }

УРА!
После следующей генерации таблиц навигационные свойства будут уже виртуальными

см. также
EF.Core, Db First Подход. Ошибка скаффолдинга (Scaffold-DbContext) Build Failure

что помогло
статья
https://stackoverflow.com/questions/50827976/scaffold-dbcontext-not-generating-virtual-navigation-properties-ef-core-2-1

и статья
https://github.com/ErikEJ/EFCorePowerTools/wiki/Reverse-Engineering

понедельник, 5 ноября 2018 г.

EF.Core, Db First Подход. Ошибка скаффолдинга (Scaffold-DbContext) Build Failure

Ситуация:

Работаю с .Net.Core проектом использую EF.Core с ви-ашкые подходом.
Сгенерировал контект и базу данных с помощью команды

Scaffold-DbContext "Server=(server);Database=(dbname);User ID=(user);Password=(password)" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models

Первая генерация прошла хорошо.

Далее:
написал немного кода, добавил в солюшн AspNet.Core приложение.
провел изменение в базе данных и хочу перегенерировать модели БД.
Т.е. запустить Scaffold-DbContext во второй раз.

Чтобы не было пересечений - удаляю преварительно классы контекста БД и старые модели.

и, при запуске Scaffold-DbContext получаю ошибку

Build failed

Начал разбираться: нашел 2 варианта:

Вариант решения 1.
Обходной путь - подходит для небольших проектов


суть:
Выполняем 2 шага перед повторным скаффолдингом

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

Шаг 2. Выгрузка других проектов перед скаффолдингом
Щелкаете правой кнопкой мыши на других проектах решения и выберите Unload Project

теперь можете стереть классы моделей и выполнить скаффолдинг

Только после скаффолдинга нужно будет вгрузить обатно выгруженные на шаге 2 проекты.

что помогло
статья
https://github.com/aspnet/EntityFrameworkCore/issues/9515

Этот вариант подходит если у Вас в солюшене немного проектов и обновление моделей происходит не очень часто.

Вариант решения 2.
Используем EF Core Power Tools

Суть:
используем инструмент EF Core Core Power Tools в Visual Studio

Установка:
Visual Studio -> меню Tools/Extensions And Updates

ищем EF Core Power Tools
устанавливаем

Далее скаффолдинг производим через конекстное меню проекта
пункт
EF Core Power Tools/Reverse Engineer

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

public MyDbContext(DbContextOptions<MyDbContext> options)
            : base(options)
        {
        }


Примечание
Дальше я столкнулся с проблемой Lazy Loading, её регение описал в отдельной статье
EF.Core, Db First Подход. Scaffolding Lazy Loading


что помогло
статья
https://stackoverflow.com/questions/50827976/scaffold-dbcontext-not-generating-virtual-navigation-properties-ef-core-2-1

среда, 24 октября 2018 г.

HTTP Error 502.5 - Process Failure - Ошибка при Публикации ASP.NET Core приложения на Azure

Окужение

Visual Studio 2017, dot net core 2.1

Ситуация 

публикую простое ASP.NET Core приложение на Azure
Получаю
HTTP Error 502.5 - Process Failure 


Поиск причины ошибки

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

Azure/панель управления приложением/

App Service
Diagnose and solve problems

раскрыть Solutions To Common Problems
Check out the application event logs ...

у меня ошибка была:
Application 'MACHINE/WEBROOT/APPHOST/(Application-name)' with physical root 'D:\home\site\wwwroot\' failed to start process with commandline 'D:\home\site\wwwroot\(Appliction-name.exe) ', ErrorCode = '0x80004005 : 80008096.

смотрю

https://stackoverflow.com/questions/42713848/net-core-app-unable-to-start-in-iis-due-to-errorcode-0x80004005-80008083

советуют через консоль идти

Azure/панель управления приложением/
Development Tools/Console

Решение в моем случае


в конце концов мне помогло изменение настроек публикации в Visual Studio

Форма настроек публикации
Вкладка Settings
поле Target Runtime установил в значение Portable
(поле Deployment Mode у меня было в значении Framework-Dependent)

вторник, 16 октября 2018 г.

VS Code: как остановить выполнение команды ng serve

Окружение
Visual Studio Code

Ситуация
Запустил команду в терминале
ng serve -o

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


Вопрос
Как остановить выполнение команды

Ответ
Ctrl+C

если не помогает то
Ctrl+C , Ctrl+C
(два раза жмем Ctrl+C)


помог ответ отсюда





четверг, 16 августа 2018 г.

PostMan не проходят запросы к localhost (Could not get any response)

Проблема

В программе Postman (https://www.getpostman.com/) не удается получить данные с localhost

Решение

Settings/General
выключить 'SSL cerificate verification'


Как понял

Включил консоль
view/ShowPostmanConsole

Материалы по теме

Помогли заметки
Call to localhost:8000 "Could not get any response"
https://github.com/postmanlabs/postman-app-support/issues/2214

Self-signed certificates for localhost not working with Postman
https://github.com/postmanlabs/postman-app-support/issues/3136

вторник, 15 мая 2018 г.

Ошибка подключения к удаленному рабочему столу "CredSSP"

Проблема

При попытке подключения к удаленному рабочему столу на одном из серверов получил такую ошибку

Подключение к удаленному рабочему столу
Произошла ошибка при проверке подлинности.
Указанная функция не поддерживается
Причиной ошибки может быть исправление шифрования CredSSP


Решение

Причина и решеиние достаточно подробно описаны в статье
https://habr.com/company/vps_house/blog/358190/

Помогла служба поддержки хостинга

суббота, 12 мая 2018 г.

Генерация файла sitemap.xml на C# для ASP.NET проекта

Задача

Сгенерировать файл sitemap.xml на C# для ASP.NET проекта

Файлов в проекте нет - контент генерируется динамически

Решение


помог проект https://github.com/aseemgautam/google-sitemap

нашел его в ветке https://stackoverflow.com/questions/13449103/how-to-create-xml-sitemap-programmatically-in-c-sharp


Проект достаточно простой. Я просто интегрировал 3 файла в свой проект (немного переписав неймспейсы)

Идея: создать список объектов SitemapLocation и заслать их в объект SiteMap.
Ниже - 2 примера использования

                  public static string GetSitemap(
            List<SitemapLocation> locations
            )
        {
            Sitemap sitemap = new Sitemap();
            sitemap.AddRange(locations);            
            return sitemap.WriteSitemapToString();
        }

        public static void WriteSitemapToFile(
            List<SitemapLocation> locations,
            string fileName
        )
        {
            Sitemap sitemap = new Sitemap();
            sitemap.AddRange(locations);
            sitemap.WriteSitemapToFile(fileName);            
        }

Сам список локейшенов создается примерно так

            var res = new List<SitemapLocation>();

            res.Add(new SitemapLocation
            {
                ChangeFrequency = SitemapLocation.eChangeFrequency.weekly,
                Priority = 0.5,
                Url = UrlPrefix + "/news",
            });


Для понимания формата файла хорошо помогла статья
XML-формат файла Sitemap

см. также


XML-формат файла Sitemap

Что такое Sitemaps?

How to create XML sitemap programmatically in c#
https://stackoverflow.com/questions/13449103/how-to-create-xml-sitemap-programmatically-in-c-sharp

Как создать карту сайта? Создаем sitemap для Google и Яндекс
https://seoprofy.ua/blog/optimizaciya-sajtov/kak-sozdat-kartu-sajta

Карта сайта (файл Sitemap) от А до Я
http://pr-cy.ru/news/p/5433

Правильный файл sitemap.xml или как создать карту сайта своими руками | Карта сайта для Joomla + VirtueMart с помощью компонента Xmap




понедельник, 30 апреля 2018 г.

Трубка GrandStream DP 720 не перезванивает по списку номеров: пишет User Unknown (Базовая станция Grandstream DP 750)

Ситуация

внедряю IP телефонию на одном из проектов. Базовая станция Grandstream DP 750, трубки Grandstream DP 720.

Проблема

Трубка Grandstream DP 720 не перенабирает номер из списка номеров (Принятых, Пропущенных, Набранных и т.д.)
При попытке набрать номер пишет User Unknown
Очень неудобно, так как менеджерам приходилось переписывать номер на листик и вносить его на клавиатуре трубки.

Решение

Помогла служба поддержки провайдера IP-телефонии Phonet.

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

Первая задача: определить ip-адрес базовой станции.

Я использовал программу Advanced IP-Scanner
Подробнее по определению IP-адреса описано в статье.

Смотрите IP-адрес устройства, у которого в графе производитель будет стоять "Grandstream Networks Inc."


Далее заходим в Веб-интерфейс базовой станции.

У меня http://192.168.0.108
(у Вас, скорее всего, последняя цифра будет оличаться)

Стандартный логин/пароль: admin/admin

Далее проверим на каком профиле работает трубка
Меню: DECT/SIP Account Settings



Видим, что у меня трубка работает через первый профиль "Profile 1"
Теперь заходим в профиль: Profiles/Profile 1/Call settings
(не забываем, что у меня профиль первый, у вас - может отличаться)
и ищем поле Dial Plan (его-то нам и нужно будет поменять)




В поле Dial Plan старое значение заменяем на такое

{ x+ | *x+ | \ +x+ | *xx*x+ | x*x+x }


Внимание! тут есть тонкий момент: когда Вы заменяете строку в одном из фрагметнов есть исимвол "\". Он важен, но, видимо, он воспринимается системой как служебный символ и после сохранения значения он исчезает (система его "проглатывает").

После сохранения вы увидите в поле Dial Plan такое значение (уже без \)
{ x+ | *x+ |  +x+ | *xx*x+ | x*x+x }

И если Вы захотите скопипасить его в другой профиль - оно не сработает: сделает вид что сохранило, а на самом деле не сохранит. Поэтому обязательно используйте вариант строки с "\"