简体   繁体   中英

AppDomain.CurrentDomain.BaseDirectory changes to wrong directory

I have a created a dll with a Cmdlet command (see Get_DemoNames.cs). From this cmdlet I call a method UpdateXml() , so far everything is working. But UpdateXml() also creates files if they don't exist. When I call UpdateXml() in a class file like this:

var parser = new Parser();
parser.UpdateXml();

And I run the project it goes to the correct directories.

But if I load the import the dll and run the command DemoNames in a seperate test project like this:

PM> Import-Module C:\projects\EF.XML\EF.XML.dll
PM> DemoNames

The program goes to a wrong directory resulting in the following error:

Get-DemoNames : Access to the path 'C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\IDE\\beheer_extern\\config' is denied. At line:1 char:10 + DemoNames <<<< + CategoryInfo : NotSpecified: (:) [Get-DemoNames], UnauthorizedAccessException + FullyQualifiedErrorId : System.UnauthorizedAccessException,EF.XML.Get_DemoNames

I searched on the net for this error and found out that some other people were able to solve it by adding this line to the constructor:

public Parser()
{
    AppDomain.CurrentDomain.SetData("APPBASE", Environment.CurrentDirectory);
}

This gives me another wrong path:

Get-DemoNames : Access to the path 'C:\\Windows\\system32\\beheer_extern\\config' is denied. At line:1 char:10 + DemoNames <<<< + CategoryInfo : NotSpecified: (:) [Get-DemoNames], UnauthorizedAccessException + FullyQualifiedErrorId : System.UnauthorizedAccessException,EF.XML.Get_DemoNames

Get_DemoNames.cs

namespace EF.XML
{
using System;
using System.Linq;
using System.Management.Automation;

[Cmdlet(VerbsCommon.Get, "DemoNames")]
public class Get_DemoNames : PSCmdlet
{

    [Parameter(Position = 0, Mandatory = false)]
    public string prefix;

    protected override void ProcessRecord()
    {

        var names = new[] { "Chris", "Charlie", "Isaac", "Simon" };

        if (string.IsNullOrEmpty(prefix))
        {
            WriteObject(names, true);
        }
        else
        {
            var prefixed_names = names.Select(n => prefix + n);

            WriteObject(prefixed_names, true);
        }

        System.Diagnostics.Debug.Write("hello");

        var parser = new Parser();
        parser.UpdateXml();

    }

  }
}

Parser.cs

 public class Parser
{
    public void UpdateXml()
    {
                var directoryInfo = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory); // www directory

                var path = Path.Combine(directoryInfo.FullName, @"beheer_extern\config");

                //Creates the beheer_extern\config directory if it doesn't exist, otherwise nothing happens.
                Directory.CreateDirectory(path);

                var instellingenFile = Path.Combine(path, "instellingen.xml");
                var instellingenFileDb = Path.Combine(path, "instellingenDb.xml");

                //Create instellingen.xml if not already existing
                if (!File.Exists(instellingenFile))
                {
                    using (var writer = XmlWriter.Create(instellingenFile, _writerSettings))
                    {
                        var xDoc = new XDocument(
                            new XElement("database", string.Empty, new XAttribute("version", 4)));
                        xDoc.WriteTo(writer);
                    }
                }
      }
}

How can I get the right directory of the project (www directory)?

Okay, so you're trying to access a project, loaded within Visual Studio, from within the Package Manager Console.

Know that the executable is Visual Studio , and so AppDomain.CurrentDomain.BaseDirectory is going to be the Visual Studio install directory. It absolutely will not be the directory of the current project.

In order to get the project directory for the currently loaded solution, you need to interact with the running instance of Visual Studio via automation. Typically that's done by writing an extension or via the Visual Studio core automation, AKA the EnvDTE com object . This is complex . Want to do this? You'll probably have to grab a book on the subject and read.

Luckily, the PMC does provide a cmdlet that will simplify this greatly for you-- get-project . It returns the DTE representation of the project , which you can then use this to get the project file's full filename , from which you can get the directory name.

Those are the pieces and parts you need. As for calling the cmdlet from your code, that's another question.

FIX

I managed to get it working with the following code

Get_DemoNames.cs

namespace EF.XML
{
using System;
using System.Linq;
using System.Management.Automation;

[Cmdlet(VerbsCommon.Get, "DemoNames")]
public class Get_DemoNames : PSCmdlet
{

[Parameter(Position = 0, Mandatory = false)]
public string prefix;

protected override void ProcessRecord()
{

    var names = new[] { "Chris", "Charlie", "Isaac", "Simon" };

    if (string.IsNullOrEmpty(prefix))
    {
        WriteObject(names, true);
    }
    else
    {
        var prefixed_names = names.Select(n => prefix + n);

        WriteObject(prefixed_names, true);
    }

    //added
    const string networkPath = "Microsoft.PowerShell.Core\\FileSystem::";
    var currentPath = SessionState.Path.CurrentFileSystemLocation.Path;

    var curProjectDir = currentPath.Substring(networkPath.Length); 

    WriteObject(curProjectDir);

    System.Diagnostics.Debug.Write("hello");

    var parser = new Parser {CurrentProjectDirectory = curProjectDir };
    parser.UpdateXml();

    }

  }
}

Parser.cs

public class Parser
{    



public string CurrentProjectDirectory{ get; set; }

public void UpdateXml()
{

    var wwwDirectory = Path.Combine(CurrentProjectDirectory, @"www"); // www directory

    var path = Path.Combine(wwwDirectory, @"beheer_extern\config");

    //Creates the beheer_extern\config directory if it doesn't exist, otherwise nothing happens.
    Directory.CreateDirectory(path);

    var instellingenFile = Path.Combine(path, "instellingen.xml");
    var instellingenFileDb = Path.Combine(path, "instellingenDb.xml");

    //Create instellingen.xml if not already existing
    if (!File.Exists(instellingenFile))
    {
        using (var writer = XmlWriter.Create(instellingenFile, _writerSettings))
        {
            var xDoc = new XDocument(
                new XElement("database", string.Empty, new XAttribute("version", 4)));
            xDoc.WriteTo(writer);
        }
    }
  }
}

I also tried EnvDTE which also works.

Required imports:

using EnvDTE;
using EnvDTE80;
using Microsoft.VisualStudio.Shell;

Code to get the current solution (path):

 DTE2 dte2 = Package.GetGlobalService(typeof(DTE)) as DTE2;

        if (dte2 != null)
        {
            WriteObject(dte2.Solution.FullName);
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM