Я подозреваю, что вопрос можно перефразировать следующим образом:
Почему они не предоставляют перегрузки, которые принимают FormattableString для передачи шаблонов и параметров сообщений с использованием синтаксиса строковой интерполяции, как это делает EF Core для параметризованных запросов?
Я бы сказал, что они правильно поняли. На данный момент использование FormattableString предлагает минимальные преимущества, но создает лот путаницы.
Я только что обнаружил, что Автор Serilog объясняет, почему это не такая хорошая идея , хотя библиотека семантической регистрации выглядит естественным образом для этого сценария
Семантическое ведение журнала
Можно утверждать, что FormattableString
будет отличным дополнением к библиотекам семантической регистрации, таким как Serilog. В этом случае интерполированная строка действительно теряет важную информацию.
Звонок
Log.Information("Logged in {UserId}", loggedInUserId);
Не будет просто записывать строку на основе шаблона, он будет хранить имена и значения параметров и предоставлять их фильтрам и целям. Не было бы замечательно получить тот же результат с:
Log.Information($"Logged in {loggedInUserId}");
Автор Серилога так не считает и объясняет, что:
- Хорошее имя переменной не обязательно является хорошим именем свойства
- Отверстия не всегда имеют очевидные имена, например
Log.Information($"Enabling categories {new[]{1, 2, 3}}");
и приходит к выводу, что
Строковая интерполяция - отличная функция, которую я давно ждал в C #. Идея предоставления прямой поддержки Serilog очень интересна и заслуживает изучения, но я все больше убеждаюсь, что в этом нет необходимости.
Интерполяция удобна, когда она сохраняет код СУХОЙ, удаляя лишний беспорядок {0} и {1} и предотвращая несоответствия параметров.
В случае с Serilog я считаю неправильным считать имена свойств, такие как {UserId}, как избыточные; в хорошо реализованной стратегии ведения журнала они являются невероятно важной частью картины, которая заслуживает их собственного рассмотрения. Вы не позволите именам переменных определять имена таблиц и столбцов в реляционной базе данных - здесь рассматривается тот же компромисс.
Исходное объяснение
На самом деле это одна из самых противоречивых возможностей EF Core, и она может легко привести к тем проблемам с SQL-инъекцией и преобразованием, которых нужно избегать с помощью параметров.
Этот звонок:
string city = "London";
var londonCustomers = context.Customers
.FromSql($"SELECT * FROM Customers WHERE City = {city}");
вызывает FromSql(FormattableString)
и создает параметризованный запрос:
SELECT * FROM Customers WHERE City = @p0
И передать London
в качестве значения параметра.
С другой стороны это:
string city = "London";
var query=$"SELECT * FROM Customers WHERE City = {city}";
var londonCustomers = context.Customers.FromSql(query);
вызывает FromSql(string)
и генерирует:
SELECT * FROM Customers WHERE City = London
Что неверно. Слишком часто можно попасть в эту ловушку, даже если вы действительно знаете о риске.
Это совсем не помогает, если у вас уже есть предопределенные запросы или сообщения. Такое использование гораздо чаще встречается в журналах, где вы (должны) использовать определенные шаблоны сообщений, определенные в хорошо известных местах, вместо того, чтобы разбрасывать похожие строки в каждом месте журнала.
Можно утверждать, что это добавление сделало EF Core 2.0 несколько безопаснее , потому что люди уже начали использовать интерполяцию строк в EF Core 1.0, что приводило к неверным запросам. Добавив перегрузку FormattableString
, команда EF Core смогла смягчить сценарий , упрощая случайное возникновение другой проблемы.
На данный момент разработчики лесозаготовок решили избежать этой путаницы. Регистрация необработанной строки не имеет таких катастрофических последствий.