Чтобы решить эту проблему, я хотел бы использовать объект запроса в качестве параметров маршрута для привязки TagHelper.Это означает, что все ссылки на маршруты определены только в одном месте, а не во всем решении.Изменения, сделанные в запросе объектной модели, автоматически распространяются на URL для <a asp-action>
-tags.
Преимущество этого состоит в уменьшении количества мест в коде, которое мы должны изменить при изменении сигнатуры метода для действия контроллера.Мы локализуем изменение только для модели и действия.
Я думал, что написание помощника по тегам для пользовательского asp-object-route
может помочь.Я посмотрел в цепочку Taghelpers, чтобы мой мог работать до AnchorTagHelper
, но это не работает.Создание экземпляра и его размещение требует от меня жесткого кодирования всех свойств ASP.Net Cores AnchorTagHelper , которые могут потребовать обслуживания в будущем.Также рассматривается возможность использования пользовательского метода с UrlHelper для создания URL-адреса, но тогда TagHelper не будет работать.
Решение, на котором я остановился, заключается в использовании asp-all-route-data
, как предложено @ kirk-larkin, наряду с методом расширения для сериализации.в словарь.Любой asp-all-route-*
переопределит значения в asp-all-route-data
.
<a asp-controller="Test" asp-action="HelloWorld" asp-all-route-data="@Model.RouteParameters.ToDictionary()" asp-route-somestring="optional override">Link</a>
. ASP.Net Core может десериализовать сложные объекты (включая списки и дочерние объекты).public IActionResult HelloWorld(HelloWorldRequest request) { }
В объекте запроса (при его использовании) обычно есть только несколько простых свойств.Но я подумал, что было бы неплохо, если бы он также поддерживал дочерние объекты.Сериализация объекта в словарь обычно выполняется с использованием отражения, которое может быть медленным.Я подумал, что Newtonsoft.Json будет более оптимизирован, чем сам писать простой код отражения, и нашел, что эта реализация готова к работе:
public static class ExtensionMethods
{
public static IDictionary ToDictionary(this object metaToken)
{
// From https://geeklearning.io/serialize-an-object-to-an-url-encoded-string-in-csharp/
if (metaToken == null)
{
return null;
}
JToken token = metaToken as JToken;
if (token == null)
{
return ToDictionary(JObject.FromObject(metaToken));
}
if (token.HasValues)
{
var contentData = new Dictionary();
foreach (var child in token.Children().ToList())
{
var childContent = child.ToDictionary();
if (childContent != null)
{
contentData = contentData.Concat(childContent)
.ToDictionary(k => k.Key, v => v.Value);
}
}
return contentData;
}
var jValue = token as JValue;
if (jValue?.Value == null)
{
return null;
}
var value = jValue?.Type == JTokenType.Date ?
jValue?.ToString("o", CultureInfo.InvariantCulture) :
jValue?.ToString(CultureInfo.InvariantCulture);
return new Dictionary { { token.Path, value } };
}
}