AppDomain.CurrentDomain.BaseDirectory изменяется на неправильный каталог
Я создал dll
с Cmdlet
команда (см. Get_DemoNames.cs). Из этого cmdlet
Я называю метод UpdateXml()
пока все работает. Но UpdateXml()
также создает файлы, если они не существуют. Когда я звоню UpdateXml()
в файле класса, как это:
var parser = new Parser();
parser.UpdateXml();
И я запускаю проект, он идет в правильные каталоги.
Но если я загружаю импорт dll и запускаю команду DemoNames
в отдельном тестовом проекте, как это:
PM> Import-Module C:\projects\EF.XML\EF.XML.dll
PM> DemoNames
Программа переходит в неправильный каталог, что приводит к следующей ошибке:
Get-DemoNames: доступ к пути "C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\beheer_extern\config" запрещен. В строке:1 символ:10 + DemoNames <<<< + CategoryInfo: Не указано: (:) [Get-DemoNames], UnauthorizedAccessException + FullyQualifiedErrorId: System.UnauthorizedAccessException,EF.XML.Get_DemoNames
Я искал в сети эту ошибку и обнаружил, что некоторые другие смогли решить ее, добавив эту строку в конструктор:
public Parser()
{
AppDomain.CurrentDomain.SetData("APPBASE", Environment.CurrentDirectory);
}
Это дает мне другой неправильный путь:
Get-DemoNames: доступ к пути "C:\Windows\system32\beheer_extern\config" запрещен. В строке:1 символ:10 + DemoNames <<<< + CategoryInfo: Не указано: (:) [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);
}
}
}
}
Как я могу получить правильный каталог проекта (www каталог)?
2 ответа
Итак, вы пытаетесь получить доступ к проекту, загруженному в Visual Studio, из консоли диспетчера пакетов.
Знайте, что исполняемый файл Visual Studio, и так AppDomain.CurrentDomain.BaseDirectory
будет каталог установки Visual Studio. Это абсолютно не будет каталогом текущего проекта.
Чтобы получить каталог проекта для загруженного в данный момент решения, вам нужно взаимодействовать с работающим экземпляром Visual Studio с помощью автоматизации. Обычно это делается путем написания расширения или посредством автоматизации ядра Visual Studio, также называемой com-объектом EnvDTE. Это сложно. Хочешь сделать это? Возможно, вам придется взять книгу на эту тему и прочитать.
К счастью, PMC действительно предоставляет командлет, который значительно упростит это для вас - get-project. Он возвращает представление проекта в DTE, которое затем можно использовать для получения полного имени файла файла проекта, из которого можно получить имя каталога.
Это те части и детали, которые вам нужны. Что касается вызова командлета из вашего кода, это другой вопрос.
FIX
Мне удалось заставить его работать со следующим кодом
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);
}
}
}
}
Я тоже пробовал EnvDTE
который также работает.
Требуемый импорт:
using EnvDTE;
using EnvDTE80;
using Microsoft.VisualStudio.Shell;
Код для получения текущего решения (путь):
DTE2 dte2 = Package.GetGlobalService(typeof(DTE)) as DTE2;
if (dte2 != null)
{
WriteObject(dte2.Solution.FullName);
}