Страницы

Поиск по вопросам

Показаны сообщения с ярлыком asp.net-core. Показать все сообщения
Показаны сообщения с ярлыком asp.net-core. Показать все сообщения

воскресенье, 29 марта 2020 г.

Связка Nginx и Kestrel - где использовать https?

#c_sharp #nginx #aspnet_core #net_core #kestrel


Есть веб-приложение на .NET Core. По умолчанию в нем используется Kestrel, имеющий
всю необходимую для работы приложения базовую функциональность, в пом числе использование
https. Но сам MS советует использовать другие веб-серверы (IIS, Apache, Nginx) для
расширения возможностей взаимодействия с веб-службами, в т.ч. в качестве reverse proxy.
В связи с чем возник такой вопрос - необходимо ли включать поддержку https в Kestrel,
или же достаточно будет включить ее в Nginx и передавать запросы на Kestrel по http?
Примерный конфиг Nginx в рамках данного вопроса:

server {
    listen 80;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;

    ssl_certificate           /etc/nginx/cert.crt;
    ssl_certificate_key       /etc/nginx/cert.key;

    ssl_session_cache  builtin:1000  shared:SSL:10m;
    ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
    ssl_prefer_server_ciphers on;

    location / {

        proxy_set_header        Host $host;
        proxy_set_header        X-Real-IP $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header        X-Forwarded-Proto $scheme;

        proxy_pass          http://kestrel;
        proxy_read_timeout  90;

    }
}


    


Ответы

Ответ 1



Для работоспособности достаточно включить HTTPS на Nginx. HTTPS между реверс-прокси и сервером приложений не обязателен, но его следует использовать из соображений безопасности. Угрозы такие: прослушивание TCP трафика MITM-атаки Если таких угроз нет, HTTPS между Nginx и Kestrel как таковой не нужен. Сюда можно отнести такие частные случаи: оба демона находятся на одном сервере, доступ к серверу только у доверенных трафик ходит внутри DMZ

четверг, 5 марта 2020 г.

Как в ASP.Net Core работать с PostgreSQL?

#c_sharp #postgresql #aspnet_core


С помощью каких библиотек Вы работаете в ASP.Net Core с PostgreSQL?
    


Ответы

Ответ 1



Можете использовать Entity Framework. Чистый ADO.NET. Dapper (методы расширения для ADO.NET). Рабочий пример.

среда, 4 марта 2020 г.

Не работает .UseKestrel() в ASP.NET Core [закрыт]

#aspnet_core


        
             
                
                    
                        
                            Закрыт. Этот вопрос не по теме. Ответы на него в данный
момент не принимаются.
                            
                        
                    
                
                            
                                
                
                        
                            
                        
                    
                        
                            Хотите улучшить этот вопрос? Переформулируйте вопрос,
чтобы он соответствовал тематике «Stack Overflow на русском».
                        
                        Закрыт 2 года назад.
                                                                                
           
                
        


Есть какие соображения по этому поводу?
    


Ответы

Ответ 1



UseKestrel - это extension-метод. Проверь, есть ли ссылка на Microsoft.AspNetCore.Server.Kestrel.dll.

понедельник, 10 февраля 2020 г.

XDocument.Save нету перегрузки string

#c_sharp #xml #aspnet_core


Проблема заключается в отсутствии перегрузки. В чем может быть проблема ?  

List outFiles = new List();
XDocument xDoc = XDocument.Load("files.xml");
XElement root = xDoc.Element("files");
int i = 1;
foreach (XElement xe in root.Elements("file"))
{
    if (xe.Element("name").Value + xe.Element("extention").Value == src)
    {
        xe.Remove();
        continue;
    }
    outFiles.Add(new Image { Id = i, Src = xe.Element("name").Value + xe.Element("extention").Value,
Selected = false });
    i++;
}

xDoc.Save("files.xml");
return outFiles;

    


Ответы

Ответ 1



Вы пишете под .NET Core, это не то же самое, что .NET Framework. .NET Core — это новая платформа, в ней ещё нету всех тех же вызовов, что есть в старом Framework. Согласно документации, и правда XDocument.Save доступен только с Stream'ом, TextWriter'ом и XmlWriter'ом. Должно про идее работать так: using (var stream = File.Create("files.xml")) xDoc.Save(stream);

среда, 5 февраля 2020 г.

ASP.NET Core. Защита jwt токенов

#c_sharp #net #aspnet #aspnet_core #jwt


Я использую в своем проекте jwt токены. Код для создания ClaimsIdentity:

public async Task GetClaimsIdentityAsync(User user)
{
    var roles = await _roleService.GetUserRolesAsync(user);

    var claims = new List
    {
        new Claim(ClaimsIdentity.DefaultNameClaimType, user.Username),
    };
    foreach (var role in roles)
    {
        claims.Add(new Claim(ClaimsIdentity.DefaultRoleClaimType, role.Name));
    }
    ClaimsIdentity claimsIdentity =
        new ClaimsIdentity(claims, "Token", ClaimsIdentity.DefaultNameClaimType,
            ClaimsIdentity.DefaultRoleClaimType);
    return claimsIdentity;
}


Код для создания токена:

public async Task GetJwtToken(User user)
{
    var identity = await _sinInService.GetClaimsIdentityAsync(user);

    var now = DateTime.UtcNow;

    var jwt = new JwtSecurityToken(
        issuer: AuthOptions.ISSUER,
        audience: AuthOptions.AUDIENCE,
        notBefore: now,
        claims: identity.Claims,
        expires: now.Add(TimeSpan.FromMinutes(AuthOptions.LIFETIME)),
        signingCredentials: new SigningCredentials(AuthOptions.GetSymmetricSecurityKey(),
SecurityAlgorithms.HmacSha256));
    return new JwtSecurityTokenHandler().WriteToken(jwt);
}


Код в классе Startup:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.RequireHttpsMetadata = false;
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidIssuer = AuthOptions.ISSUER,

            ValidateAudience = true,
            ValidAudience = AuthOptions.AUDIENCE,
            ValidateLifetime = true,

            IssuerSigningKey = AuthOptions.GetSymmetricSecurityKey(),
            ValidateIssuerSigningKey = true,
        };
    });


Код был взят из этой статьи: https://metanit.com/sharp/aspnet5/23.7.php

Получив строку токена можно авторизоваться с любого браузера или устройства.

Необходимо сделать так, чтобы токеном мог воспользоваться только тот, кому он был
предназначен. 
Думаю сделать это таким образом: на серверной стороне генерируется уникальный ключ.
Этот ключ потом отправляется вместе с jwt токеном в каждом запросе, что позволяет определить
какое устройство получает доступ. Но этот ключ тоже могут украсть, как и сам токен :(

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


Ответы

Ответ 1



Получив строку токена, можно авторизоваться с любого браузера или устройства. Да, эта проблема, которую токены аутентификации не решают. Поэтому важно реализовать следующие возможности: Использовать HTTPS вместо HTTP, это защитит от перехвата токенов. При сохранении токенов, использовать средства ОС, которые прячут их от других программ/пользователей. Например, в Андроид-приложениях задействуйте Internal Storage с флагом MODE_PRIVATE. Делайте время жизни токена небольшим, например, 20 или 30 минут. Плюсом токена, относительно логина и пароля является время жизни: даже если его удалось перехватить, обычно это случается слишком поздно. Ничего лучше, чем черный список токенов в бд я для этого не придумал. Должны же быть какие-то стандартные методы для сброса токенов. Для того, чтобы токены можно было отключать, например, реализовывать логаут, их действительно придётся хранить. Мы для этого используем не БД, а кэш Redis, где указываем время хранения. И работает быстрее, и старые записи чистить не надо. Порядок действий: При создании токена генерируете уникальный идентификатор токена "jti" (JWT ID). Создаёте токен доступа (access token). В Redis (ну или в БД) заносите access_token с ключом, основанном на "jti", указав время жизни токена доступа (30 минут). При аутентификации проверяете подпись JWT и время жизни, хранящееся в самом JWT. Если всё нормально, извлекаете значение "jti" и проверяете, есть ли такой ключ в Redis. Если есть, всё нормально, если нет, значит, был логаут, или пользователя выкинул администратор. В любом случае считаем, что пользователь аутентификацию не прошёл. Такое решение позволяет реализовать логаут и бан и является достаточно безопасным. Из-за короткого времени жизни токена доступа, необходимо реализовать перелогин через токен обновления. Этот токен тоже нужно хранить в Redis, только время жизни задавать больше (вполне нормальным считается даже месяц, но вы смотрите, что подходит к вашей предметной области). При логауте/бане токен обновления также нужно удалять, как и токен доступа. Дальше идут детали, которые вам придётся учитывать. Если нужен бан, значит, администратору каким-то образом нужно уметь узнавать "jti" по идентификатору пользователя. Можно например "jti" делать равным "sub" (то есть идентификатору пользователя). В этом случае пользователь не сможет одновременно работать с разных устройств, потому что у него может быть только один токен доступа. Если нужно, чтобы мог работать, можно например "jti" формировать в виде $"{sub}:{random}". Тут возможны разные решения в зависимости от предметной области, но в целом ничего сложного нет.

Ответ 2



Сервер знает о клиенте только то, что клиент прислал ему в http-запросе. По сути, это только: Client IP, который может меняться. UserAgent, который неуникален. Так что ответ - провалидировать привязку токена к девайсу не получится.

вторник, 28 января 2020 г.

ASP.NET CORE. Выйти со всех устройств если изменились данные пользователя

#c_sharp #net #aspnet #aspnet_mvc #aspnet_core


Необходимо, чтобы если у пользователя изменилось имя, email или пароль произошел
выход со всех других устройств. По умолчанию авторизация сохраняется, даже если старая
комбинация логина и пароля в бд отсутствует. Используется ASP.NET Core Identity

Сделал костыль с сохранением токинов в базе данных и их проверкой при каждом запросе
к не статическим ресурсам. При смене пароля или email все сохраненные токины удаляются
из бд. Я уверен, что в  ASP.NET Core Identity должен быть какой-то более простой способ
для сброса авторизаций.
    


Ответы

Ответ 1



Сначала кратко опишу терминологию, чтобы не путаться в дальнейшем. В стандарте OAuth2 клиенты получают у сервера авторизации токен доступа (access token) и передают его владельцу ресурса в каждом запросе. Передавать токен можно в куках либо в заголовке HTTP, последний способ аутентификации называется Bearer. Сам токен является зашифрованной или по меньшей мере подписанной информацией о пользователе. Часто для подписания и шифровки используют стандарт JWT, тогда данные хранятся в виде json-объекта. У токена доступа есть время жизни. Дата/время завершения токена хранится непосредственно в нём, поэтому сервер может вычислить, жив токен или нет. Проблематика Такая схема не позволяет деаутентифицировать клиентов при наступлении определённых условий, потому что пока время жизни не истекло, владелец ресурса считает токен валидным. Решение Чтобы можно было сделать токены невалидными, владелец ресурса должен складывать их в кеш memcached или Redis. Тогда проверка токена будет проходить в два этапа: сначала мы должны убедиться, что токен есть в кеше, а потом проверить время его жизни. При несоблюдении любого из этих условий токен считается невалидным. Соответственно, при смене пароля надо удалить из кеша все токены доступа данного пользователя. Если помимо токенов доступа вы реализовали токены обновления (refresh tokens), их также надо хранить в кеше, и также надо удалять. Конкретика Этот механизм может быть реализован разными способами. Вот статья на MSDN, описывающая, как могут быть кешированы токены доступа в ASP.NET Core.

Ответ 2



Обычно (в стандартных проектах ASP.NET MVC) в классе Startup вызывается метод ConfigureAuth(app), код которого выглядит примерно так: app.UseCookieAuthentication(new CookieAuthenticationOptions { Provider = new CookieAuthenticationProvider { OnValidateIdentity = SecurityStampValidator .OnValidateIdentity( validateInterval: TimeSpan.FromMinutes(30), regenerateIdentityCallback: (manager, user) => user.GenerateUserIdentityAsync(manager), getUserIdCallback: (id) => (Int32.Parse(id.GetUserId()))) }, // other configurations }); Смысл кода в том, что при смене пароля (или даже при логине пользователя) генерируется некий SecurityStamp (например, рандомный гуид) и сохраняется в базе с привязкой к пользователю (как правило, в той же таблице, где и креденшиалы пользователя). Далее каждые 30 минут (validateInterval: TimeSpan.FromMinutes(30)) вызывается метод OnValidateIdentity, который проверяет, совпадает ли текущий SecurityStamp из куков пользователя с SecurityStamp из базы. Если не совпадает, то пользователь будет разлогинен. На примере: пользователь залогинился на устройстве A, через 5 минут он же залогинился на устройстве B и сменил пароль. При смене пароля сгенерировался новый SecirityStamp и сохранился в базу, на устройтсве B куки также обновились. Далее пользователь вернулся к устройству A и продолжил работать. Здесь он не менял пароль, поэтому SecurityStamp в куках останется старый и через 25 минут этот самый SecurityStamp не пройдет проверку. Пользователь будет разлогинен. То же самое (генерация SecurityStamp) можно делать при логине пользователя. Тогда пользователь не сможет продолжительно работать на нескольких устройствах. Интервал валидации SecurityStamp выбираете сами. Также не забудьте проверять его и при таких важных операциях, как смена пароля. В целом суть именно такая. В большинстве случаев достаточно этого стандартного подхода, иногда лишь придется написать свой метод для присвоения его свойству OnValidateIdentity экземпляра класса CookieAuthenticationProvider.

пятница, 24 января 2020 г.

Как в .NET Core установить другой уровень ведения логов

#c_sharp #aspnet_core #логирование


Не могу понять — вроде делаю всё правильно. Но почему то в логи .NET Core пишет сообщения
уровня Information. Хотя я явно указал в настройках писать только Error.
Вот часть Program.cs:

public static IWebHost BuildWebHost(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup()
        .ConfigureLogging((hostingContext, logging) =>
        {
            logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
        })
        .Build();


Конфиг appsettings.json выглядит так:

"Logging": {
  "IncludeScopes": false,
  "LogLevel": {
    "Default": "Error"
  }
}


Что я делаю не правильно?
    


Ответы

Ответ 1



Разобрался... Причина была в том, что в директории приложения был файл appsettings.Development.json и настройки логгирования брались из него а не из appsettings.json, причем этот фал в обозревателе VisualStudio не было видно, а я и не догадался сам сходить в директорию приложения и посмотреть что там есть. Откуда этот файл и кто его создал непонятно.

Отсутствуют AccountController и папка Account во Views при использовании Identity

#c_sharp #aspnet_mvc #aspnet_core #visual_studio_2017


При создании проекта ASP.NET Core(2.1) Web Application => MVC Не нахожу в архитектуре
AccountController и папки Account во Views. Авторизацию сделал, проходит, но внести
изменения в оформление и функционал страниц логина не могу, так как не нахожу их в
проекте. Подскажите, где их найти, или как вносить изменения?
    


Ответы

Ответ 1



Начиная с Asp.Net Core 2.1, Identity вынесена в отдельную либу (Razor Class Library), поэтому нет ни контроллеров, ни представлений. Чтобы кастомизировать Identity, нужно использовать Scaffolder - он позволяет выборочно добавлять исходный код нужных компонентов в проект, чтобы его можно было править. Вот, как это сделать: From Solution Explorer, right-click on the project > Add > New Scaffolded Item (Создать шаблонный элемент). From the left pane of the Add Scaffold dialog, select Identity(Удостоверение) > Add. In the Add Identity dialog, select the options you want. Подробности в документации.

Как правильно сделать маршрутизацию в web api?

#net #aspnet_core


Я начинающий разработчик и пытаюсь написать web api для выбора товара из БД.
Подскажите пожалуйста, возможна ли такая маршрутизация и правильная ли она?
Архитектура видится следующая:
Аутентификация и авторизация пользователя. Каждой паре логин/пароль соответсвует
определённый код. Пусть будет 966 для примера.
Далее пользователь переводи по маршруту

1.
GET http://localhost:6171/api/orders/966/
    [HttpGet("{kod}")]
Выводиться список номенклатуры для выбора.

2.
Далее пользователь выбирает позицию и надо вывести ему доступное количество товара
GET http://localhost:6171/api/orders/966/GetKolvo?nom=карандаш

[HttpGet("{kod}/[action]")]

public IEnumerable GetKolvo([FromRoute]int kod, [FromQuery(Name = nom")]string nom)
{

выведет количество

}


3.
Метод, который отображает количество товара
И последний метод, который показывает номер ячейки, где данный товар находится
GET http://localhost:6171/api/orders/966/GetNomer?nom=карандаш&kol=6

???

На втором методе я застрял : ( то ли так вообще нельзя сделать/ неправильно , то
ли я криво маршрутизирую, но при таком запросе я получаю ошибку 404 и на этом всё : (

UPD!
Со вторым контроллером я разобрался.

Как же правильно делать в этом случае?Как должен выглядеть маршрут для третьего контроллера,
когда контроллеру передаются два параметра?

GET http://localhost:6171/api/orders/966/GetNomer?nom=карандаш&kol=6

Заранее спасибо!

Буду рад ссылке на документацию с примером.
    


Ответы

Ответ 1



Ура! Разобрался! В Startup.cs прописал : routes.MapRoute( name: "GetNomer", template: "api/[controller]/{kod}/{action}"); И по ссылке GET http://localhost:6171/api/orders/966/GetNomer?nom=карандаш&kol=6 стал возвращаться нужный результат. Вроде с маршрутами разобрался. Спасибо Всем!

среда, 22 января 2020 г.

Готов ли ASP.NET Core MVC для продакшена? [закрыт]

#c_sharp #net #aspnet_mvc #aspnet_core #net_core


        
             
                
                    
                        
                            Закрыт. На этот вопрос невозможно дать объективный ответ.
Ответы на него в данный момент не принимаются.
                            
                        
                    
                
                            
                                
                
                        
                            
                        
                    
                        
                            Хотите улучшить этот вопрос? Переформулируйте вопрос,
чтобы на него можно было дать ответ, основанный на фактах и цитатах, отредактировав его.
                        
                        Закрыт 2 года назад.
                                                                                
           
                
        
Здравствуйте, вопрос к тем, кто уже работал с платформой ASP.NET Core MVC. Ранее
работал с ASP.NET MVC, однако сейчас приобрел по новой платформе литературу и планирую
после прочтения заняться разработкой на ней. Безусловно будущего никто не знает, но
я думаю общую картину уже можно обрисовать. На сколько сильно фремверк может претерпеть
изменений, что бы после нового релиза не пришлось переучиваться и переписывать проект?
На сколько сыра платформа? Как много подводных камней при работе с ней, если можно
- детальней? И вообще готова ли она к продакшену, например для разработки корпоративного
портала?
    


Ответы

Ответ 1



Я думаю, что ответ - Да. ASP.Core MVC готов для использования в продакшене. В качестве доказательства можно привести доклад Дениса Иванова из компании 2GIS на конференции DotNext 2017 (https://www.youtube.com/watch?v=ngcigr_8oxw) ASP.NET Core приложения под Linux в продакшене В качестве конспекта привожу выдержки из слайдов доклада. Сервис видеорекламы Требования: 99.99% доступности по миру время отклика 200ms Почему Linux: Существующая on-premise платформа -GitLab CI -CI starting kit на основе make -Docker hub & docker images Компоненты на любом технологическом стеке Kubernetes Поддержка принципа "12-ти факторного приложения" 1) Одно приложение - один репозиторий 2) Зависимости - вместе с приложением 3) Конфигурация через окружение 4) Используемые сервисы как ресурсы 5) Фазы билда, создания образов и исполнения разделены 6) Сервисы - отдельные stateless процессы 7) Port binding 8) Масштабирование через процессы 9) Быстрая остановка и запуск процессов 10) Среды максимально похожи 11) Логирование в stdout 12) Административные процессы .NET Core. Self-contained deployment Полный контроль зависимостей Явное указание платформы при билде (win10-x64 / ubuntu.14.04-x64 / osx.10.12-x64) Только необходимый фреймворк Вместо заключения Не бойтесь использовать .NET Core в продакшене Не бойтесь использовать Linux и .NET Core Docker и Kubernetes сильно упрощают жизнь Пишите эффективный код правильно

Создание приложения для голосового звонка

#c_sharp #aspnet_core #voip #телефония


Техническое задание

Необходимо создать сайт с одной единственной кнопкой "Позвонить". После нажатия,
пользователь на угад связывается с таким же пользователем, который нажал на эту кнопку
и в ожидании. Затем они могут разговаривать, используя микрофон. Этот сервис для начала
должен выдерживать разговор одновременно 10 000 пользователей и сразу необходимо заложить
возможность в недалеком будущем создание мобильного приложения. Я так понимаю лучше
сразу строить эту систему на микросервисах REST.

Я пока новичок в этой сфере и не знаю, как правильно это называется Интернет-телефония,
IP-телефония или VoIP. Пока даже не понял, что из этого является частным другого.



"Что говорит Google?"

Термины. Сразу конечно проблема с терминологией: по таким запросам как "voice chat"
почему-то я в основном получаю ссылки на исходники по пересылке записанных аудио, т.е.
не разговор в реальном времени, а как в современных мессенджерах предварительное записывание
голоса с задерживанием кнопки микрофона. Если пишу "Интернет телефония" то тогда получаю
ссылки по созданию приложений для звонка на мобильный телефон. Но мне не надо звонить
на мобильный телефон, а необходимо связать два компьютера в интернете как это делает
Skype и т.п.

P2P. Мне, я так понимаю лучше сразу обеспечить связь P2P между клиентами?

.NET. Как .NET разработчик мне конечно хочеться использовать в основе этот стек технологий
или лучше использовать другой стек?

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

SignalR. У меня есть небольшой опыт написание чата, где я использовал библиотеку
SignalR и на мое удивление никто не предлагал использовать SignalR.



Вопрос

Если попытаться спросить конкретно без слов "с чего начать", то мой вопрос звучит так: 
Для начала мне бы хватил какой-нибудь маленький пример для разговора двух клиентов
в локальной сети, ведь там у всех белые IP и скорость хорошая. Есть ли что-то готовое
с чем я могу сделать прототип или библиотека/фреймворк с чего я могу менее безболезненно
начать?
    


Ответы

Ответ 1



Пример собственного велосипеда о котором ты спрашиваешь, можно найти здесь. В целом скоп задач, которые необходимо решить для разработки эффективной системы огромен, поэтому я бы на твоём месте смотрел исключительно в сторону готовых фреймворков. Большая часть из них строится на основе протокола SIP. Есть готовые коммерческие продукты, есть открытые и гибридные. Выбирай то, что тебе подходит и вперёд.

суббота, 11 января 2020 г.

Docker: можно ли контейнер, созданный из Windows разместить на Linux?

#c_sharp #администрирование #docker #aspnet_core #docker_compose


У нас стартап и мы все еще активно пополняемся единомышленниками, но наш продукт
уже в скором времени близится к пилотному запуску. ПО наше состоит из следующих модулей:


API — проект ASP.NET Core Web API 2 
MySQL
Web-клиент — приложение на Angular 5. Мы не скрестили ASP.NET Core и
Angular, а разрабатываем веб-клиент Angular отдельно с Node.js на борту.


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

Операционная система, которая будет крутиться на сервере клиента неизвестна и хотелось
сделать некий универсальный процесс инсталяции который подходил бы как на Windows так
и для Linux. Понятное дело, что за универсальность надо платить.

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

Docker. Докер, Docker и еще раз Докер. Естественно в первую очередь программисту
приходит в голову это ПО одной из задач (я сказал одной из) которого является избавить
программиста от проблем развертывания и дать максимально сфокусироваться на кодинге.
Ох если бы это было так.

Прокси-сервер. И как не крути, но плюс к Kestrel/HTTP.sys какой-то из серверов Apache,
IIS, nginx и т.д. все же нужен на сколько понял я. Даже если клиент планирует работать
с нашим продуктом только внутри корпоративной сети. 
Дела с HTTP.sys конечно лучше: он не такой голый как Kestrel, но у нас то речь об
универсальности, а HTTP.sys только для Windows.
Пытался к примеру установить nginx на Windows Server в качестве эксперимента: мама
родная, со стороны казалось, что я в первый раз вижу компьютер).



И если можно я задал бы два вопроса:

1) Первый вопрос он более общий, вы наверное догадались: что посоветуете?

2) А теперь, чтобы конкретизироваться: я сейчас работаю на Windows 10 и если я задумал
использовать Docker, то я ведь правильно понимаю, что мне надо создать четыре контейнера


Контейнер с прокси-сервером (Apache, nginx или IIS)
Контейнер с СУБД MySQL
Контейнер с Angular-приложением
Контейнер с проектом ASP.NET Core 2 Web API


Можно ли это сделать прямо из Windows? То есть будет ли работать контейнер созданный
на Windows-машине на Linux?
    


Ответы

Ответ 1



Docker под Windows может работать в двух режимах - Windows Containers и Linux Containers. Режимы переключаются через иконку в трее: В режиме Windows Containers он собирает и хостит контейнеры прямо в текущей операционке. Собранные в этом режиме контейнеры нельзя разместить под Linux. В режиме Linux Containers он на самом деле собирает и запускает контейнеры на линуксовой виртуалке - она видна в Hyper-V Manager. Собранные в этом режиме контейнеры можно разместить под Linux. Под каждый рантайм есть свой набор тэгов - все доступные можно посмотреть на https://hub.docker.com/r/microsoft/aspnetcore/ Т.е. да, вы можете включить режим Linux Containers, собрать набор из 4-х контейнеров (взяв nginx в качестве прокси), и потом запустить все это под Linux.

четверг, 9 января 2020 г.

asp.core2 не работает пример инициализации базы данных из документации microsoft

#c_sharp #entity_framework #aspnet_core #dependency_injection #entity_framework_core


На сайте Microsoft в разделе документации asp.core 2, приводится пример инициализации
базы данных тестовыми данными.

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

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext(options =>
      options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddMvc();
}


Затем получаю контекст базы данных из контейнера внедрения зависимостей.

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args).Configure(_ => { }).Build();

public static void Main(string[] args)
{
    var host = BuildWebHost(args);

    using (var scope = host.Services.CreateScope())
    {
        var services = scope.ServiceProvider;
        try
        {
            var context = services.GetRequiredService();
            DbInitializer.Initialize(context);
        }
        catch (Exception ex)
        {
            var logger = services.GetRequiredService>();
            logger.LogError(ex, "An error occurred while seeding the database.");
        }
    }

    host.Run();
}


У меня не работает и я думаю это логично, т.к. метод Main вызывается быстрее метода
ConfigureServices и естественно var context = services.GetRequiredService();
 ничего не вернет.

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

{System.InvalidOperationException: No service for type 'DreamPlace.WebService.Otli.Statistic.Models.SchoolContext'
has been registered.
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider
provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider
provider) ...}


Может я чего-то не понял или это действительно ошибка в документации microsoft?
    


Ответы

Ответ 1



Как указал tym32167, у меня неверный метод BuildWebHost. Правильный вариант: IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup() .Bui‌​ld();

понедельник, 6 января 2020 г.

Где обрабатывать исключения в приложении asp.net mvc?

#c_sharp #aspnet #aspnet_mvc #исключения #aspnet_core


Где необходимо отлавливать исключения в приложении asp.net mvc? Например у меня есть
функция в сервисе, которая использует базу данных:

public async Task GetAcount(string id)
{
    return await _applicationUserRepository.GetOrDefaultAsync(id);
}


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

public async Task GetOrDefaultAsync(string key)
{
    TEntity result = null;

    try
    {
        return await _entities.FirstOrDefaultAsync(e => e.Id == key);
    }
    catch { }

    return result;
}


Или в сервисе, например так:

public async Task GetAcount(string id)
{
    ApplicationUser result = null;
    try
    {
        result = await _applicationUserRepository.GetOrDefaultAsync(id);
    }
    catch
    {
    }

    return result;
}


Или в контроллере, например так:

public async Task Details(string id)
{
    if (id == null)
    {
        return NotFound();
    }
    ApplicationUser applicationUser = null;
    try
    {
        applicationUser = await _usersService.GetAcount(id);
    }
    catch
    {
        return RedirectToAction("Error");
    }
    if(applicationUser == null)
    {
        return NotFound();
    }

    return View(applicationUser);
}


Можно вообще не отлавливать исключение, тогда при ошибке пользователь увидит это:


Где и как нужно обрабатывать исключения при работе с базой данных и нужно ли вообще
их обрабатывать?
    


Ответы

Ответ 1



Исключения надо обрабатывать там, где их может обработать прикладная логика. Обрабатывать в репозитории - не рекомендуется, никакой код не сможет узнать, почему он не получил сущность. Обрабатывать в сервисе - уже вполне можно, возможно сервис должен создавать новую сущность, если не найдена нужная - это уже ваша логика и вам решать, как себя вести. В контроллере обработка тоже вполне допустима. Только вам самому надо решить, что это исключение значит и как на него реагировать. Контроллер - это уже выход на пользователя. Т.е. лучше предоставить пользователю информацию - что случилось, кто виноват и что с этим можно сделать. Просто "Ошибка" обычно абсолютно бесполезна.

Как использовать колекции в Entity Framework Core?

#c_sharp #aspnet_mvc #entity_framework #aspnet_core


С помощью EntityFramework DataBaseFirst создались классы :

public partial class ExpSections
{
    public ExpSections()
    {
        ExpRemarks = new HashSet();
    }
    public int ExpSectionId { get; set; }
    public int ExpMainId { get; set; }
    public string Name { get; set; }
    public string ExpertName { get; set; }
    public string ImageName { get; set; }

    public ExpMains ExpMain { get; set; }
    public ICollection ExpRemarks { get; set; }
}

public partial class ExpRemarks
    {
        public int ExpRemarkId { get; set; }
        public int ExpSectionId { get; set; }
        public string Number { get; set; }
        public string Question { get; set; }
        public string Answer { get; set; }
        public string Check { get; set; }

        public ExpSections ExpSection { get; set; }
    }


ExpSections связан один ко многим c ExpRemarks
Я так понимаю коллекция внутри класса ExpSections нужна для вывода связанных данных?
Как ей воспользоваться, к примеру есть метод:

public IActionResult Method(int id)
{
     ExpSections expSections = _bd.ExpSections.SingleOrDefault(m=>m.ExpSectionId == id);


А как получить связанные данные из класса ExpRemarks, если я пишу так:

Console.WriteLine(expSection.ExpRemark.Count()); 


Результат 0 записей, а в БД записи есть.
    


Ответы

Ответ 1



В EF Core нет lazy loading (надо бы уточнить, не появилось ли в 2.1), поэтому у вас связанные данные не подгружаются автоматом. Указывайте явно при загрузке, какие связанные данные вам понадобятся: _bd.ExpSections.Include(x => x.ExpRemarks) .SingleOrDefault(m=>m.ExpSectionId == id); Тут тёзка подсказывает, что в core 2.1 наконец впилили поддержку lazy loading так что если у вас есть возможность обновиться и включить lazy loading - то можете использовать как альтернативу. Я правда люблю контролировать, что и когда грузится, это же лишние накладные расходы на базу и сеть, поэтому предпочитаю держать lazyloading отключенным. Как включить lazy loading в 2.1 см. в доках, вкратце: The simplest way to use lazy-loading is by installing the Microsoft.EntityFrameworkCore.Proxies package and enabling it with a call to UseLazyLoadingProxies И, кстати, обращаю ваше внимание, что для поддержки lazy loading свойства должны быть virtual: public virtual ICollection ExpRemarks { get; set; } См. также: Загрузка связанных данных Entity Framework Core - Lazy Loading

Ответ 2



Есть большая таблица сравнения возможностей, где показано, что "умеет" EF Core и, что важно, с какой версии - если умеет. Многие, кто имеет опыт работы с EF6, очень часто забывают, что EF Core весьма сильно отличается от EF6, и, как следствие, получается такие ситуации. Как верно подсказал @Андрей-NOP, Include может тут помочь. Но, с версии 2.1 EF Core его можно больше не использовать, т.к. был реализован Lazy Loading.

пятница, 3 января 2020 г.

Проверить AntiForgeryToken в ajax-запросе?

#c_sharp #aspnet_core


Изучаю особенности asp.net core 2.0 на небольших приложениях. Хочу например сделать
небольшой ajax-запрос к списку контактов.

Вот есть у меня моделька

public class ContactSearchViewModel
{
    public string Needle { get; set; }
}


и формочка:

function getSummary(needle) { $.ajax({ type: "POST", url: '/Contact/Search/', data: "Needle=" + needle, success: function (data) { $('#results').html(data); } }); } И всё прекрасно работает... есть только одна маленькая досада: мне пришлось закомментировать ValidateAntiForgeryToken: [HttpPost] //[ValidateAntiForgeryToken] public async Task Search(ContactSearchViewModel model) { var contacts = await this.ContactService.SearchAsync(model.Needle); return View(contacts); } Если строку раскомментировать - то запросы до action не доходят (брейкпойнт не срабатывает), заворачиваются с 400 Bad Request где-то раньше в недрах вебсервера. Вопрос простой: как правильно создавать ajax-запросы в .core чтобы они проходили валидацию?


Ответы

Ответ 1



Согласно документации в представлении нужно добавить метод получения токена и скрытое поле: @inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf @functions { public string GetAntiXsrfRequestToken() { return Xsrf.GetAndStoreTokens(Context).RequestToken; } } и добавить в запрос заголовок с полученным токеном: $.ajax({ ... headers: { "RequestVerificationToken": $('#RequestVerificationToken').val() }, ... });

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

Cannot resolve scoped service 'Microsoft.AspNetCore.Identity.UserManager` from root provider

#c_sharp #aspnet_core #dependency_injection #aspnet_core_2


У меня есть сервис в проекте ASP.NET Core 2.0

public class SomeSingletonService: IUserGetPropertiesService
{
   private readonly IServiceProvider _serviceProvider;

   public SomeSingletonService(IServiceProvider serviceProvider)
   {
      _serviceProvider = serviceProvider;
   }

   public void SomeFunction() {
       // в этой строчке падает с ошибкой
       UserManager userManager = _serviceProvider.GetService>();
       // ...
   }
}


Сервис регистрируется как Singleton

services.AddSingleton();


При попытке получить UserManager из _serviceProvider падает с ошибкой


  {System.InvalidOperationException: Cannot resolve scoped service
  'Microsoft.AspNetCore.Identity.UserManager`1[MyProject.Models.User]'
  from root provider.


Не могу понять в чём дело, ведь в SomeFunction по идее можно получать scoped сервисы.
Как мне в SomeFunction прокинуть UserManager?

Не хочется ей передавать его в параметрах, так как тогда пришлось бы через всю логику
приложения носить этот UserManager, тогда как по идее можно его извлекать из
Dependance Injection Container, который я пробую передать через конструктор - IServiceProvider
serviceProvider
    


Ответы

Ответ 1



Выяснилось что Scoped сервисы нужно получать через специальный блок using (var serviceScope = _serviceProvider.GetRequiredService() .CreateScope()) { UserManager userManager = serviceScope.ServiceProvider.GetService>(); }

Ответ 2



Другое решение — отключить проверку областей видимости для сервисов, поставляемых средством DI. Это делается в Program.cs, найдите место создания IWebHostBuilder и добавьте: WebHost.CreateDefaultBuilder(args) .UseStartup() .UseDefaultServiceProvider(options => options.ValidateScopes = false); // <==

воскресенье, 29 декабря 2019 г.

Объясните на пальцах совместимость библиотек в .Net Core, .Net Framework, .Net Standart

#c_sharp #net #aspnet_core


Изучаю .Net. Хочу написать некое серверное приложение (думаю что учеба лучше на реальном
примере, нежели писать примитивные hello world). Выбор уходит в сторону .Net Core (микросервис).
В проекте нужно будет использовать некоторые библиотеки (далее пример приведу).
Из всего прочитанного понял следующее (если что не правильно понял поправьте):


Net Standart - вершина "айсберга" (своего рода типа интерфейс для остальных проектов)
Net Core, Net Framework, Xamarin - ниже по иерархии (типа как классы реализующие
интерфейс), но могут (и скорее всего так и делают) добавлять свои специфические фичи,
характерные для каждого из них.
Библиотеки (dll-ки) написанные как классы Net Standart могут использоваться в любом
из наследников (Net Core, Net Framework, Xamarin) с полной совместимостью (а если быть
точным то смотреть таблицу реализации https://docs.microsoft.com/en-us/dot...tation-support),
но не наоборот (т.е. к примеру если библиотека написана как Net Framework dll (со специфическими
для Net Framework фичами), то не факт что ее можно использовать в Net Core, потому
как он не поддерживает специфические фичи из Net Framework)
Каждая последующая версия Net Standart, Net Core, Net Framework, Xamarin включает
в себя все фичи из предыдущей версии самой себя + некоторые новые. Т.е. к примеру код
написанный под Net Standart 1.3 будет 100% работать в Net Standart 2.0, НО код написанный
под Net Standart 2.0 не будет работать в Net Standart 1.3 и выше.


И теперь собственно на реальном примере. Буду использовать .Net Core 2.0 и смотреть
совместимость естественно с Net Standart 2.0 и .NETFramework 4.6.1. Выбираю два пакета
(библиотеки) на сайте nuget. Первый к примеру Selenium Webdriver https://www.nuget.org/packages/Selenium.WebDriver/
Во вкладке dependencies смотрю что ему надо (я понимаю что все это подтянется автоматом
в visual studio, вручную не надо):

.NETFramework 3.5
No dependencies.

.NETFramework 4.0
No dependencies.

.NETFramework 4.5
No dependencies.

.NETStandard 2.0
Newtonsoft.Json (>= 10.0.3)


Как я понимаю ему не нужны никакие зависимости из .NETFramework, но нужна одна зависимость
из .NETStandard 2.0. Но для Newtonsoft.Json (>= 10.0.3) тоже нужны зависимости https://www.nuget.org/packages/Newtonsoft.Json/

.NETFramework 2.0
No dependencies.

.NETFramework 3.5
No dependencies.

.NETFramework 4.0
No dependencies.

.NETFramework 4.5
No dependencies.

.NETStandard 1.0
Microsoft.CSharp (>= 4.3.0)
NETStandard.Library (>= 1.6.1)
System.ComponentModel.TypeConverter (>= 4.3.0)
System.Runtime.Serialization.Primitives (>= 4.3.0)

.NETStandard 1.3
Microsoft.CSharp (>= 4.3.0)
NETStandard.Library (>= 1.6.1)
System.ComponentModel.TypeConverter (>= 4.3.0)
System.Runtime.Serialization.Formatters (>= 4.3.0)
System.Runtime.Serialization.Primitives (>= 4.3.0)
System.Xml.XmlDocument (>= 4.3.0)

.NETStandard 2.0
No dependencies.


Вот тут я немного в ступоре. Если я буду использовать .Net Core 2.0, а он в свою
очередь реализует .NETStandard 2.0, то как я понимаю для Newtonsoft.Json уже не нужны
зависимости из .NETStandard 1.0 и .NETStandard 1.3, потому как все это уже есть в .NETStandard 2.0.

Т.е. будет ли пакет Selenium.WebDriver совместим с .Net Core в данном случае?

И еще один пример, есть пакет cefSharp: https://www.nuget.org/packages/CefSharp.OffScreen/65.0.0-pre01
Он тянет зависимость 
CefSharp.Common (= 65.0.0-pre01)
Та еще две, но эти последние две не тянут ничего https://www.nuget.org/packages/cef.redist.x64/

This package has no dependencies.


В этом случае ни слова про .NETStandard и .NETFramework. Т.е. как я понимаю они вообще
самодостаточные? Т.е. как они будут работать в .Net Core?

Длинный вопрос получился, но надеюсь вы поняли, в чем я хочу разобраться:
Как выяснить совместимость пакета с определенной реализацией .NET?
    


Ответы

Ответ 1



Вы немного неправильно читаете раздел "dependencies". Вы читаете его как "поддерживаемые фреймворки, и необходимые части фреймворков". На самом деле это "необходимые дополнительные пакеты, при использовании этого пакета под конкретный фреймворк". Например: Как я понимаю ему не нужны никакие зависимости из .NETFramework, но нужна одна зависимость из .NETStandard 2.0. Это не "одна зависимость из .NETStandard 2.0". Это "другие nuget-пакеты, которые нужны для использования версии Selenium.WebDriver, собранной под .NETStandard 2.0.". Если ваше приложение собирается под .NETFramework 4.5 - вы можете подключить пакет Selenium.WebDriver, и код из него будет работать сам по себе, без необходимости подключать дополнительные пакеты. Если ваше приложение собирается под .NETStandard 2.0 (или любую его реализацию, под которую нет более специфической версии, например под .NET Core) - то при подключении Selenium.WebDriver вам придется подключить еще и Newtonsoft.Json.

Ответ 2



На данный момент существует три, если так можно сказать, платформы .Net: собственно .Net Framework, .Net Core и Xamarin. Каждая платформа реализует тот или иной набор API. Если перед вами стоит задача написать библиотеку, которая позволяла бы вам использовать её для различных .Net платформ, то на помощь вам приходит .Net Standard. .Net Standard - это не еще одна платформа.Net. Вы не можете создать исполняемый файл, например консольное приложение типа .Net Standard. Вы можете написать только библиотеку dll. .Net Standard - это спецификация определяющия набор API, который каждая из платформ должена реализовать. Это похоже на контракт между тремя сторонами, подписав который они обязуются соблюдать. Такая спецификация позволяет вам как разработчику создать библиотеку, которую можно будет использовать для всех трех платформ.

Какие есть способы вести лог всех ошибок приложения в ASP.NET Core?

#c_sharp #net #aspnet #aspnet_core #net_core


Какие есть способы вести лог всех ошибок приложения в ASP.NET Core? Например хотелось
бы сохранять все исключения со стеком вызова в текстовые файлы или типа того (автоматические,
не в обработчике исключений). Если были получены некорректные данные в контроллере
хотелось бы добавить информацию о некорректном запросе в лог. 

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


Ответы

Ответ 1



Добавьте в Startup Middleware: public void Configure(IApplicationBuilder app) { app.UseMiddleware(); } В Middleware вы задаёте собственную обработку запросов перед выполнением и после выполнения, так же обработку ошибок. Реализация ExceptionHandlerMiddleware (не забудьте зарегистрировать ILogger в контейнере): public sealed class ExceptionHandlerMiddleware { private readonly ILogger _logger; private readonly RequestDelegate _next; public ExceptionHandlerMiddleware(RequestDelegate next, ILogger logger) { _next = next; _logger = logger; } public async Task Invoke(HttpContext context) { try { await _next(context); } catch (Exception exp) { _logger.LogError(context, exp); await HandleExceptionAsync(context, exp.GetBaseException()); } } private static Task HandleExceptionAsync(HttpContext context, Exception exp) { var code = HttpStatusCode.InternalServerError; // 500 if unexpected var result = JsonConvert.SerializeObject(new { Code = code, Message = exp.Message, StackTrace = exp.StackTrace }); context.Response.ContentType = "application/json"; context.Response.StatusCode = (int)code; return context.Response.WriteAsync(result); } } Документация с Microsoft

Ответ 2



Из стандартных: Microsoft.Extensions.Logging. В Startup.Configure: loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddFile("C:\\log\\Лог.log"); loggerFactory.AddDebug(); Далее через DI их получаем, включая в конструктор ILogger. Далее в нужных местах пишем Log, обработку. В некоторых местах (где не обработали) может выдать сам ошибку в файл loggerFactory.AddDebug(); Возможно если покапаться, то можно писать в поток, а поток отправлять на сервер, который бы вам отправлял нужные вам сообщения. P.S. Вопрос выше даже без отдельного сервера работает и кажется предоставляет больше данных. Объедините наши ответы и (думаю) получите то, что хотите. Ну и стоит немного скурить мануалов по Microsoft.Extensions.Logging

четверг, 26 декабря 2019 г.

Ajax все равно обновляет страницу. ASP.NET Core

#html #ajax #aspnet_core


Есть асинхронный запрос AJAX, который норм работает, данные в контроллер ходят без
проблем и на контроллере тоже все норм работает. Контроллер обновляет данные пользователя.
Но если это асинхронный запрос, то он не должен перезагружать страницу.  Вот скрипт
который срабатывает при загрузке страницы, Достаем данные и распаршиваем в таблицу.
Все ок тут. 

function getDataList() {
var serviceURL = '/api/ProfessorsApi/';

$.ajax({
    type: "GET",
    url: serviceURL,
    contentType: "application/json;",
    success: successFunc,
    error: errorFunc
});
function successFunc(data, status) {
    var obj = $.parseJSON(data);


Вот скрипт пост метода асинхронного аякс

function postData() {
let nameStudent = document.querySelector('[name="Name"]').value;

let surnameStudent = document.querySelector('[name="Surname"]').value;

let midlnameStudent = document.querySelector('[name="Midlname"]').value;

let emailStudent = document.querySelector('[name="Email"]').value;

let telephoneStudent = document.querySelector('[name="TelNumber"]').value;

let oldEmailStudent = document.querySelector('[name="OldEmail"]').value;

var parametrs = {
    Name: nameStudent, Surname: surnameStudent, Midlname: midlnameStudent,
    Email: emailStudent, TelNumber: telephoneStudent, OldEmail: oldEmailStudent
};
var serviceURL = '/api/ProfessorsApi/';

$.ajax({
    type: "POST",
    url: serviceURL,
    data: JSON.stringify(parametrs),
    contentType: "application/json;",
    //success: successFunc,
    //error: errorFunc
});
function successFunc(data, status) {

}

function errorFunc() {

}


И вот форма HTML  асинхронного запроса которая на onclick отправляет на функцию potsData().
Она в диалоговом окне открывается бутстрапа. 


Ответы

Ответ 1



Проблема решилась тем что просто нужно в HTML форме поменять тег input type="submit" на button. Оно ведь так и есть. Сабмит по идеи и должен перезагружать страницу. Поменял и все ок без перезагрузки все работает.