web-dev-qa-db-fra.com

La bibliothèque de classes Razor peut-elle également emballer des fichiers statiques (js, css, etc.)?

Peut-être en double déjà, mais comme ce message n'a pas de réponse, je poste cette question.

Le nouveau Razor Class Library est génial, mais il ne peut pas emballer les fichiers de bibliothèques (comme jQuery, CSS partagé).

Puis-je en quelque sorte réutiliser le CSS sur plusieurs projets de page Razor, en utilisant la bibliothèque de classes Razor ou toute autre chose (mon but est que, plusieurs sites Web utilisent le même CSS, et une seule modification s'applique à tous les projets).

J'ai essayé de créer le dossier wwwroot dans le projet de bibliothèque de classes Razor, mais cela ne fonctionne pas comme prévu (et je peux comprendre pourquoi).

14
Luke Vo

La réponse d'Ehsan était correcte au moment de la demande (pour .NET Core 2.2), pour .NET Core 3.0, RCL peut inclure des actifs statiques sans trop d'effort:

Pour inclure des actifs compagnons dans le cadre d'une liste de révocation de certificats, créez un dossier wwwroot dans la bibliothèque de classes et incluez tous les fichiers requis dans ce dossier.

Lors de l'emballage d'une liste de révocation de certificats, tous les actifs associés dans le dossier wwwroot sont automatiquement inclus dans le package.

Les fichiers inclus dans le dossier wwwroot de la RCL sont exposés à l'application consommatrice sous le préfixe _content/{LIBRARY NAME} /. Par exemple, une bibliothèque nommée Razor.Class.Lib génère un chemin d'accès au contenu statique dans _content/Razor.Class.Lib /.

3
Luke Vo

Vous devez intégrer vos ressources statiques dans votre ensemble de bibliothèque de classes Razor. Je pense que la meilleure façon de savoir comment le faire est de jeter un œil à codes source de l'interface utilisateur ASP.NET Identity .

Vous devez suivre les 4 étapes suivantes pour intégrer vos actifs et les servir.

  1. Modifiez le fichier csproj de votre bibliothèque de classes Razor et ajoutez les lignes suivantes.

     <PropertyGroup>
      ....
           <GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
      ....
     </PropertyGroup>
    
     <ItemGroup>
         ....
         <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.1.2" />
         <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.1.1" />
         <PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="2.1.1" />
         <PackageReference Include="Microsoft.NET.Sdk.Razor" Version="$(MicrosoftNETSdkRazorPackageVersion)" PrivateAssets="All" />
        .....
     </ItemGroup>
    
    <ItemGroup>
        <EmbeddedResource Include="wwwroot\**\*" />
        <Content Update="**\*.cshtml" Pack="false" />
    </ItemGroup>
    
  2. Dans votre bibliothèque de classes Razor, créez la classe suivante pour servir et router les actifs. (il suppose que vos actifs se trouvent dans le dossier wwwroot)

    public class UIConfigureOptions : IPostConfigureOptions<StaticFileOptions>
    {
        public UIConfigureOptions(IHostingEnvironment environment)
        {
            Environment = environment;
        }
        public IHostingEnvironment Environment { get; }
    
        public void PostConfigure(string name, StaticFileOptions options)
        {
            name = name ?? throw new ArgumentNullException(nameof(name));
            options = options ?? throw new ArgumentNullException(nameof(options));
    
            // Basic initialization in case the options weren't initialized by any other component
            options.ContentTypeProvider = options.ContentTypeProvider ?? new FileExtensionContentTypeProvider();
            if (options.FileProvider == null && Environment.WebRootFileProvider == null)
            {
                throw new InvalidOperationException("Missing FileProvider.");
            }
    
            options.FileProvider = options.FileProvider ?? Environment.WebRootFileProvider;
    
            var basePath = "wwwroot";
    
            var filesProvider = new ManifestEmbeddedFileProvider(GetType().Assembly, basePath);
            options.FileProvider = new CompositeFileProvider(options.FileProvider, filesProvider);
        }
    }
    
  3. Faites l'application Web dépendante pour utiliser votre routeur de bibliothèque de classes Razor. Dans la méthode ConfigureServices de la classe Démarrage , ajoutez la ligne suivante.

    services.ConfigureOptions(typeof(UIConfigureOptions));
    
  4. Vous pouvez donc maintenant ajouter une référence à votre fichier. (supposons qu'il se trouve sur wwwroot/js/app.bundle.js).

    <script src="~/js/app.bundle.js" asp-append-version="true"></script>
    
12
Ehsan Mirsaeedi

Merci pour les informations utiles Ehsan.

Voici une version étendue pour permettre le débogage de javascript et TypeScript ainsi que la possibilité d'apporter des modifications sans recompiler. Le débogage TypeScript ne fonctionne pas dans Chrome mais est dans IE. Si vous savez pourquoi, veuillez poster une réponse. Merci!

public class ContentConfigureOptions : IPostConfigureOptions<StaticFileOptions>
{
    private readonly IHostingEnvironment _environment;

    public ContentConfigureOptions(IHostingEnvironment environment)
    {
        _environment = environment;
    }

    public void PostConfigure(string name, StaticFileOptions options)
    {
        // Basic initialization in case the options weren't initialized by any other component
        options.ContentTypeProvider = options.ContentTypeProvider ?? new FileExtensionContentTypeProvider();

        if (options.FileProvider == null && _environment.WebRootFileProvider == null)
        {
            throw new InvalidOperationException("Missing FileProvider.");
        }

        options.FileProvider = options.FileProvider ?? _environment.WebRootFileProvider;

        if (_environment.IsDevelopment())
        {
            // Looks at the physical files on the disk so it can pick up changes to files under wwwroot while the application is running is Visual Studio.
            // The last PhysicalFileProvider enalbles TypeScript debugging but only wants to work with IE. I'm currently unsure how to get TS breakpoints to hit with Chrome.
            options.FileProvider = new CompositeFileProvider(options.FileProvider, 
                                                             new PhysicalFileProvider(Path.Combine(_environment.ContentRootPath, $"..\\{GetType().Assembly.GetName().Name}\\wwwroot")),
                                                             new PhysicalFileProvider(Path.Combine(_environment.ContentRootPath, $"..\\{GetType().Assembly.GetName().Name}")));
        }
        else
        {
            // When deploying use the files that are embedded in the Assembly.
            options.FileProvider = new CompositeFileProvider(options.FileProvider, 
                                                             new ManifestEmbeddedFileProvider(GetType().Assembly, "wwwroot")); 
        }

        _environment.WebRootFileProvider = options.FileProvider; // required to make asp-append-version work as it uses the WebRootFileProvider. https://github.com/aspnet/Mvc/issues/7459
    }
}

public class ViewConfigureOptions : IPostConfigureOptions<RazorViewEngineOptions>
{
    private readonly IHostingEnvironment _environment;

    public ViewConfigureOptions(IHostingEnvironment environment)
    {
        _environment = environment;
    }

    public void PostConfigure(string name, RazorViewEngineOptions options)
    {
        if (_environment.IsDevelopment())
        {
            // Looks for the physical file on the disk so it can pick up any view changes.
            options.FileProviders.Add(new PhysicalFileProvider(Path.Combine(_environment.ContentRootPath, $"..\\{GetType().Assembly.GetName().Name}")));
        }
    }
}
1
KJ.Coding

Il existe une solution plus simple: dans le projet de votre RCL, vous pouvez marquer le wwwroot à copier dans le répertoire de publication:

<ItemGroup>
  <Content Include="wwwroot\**\*.*" CopyToPublishDirectory="Always" />
</ItemGroup>

Lorsque vous déployez une application qui dépend de la RCL, tous les fichiers sont accessibles comme prévu. Vous devez juste faire attention à ce qu'il n'y ait pas de conflit de dénomination.

Attention: cela ne fonctionne que lors du déploiement sur Azure, mais pas sur votre machine locale (vous aurez besoin d'un fournisseur pour cela).

0
Métoule

Veuillez noter que ces solutions fournies ne fonctionneront que pour les applications côté serveur. Si vous utilisez le côté client Blazor, cela ne fonctionnera pas. Pour inclure des actifs statiques côté client Blazor à partir d'une bibliothèque de classes de rasoir, vous devez référencer directement les actifs comme ceci:

<script src="_content/MyLibNamespace/js/mylib.js"></script>

J'ai perdu des heures à essayer de comprendre cela. J'espère que cela aide quelqu'un.

0
revobtz

J'ai atteint ce problème il y a longtemps. Vous pouvez suivre l'article comment inclure des fichiers statiques dans une bibliothèque de rasoir qui explique comment contourner ce problème.

La solution à laquelle j'ai abouti après de nombreuses investigations n'est pas loin de la réponse acceptée dans cette question:

1 Définissez les fichiers en tant que ressources intégrées

  <ItemGroup>
    <EmbeddedResource Include="wwwroot\**\*" />
    <EmbeddedResource Include="Areas\*\wwwroot\**\*" />
  </ItemGroup>

2 Inclure des fichiers statiques dans le manifeste

  <PropertyGroup>
    <TargetFramework>netcoreapp2.1</TargetFramework>
    <GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
  </PropertyGroup>

3 Recherchez les dossiers appropriés

(vous pouvez trouver plus de détails dans l'article lié, voire automatiser cette recherche depuis cet article )

// first we get the Assembly in which we want to embedded the files
var Assembly = typeof(TypeInFeatureAssembly).Assembly;

// we filter only files including a wwwroot name part
filePaths = (from rn in Assembly.GetManifestResourceNames().Where(rnn => rnn.Contains(".wwwroot."))
    let hasArea = rn.Contains(".Areas.")
    let root = rn.Substring(0, rn.LastIndexOf(".wwwroot.") + ".wwwroot.".Length)
    let rootPath = !hasArea ? root : root.Substring(0, root.IndexOf(".Areas."))
    let rootSubPath = !hasArea ? "" : root.Substring(root.IndexOf(".Areas.")).Replace('.', '/')
    select  hasArea ? rootSubPath.Substring(1, rootSubPath.Length - 2) : "wwwroot" )
    .Distinct().ToList();

Cela extrait toutes les ressources incorporées dans un dossier wwwroot situé dans un chemin d'accès approprié.

4 Ajoutez les chemins trouvés au fournisseur de fichiers webroot

var allProviders = new List<IFileProvider>();
allProviders.Add(env.WebRootFileProvider);
allProviders.AddRange(filePaths.Select(t => new ManifestEmbeddedFileProvider(t.Assembly, t.Path)));
env.WebRootFileProvider = new CompositeFileProvider(allProviders);

0
Jean