W ASP.NET MVC można dość łatwo zwrócić ActionResult przekierowania:
return RedirectToAction("Index");
or
return RedirectToRoute(new { controller = "home", version = Math.Random() * 10 });
To faktycznie da przekierowanie HTTP, które zwykle jest w porządku. Jednak podczas korzystania z Google Analytics powoduje to duże problemy, ponieważ oryginalny odnośnik jest zagubiony, więc Google nie wie, skąd pochodzisz. Spowoduje to utratę przydatnych informacji, takich jak terminy wyszukiwarek.
Na marginesie, ta metoda ma tę zaletę, że usuwa wszelkie parametry, które mogły pochodzić z kampanii, ale nadal pozwala mi przechwytywać je po stronie serwera. Pozostawienie ich w ciągu zapytania powoduje, że ludzie tworzą zakładki, twitter lub blogują łącze, którego nie powinni. Widziałem to kilka razy, gdy ludzie umieszczali na Twitterze linki do naszej witryny zawierające identyfikatory kampanii.
W każdym razie piszę kontroler „bramy” dla wszystkich przychodzących wizyt w witrynie, które mogę przekierować w inne miejsca lub alternatywne wersje.
Na razie bardziej zależy mi na Google (niż na przypadkowym dodawaniu zakładek) i chcę móc wysłać kogoś, kto odwiedziłby /
stronę, którą dostałby, gdyby przeszła /home/7
, czyli wersję 7 strony domowej.
Tak jak powiedziałem wcześniej, jeśli to zrobię, stracę zdolność Google do analizowania osoby odsyłającej:
return RedirectToAction(new { controller = "home", version = 7 });
To, czego naprawdę chcę, to plik
return ServerTransferAction(new { controller = "home", version = 7 });
co da mi ten widok bez przekierowania po stronie klienta. Nie sądzę jednak, żeby coś takiego istniało.
Obecnie najlepszą rzeczą, jaką mogę wymyślić, jest skopiowanie całej logiki kontrolera HomeController.Index(..)
w mojej GatewayController.Index
akcji. Oznacza to, musiałem przenieść 'Views/Home'
się 'Shared'
więc było dostępne. Musi być lepszy sposób ?? ..
źródło
ServerTransferAction
, które próbujesz odtworzyć? Czy to jest rzeczywista rzecz? (nie mogłem znaleźć żadnych informacji na ten temat ... dzięki za pytanie, przy okazji, odpowiedź poniżej jestif
stwierdzenie jest zbyt kuszące.RouteBase
, abyś mógł umieścićif
tam swoje oświadczenie zamiast zginać wszystko do tyłu, aby przeskoczyć z jednego kontrolera do drugiego?Odpowiedzi:
A co z klasą TransferResult? (na podstawie odpowiedzi Stansa )
Zaktualizowano: Teraz działa z MVC3 (używając kodu z postu Simona ). to powinno (nie udało się go przetestować) również prace w MVC2 patrząc, czy nie jest uruchomiony w ramach zintegrowanego rurociągu IIS7 +.
Dla pełnej przejrzystości; W naszym środowisku produkcyjnym nigdy nie używaliśmy bezpośrednio TransferResult. Używamy TransferToRouteResult, który z kolei wywołuje wykonanie TransferResult. Oto, co faktycznie działa na moich serwerach produkcyjnych.
A jeśli używasz T4MVC (jeśli nie ... zrób!), To rozszerzenie może się przydać.
Używając tego małego klejnotu, możesz to zrobić
źródło
Edycja: zaktualizowano w celu zapewnienia zgodności z ASP.NET MVC 3
Zakładając, że używasz IIS7, wydaje się, że następująca modyfikacja działa dla ASP.NET MVC 3. Dzięki @nitin i @andy za wskazanie, że oryginalny kod nie działa.
Edycja 11.04.2011: TempData zrywa z Server.TransferRequest od MVC 3 RTM
Zmodyfikowano poniższy kod, aby zgłosić wyjątek - ale obecnie nie ma innego rozwiązania.
Oto moja modyfikacja oparta na zmodyfikowanej wersji oryginalnego postu Stana Markusa. Dodałem dodatkowy konstruktor, aby wziąć słownik wartości trasy - i zmieniłem jego nazwę na MVCTransferResult, aby uniknąć nieporozumień, że może to być po prostu przekierowanie.
Teraz mogę wykonać następujące czynności dla przekierowania:
Moja zmodyfikowana klasa:
źródło
Zamiast tego można użyć Server.TransferRequest w usługach IIS7 +.
źródło
Niedawno dowiedziałem się, że ASP.NET MVC nie obsługuje Server.Transfer (), więc stworzyłem metodę stub (zainspirowaną Default.aspx.cs).
źródło
Czy nie mógłbyś po prostu utworzyć instancji kontrolera, do którego chcesz przekierować, wywołać żądaną metodę akcji, a następnie zwrócić wynik? Coś jak:
źródło
otherController.ControllerContext = this.ControllerContext;
Chciałem przekierować bieżące żądanie do innego kontrolera / akcji, zachowując dokładnie taką samą ścieżkę wykonania, jak w przypadku żądania tego drugiego kontrolera / akcji. W moim przypadku Server.Request nie działałby, ponieważ chciałem dodać więcej danych. W rzeczywistości jest to odpowiednik bieżącego programu obsługi wykonującego inny protokół HTTP GET / POST, a następnie przesyłającego wyniki strumieniowo do klienta. Jestem pewien, że będą lepsze sposoby na osiągnięcie tego, ale oto, co działa w moim przypadku:
Twoje przypuszczenie jest słuszne: umieściłem ten kod
i używam go do wyświetlania błędów programistom, podczas gdy w środowisku produkcyjnym będzie używać zwykłego przekierowania. Zauważ, że nie chciałem używać sesji ASP.NET, bazy danych ani innych sposobów przekazywania danych wyjątków między żądaniami.
źródło
Zamiast symulować transferu serwera, MVC jest nadal w stanie faktycznie robi Server.TransferRequest :
źródło
Po prostu uruchom drugi kontroler i wykonaj jego metodę akcji.
źródło
Możesz utworzyć nowy kontroler i wywołać metodę akcji zwracającą wynik. Będzie to jednak wymagało umieszczenia widoku w folderze udostępnionym.
Nie jestem pewien, czy to właśnie miałeś na myśli mówiąc o duplikacie, ale:
Edytować
Inną opcją może być utworzenie własnej fabryki ControllerFactory, w ten sposób można określić, który kontroler ma zostać utworzony.
źródło
Czy routing nie zajmuje się tylko tym scenariuszem? tj. dla scenariusza opisanego powyżej, możesz po prostu utworzyć procedurę obsługi trasy, która zaimplementowała tę logikę.
źródło
Dla każdego, kto używa routingu opartego na wyrażeniach i używa tylko powyższej klasy TransferResult, oto metoda rozszerzenia kontrolera, która załatwia sprawę i zachowuje TempData. Nie ma potrzeby TransferToRouteResult.
źródło
Server.TransferRequest
jest całkowicie niepotrzebne w MVC . Jest to przestarzała funkcja, która była konieczna tylko w ASP.NET, ponieważ żądanie przyszło bezpośrednio do strony i musiał istnieć sposób na przesłanie żądania na inną stronę. Nowoczesne wersje ASP.NET (w tym MVC) mają infrastrukturę routingu, którą można dostosować w celu kierowania bezpośrednio do żądanego zasobu. Nie ma sensu pozwalać, aby żądanie dotarło do kontrolera tylko po to, aby przesłać je do innego kontrolera, gdy możesz po prostu skierować żądanie bezpośrednio do kontrolera i żądanej akcji.Co więcej, ponieważ odpowiadasz na pierwotne żądanie, nie ma potrzeby wkładania czegokolwiek do
TempData
lub innego magazynu tylko po to, aby skierować żądanie we właściwe miejsce. Zamiast tego dochodzisz do akcji kontrolera z nienaruszonym pierwotnym żądaniem. Możesz również mieć pewność, że Google zaakceptuje to podejście, ponieważ dzieje się to całkowicie po stronie serwera.Chociaż możesz zrobić sporo z obu
IRouteConstraint
iIRouteHandler
, najpotężniejszym punktem rozszerzenia dla routingu jestRouteBase
podklasa. Tę klasę można rozszerzyć, aby zapewniała zarówno trasy przychodzące, jak i generowanie wychodzących adresów URL, co sprawia, że jest to punkt kompleksowej obsługi wszystkiego, co ma związek z adresem URL i akcją wykonywaną przez URL.Tak więc, aby podążać za drugim przykładem, aby dostać się z
/
do/home/7
, potrzebujesz po prostu trasy, która dodaje odpowiednie wartości trasy.Ale wracając do pierwotnego przykładu, w którym masz losową stronę, jest to bardziej złożone, ponieważ parametry trasy nie mogą się zmieniać w czasie wykonywania. Więc można to zrobić z
RouteBase
podklasą w następujący sposób.Które można zarejestrować w routingu, na przykład:
Zauważ, że w powyższym przykładzie sensowne może być również przechowywanie pliku cookie rejestrującego wersję strony głównej, na którą wszedł użytkownik, aby po powrocie otrzymali tę samą wersję strony głównej.
Należy również zauważyć, że przy użyciu tego podejścia można dostosować routing, aby uwzględnić parametry ciągu zapytania (domyślnie całkowicie je ignoruje) i odpowiednio skierować do odpowiedniej akcji kontrolera.
Dodatkowe przykłady
źródło
Server.TransferRequest
nie jest w końcu „całkowicie niepotrzebna w MVC”.Nie jest to odpowiedź sama w sobie, ale oczywiście wymaganie polegałoby nie tylko na tym, aby rzeczywista nawigacja „wykonywała” równoważną funkcjonalność Webforms Server.Transfer (), ale także aby to wszystko było w pełni obsługiwane w ramach testów jednostkowych.
Dlatego ServerTransferResult powinien "wyglądać" jak RedirectToRouteResult i być możliwie jak najbardziej podobny pod względem hierarchii klas.
Myślę o zrobieniu tego, patrząc na Reflector i robiąc wszystko, co robią klasa RedirectToRouteResult, a także różne metody klasy bazowej kontrolera, a następnie „dodając” to drugie do kontrolera za pomocą metod rozszerzających. Może mogłyby to być metody statyczne w tej samej klasie, dla ułatwienia / lenistwa w pobieraniu?
Jeśli się do tego zabiorę, opublikuję to, w przeciwnym razie może ktoś inny mnie pobije!
źródło
Osiągnąłem to, wykorzystując
Html.RenderAction
pomocnika w widoku:A w moim kontrolerze:
źródło