Vraag MEF en Razor Views in Class Library


Ik heb een samengestelde ASP .NET MVC 3 Razor-applicatie met MEF. Alles gaat goed als ik plug-ins moet gebruiken als DLL-bestanden en views (CSHTML) onder de reguliere Views map van de toepassing. Maar dit is niet erg schoon en het zal geen echte plug-in zijn als ik views niet als ingesloten bronnen in de DLL-bestanden plaats (samen met zowel controllers als modellen).

Ik heb veel artikelen gevolgd (de meeste zijn verouderd). In feite is er hier een hele goede op Stack Overflow: Controllers en weergaven in een klassebibliotheek

Ik heb ook documenten gecontroleerd voor VirtualPathProvider en ik heb een aangepast bestand kunnen maken dat het bestand binnen de assembly vindt en het perfect laadt (of er in ieder geval de stream naartoe krijgt). Hiervoor heb ik de VirtualPathProvider  documentatie op MSDN.

Er is ook een implementatie voor VirtualFile maar nog niet voor VirtualDirectory.

Dit is het probleem. Ik werk met Razor-standpunten. Ik weet dat ze configuratie specificaties van de web.config bestand voor Razor om ze te bouwen. Maar als ik ze insluit in de DLL is deze config gewoon verloren.

Ik vraag me af of ik daarom steeds de foutmelding krijg:

De weergave op ~ ~ / Plugins / CRM.Web.Views.CRM.Index.cshtml 'moet afgeleid zijn   van WebViewPage of WebViewPage.

Misschien moet ik gewoon wat code toevoegen om het te laten werken? Om het even welke ideeën?


27
2018-02-15 17:56


oorsprong


antwoorden:


Mijn favoriete manier om Razor-weergaven in een klassenbibliotheek in te bedden, is door ze naar de mappen Views / Areas van de MVC-website te kopiëren met een post-build-gebeurtenis. Aangepaste weergave locaties kunnen worden opgegeven als u de ViewEngine of VirtualPathProvider overschrijft.

Het lastige voor mij was om intellisense te laten werken in deze View Class-bibliotheken. Eerst moet u een Web.Config toevoegen aan uw View-assembly. Merk op dat je het niet echt in je assembly hoeft op te nemen. Het moet alleen in de rootmap van de assembly staan ​​(of in de viewmap). Hier is een voorbeeld. Bekijk de belangrijke sectie Assemblies / Compilatie.

<?xml version="1.0"?>
<configuration>
  <configSections>
    <sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
      <section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
      <section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
    </sectionGroup>
  </configSections>

  <system.web.webPages.razor>
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <pages pageBaseType="System.Web.Mvc.WebViewPage">
      <namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Routing" />
      </namespaces>
    </pages>
  </system.web.webPages.razor>

  <appSettings>
    <add key="webpages:Enabled" value="false" />
  </appSettings>

  <system.web>
    <compilation targetFramework="4.0">
      <assemblies>
        <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
        <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
        <add assembly="System.Data.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
        <add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      </assemblies>
    </compilation>

    <httpHandlers>
      <add path="*" verb="*" type="System.Web.HttpNotFoundHandler"/>
    </httpHandlers>

    <!--
        Enabling request validation in view pages would cause validation to occur
        after the input has already been processed by the controller. By default
        MVC performs request validation before a controller processes the input.
        To change this behavior apply the ValidateInputAttribute to a
        controller or action.
    -->
    <pages
        validateRequest="false"
        pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
        pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
        userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
      <controls>
        <add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" />
      </controls>
    </pages>
  </system.web>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <handlers>
      <remove name="BlockViewHandler"/>
      <add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
    </handlers>
  </system.webServer>
</configuration>

Vervolgens moet u het vbproj-bestand van uw klassebibliotheek wijzigen, zodat alle OutputPath-elementen verwijzen naar 'bin \' in plaats van 'Debug \ bin \' of 'Release \ bin \'. Dit is het belangrijkste verschil dat ik vond tussen klassenbibliotheken en ASP.Net-webprojecttypen die intellisense-bugs kunnen veroorzaken.

Als u nog steeds de fout ervaart die u overneemt, overweeg dan @Inherits System.Web.Mvc.WebViewPage te gebruiken in uw views. Als u uw weergaven niet kopieert naar uw websiteproject, laadt u ze mogelijk vanuit Embedded Resources met behulp van een aangepaste ViewEngine / VirtualPathProvider. Als dat het geval is, hebt u absoluut de Inherits nodig, zodat Razor weet wat uw basisklasse voor weergave is, helaas.

Succes.


7
2017-11-23 17:41



Je zou eens kunnen kijken naar de blogbericht volgen.


3
2018-02-15 18:16



Hossam,

De post waar je het over hebt is wat Darin al heeft voorgesteld. De belangrijkste keerzijde van die aanpak is het gebruik van de aangepaste MvcRazorClassGenerator-compiler om de CSHTML-viewbestanden naar klassenbestanden om te zetten. Hiertoe moet u elke CSHTML-view in uw project instellen op Content en het Custom Tool instellen op MvcRazorClassGenerator.

Ik kan niet spreken voor LordALMMa, maar ik heb de compilerbron wel gedownload en het een kans gegeven en het werkt niet precies zoals ik hoopte.

Mijn andere benadering was om de CSHTML-bestanden als Embeded Resources in het externe DLL-bestand op te nemen, in de onbewerkte inhoud van het bestand te lezen en de weergave als een tekenreeks uit te voeren (zie de RazorEngine op CodeProject voor een voorbeeld: http://razorengine.codeplex.com/)

Ik wilde niet volledig afhankelijk zijn van de RazorEngine in een bedrijfsapplicatie omdat ik niet weet hoe goed het compatibel is met de syntaxis van Razor, dus heb ik dat voorlopig opgegeven.

Ik kom uit een prototype dat ik heb gebouwd in ASP.NET MVC 2.0, dat een veelzijdige toepassing is. Op een serverfarm hebben we één instantie van een toepassing die draait op alle clients die dezelfde codebase gebruiken. In mijn MVC 2.0-prototype was ik in staat om te bepalen voor welke "klant" het verzoek werd gedaan, controleer of er een aangepaste controller is die het basisstation overtreft (voor aanpassingen van de kerncode) en controleer ook op aangepaste weergaven (voor aanpassingen van de kernweergave). Wat dit doet, is ons in staat stellen om voor elke klant een "plug-in" per stem uit te voeren. De software detecteert of de client een aangepaste controller heeft die overeenkomt met de aanvraag, evenals een aangepaste actie die overeenkomt en als dat wel het geval is, wordt in plaats daarvan de aangepaste controller / actie gebruikt.

Toen ik begon met het migreren van mijn prototype naar MVC 3, rende ik naar hetzelfde probleem als LordALMMa, de fout "The view at '... Index.cshtml' moet zijn afgeleid van WebViewPage of WebViewPage". Ik zal kijken naar het plaatsen van "@inherits System.Web.Mvc.WebViewPage" in mijn CSHTML-views en kijken of dat me dichter bij het werken brengt.

Omdat ik een werkend MVC 2.0-prototype heb met MVC 3, heeft Razor geen topprioriteit en verspil ik er niet veel tijd aan. Ik weet zeker dat ik de MVC 2.0 naar MVC 3.0 kan overbrengen met behulp van de WebForms-engine als we het 4.0 Framework moeten gebruiken.


2
2018-05-25 03:13



Hé, ik vermoed dat je goede redenen hebt om views te willen in DLL's. Overweeg echter ook dat het een ongebruikelijke manier is om alles in één geheel te verpakken.

Als u een plug-in ontwikkelt, kiezen mensen tegenwoordig voor verpakking in het NUGET-formaat, waarmee u onder andere uw probleem oplost. Het heeft een .nupkg-structuur, die ook een manier is om plug-ins te distribueren als pakketten en bibliotheken.

Een andere oplossing die communities over het algemeen volgen is (als ze niet zo uitgebreid willen zijn als nuget) coderen ze de plug-in DLL's zodanig dat het geen view engines zoals razor gebruikt, maar in plaats daarvan HTML alleen uitvoert met de oude primitieve manier van Response .Schrijf en wordt dus onafhankelijk van cshtml-bestanden. Als u nog steeds cshtml wilt gebruiken - zie dit blogbericht voor het precompileren van die in klassen.


0
2017-11-23 17:55