Эффективный способ ввести параметры в URL действий контроллера - PullRequest
0 голосов
/ 05 декабря 2018

В ASP.Net Core у вас есть несколько способов сгенерировать URL для действия контроллера, самые новые из которых - помощники тегов.

Использование тегов-помощников для GET-запросов asp-route используется для указания параметров маршрута.Насколько я понимаю, не поддерживается использование сложных объектов в запросе маршрута.И иногда на странице может быть много разных ссылок, указывающих на себя, возможно с незначительным добавлением URL для каждой ссылки.

Мне кажется неправильным, что любое изменение сигнатуры действия контроллера требует изменения всех помощников тегов, использующих этодействие.То есть, если добавить к контроллеру string query, нужно добавить запрос к модели и добавить asp-route-query="@Model.Query" 20 различных мест, распределенных по cshtml-файлам.Используя этот подход, вы настраиваете код для будущих ошибок.

Есть ли более элегантный способ справиться с этим?Например, какой-нибудь способ иметь объект запроса?(То есть объект запроса от контроллера может быть помещен в модель и возвращен обратно в URL действия.)

Ответы [ 3 ]

0 голосов
/ 06 декабря 2018

Чтобы решить эту проблему, я хотел бы использовать объект запроса в качестве параметров маршрута для привязки 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 } };
    }
}
0 голосов
/ 06 декабря 2018

В моем другом ответе я нашел способ предоставления объекта запроса через Model.

Из статьи SO @tseng при условии, что я нашел меньшее решение.Этот объект не использует объект запроса в модели, но сохраняет все параметры маршрута, если он не переопределен явно.Он не позволит вам указать маршрут через объект запроса, который чаще всего совсем не тот, который вам нужен.Но это решило проблему в OP.

<a asp-controller="Test" asp-action="HelloWorld" asp-all-route-data="@Context.GetQueryParameters()" asp-route-somestring="optional override">Link</a>

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

public static Dictionary GetQueryParameters(this HttpContext context) { return context.Request.Query.ToDictionary(d => d.Key, d => d.Value.ToString()); }

0 голосов
/ 05 декабря 2018

Здесь есть обоснование, которое я не думаю, что вы получаете.GET-запросы намеренно упрощены.Они должны описывать конкретный ресурс.У них нет тел, потому что вы не должны передавать сложные объекты данных в первую очередь.Это не то, как разработан протокол HTTP.

Кроме того, параметры строки запроса обычно должны быть необязательными.Если для идентификации ресурса требуется какой-то бит данных, он должен быть частью основного URI (т. Е. Пути).Таким образом, игнорирование добавления чего-то вроде query параметра должно просто привести к тому, что будет возвращен полный набор данных вместо некоторого подмножества, определенного query.Или в случае чего-то вроде страницы поиска, это обычно приводит к тому, что пользователю предоставляется форма для сбора query.Другими словами, вы должны учитывать, что этот параметр отсутствует, и обрабатывать эту ситуацию соответствующим образом.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...