Pytanie 404 na kontrolerach w zewnę trznych zespołach


Mam problem z rozwiązaniem 404 odpowiedzi w moim projekcie Asp.Net MVC 4. Jest wbudowany w kierowanie VS2012 4.5.

Mam wstępnie skompilowane widoki i kontrolery wbudowane w autonomiczne biblioteki DLL. Mogę dynamicznie ładować biblioteki DLL i sprawdzać je z mojego głównego projektu, nawet wywoływać na nich metody; wydaje się jednak, że MVC Framework nie zna kontrolerów. Jestem tu blisko, ale czegoś brakuje.

Tło na kontrolerach i widokach

Kontrolery są zbudowane w samodzielnym projekcie MVC i dziedziczą z Controller. Nic ciekawego się tam nie dzieje. Widoki używają RazorGenerator i stają się klasami, które żyją w projekcie.

Dane wyjściowe projektu to biblioteka DLL, która poprawnie zawiera kontrolery i widoki.

Pliki DLL implementują określony interfejs, my go nazwiemy IPlugin, w oddzielnej klasie (nie należącej do kontrolera) w bibliotece.

Ładowanie bibliotek DLL

Działając jako administrator w Visual Studio, kompiluję moją aplikację hostowaną pod IIS. Po zbudowaniu projektu upuszczam bibliotekę DLL wtyczki do mojego katalogu "Plugins". Bez debugowania (to staje się ważne później), otwieram IE i przechodzę do strony. Zauważ, że w tym momencie aplikacja została zbudowana, ale nigdy nie działa, więc zdarzenia startowe będą uruchamiane. Wszystko tutaj jest nadal spójne, jeśli zrekonstruuję pulę aplikacji.

mam Startup klasa z dwoma metodami, PreStart i PostStart i wywołaj metody używając WebActivator.PreApplicationStartMethod i WebActivator.PostApplicationStartMethod odpowiednio.

PreStart gdzie robię co następuje:

  • Uzyskaj listę wszystkich bibliotek DLL wtyczek w moim katalogu "Wtyczki"
  • Skopiuj wszystkie wtyczki do AppDomain.CurrentDomain.DynamicDirectory
  • Załaduj typ ... jeśli zawiera IPlugin Ja wtedy
    • Dodaj zespół do BuildManager
    • Wywołaj niektóre metody z klasy implementującej IPlugin

W "PostStart" robię ten fragment kodu (w oparciu o kod z RazorGenerator.Mvc):

foreach (var assembly in Modules.Select(m=>m.Value))
{
    var engine = new PrecompiledMvcEngine(assembly)
    {
        UsePhysicalViewsIfNewer = HttpContext.Current.Request.IsLocal
    };

    ViewEngines.Engines.Insert(0, engine);
    VirtualPathFactoryManager.RegisterVirtualPathFactory(engine);
}

Modules w tym kontekście jest to para klucz / wartość, w której wartości są obciążonymi złożeniami. Celem tego kodu jest upewnienie się, że MVC ma świadomość widoków przez dodanie mechanizmu wyświetlania dla każdego zespołu, który wie, jak rozwiązywać widoki (jest to część RazorGenerator).

Jak wiem, że jestem blisko (ale wyraźnie brakuje cygara)

IPlugin definiuje metodę zwaną RegisterRoutes gdzie, jak się domyślacie, trasy zostaną zarejestrowane dla tych, którzy implementują interfejs. Ja nazywam tę metodę w PreStart i dodawane są trasy - zweryfikowałem, że istnieją one w mojej tabeli routingu. Na przykład na trasie zdefiniowanej w mojej wtyczce, utworzonej poprzez dynamiczne wywołanie metody podczas PreStartWidzę coś takiego jak DataToken podczas badania moich tras:

Namespaces = Plugin.Name.Controllers

Tak więc, rejestrowana jest trasa, zespół jest załadowany, zweryfikowałem, że biblioteka DLL jest poprawnie skopiowana do DynamicDirectory AppDomain. Jestem w stanie wywołać członków klas, które są ładowane dynamicznie w środowisku wykonawczym. Ale gdy przejdę do adresu URL dopasowanego do trasy Dostaję 404. To jest nie "nie można zlokalizować widoku" YSOD, bardziej przypomina to znalezienie w ogóle kontrolera.

Oto ta część, która mnie zmyli: jeśli w tym momencie, bez robienia czegokolwiek, wrócę do Visual Studio i uderzę w F5 ... wszystko działa.

To tak, jak Visual Studio staje się świadomy kontrolera w jakiś sposób, którego nie mogę zidentyfikować, a MVC Framework zaczyna na nim działać.

Wreszcie pytanie

Czego mi brakuje i jak mogę uzyskać wiedzę na temat kontrolera MVC Framework?

I hej, w tym momencie, jeśli wciąż to czytasz, dzięki. :)


12
2018-02-15 19:26


pochodzenie


1. Czy VS działa z wykorzystaniem Cassini? Spróbuj zmienić go na IIS Express i sprawdź, czy nadal działa poprawnie. 2. Spróbuj zainstalować RouteDebugger - może może dać ci wskazówki, czy trasy są poprawnie rejestrowane w IIS - Pranav
Dzięki @Pranav, ale już jest na IIS. Debugger trasy pokazuje, że trasy działają. - MisterJames
Czy to może być problem? stackoverflow.com/questions/14971895/... - Tengiz
+1, ale nie, jeszcze nie, tak czy inaczej. Struktura nie znajduje kontrolera, więc nic nie szuka jeszcze widoku. I znowu, kiedy rekompiluję, wszystko działa dobrze. - MisterJames


Odpowiedzi:


Okazuje się, że jest to błąd w samej Asp.Net.

Po omówieniu problemu z Eilonem Liptonem z zespołu Asp.Net i myśląc, że to było coś nie tak w MVC Framework, Eilon i kilku członków zespołu wpadło w różne rzeczy i odkryli, że błąd był na niższym poziomie dla tej rozmowy: http://aspnetwebstack.codeplex.com/discussions/403529

Zasugerowali również obejście, które obejmowało kolejne zgłoszenie BuildManager po telefonie do AddReferencedAssembly, które zaimplementowałem za pomocą następującego kodu:

    // Add the plugin as a reference to the application
    BuildManager.AddReferencedAssembly(assembly);
    BuildManager.AddCompilationDependency(assembly.FullName);

Dzięki temu możesz dodać dodatkowe kontrolery / skompilowane widoki podczas uruchamiania na etapie inicjacji przed aplikacją. Teraz zajmuję się przeglądaniem listy bibliotek DLL w katalogu z wtyczkami i wysyłam do nich BuildManager jak powyżej.

Jedynym ograniczeniem jest to, że nie możesz usunąć złożenia lub wyczyść pamięć podręczną dynamicznie. Jedynym sposobem, jaki udało mi się to zrobić, jest dodanie nieznanego wcześniej zestawu do przywołanych złożeń i zależności kompilacji. Eksperymentuję z dynamicznym emitowaniem nowego zestawu podczas inicjacji przedaplikacyjnej, dzięki czemu mogę zawsze, skutecznie wyczyścić pamięć podręczną i usunąć wcześniej dołączone wtyczki, wykonując fałszywy nowy zespół.

Mam nadzieję, że to pomoże komuś innemu.

Twoje zdrowie.


5
2018-03-04 16:29



Dziękuję bardzo za szczegółowe pytanie i odpowiedź. Jedną z rzeczy, których nie otrzymuję, jest to, dlaczego nie używasz fabryki kontrolerów niestandardowych (patrz ControllerBuilder.Current.SetControllerFactory)? To pozwoliłoby ci mieć pełną kontrolę nad tym, kiedy wydać kontroler, nieprawdaż? - Dejan


Wygląda na to, że ten problem:

MVC używa nazwy typu zestawu kwalifikowanego silnika widoku do   disambiguate wyświetlanie wpisów pamięci podręcznej z różnych mechanizmów wyświetlania. Więc jest to   nie można mieć więcej niż jednego obiektu PrecompiledMvcEngine (jak   gdy masz wstępnie skompilowane widoki w więcej niż jednym złożeniu). The   Problem można rozwiązać, tworząc inną klasę pochodną od   PrecompiledMvcEngine dla każdego zespołu. Lub tworząc singiel   klasa pochodna generyczna sparametryzowana z pewnym typem ze złożenia.

Artykuł jest tutaj.


1
2018-02-21 17:49



Dzięki Nenad, ale w tej chwili używam tylko jednej wtyczki, więc próba wczytania jest tylko jedna. To może wpływać, ale miałem też 2 wtyczki uruchomione na raz, więc nie jestem pewien, że tak. Co więcej, nie rozwiązuje to problemu, który mam, ponieważ kontroler nie znajduje się. To jest klucz do nagrody. Twoje zdrowie. - MisterJames
Czy możesz podać więcej szczegółów na temat błędu? Ślad stosu? - Nenad
Szkoda, że ​​nie było. Wszystko, co dostaję, to 404 na kontrolerze, gdy próbuję uzyskać dostęp do widoku, który jest. Mam Log4Net i ELMAH, i nie ma nic złego, co podniosę (z logowaniem na każdym kroku). Mam więcej szczegółów, które dodam do tego pytania później po omówieniu kilku rzeczy z niektórymi członkami zespołu Asp.Net w tym tygodniu. - MisterJames


@MisterJames, spójrz na to:

Aplikacja wtykowa Asp.Net Mvc

Mam nadzieję, że jest to przydatne.


0
2018-02-21 19:21



Felipe, to wykorzystuje obszary w projekcie z tego samego rozwiązania i jest zupełnie inne podejście. Moje potrzeby to posiadanie samodzielnych rozwiązań dla wtyczek. Omówię to bardziej szczegółowo, aby sprawdzić, czy są jakieś wskazówki, ale w tej kwestii nie wierzę, że pomoże to w moim scenariuszu. - MisterJames