Страницы

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

Показаны сообщения с ярлыком .net-core. Показать все сообщения
Показаны сообщения с ярлыком .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

Как переконвертировать .NET Core проект в .Net Framework на линуксе или онлайн?

#c_sharp #net #net_core #msbuild


Сейчас пишу тестовое задание на .Net Core (.Net Standard 2.0) на линуксе (Mint 19.1).
Но проверяющий наверняка будет смотреть мое решение на Windows в Visual Studio без
установленного .Net Core SDK. Устанавливать второй системой Windows долго и муторно.
Windows в виртуалке мой ноутбук не потянет (4 гигабайта ОЗУ).

Потому задаюсь вопросом, есть ли на linux какой-нибудь конвертор проекта с .Net Core
на встроенный в Windows 10 .Net Framework 4.6.1? Или может есть онлайн-сервис по пересборке
.Net проектов на разные версии .Net Framework и .Net Core?
    


Ответы

Ответ 1



переконвертировать .NET Core проект в .Net Framework на линуксе Смотря, что Вы хотите сконвертировать. Если Вы не выходите за рамки .NET Standard, то проблем быть не должно. Но, если речь идёт о других типах проектов (тот же ASP.NET), то здесь всё гораздо сложнее. Всё-таки .NET Framework это про Windows. проверяющий наверняка будет смотреть мое решение на Windows в Visual Studio без установленного .Net Core SDK Зачем пользователю приложения для работы с ним Visual Studio и пр.? Сделайте нормальный инсталлятор в котором будет упакована уже собранная рабочая версия с нужными зависимостями и киньте ему с инструкцией как установить проект.

Ответ 2



.NET Framework 4.6.1 поддерживает .Net Standard 2.0 главное не использовать библиотеки строго под .net Core вот ссылка на таблицу совместимости

суббота, 21 марта 2020 г.

Проверить генерик-тип интерфейса в C#?

#c_sharp #net #рефлексия #net_core


У меня есть тип AType который реализует генерик-интерфейс IA
Тип BType реализует интерфейс IC.
Как я могу проверить связан AType с IC или нет?

class AType : IA
{}

class BType : IC
{}

interface IA
{ }

interface IC
{ }


Тип BType может быть любым и мне о нем ничего неизвестно. У меня есть экземпляр AType
и мне нужно понять реализует ли он IC через generic тип промежуточного интерфейса IA
Проверка ниже не работает: 

var aInstance = new AType();
aInstance is IA // false
...


Также для Type.IsAssignableFrom(Type)

typeof(IC).IsAssignableFrom(aInstance.GetType()) // false

    


Ответы

Ответ 1



Проверка ниже не работает: Верно, потому что компилятор ничего не знает о вариантности интерфейса. Если ваш интерфейс IA фактически является ковариантным, то укажите это явно: interface IA { } потом: var aInstance = new AType(); Console.WriteLine(aInstance is IA); // True Но явная вариантность — это ограничение и интерфейс может считаться ковариантным только в случае когда все его члены используют тип T только для возврата. Скомпилируется: interface IA { T Method(); } Не скомпилируется: interface IA { void Method(T t); } подробно: Вариативность в универсальных интерфейсах (C#) Если ваш тип не является ковариантным, то вам придется разбирать это явно. Для проверок внутри класса можно написать что-то вроде: class AType : IA { public bool HasParamenterOfTypeIC() { return typeof(IC).IsAssignableFrom(typeof(T)); } } тогда: var a = new AType(); Console.WriteLine(a.HasParamenterOfTypeIC()); // True var b = new AType(); Console.WriteLine(b.HasParamenterOfTypeIC()); // False для проверок снаружи вы должны еще и явно достать дженерик-параметр и проверить его на совместимость: class OType : IA { } class AType : IA { } class Program { static void Main() { Console.WriteLine(HasParamenterOfTypeIC(typeof(AType))); // True Console.WriteLine(HasParamenterOfTypeIC(typeof(OType))); // False } static bool HasParamenterOfTypeIC(Type type) { return type .GetInterfaces() .SelectMany(i => i.GetGenericArguments()) .Any(i => typeof(IC).IsAssignableFrom(i)); } }

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

Локальные переменные в C#

#c_sharp #net #события #net_core


Есть следующий код на C# (.NET Core):

using System;

public class LambdaTest {
 public static void Main() {
  MyClass obj = new MyClass(32);

  UnsafeFunc(obj);
  obj.EventCall();
  Console.WriteLine();
  obj.EventCall();
 }

 public static void UnsafeFunc(MyClass obj) {
  int local = 10;

  obj.MyEvent += delegate {
   Console.WriteLine("Unsafe event");
   local++;
   Console.WriteLine("Variable from function: {0}", local);
  };
 }
}

public class MyClassArgs: EventArgs {
 public int Prop {
  get;
  set;
 }
 public MyClassArgs(int arg) {
  Prop = arg;
 }
}

public class MyClass {
 public int ObjProp {
  get;
  set;
 }
 public event EventHandler < MyClassArgs > MyEvent;

 public MyClass(int arg) {
  ObjProp = arg;
 }

 public void EventCall() {
  Console.WriteLine("Event call");
  MyEvent(this, new MyClassArgs(64));
 }
}


Метод UnsafeFunc(MyClass obj) назначает событию obj.MyEvent анонимный метод, который
изменяет и выводит локальную переменную local, объявленную в UnsafeFunc(MyClass obj).
При первом вызове события выводится значение local: 11. При втором вызове: 12. Но дело
в том, что local - локальная переменная метода, т.е. после выполнения метода выделенная
ей память вроде как должна очищаться. Тогда как объяснить, что обработчик события имеет
доступ к памяти, которая не должна существовать?
    


Ответы

Ответ 1



В языках программирования, в том числе и в C# есть такое понятие, как замыкание (closure). Смысл его в том, что если в каком-либо методе (назовём его Outer) объявлен анонимный метод (скажем Inner), использующий локальные переменные метода Outer, то ссылки на эти переменные будут живы до тех пор, пока Inner не завершит свою работу, даже если Outer уже завершился. В вашем случае метод UnsafeFunc уже отработал, но переменная local используется в обработчике события obj.MyEvent, и поэтому ссылка на неё сохраняется сборщиком мусора и после выхода из метода UnsafeFunc. Фактически в этом случае компилятор создаёт анонимный класс, в поля которого записываются захваченные переменные, а в анонимные методы, захватывающие эти переменные, он передаёт поля этого класса.

пятница, 28 февраля 2020 г.

Папки с дополнительными NuGet пакетами для .net Core

#visual_studio_2017 #net_core #nuget


Исходные данные: ПК без доступа к интернету, VS2017 и проект на .net Core.
На ПК есть общая "офлайн папка с пакетами", откуда черпаются все основные (например
%userprofile%\.nuget\packages\).
Вопрос: Можно ли проекту указать дополнительную папку, в которой бы брались пакеты,
которые не были найдены в общей папке? Только для этого проекта.
    


Ответы

Ответ 1



Папка %userprofile%\.nuget\packages\ представляет из себя Local Feeds - папка с иерархичной структурой хранения nuget-пакетов, из которой можно устанавливать nuget-пакеты. Для того, чтобы подключить дополнительный Local Feeds в проект, вы можете сделать: На уровне папки проекта создайте файл NuGet.Config. В этом файле прописать следующее содержимое Элемент packageSources содержит список источников для установки пакетов. Если вы используете NetCore2.0, тогда путь до источника nuget-пакетов можно указать прямо в файле проекта(csproj) следующим образом $(RestoreSources);c:\packages; https://api.nuget.org/v3/index.json

Ответ 2



Может то, а может не совсем, но тем не менее. Из [Spec] Fallback package folders: Fallback package folders allow packages to be shared across users and machines to reduce disk space. These folders are treated as fallback folders for the primary global packages folder (%USERPROFILE%.nuget\packages). They differ from package sources in that the package assets will be referenced directly and will not be copied into the user's packages folder. The concept of a fallback package folder can be thought of as a GAC for nupkgs. [Spec] NuGet settings in MSBuild Свойство RestoreFallbackFolders - Fallback folders, these are used in the same way the user packages folder is used. Свойство RestoreAdditionalProjectFallbackFolders - Additional fallback folders appended to the resulting list of fallback folders Имеется пакет NLog в global packages folder. Если запустить сборку проекта, то в логах будет видно, что пакет подгружается из упомянутой директории: 1> Primary reference "NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c". 1> Resolved file path is "C:\Users\username\.nuget\packages\nlog\4.5.7\lib\netstandard2.0\NLog.dll". 1> Reference found at search path location "{HintPathFromItem}". 1> This reference is not "CopyLocal" because at least one source item had "Private" set to "false" and no source items had "Private" set to "true". 1> The ImageRuntimeVersion for this reference is "v4.0.30319". Добавим в проект с помощью свойства RestoreAdditionalProjectFallbackFolders резервный источник: C:\Users\username\Desktop\Username Удаляем NLog из global packages folder (в искомой "офлайн папке" пакета не оказалось) и запускаем сборку проекта: 1> Primary reference "NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c". 1> Resolved file path is "C:\Users\username\Desktop\Username\nlog\4.5.7\lib\netstandard2.0\NLog.dll". 1> Reference found at search path location "{HintPathFromItem}". 1> This reference is not "CopyLocal" because at least one source item had "Private" set to "false" and no source items had "Private" set to "true". 1> The ImageRuntimeVersion for this reference is "v4.0.30319". В рамках restore операции пакет подгружается из FallbackFolder если оный отсутствует в global packages folder, и не копируется в него по окончанию. Даже при наличии доступа к сети, пакет берется из FallbackFolder. UPD: В случае использования packageSources не до конца понятна ситуация с приоритетностью источников, ибо тут сказано, что: All feeds are queried and the one with the shortest response time wins. Кроме того, пакеты из локального источника будут копироваться в global packages folder, т.е дублироваться.

пятница, 14 февраля 2020 г.

Как правильно тестировать AutoMapper?

#c_sharp #net_core #automapper


Продакшен код работает с автомаппером, есть цель протестировать работу автомаппера.
Имеется в виду : протестировать правильность маппинга тех или иных сущностей.

Вот что написал я:

[Test]
public void MapFromUserToDalUser()
{
    // arrange
    var user = new User()
    {
        Id = 1,
        Email = "kek@cheburek.ru",
        Name = "Birsultan Nazarbaev",
        Phone = "233-655-900",
        SsoId = "myuniquessoid",
        ContactDetails = "shieee",
        Roles = new List() { RolesEnum.User, RolesEnum.Moderator }
    };

    // act
    var dalUser = mapper.Map(user);

    // assert
    Assert.AreEqual(user.Id, dalUser.Id);
    Assert.AreEqual(user.Name, dalUser.Name);
    Assert.AreEqual(user.Phone, dalUser.Phone);
    Assert.AreEqual(user.SsoId, dalUser.SsoId);
    Assert.AreEqual(user.Email, dalUser.Email);
    Assert.AreEqual(user.ContactDetails, dalUser.ContactDetails);
    Assert.AreEqual(
        user.Roles.Select(x => (int)x).OrderBy(x => x).ToList(),
        dalUser.DalUserDalRoles.Select(x => x.DalRoleId).OrderBy(x => x).ToList());
}


Как по мне - это не особо верный подход написания тестов для автомаппера, т.к. я
создаю сущность вручную после делаю маппинг и сравниваю. 
Знаю, что у автомаппера есть возможность автоматически генерить фейк и проверить
смапилось ли корректно или нет.
Вопрос в том, как сделать то ,что я сделал вручную, автоматически?
    


Ответы

Ответ 1



AutoMapper тестировать не надо. Для этого у него есть Mapper.Configuration.AssertConfigurationIsValid(); http://docs.automapper.org/en/stable/Configuration-validation.html Если у вас есть сложная функция конвертации, которую вы вызываете при маппинге, то тестируйте конкретно эту функцию.

воскресенье, 2 февраля 2020 г.

c# Net core Поиск номера строки ошибки в файле XML, имея путь к тегу (cases XPath, Regex, JSON?)

#c_sharp #регулярные_выражения #json #xpath #net_core


Здравствуйте. Ситуация: есть модель(дисериализованный файл), довольно большая. В
ней много строк и вложенных объектов. (Модель YML каталога).

[XmlRoot("yml_catalog")]
public class YMLCatalog
{
    /// 
    /// Дата и время генерации YML файла на стороне магазина
    /// 
    [Required]
    [XmlAttribute("date")]
    public string Date { get; set; }

    /// 
    /// Магазин
    /// 
    [Required]
    [ValidateObject]
    [XmlElement(ElementName = "shop")]
    public Shop Shop { get; set; }
}

/// 
/// Точка продаж
/// https://yandex.ru/support/webmaster/goods-prices/technical-requirements.html
/// 
public class Shop
{
    /// 
    /// Название магазина.
    /// 
    [Required]
    [XmlElement("name")]
    public string Name { get; set; }

    /// 
    /// Название компании
    /// 
    [Required]
    [XmlElement("company")]
    public string Company { get; set; }
    ... и тд.
}


При валидации модели, в случае ошибки, я получаю (при помощи магии. См. краткое описание
в комментариях) путь к ошибке. Например для YML файла с ошибкой в теге price, 0го оффера,
в виде отсутствия цены, я получаю путь: shop/offers/offer['0 или 1', смотря как удобнее.
Для XPath лучше 1]/price Value: Текст ошибки. (Value - поле со значением тега, аналогично
может быть для атрибутов)

Нас интересует: shop/offers/offer[0]/price

По этому пути, мне нужно определить номер строки, где находиться этот тег. Чтобы
указать пользователю где ошибка.

Что я пробовал:

1) Сделал через  регулярные выражения. Сначала последовательно нахожу индекс элементов
по пути, как получу индекс начала тега Price в файле. Затем собираю список строк в
файле и нахожу номер строки для вывода, относительно всего файла. - Это работает, но
меня не устраивает. Слишком медленно, а у меня могут быть очень большие файлы

2) Попробовал сделать через XPath. Т.е например можно легко получить элемент тега
вот так: 

XmlDocument document = new XmlDocument();
document.LoadXml(text);
var node = document.SelectSingleNode("//shop/offers/offer[1]/price");// это для примера


3) Есть вариант с созданием своего дессериализатора + атрибутов валидации для него,
чтобы к каждому полю в модели приписывать в метаданных IXmlLineInfo - который в стандартном
XmlSerializer к сожалению используется только при выдаче информации об ошибке - но
это долго, а те готовые, что я нашел, не поддерживаются в net core... UPD: также в
таком случае требуется поддержка не только составных объектов, но и простых + простых
атрибутов (string, int, long и тп)

Вопрос 1: XPath как-нибудь позволяет получить кол-во элементов выше (или лучше их
список)  ? Вроде комбинировать preceding и ancestor нельзя (ссылка) - Но опять же,
даже если это получиться, придется искать индекс, создавая список строк файла. - Не
очень хорошо, хотелось бы узнать номер строки ошибки другим способом

Пробовал "//shop/offers/offer[ 1 ]/price/preceding::*", но в таком случае игнорируются
все элементы выше shop, почему не знаю. (когда использовал count(...), получал 27 элементов)
- Думаю это всяко лучше только регулярных выражений

Знаете еще способ? Прошу в ответы:)

Главный вопрос: Так как лучше всего найти номер строки ошибки, имея XML и путь к тегу?

P.S Производительность решения приветствуется)
    


Ответы

Ответ 1



Не выдержал, решил дать свой ответ. Во-первых, XmlSerializer выдаёт ошибку не только при ошибке синтаксиса XML (например, незакрытый тег), но и в том случае, если тип данных не соответствует ожидаемому (например, свойство Price имеет тип decimal, а в узле Price пусто или нечисловая строка). При этом в выбрасываемом исключении содержится сообщение, содержащее номер и позицию ошибки: В документе XML (4, 18) присутствует ошибка. На мой взгляд, это уже фактически решает вопрос. Строка с ошибкой известна, можно её исправлять. Чуть погуглив, я легко выяснил, что для документов YML имеется схема. Скачать её можно здесь. При валидации по схеме будет выдаваться описание ошибки наподобие следующего: Элемент "Price" недействителен: значение "" недействительно с точки зрения его типа данных "http://www.w3.org/2001/XMLSchema:decimal" - Строка "" не является допустимым значением Decimal. Это даёт огромное удобство: пользователь легко поймёт и исправит ошибку. Сама валидация делается в несколько строк: var xs = new XmlSerializer(typeof(Test)); var settings = new XmlReaderSettings { ValidationType = ValidationType.Schema }; var schemas = new XmlSchemaSet(); schemas.Add(null, "schema.xsd"); settings.Schemas = schemas; settings.ValidationEventHandler += Settings_ValidationEventHandler; using (var xr = XmlReader.Create("test.xml", settings)) //while (xr.Read()) ; item = (Test)xs.Deserialize(xr); private void Settings_ValidationEventHandler(object sender, ValidationEventArgs e) { Console.WriteLine(e.Severity); Console.WriteLine(e.Message); Console.WriteLine(e.Exception.LineNumber + " " + e.Exception.LinePosition); } В данном коде валидация происходит в процессе чтения xml. То есть нет лишних проходов/загрузок, всё максимально эффективно по скорости и объёму памяти. Если нужно только валидация без десериализации, то раскомментируйте строку с while, закомментировав следующую. В том подходе, который используете вы сейчас, всё делается, имхо, очень неэффективно. Десериализация - отдельно (проход по xml, потребление памяти). Валидация - отдельно (ещё проход, ещё память). Поиск строки с ошибкой с помощью XPath - ещё одна загрузка xml в XmlDocument/XDocument (опять полный парсинг xml, опять тратится время и память). Кроме того, если xml синтаксически некорректен (незакрытый тег), то он вообще не загрузится в XmlDocument/XDocument и вы никогда не узнаете, где же ошибка... Кроме того, вы вручную расставляете атрибуты валидации и пишете код валидации... Лишняя работа.

Ответ 2



а через LINQ to XML нельзя сделать? что-то вроде такого ... XDocument xdoc = XDocument.Load(file, LoadOptions.SetLineInfo); var node = xdoc.XPathSelectElement("//shop/offers/offer[1]/price"); var lineNumber = ((IXmlLineInfo)node).LineNumber;

Ответ 3



а нельзя добавить в сам цикл и обработку, индекс, который и будет указывать на номер тега. Прошу прощения, вы это сами уже предложили и отвергли. И все таки почти всегда есть главный цикл обработки, и передать место сбоя в виде текущего номера обрабатываемого элемента, вроде как можно, ведь оно будет равняться текущему элементу цикла. ParentNode возвращает родительский узел у текущего узла. Наверное можно обратиться к родителю, узнать количество смежных узлов, обратиться к родителю родителя и так далее. Можно посчитать количество переводов строки после закрывающихся тегов, не уверен что это вообще из этой оперы, но может помочь в идентификации нужного узла и места.

Сборка проекта для .NET и .NET Core

#c_sharp #net #visual_studio #visual_studio_2017 #net_core


При написании библиотеки, код которой валиден как для .NET Framework, так и для .NET
Core, приходится создавать два разных проекта со своими зависимостями и практически
одинаковым кодом.

Текущее положение дел (необходимость отдельно обновлять код соседнего проекта и отдельно
его собирать) меня не очень устраивает. И пусть я написал скрипт для автоматизации
этого, знаю, что есть решение получше. Можно как-то модифицировать сам проект в Visual
Studio для достижения таковых целей:


Возможность выбирать целевую платформу
В зависимости от неё указывать символы в духе NETCORE, NET (по
типу DEBUG), дабы в некоторых местах менять платформо-зависимый код
В зависимости от неё использовать определённые пакеты




Как лучше организовать решение поставленной задачи?
    


Ответы

Ответ 1



При использовании SDK based формата для файлов проекта (.csproj) можно указать несколько целевых платформ для сборки в элементе TargetFrameworks. Также можно использовать атрибут Condition для условного указания зависимостей. Test.csproj: Latest Exe netcoreapp2.1; net472; AnyCPU Test.cs: using System; namespace Test { class Program { static void Main() { Console.WriteLine("Hello World!"); #if NETFRAMEWORK Console.WriteLine(".NET Framework"); Console.WriteLine((System.Numerics.Vector)new System.Numerics.Vector(42)); #elif NETCOREAPP Console.WriteLine(".NET Core"); Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(new { a = 1, b = 2 })); #else Console.WriteLine("Unknown"); #endif } } } Gist

Ответ 2



отдельно обновлять код соседнего проекта у Вас две копии кода? Положите cs файлы в третье место и добавьте их в оба проекта, используя опцию "Add As Link" в окне "Add Existing File".

среда, 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 сильно упрощают жизнь Пишите эффективный код правильно

.net core mvc 6 (razor) не английские символы автоматом переводятся в Unicode Hex Character

#razor #net_core #aspnet_core_mvc


В .net core в представлениях (Razor) теперь все НЕ английские символы автоматически
конвертируются в соотвествующий хекс код. 

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

Мы не #x441;мо ...


И чтоб получить нормальный текст на русском нужно её значение выводить используя
Html.Raw()

тоесть если я в контроллере присвою переменной 

string txt="текст на русском";


и в представлении напишу

Смотрите это: @txt


то в html разметке я увижу:

смотрите это:  Мыне#x441;можем 


Если же использовать стандартные структуры типа 




то из модели весь текст с валидацией на русском автоматом преобразуется и получим  




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

Как "обьяснить" .net core, что символы латинские "не опасны" и не нужно их заменять
при выводе вместе с символами "&<> и т.п. ?

В общем сделать так как было раньше...
    


Ответы

Ответ 1



в файле Startup.cs в public void ConfigureServices(IServiceCollection services) { .... //Чтобы кирилические символы не переводились в соответствующий Unicode Hex Character Code services.Configure(options => { options.TextEncoderSettings = new TextEncoderSettings(UnicodeRanges.All); }); }

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

Возможно ли подключить библиотеки .NET Framework в .NET Core 2.1.4?

#c_sharp #net #net_core #lib #sfml


Нужно подключить библиотеку в виде DLL, но у меня не получается. Возможно ли это?
    


Ответы

Ответ 1



В общем случае нельзя. Например, потому, что .NET Core является подмножеством .NET Framework. Выход: перевести библиотеку на ту версию .NET Standard, которая поддерживает .NET Core. Многие 3rd party библиотеки потихоньку обзаводятся соответствующии версиями. Upd Говорят еще, что если библиотека не содержит Windows-specific вызовов, то ее можно зареференсить прямо так. Но я не проверял. Какую библиотеку вы пытаетесь подключить и что именно у вас не получается? P.S. Ну и заодно привяжу "обратный" вопрос: Использование Net.Core библиотек в Net.Framewok

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

.NET Core 2.0 Encoding.GetEncoding

#c_sharp #encoding #net_core


Всем привет. Столкнулся с проблемой: нужно отправлять сообщение на почтовый ящик
в кодировке koi8-u(21866). Использую пакет System.Text.Encoding.CodePages:

        Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
        MailAddress fr = new MailAddress("***@**.com", "Name");
        MailAddress to = new MailAddress("***@**.com");
        MailMessage m = new MailMessage(fr, to)
        {
            Body = "test",
            BodyEncoding = Encoding.GetEncoding("koi8-u")
        };
        await smtp.SendMailAsync(m);


Но при отправке получаю: No data is available for encoding 21866. For information
on defining a custom encoding, see the documentation for the Encoding.RegisterProvider
method.

В обычном .NET Framework-е все отлично отправляется, в .NET Core увы. Как можно решить это?

P.S: такая же ситуация и для windows-1252 и прочих.
    


Ответы

Ответ 1



Просто подключите в проект NuGet-пакет с расширенными кодировками: System.Text.Encoding.CodePages И перед использованием зарегистрируйте их: Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); Должно помочь.

Использование Net.Core библиотек в Net.Framewok

#c_sharp #net #net_core


Возможно ли использование библиотеки написанной в .Net Core в проекте .Net Framework?
Или нужно юзать .Net Standart?
    


Ответы

Ответ 1



Нет, напрямую нельзя. Варианта два: писать под .NET Standard, если возможно использовать кросс-компиляцию сразу под несколько платформ, VS 2017 поддерживает это из коробки: net452;netstandard1.3

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

Какие есть способы вести лог всех ошибок приложения в 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

среда, 25 декабря 2019 г.

CLR/System.EntryPointNotFoundException при запуске неуправляемого кода на Си из программы на C# в среде Linux

#c_sharp #c #gcc #net_core


Код на Си:

#include 
void main()
{
    printf("Hello world\n");
}


Команда сборки этого кода в модуль main.dll для Терминала Linux:

gcc main.c -o main.dll


Вызывающий код на C# (сборка dllimportc.dll):

using System;
using System.Runtime.InteropServices;  
namespace netcore
{
    class Program
    {
        static void Main()
        {
            Console.WriteLine("Hello World!");
            main();
            Console.ReadLine();
        }
        [DllImport("main.dll", EntryPoint = "main", CallingConvention = CallingConvention.Cdecl)]
        public static extern void main ();
    }
}


На вызове main(); возникает исключение: 


  Exception has occurred: CLR/System.EntryPointNotFoundExceptionAn unhandled exception
of type 'System.EntryPointNotFoundException' occurred in dllimportc.dll: 'Unable to
find an entry point named 'main' in shared library 'main.dll'.'
  at dllimportc.Program.main()
  at dllimportc.Program.Main() 


Как откорректировать программу, чтобы .Net Core в консольном приложении находил точку
входа и Hello World выводился два раза без исключений?

ОБНОВЛЕНО
В коде выше библиотека в Linux создавалась неправильно. Правильные инструкции можно
подсмотреть здесь - Создание библиотеки в Linux.
Для Ubuntu 18.04 LTS  пришлось добавить возвращаемый тип в функцию на Си и вместо
команды 


  ldconfig -v -n .


использовать 


  ldconfig -v -n -l main.so.0.0


ОБНОВЛЕНО 06.10.2018

Можно проще: использовать для сборки только команду


  gcc -o main.so -s -shared -O2 main.c -m64


Затем подкладываем main.so в bin, и в C# для .Net Core всё просто: 

 [DllImport("main.so")]
  public static extern void main ();  

    


Ответы

Ответ 1



Для подключения через extern внешний код должен быть собран как библиотека. Для этого можно в Linux использовать для сборки команду (предварительно должен быть установлен компилятор GCC, если его не было в системе): gcc -o main.so -s -shared -O2 main.c -m64 Для библиотеки наличие функции main не обязательно. Исходный файл на чистом Си main.c эта команда скомпилирует в библиотеку (за это отвечает флаг shared) main.so (в Linux рекомендуется называть библиотеки с префиксом lib и давать им расширение so). Флаги s и O2 отвечают за оптимизацию для продуктива, а флаг m64 настраивает принудительную сборку для платформы x64. Затем подкладываем main.so в подпапку папки bin, где лежит собранный файл вашего проекта, и в C# для .Net Core всё просто: [DllImport("main.so")] public static extern void main (); Чтобы увидеть текстовое сообщение из внешней библиотеки, можно собрать проект .Net Core как консольное приложение, сделать вызов main() как обычного метода C# в теле вашей программы и запустить собранный проект из Терминала.

вторник, 24 декабря 2019 г.

MS SQL SERVER (Ubuntu 16.04.2) Требования

#c_sharp #ubuntu #sql_server #entity_framework #net_core


Здравствуйте! 
Есть некоторый чат-бот(написан на c# с использованием .net core и Entity Framework
Core.), который использует в качестве бд MS SQL на MS SQL Server. 

Недавно решил залить его на сервер (2.2ГГц, 0.5 RAM, 10 gb hdd), чтобы он не зависел
от состояния моего пк и столкнулся с проблемой при установке. 

Для установки MS SQL Server требуется минимум 3.25gb ram, хотя при работе он у меня
ест не более 200 мб, на серваке же всего 500мб Ram. Более дорогой сервер не потяну.  

Посоветуйте, как поступить. Можно ли обойти это ограничение при установке? Или же
лучше поменять субд? Если да, то что лучше выбрать? ('легковесное') 

P.S EF core вроде поддерживает скажем SQLite и MySQL. Установку проводил по этой
инструкции. 



    


Ответы

Ответ 1



При размере RAM 500Mb в принципе работа SqlServer невозможна. Вот вам пример, у меня запущен сервер на виртуалке Кроме сервера ничего более не установлено, а он уже жрет память в таком кол-ве, заметьте без нагрузки и с 5-ю копеечными тестовыми базами.

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

Не получается из консольного .Net Core сослаться на библиотеку .Net Standard

#net #visual_studio_2017 #net_core #net_standard


Создал библиотеку .net-standard, в ней определил класс Class1 и константу MyConst.

Далее создал консольное приложение .net-core, в нём набросал такой код:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(Class1.MyConst);
        Console.ReadLine();
    }
}


В моем случае .Net Standard имеет версию 1.3, а .Net Core имеет версию 1.0.

UPD: Версия студии:  Microsoft VS Enterprise 2017 v. 15.4.0

(!)  Проблема в том, что не получается запустить консольное приложение. Консоль мигает
примерно на миллисекунду, но не ведет себя как ожидается, то есть, не выводит константу
с содержанием "Hello world" и не останавливается на Console.ReadLine();.

В output выводится следующая инфо:

Программа "[8376] dotnet.exe" завершилась с кодом -2147450749 (0x80008083).
Программа "[8376] dotnet.exe: Трассировка программы" завершилась с кодом 0 (0x0).


Ну да и из картинки видно, что к библиотеке .net-standard (в которой класс Class1,
в котором константа MyConst) так же идет обращение из WPF-ного приложения (.Net Framework
4.6). Здесь добавил нугет пакет и ссылка на библиотеку работает нормально, то есть,
приложение запускается и константа отображается. Думаю, что этот аспект к теме не относится.

Благодарю! 
    


Ответы

Ответ 1



По коду ошибки удалось найти: Перечисление StatusCode, в котором указано поле с данным значением - CoreHostLibMissingFailure ; Место где используется поле CoreHostLibMissingFailure - read_config_and_execute. Можно сделать вывод, что отсутствуют требуемые версии библиотек. После установки .NET Core SDK 1.1.10 ошибка у меня воспроизводиться перестала.

Кто-нибудь может пояснить как запускаются программы NetCoreApp?

#c_sharp #net_core


Кто-нибудь может пояснить как запускаются программы NetCoreApp?

Здесь есть только dll. Как её запускать? Только через консоль dotnet dll? Можно создать
для запуска exe? (Windows 10)

\StartApp\bin\Debug\netcoreapp1.1\StartApp.dll
\StartApp\bin\Debug\netcoreapp1.1\StartApp.deps.json
\StartApp\bin\Debug\netcoreapp1.1\StartApp.runtimeconfig.json
\StartApp\bin\Debug\netcoreapp1.1\StartApp.runtimeconfig.dev.json
\StartApp\bin\Debug\netcoreapp1.1\StartApp.pdb

    


Ответы

Ответ 1



Процесс достаточно подробно расписан в .NET Core 1.1 – How to publish a self-contained application Минимальный набор изменений: Добавить в csproj нужный RuntimeIdentifier: Exe netcoreapp1.1 win10-x64 Восстановить зависимости: dotnet restore Опубликовать с указанием рантайма: dotnet publish -c release -r win10-x64 Бинарники будут собраны в папку bin\release\netcoreapp1.1\win10-x64. Аналогично для других рантаймов - достаточно вписать несколько RuntimeIdentifiers, и при сборке указать нужный: win10-x64;osx.10.11-x64;ubuntu.16.10-x64 dotnet publish -c release -r ubuntu.16.10-x64 dotnet publish -c release -r osx.10.11-x64 Способ работает и для других типов приложений, например, для ASP.NET Core.

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

.NET Core: Случай получения значения поля из свойства

#c_sharp #aspnet_core #net_core


Работая с ASP.NET Core Identity, я очередной раз заглянул в исходный код на GitHub
и увидел в классе IdentityResult следующие строки:

public class IdentityResult
    {
        private List _errors = new List();
        ...

        public IEnumerable Errors => _errors;
        ...
    }


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

public List Errors { get; } = new List();


Я бы понял если бы это был какой-то легаси код, но как никак .NET Core.
    


Ответы

Ответ 1



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

Ответ 2



вместо того, чтобы просто написать: public List Errors { get; } = new List(); Тогда извне будут доступны методы интерфейса IList, которые изменяют коллекцию: Clear, Add, Remove. Видимо автор кода не хотел, чтобы кто-то мог вносить изменения, поэтому коллекцию Errors сделали доступным только для перечисления через интерфейс IEnumerable, который не содержит методов способных внести изменения.

Ответ 3



Определил два преимущества , который много используется в фреймворках. ваше пример: // конкретный: структура данных List 1. "private" List _errors = new List(); // абстрактный контракт - перечисление (base contract) 2. "public" IEnumerable Errors => _errors; Смотрите на модификатор доступа то есть конкретный тип (1) private. Ну абстрактный контракт (2) public. это является локализация для дальнейшей изменения чтобы не влиять другим модулем. То есть мы можем List изменить на Stack это не будет влиять на другим клиентам то есть изменения локализован (здесь и подразумевается слабая связанность (то есть автор гарантирует)). Здесь нарушается сокрытие информации потому что возвращает структуру данных.И поэтому он использует тип перечисление IEnumerable чтобы сокрыть внутренние данные , чтобы клиент не манипулировал Remove , Update , Add. То есть можно было использовать клонирование но это дорогостоящая операция (оперативная память и так далее) поэтому здесь использовано сокрытие информации (высокоуровневый,абстрактный интерфейс перечисление) IEnumerable (доступ только для перечисления). P.S Localization : Когда будет изменение изменение будет в одном месте или изменение будет минимизирован.

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

Как продуктивно создавать оболочки совместимости (shims), для .Net Core, Framework, Standard

#c_sharp #net #net_core #netcore20 #net_standard


Как продуктивно создавать оболочки совместимости (shims), для .Net Core, Framework,
Standard?

Версии: Framework 4.6.1; Core 2.0; Standard 2.0.

Например, интересуют следующие 3 штуки, для использования между .net core, .net standard
и .net framework:

System.Windows.Threading.Dispatcher, System.ComponentModel.ItemPropertyInfo.Descriptor,
даже 
System.Windows.Controls.MenuItem.

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



Пояснение задачи на грубом примере, если делать вручную: 

Например, для Core 2.0 не реализован Dispatcher.

Делается абстрактная оболочка / интерфейс / фасад, :

public enum DispatcherShimPriority
{
    Background
    //...
}

public interface DispaicherShim
{
    void Invoke(Action action, DispatcherShimPriority prio);
    void BeginInvoke(Action action, DispatcherShimPriority, prio);
}


Далее 2 реализации:

public class DispatcherCore: DispaicherShim;
//здесь по началу можно просто вызывать Action


и

public class DispatcherFramework: DispaicherShim;
//здесь используется реальный Dispatcher внутри


Далее делается какой-то мультинацеленный класс-активатор, например, Shims, в котором:

public static DispaicherShim CreateDispatcher()
{
#if NETCOREAPP2_0
    return new DispatcherCore();
#else
    return new DispatcherFramework();
#endif       
}


Таким образом, получается оболочка, которую можно использовать как в Framework-овских,
так и в Core-овских приложениях.

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



Про Microsoft.Windows.Compatibility pack в курсе. Имею ввиду создание оболочек для
элементов, не покрывающихся данным пакетом.

Про Microsoft.Windows.Compatibility.Shims слышал, но подозреваю, что там нет оболочек
для элементов, не покрывающихся самим пакетом.



Общая задача состоит в том, чтобы основную часть WPF приложения перевести на кор
под потенциальный web-client (оставляя работающий WPF), при том, что многие элементы
.net framework основной части не переводятся на кор.
    


Ответы

Ответ 1



К этому моменту нашел, по крайней мере, удовлетворяющие способы создания оболочек совместимости. Может есть более продуктивные методы. Спасибо Firda из Чехии. Вот его ответ 1) В принципе достаточно простой generic оболочки public abstract class Shim { internal TImpl It { get; } protected Shim(TImpl it) { It = it; } } EXAMPLE: public class DispatcherPriorityShim : Shim< #if NETFULL DispatcherPriority #elif NETCORE string #endif > { public DispatcherPriorityShim(string it) #if NETFULL : base((DispatcherPriority)Enum.Parse(typeof(DispatcherPriority), it)) #elif NETCORE : base(it) #endif { } } 1.a) Visual Studio snippets drv #if NETFULL #elif NETCORE #endif shimenum namespace PortabilityLibrary.Shims { public class $enumname$Shim : Shim< #if NETFULL $enumname$ #elif NETCORE string #endif > { public $enumname$Shim(string it) #if NETFULL : base(($enumname$)Enum.Parse(typeof($enumname$), it)) #elif NETCORE : base(it) #endif { } } } shimsnip namespace PortabilityLibrary.Shims { public class $classname$Shim : Shim< #if NETFULL $classname$ #elif NETCORE $classname$ //NullObject #endif > { public $classname$Shim() #if NETFULL : base(new $classname$()) #elif NETCORE : base(new $classname$()) //: base(new NullObject()) #endif {} } } shimmeth public void $methodname$() { #if NETFULL It.$methodname$(); #elif NETCORE It.$methodname$(); //throw new ShimException(); #endif } shimprop - аналогично, пока не сделал 1.b) Пояснение на счет NETCORE и NETFULL Sdk-style .csproj file to make clear about NETFULL and NETCORE: netstandard2.0;netcoreapp2.0;net461 NETCORE; NETFULL; 2) Более продвинутый вариант позволяющий наследственность public interface IShimOne { void MethodOne(); } public interface IShimTwo: IShimOne { void MethodTwo(); } class One: RealOne, IShimOne {} class Two: RealTwo, IShimTwo {} public static class ShimFactory { public static IShimOne CreateOne() { return new One(); } public static IShimTwo CreateTwo() { return new Two(); } } 2.a) Объекты public class WrapperOne { protected IShimOne It { get; } protected WrapperOne(IShimOne it) { It = it; } public WrapperOne() { It = ShimFactory.CreateOne(); } public void MethodOne() { It.MethodOne(); } } public class WrapperTwo: WrapperOne { protected new IShimTwo It => (IShimTwo)base.It; protected WrapperTwo(IShimTwo it): base(it) {} public WrapperTwo(): base(ShimFactory.CreateTwo()) {} public void MethodTwo() { It.MethodTwo(); } 3) Готовые "двойники" для GUI контролов (Eto.Forms) (вообще, Eto.Forms имеет более широкое применение - они сами по себе уже оболочки) //Не до конца сделано, просто чтобы показать идею: #if NETFULL using System.Windows.Controls; #elif NETCORE using Eto.Forms; #endif namespace PortabilityLibrary.Shims { public class MenuItemShim : Shim< #if NETFULL MenuItem #elif NETCORE MenuItem #endif > { public MenuItemShim(EventHandler dlg) #if NETFULL : base(new MenuItem(/*not implemented*/)) #elif NETCORE : base(new ButtonMenuItem(dlg)) #endif { } } }