VSX: Save ProjectItem in folder - c#

I have an visual studio 2015 extension which reads files from a DB and creates a solution and project from a template. The files are then added as ProjectItems to the project (type VSProject2).
I would like to save the files in a folder, together with the csproj and sln file so that one can open it later without the extension.
However, the folder which contains the files in the solution window, is empty on disk.
So I'm confused. I've tried to save the projectItems, but it still doesn't end up in die folder on disk.
I add the folder with variable name "foldername" to the project. Let's make it TimeAndAttendance. So on disk a folder TempProject is created and in that, a folder TimeAndAttendance. I would like the csproj file and the source files (added as ProjectItems) to be saved in that folder.
public void CreateSolution()
{
// This function creates a solution and adds a Visual C# Class library project to it.
try
{
Solution2 soln = (Solution2)visualStudioInstance.Solution;
String csTemplatePath;
Project projCS = null;
parameterWindowEventsList = new Dictionary<EnvDTE.Window, WindowEvents>();
String csPrjPath = Path.Combine(Config.Cluster.WorkingPath, "TempProject");
if (Directory.Exists(csPrjPath))
{
DirectoryInfo di = new DirectoryInfo(csPrjPath);
foreach (var dir in di.GetDirectories())
{
dir.Attributes = FileAttributes.Normal;
FileInfo fi = new FileInfo(dir.FullName);
fi.IsReadOnly = false;
dir.Delete(true);
}
di.Attributes = FileAttributes.Normal;
di.Delete(true);
}
csTemplatePath = soln.GetProjectTemplate("TAEngineTemplate.zip", "CSharp");
// Create a new C# Class Library project using the template obtained above.
soln.AddFromTemplate(csTemplatePath, csPrjPath, "TAEngineProject", false);
foreach (Project p in soln.Projects)
{
if (String.Compare(p.Name, "TAEngineProject") == 0)
{
projCS = p;
break;
}
}
System.Windows.Forms.Application.DoEvents();
if (projCS != null)
{
taEngineProject = projCS.Object as VSProject2;
}
taEngineProject.References.Add(Path.Combine(Config.Engine.EngineBinPath, "Engines.TimeAndAttendance.dll"));
taEngineProject.References.Add("System.Data.DLL");
taEngineProject.References.Add("System.Xml.DLL");
taEngineProject.References.Add("System.Core.dll");
taEngineProject.Project.ProjectItems.AddFolder(folderName);
taEngineProject.Project.Save(null);
}
catch (SystemException ex)
{
log.Error("Problem with creating solution. " + ex);
}
}
The last line
taEngineProject.Project.Save(null);
doesn't seem to do anything.
The following is where I load a source file as a ProjectItem. Any improvement on how to do it without the try-catch functionality is also welcome. I inherited this code and just shook my head the first time I saw it, but I don't know how to improve it either. :-(
public ProjectItem LoadAsProjectItem(string sourcePath)
{
if (taEngineProject != null)
{
string filename = sourcePath.Substring(sourcePath.LastIndexOf("\\") + 1);
ProjectItem retItem;
ProjectItem projFolderItem = taEngineProject.Project.ProjectItems.Item(folderName);
try
{
retItem = projFolderItem.ProjectItems.Item(filename);
}
catch (Exception)
{
retItem = projFolderItem.ProjectItems.AddFromFile(sourcePath);
}
return retItem;
}
return null;
}

Related

How to copy dll file dependency to Temp compilation folder for Azure Function App?

I am working with an azure function app that uses a third-party DLL, that has a dependency on an XML mapping file being present in a folder relative to the current execution. When I publish and run my function on my Azure stack, I run into an exception that the dll cannot load the XML file. I have the XML present in my bin directory with the dll, but Azure appears to be moving the compiled dlls to a temporary folder without the required XML, and proceeds to be looking for the XML relative to that temporary path based on the following exception message:
"Could not find a part of the path 'D:\\local\\Temporary ASP.NET Files\\root\\da2a6178\\25f43073\\assembly\\dl3\\28a13679\\d3614284_4078d301\\Resources\\RepresentationSystem.xml'."
Is there any way I can make sure these additional files are also copied to the temporary folder that Azure is running? Alternatively, can I just force it to run from bin rather than temp?
Update: Unfortunately I am not permitted to share any info on the dll. What I can say is that everything is published to my wwwroot folder, however when outputing some debug info, I can see that the execution is happening from the "Temporary ASP.NET Files" folder. Each dll is copied to its own seperate folder. D:\local\Temporary ASP.NET Files\root\da2a6178\25f43073\assembly\dl3\28a13679\d3614284_4078d301\ThirdParty.dll is that path were the dll in question is, and it lines up with where it expects the xml to be.
While this isn't a true answer to the issue, a workaround for this problem was to have a function in code before the dll functions run, that searches for the dll in question in the Temp ASP.Net folder, and then copies the xml files from a known location to that directory.
// Work Around Begin Here
string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
// Check if we are in temp dir
if (assemblyFolder.Contains("Temporary ASP.NET Files"))
{
DirectoryInfo dir = new DirectoryInfo(assemblyFolder);
// Go up 2 dirs
DirectoryInfo top = dir.Parent.Parent;
DirectoryInfo[] dirs = top.GetDirectories();
foreach (DirectoryInfo child in dirs)
{
DirectoryInfo[] dirs2 = child.GetDirectories();
foreach (DirectoryInfo child2 in dirs2)
{
// Find out if this is the Rep
if (File.Exists(child2.FullName + "\\ThirdParty.Representation.dll"))
{
// Look to see if resource folder is there
if (!Directory.Exists(child2.FullName + "\\Resources"))
{
child2.CreateSubdirectory("Resources");
}
DirectoryInfo resDir = new DirectoryInfo(child2.FullName + "\\Resources");
if (File.Exists(resourceDir + "RepresentationSystem.xml"))
{
if(!File.Exists(resDir.FullName + "\\RepresentationSystem.xml"))
{
File.Copy(resourceDir + "RepresentationSystem.xml", resDir.FullName + "\\RepresentationSystem.xml");
}
}
if (File.Exists(resourceDir + "UnitSystem.xml"))
{
if (!File.Exists(resDir.FullName + "\\UnitSystem.xml"))
{
File.Copy(resourceDir + "UnitSystem.xml", resDir.FullName + "\\UnitSystem.xml");
}
}
}
}
}
}
Thank you DoubleHolo for this workaround. It run fine.
I have changed the code adding only Path.Combine to simplify the code.
private void CopyResourcesToTemporaryFolder()
{
// Work Around Begin Here
string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string resourceDir = Path.Combine(FileUtils.WebProjectFolder, "Resources");
// Check if we are in temp dir
if (assemblyFolder.Contains("Temporary ASP.NET Files"))
{
DirectoryInfo dir = new DirectoryInfo(assemblyFolder);
// Go up 2 dirs
DirectoryInfo top = dir.Parent.Parent;
DirectoryInfo[] dirs = top.GetDirectories();
foreach (DirectoryInfo child in dirs)
{
DirectoryInfo[] dirs2 = child.GetDirectories();
foreach (DirectoryInfo child2 in dirs2)
{
// Find out if this is the Rep
if (File.Exists(Path.Combine(child2.FullName, "AgGateway.ADAPT.Representation.DLL")))
{
// Look to see if resource folder is there
if (!Directory.Exists(Path.Combine(child2.FullName, "Resources")))
{
child2.CreateSubdirectory("Resources");
}
DirectoryInfo resDir = new DirectoryInfo(Path.Combine(child2.FullName, "Resources"));
if (File.Exists(Path.Combine(resourceDir, "RepresentationSystem.xml")))
{
if (!File.Exists(Path.Combine(resDir.FullName, "RepresentationSystem.xml")))
{
File.Copy(Path.Combine(resourceDir, "RepresentationSystem.xml"), Path.Combine(resDir.FullName, "RepresentationSystem.xml"));
}
}
if (File.Exists(Path.Combine(resourceDir, "UnitSystem.xml")))
{
if (!File.Exists(Path.Combine(resDir.FullName, "UnitSystem.xml")))
{
File.Copy(Path.Combine(resourceDir, "UnitSystem.xml"), Path.Combine(resDir.FullName, "UnitSystem.xml"));
}
}
}
}
}
}
}

Why with Script task in SSIS i can't unzip exactly the path like winzip or 7zip?

I'm using Script task with Microsoft Visual C# 2012 in SSIS.
I want to unzip 20160423.zip which have inside a test folder and inside of the test folder have insert, delete and update folders and in each folder have .dat files:
20160423.zip:
I want to unzip like this:
This is the hierarchy
20160423
test
insert
abc.dat
def.dat
delete
abc.dat
def.dat
update
abc.dat
def.dat
The Script Task looks like
public void Main()
{
string zipfullpath = Dts.Variables["User::ZipFullPath"].Value.ToString();
string inputfolder = Dts.Variables["$Project::InputFolder"].Value.ToString();
using (ZipArchive arch = ZipFile.OpenRead(zipfullpath))
{
foreach (ZipArchiveEntry entry in arch.Entries)
{
entry.ExtractToFile(Path.Combine(inputfolder, entry.FullName),true);
//ZipFile.ExtractToDirectory(zipfullpath, inputfolder);
}
}
//File.Delete(zipfullpath);
// TODO: Add your code here
Dts.TaskResult = (int)ScriptResults.Success;
}
UPDATE:
I did some changes in the code and now i can create the main/root folder i.e. 20160423 but I can't create the subdirectories (Insert, Delete, Update) to extract the .dat files in each folders. When i tried to run the code the debug prompt an error that the path don't exist because the folder insert, update and delete.
public void Main()
{
// TODO: Add your code here
string zipfullpath = Dts.Variables["User::ZipFullPath"].Value.ToString();
string inputfolder = Dts.Variables["$Project::InputFolder"].Value.ToString();
string rootfolder = Path.GetFileNameWithoutExtension(zipfullpath);
using (ZipArchive arch = ZipFile.OpenRead(zipfullpath))
{
//var root = arch.Entries[0].FullName;
//var result = from curr in arch.Entries
// where Path.GetDirectoryName(curr.FullName) != root
// where !string.IsNullOrEmpty(curr.Name)
// select curr;
foreach (ZipArchiveEntry entry in arch.Entries)
{
//entry.ExtractToFile(Path.Combine(inputfolder, entry.FullName),true);
//ZipFile.ExtractToDirectory(zipfullpath, inputfolder);
//Gets the complete path for the destination file, including any
//relative paths that were in the zip file
string destinationFileName = Path.Combine(inputfolder,rootfolder, entry.FullName);
//Gets just the new path, minus the file name so we can create the
//directory if it does not exist
string destinationFilePath = Path.GetDirectoryName(destinationFileName);
//var newName = entry.FullName.Substring(root.Length);
//Creates the directory (if it doesn't exist) for the new path
Directory.CreateDirectory(destinationFileName);
//if (!File.Exists(destinationFileName) || File.GetLastWriteTime(destinationFileName) < entry.LastWriteTime)
//{
//Either the file didn't exist or this file is newer, so
//we will extract it and overwrite any existing file
entry.ExtractToFile(destinationFileName, true);
//}
}
}
//File.Delete(zipfullpath);
Dts.TaskResult = (int)ScriptResults.Success;
}
Why not just use 7zip. Have a look at http://sqlserversolutions.blogspot.de/2008/10/zip-and-unzip-files-in-folder.html
regards

How to cast ComObject to ENVDTE.Project for Unmodeled projects?

My question is very similar to this one: How to cast ComObject to ENVDTE.Project?
I want to process the Project items selected in Visual Studio -> Solution Explorer. If project is loaded the code works fine but I have troubles for unloaded projects (they are called Unmodeled projects (http://msdn.microsoft.com/en-us/library/hw7ek4f4%28v=vs.80%29.aspx).
Casting selected item for loaded projects uiItem.Object is EnvDTE.Project is fine, but how to cast Unmodeled projects?
There is no 'UnmodeledProject' class and casting uiItem.Object is ProjectItem does not work.
This is my code:
Window solutionExplorer = mApplicationObject.Windows.Item(Constants.vsWindowKindSolutionExplorer);
if(solutionExplorer != null)
{
UIHierarchy uiHierarchy = (UIHierarchy)solutionExplorer.Object;
if (uiHierarchy != null)
{
object[] selectedItems = (object[])uiHierarchy.SelectedItems;
foreach (UIHierarchyItem uiItem in selectedItems)
{
// Valid project
if (uiItem.Object is EnvDTE.Project)
{
EnvDTE.Project project = uiItem.Object as EnvDTE.Project;
if (project.FullName.Contains(".vdproj") || project.Kind == "{54435603-DBB4-11D2-8724-00A0C9A8B90C}")
{
}
}
else if (uiItem.Object is ProjectItem)
{
// This is never jumped...
}
else
{ ...
As I did not find a solution for this situation I used this trick:
string pathToVdProject = null;
try
{
Window solutionExplorer = mApplicationObject.Windows.Item(Constants.vsWindowKindSolutionExplorer);
if (solutionExplorer != null)
{
UIHierarchy uiHierarchy = (UIHierarchy)solutionExplorer.Object;
if (uiHierarchy != null)
{
object[] selectedItems = (object[])uiHierarchy.SelectedItems;
foreach (UIHierarchyItem uiItem in selectedItems)
{
// Valid project
if (uiItem.Object is EnvDTE.Project)
{
EnvDTE.Project project = uiItem.Object as EnvDTE.Project;
if (project.FullName.Contains(".vdproj") || project.UniqueName.Contains(".vdproj")
|| (String.Compare(project.Kind, ProjectsGuids.guidVdSetupProject, true) == 0))
{
// Valid Project has property FullName which is full path to .vdproj file
pathToVdProject = project.FullName;
break;
}
}
else if (uiItem.Object is ProjectItem)
{
// This never happens...
}
else
{
// This is a little tricky: Unmodeled Projects cannot be casted to EnvDTE.Project http://msdn.microsoft.com/en-us/library/hw7ek4f4%28v=vs.80%29.aspx
Solution2 solution = (Solution2)mApplicationObject.Solution;
// So get all projects in solution (including unmodeled) and try to find a match by name
foreach (Project project in solution.Projects)
{
if (project.Kind == EnvDTE.Constants.vsProjectKindUnmodeled)
{
// Unmodeled project found (Normal projects are recognized in 'uiItem.Object is EnvDTE.Project'
if (project.Name.Contains(uiItem.Name))
{
// This is 'Project' for selected item
if (project.Name.Contains(".vdproj") || project.UniqueName.Contains(".vdproj"))
{
// Unmodeled projects does not offer property FullName and UniqueName does NOT contain full path to file!
FileInfo fileInfo = new FileInfo(solution.FullName);
// Create full path from solution (.sln) path and project relative path
pathToVdProject = fileInfo.DirectoryName + "\\" + project.UniqueName;
break;
}
}
}
}
}
}
}
}
List of all loaded/Unloaded projects inside the solution explorer will be available in your EnvDTE application object. Without using solution Explorer window and UIHierarchy i got the project details. Below code snippets working fine for me. Please check out weather it will fit for you..
For Each item As EnvDTE.Project In mApplicationObject.Solution.Projects
If item.Globals Is Nothing AndAlso item.Object Is Nothing Then
Console.WriteLine(item.Name + " is currently unloaded!")
End If
Next

How to create directory and subdirectory if it does not exist in sharepoint Document Library

I have a user input as D:\Test1\Test2\Test3\Test4\a\b\c\d\file.jpg as per the user input i need to check if folder and sub folder exist in a Document Library.
i.e
DocLib>>Test1>>Test2....d i want to replicate the folder structure in Document Library, if it exist than directly read and save the file else create directory and than subdirectory and upto the level wherin file should be saved.
Can anyone help me to understand how can i go with this? I tried with creating files in local system on hard drive
static void CopyFolder(string sourceFolder, string destFolder)
{
if (!Directory.Exists(sourceFolder))
Directory.CreateDirectory(destFolder);
string[] files = Directory.GetFiles(sourceFolder);
foreach (string file in files)
{
string name = Path.GetFileName(file);
string dest = Path.Combine(destFolder, name);
File.Copy(file, dest);
}
//check folder in the source destination
string[] folders = Directory.GetDirectories(sourceFolder);
foreach (string folder in folders)
{
string name = Path.GetFileName(folder);
string dest = Path.Combine(destFolder, name);
System.IO.Directory.CreateDirectory(dest);
CopyFolder(folder, dest);
}
}
No idea how to check if directory exist and than check for subdirectory in sharepoint. i.e add a file by retaining the folder structure specified. Kindly help
To do this you will need to createthe structure of the tree path one by one: here is a short code how it can be done on the root site with UserDocument folder as a root folder:
// This will contain all information about the path
DirectoryInfo infoDir = new DirectoryInfo(#"C:\Users\Administrator\Pictures2\WallPaperHD - 078.jpg");
// Root folder passed => Default in SharePoint
if (infoDir.Parent != null)
{
// All folders are stored here
List<string> folders = new List<string>();
// Set current folder to parent
DirectoryInfo currentDir = infoDir.Parent;
do
{
// Add its name to array
folders.Add(currentDir.Name);
// Set parent of current as current if available
if (currentDir.Parent != null)
currentDir = currentDir.Parent;
}
while (currentDir.Parent != null);
// Add SP structure)
using (SPSite site = new SPSite("http://testsite.dev"))
{
SPWeb web = site.RootWeb;
// Get doc library
SPList documentLibrary = web.GetList("/UserDocuments");
// If library root exists
if (documentLibrary != null)
{
string folderUrl = "/UserDocuments/";
for (int i = folders.Count - 1; i >= 0; i--)
{
string folder = folders[i];
SPFolder newFolder = site.RootWeb.GetFolder(folderUrl + folder);
if (!newFolder.Exists)
{
site.RootWeb.Folders.Add(folderUrl + folder);
// Save changes
site.RootWeb.Update();
folderUrl += folder + "/";
}
}
}
}
}
This will create the same structure of folders on the SharePoint side as it was specified in the path passed by user.
After this all you need is to save file in the specified folder.
Hope it helps,
Andrew

How do I create a file AND any folders, if the folders don't exist?

Imagine I wish to create (or overwrite) the following file :- C:\Temp\Bar\Foo\Test.txt
Using the File.Create(..) method, this can do it.
BUT, if I don't have either one of the following folders (from that example path, above)
Temp
Bar
Foo
then I get an DirectoryNotFoundException thrown.
So .. given a path, how can we recursively create all the folders necessary to create the file .. for that path? If Temp or Bar folders exists, but Foo doesn't... then that is created also.
For simplicity, lets assume there's no Security concerns -- all permissions are fine, etc.
To summarize what has been commented in other answers:
//path = #"C:\Temp\Bar\Foo\Test.txt";
Directory.CreateDirectory(Path.GetDirectoryName(path));
Directory.CreateDirectory will create the directories recursively and if the directory already exist it will return without an error.
If there happened to be a file Foo at C:\Temp\Bar\Foo an exception will be thrown.
DirectoryInfo di = Directory.CreateDirectory(path);
Console.WriteLine("The directory was created successfully at {0}.",
Directory.GetCreationTime(path));
See this MSDN page.
Use Directory.CreateDirectory before you create the file. It creates the folder recursively for you.
. given a path, how can we recursively create all the folders necessary to create the file .. for that path
Creates all directories and subdirectories as specified by path.
Directory.CreateDirectory(path);
then you may create a file.
You will need to check both parts of the path (directory and filename) and create each if it does not exist.
Use File.Exists and Directory.Exists to find out whether they exist. Directory.CreateDirectory will create the whole path for you, so you only ever need to call that once if the directory does not exist, then simply create the file.
You should use Directory.CreateDirectory.
http://msdn.microsoft.com/en-us/library/54a0at6s.aspx
Assuming that your assembly/exe has FileIO permission is itself, well is not right. Your application may not run with admin rights. Its important to consider Code Access Security and requesting permissions
Sample code:
FileIOPermission f2 = new FileIOPermission(FileIOPermissionAccess.Read, "C:\\test_r");
f2.AddPathList(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, "C:\\example\\out.txt");
try
{
f2.Demand();
}
catch (SecurityException s)
{
Console.WriteLine(s.Message);
}
Understanding .NET Code Access Security
Is “Code Access Security” of any real world use?
You want Directory.CreateDirectory()
Here is a class I use (converted to C#) that if you pass it a source directory and a destination it will copy all of the files and sub-folders of that directory to your destination:
using System.IO;
public class copyTemplateFiles
{
public static bool Copy(string Source, string destination)
{
try {
string[] Files = null;
if (destination[destination.Length - 1] != Path.DirectorySeparatorChar) {
destination += Path.DirectorySeparatorChar;
}
if (!Directory.Exists(destination)) {
Directory.CreateDirectory(destination);
}
Files = Directory.GetFileSystemEntries(Source);
foreach (string Element in Files) {
// Sub directories
if (Directory.Exists(Element)) {
copyDirectory(Element, destination + Path.GetFileName(Element));
} else {
// Files in directory
File.Copy(Element, destination + Path.GetFileName(Element), true);
}
}
} catch (Exception ex) {
return false;
}
return true;
}
private static void copyDirectory(string Source, string destination)
{
string[] Files = null;
if (destination[destination.Length - 1] != Path.DirectorySeparatorChar) {
destination += Path.DirectorySeparatorChar;
}
if (!Directory.Exists(destination)) {
Directory.CreateDirectory(destination);
}
Files = Directory.GetFileSystemEntries(Source);
foreach (string Element in Files) {
// Sub directories
if (Directory.Exists(Element)) {
copyDirectory(Element, destination + Path.GetFileName(Element));
} else {
// Files in directory
File.Copy(Element, destination + Path.GetFileName(Element), true);
}
}
}
}
Following code will create directories (if not exists) & then copy files.
// using System.IO;
// for ex. if you want to copy files from D:\A\ to D:\B\
foreach (var f in Directory.GetFiles(#"D:\A\", "*.*", SearchOption.AllDirectories))
{
var fi = new FileInfo(f);
var di = new DirectoryInfo(fi.DirectoryName);
// you can filter files here
if (fi.Name.Contains("FILTER")
{
if (!Directory.Exists(di.FullName.Replace("A", "B"))
{
Directory.CreateDirectory(di.FullName.Replace("A", "B"));
File.Copy(fi.FullName, fi.FullName.Replace("A", "B"));
}
}
}

Categories