4
votes

Directory.GetCurrentDirectory () ne renvoie pas le bon répertoire

Dans mon serveur MVC ASP.NET Core 2.2, je souhaite ajouter un dossier pour stocker les fichiers statiques. J'ai trouvé le code suivant pour effectuer cela:

'System.IO.DirectoryNotFoundException' in Microsoft.Extensions.FileProviders.Physical.dll C:\Program Files\IIS Express\StaticFiles\

Sur mon ordinateur, le projet se trouve dans "C: \ Users \ MyUsername \ source \ repos \ WebApplication1 \ WebApplication1" code>, dans le même répertoire il y a un dossier appelé "StaticFiles" et un fichier Startup.cs où le code ci-dessus est écrit.

Mais quand j'exécute le code, j'ai l'erreur suivante:

app.UseStaticFiles(new StaticFileOptions {
    FileProvider = new PhysicalFileProvider(
        Path.Combine(Directory.GetCurrentDirectory(), "StaticFiles")),
    RequestPath = "/StaticFiles"
});

Le Directory.GetCurrentDirectory () renvoie "C: \\ Program Files \\ IIS Express" au lieu de "C: \ Users \ MyUsername \ source \ repos \ WebApplication1 \ WebApplication1" . Comment puis-je obtenir la bonne direction?


5 commentaires

Salut :) Si vous voulez que ce soit la route où se trouve l'application, passez de IIS Express à "YourProjectName" lors du débogage


Je pense que vous devriez inclure tous les fichiers du dossier StaticFiles dans votre projet et définir BuildAction sur Content dans Propriétés pour tous. De cette façon, ils seront inclus dans le fichier d'installation.


@ NikolaMarkovinović StaticFiles se trouve dans le dossier du projet. Que voulez-vous dire par BuildAction ? Mon Visual Studio est en espagnol, je n'ai trouvé aucun bouton similaire, où est censé être ce bouton?


Cliquez avec le bouton droit sur un fichier, puis cliquez sur Propriétés .


Directory.GetCurrentDirectory () peut changer pendant l'exécution d'un programme - il ne devrait pas être utilisé pour rechercher des fichiers relatifs à l'emplacement d'une application.


3 Réponses :


1
votes

Il semble que le répertoire de travail par défaut de votre application pointe vers le Répertoire de travail d'IIS Express

Essayez d'abord de définir le chemin de base à partir de Program.cs en utilisant HostingEnvironment

new HostBuilder()
    .CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((context, builder) =>
    {               
         builder
            .SetBasePath(context.HostingEnvironment.ContentRootPath)

Si cela ne fonctionne pas, l'option la plus simple est de définir le répertoire de travail de votre profil de lancement IIS Express à partir de launchSettings.json . Pour cela,

  • Faites un clic droit sur votre projet et sélectionnez ses propriétés.
  • Passer au débogage
  • Sélectionnez le profil qui va être utilisé
  • Allez dans la zone de texte Répertoire de travail et définissez votre répertoire de travail

Remarque: cela n'affecte pas vos builds, c'est juste une configuration de débogage.


  var builder = new ConfigurationBuilder()
      .SetBasePath(env.ContentRootPath)


2 commentaires

env n'existe pas, que voulez-vous dire par là? De plus, j'utilise actuellement CreateDefaultBuilder () , puis-je utiliser SetBasePath dessus?


s'il vous plaît vérifier ma modification



3
votes

L'interface IHostingEnvironment fournit des informations sur l'environnement, y compris le chemin de base. Vous pouvez obtenir une instance en utilisant l'injection de dépendances.

public class Startup
{
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        // env.ContentRootPath;
    }
}


0 commentaires

3
votes

Il s'agit d'un bogue dans ASP.NET Core 2.2 qui a été signalé dans GitHub et l'équipe Microsoft ASP.NET Core ont fourni une solution comme suit et ils ajouteront cette solution à la version de fonctionnalités d'ASP.NET Core.

Écrivez une classe d'assistance comme suit: p >

app.UseStaticFiles(new StaticFileOptions {
    FileProvider = new PhysicalFileProvider(

        CurrentDirectoryHelpers.SetCurrentDirectory(); // call it here

        Path.Combine(Directory.GetCurrentDirectory(), "StaticFiles")),
    RequestPath = "/StaticFiles"
});

Puis appelez la méthode SetCurrentDirectory () dans votre code comme suit:

public class CurrentDirectoryHelpers
{
    internal const string AspNetCoreModuleDll = "aspnetcorev2_inprocess.dll";

    [System.Runtime.InteropServices.DllImport("kernel32.dll")]
    private static extern IntPtr GetModuleHandle(string lpModuleName);

    [System.Runtime.InteropServices.DllImport(AspNetCoreModuleDll)]
    private static extern int http_get_application_properties(ref IISConfigurationData iiConfigData);

    [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
    private struct IISConfigurationData
    {
        public IntPtr pNativeApplication;
        [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.BStr)]
        public string pwzFullApplicationPath;
        [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.BStr)]
        public string pwzVirtualApplicationPath;
        public bool fWindowsAuthEnabled;
        public bool fBasicAuthEnabled;
        public bool fAnonymousAuthEnable;
    }

    public static void SetCurrentDirectory()
    {
        try
        {
            // Check if physical path was provided by ANCM
            var sitePhysicalPath = Environment.GetEnvironmentVariable("ASPNETCORE_IIS_PHYSICAL_PATH");
            if (string.IsNullOrEmpty(sitePhysicalPath))
            {
                // Skip if not running ANCM InProcess
                if (GetModuleHandle(AspNetCoreModuleDll) == IntPtr.Zero)
                {
                    return;
                }

                IISConfigurationData configurationData = default(IISConfigurationData);
                if (http_get_application_properties(ref configurationData) != 0)
                {
                    return;
                }

                sitePhysicalPath = configurationData.pwzFullApplicationPath;
            }

            Environment.CurrentDirectory = sitePhysicalPath;
        }
        catch
        {
            // ignore
        }
    }
}

Maintenant, tout devrait fonctionne bien!


13 commentaires

Merci. Je ne veux pas paraître pessimiste, mais quel avantage votre code a-t-il sur les réponses de Jonas Tuemand Møller . Ses codes fonctionnent et n'ont qu'une ligne. Votre code comporte ... quelques lignes supplémentaires. Quoi qu'il en soit, mjwills a déclaré dans les commentaires sur ma question, qu'en aucun cas Directory.GetCurrentDirectory () ne devrait être utilisé pour obtenir le chemin car il peut changer pendant que le programme s'exécute. Mais merci d'avoir signalé le bogue.


@EnderLook peut être une approche Jonas Tuemand Møller ne fonctionnant pas si vous utilisez le modèle d'hébergement InProcess dans ASP.NET Core 2.2 . Le moyen le plus sûr d'utiliser cette solution, comme le suggère Microsoft ASP.NET Core.


Ok, je n'ai aucune idée de ce qu'est InProcess mais cela semble important :). J'utilise ça. Merci! (Je ne l'accepte pas encore car il est courant d'attendre au moins 24 heures avant d'accepter une réponse).


Haha! :) Aucun problème! un autre point à noter qu'il fonctionnera en mode débogage sans ajouter ce PreserveNewe‌ st dans le fichier .csproj


Je sais, mais j'ai remarqué que VS ne copie pas les "StaticFiles" (ni son contenu) dans la version officielle lorsque j'appuie sur "publier". En essayant une erreur, j'ai trouvé qu'en ajoutant cette ligne à .csproj , le dossier avait été copié dans la version.


Oh! Oui! Pour publier, vous devez ajouter ceci.


C'est exagéré pour la situation du PO. La réponse de Jonas est tout ce dont vous avez besoin ici.


@KirkLarkin Merci, mais en cas de modèle d'hébergement InProcess , IHostingEnvironment env sera-t-il suffisant?


Oui, il sera. IHostingEnvironment.ContentRootPath sera défini correctement quel que soit le modèle d'hébergement utilisé.


D'accord! Je vais un chèque!


OutOfProcess n'est-il pas la valeur par défaut, avec InProcess comme opt-in? De toute évidence, l'OP l'a configuré comme tel qu'il passe dans InProcess (d'où les chemins IIS), se demandant simplement si c'est pertinent


Pardon quoi? @TanvirArjel. Alors, que dois-je utiliser? CurrentDirectoryHelpers ou IHostingEnvironment env; env.ContentRootPath ?


C'est maintenant votre choix! Qu'est-ce qui vous convient le mieux? 😄