1

Я перестраиваю интерфейс приложения и из-за его сложности должен работать над существующим бизнес-слоем. В результате у нас есть вещи, называемые «Новости» и «Документы», но на самом деле оба являются «Документами», где они хранятся.Результат Url.Action не разрешается с использованием атрибута Route

Я сделал DocumentController, который обрабатывает все как можно точнее, хлопая [Route("News/{action=index}")] и [Route("Documents/{action=index}")] на контроллере, чтобы я мог обращаться к контроллеру как к Новостям, так и к Документам. Все идет нормально. Просмотр конкретного документа с использованием одного ActionResult с атрибутами [Route("Documents/View/{id}"] и [Route("News/View/{id}"] также отлично работает. Однако я столкнулся с проблемой, когда пытаюсь использовать что-либо кроме id в качестве параметра, но только для части новостей.

Мой ActionResult метод имеет следующее определение

[Route("Documents/Download/{documentGuid}/{attachmentGuid}")] 
[Route("News/Download/{documentGuid}/{attachmentGuid}")] 
public ActionResult Download(Guid documentGuid, Guid attachmentGuid) 
... 

И мой взгляд, имеет следующий, чтобы получить ссылку

<a href="@Url.Action("Download", "Documents", new { documentGuid = Model.Id, attachmentGuid = attachment.AttachmentId })">Download</a> 

Это сгенерирует ссылку сродни site/Documents/Download/guid/guid прекрасно, когда у меня есть «Документы» как контроллер, но если я поставлю «Новости», я получаю созданный URL-адрес, который использует querystring, сходный с параметрами site/News/Download?guid&guid, и разрешается на 404. Если я вручную удалю маркеры с запросами и отформатирую URL-адрес manu союзник это решит хорошо.

Что здесь происходит, что-то противоречивое, что мне не хватает?

ответ

1

При поиске маршрута по входящему запросу маршрутизация будет использовать URL-адрес, чтобы определить, какой маршрут соответствует. Ваши входящие URL-адреса уникальны, поэтому он работает нормально.

Однако при поиске маршрута для генерации MVC будет использовать значения маршрута , чтобы определить, какой маршрут соответствует. Литеральные сегменты в URL-адресе (News/Download/) полностью игнорируются для этой части процесса.

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

| Key    | Value   | 
|-----------------|-----------------| 
| controller  | Documents  | 
| action   | Download  | 
| documentGuid | <some GUID>  | 
| attachmentGuid | <some GUID>  | 

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

Чтобы обойти эту проблему, вы можете использовать именованные маршруты.

[Route("Documents/Download/{documentGuid}/{attachmentGuid}", Name = "Documents")] 
[Route("News/Download/{documentGuid}/{attachmentGuid}", Name = "News")] 
public ActionResult Download(Guid documentGuid, Guid attachmentGuid) 
... 

Затем разрешить URL-адреса с @Url.RouteUrl или @Html.RouteLink.

@Html.RouteLink("Download", "News", new { controller = "Documents", action = "Download", documentGuid = Model.Id, attachmentGuid = attachment.AttachmentId }) 

Или

<a href="@Url.RouteUrl("News", new { controller = "Documents", action = "Download", documentGuid = Model.Id, attachmentGuid = attachment.AttachmentId })">Download</a> 
+0

Спасибо за подробный ответ, это был именно этот вопрос и рабочее решение:) – Perry

1

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