I have an SSIS project that I can run as is, but when I try to edit it, I get an error:
The name 'zipfile' does not exist in the current context
Without editing, it works fine.
The code that's producing the error:
public void Main()
{
// TODO: Add your code here
string moduleName = Dts.Variables["User::ModuleName"].Value.ToString();
string s = Dts.Variables["User::ZipFileLocation"].Value.ToString().TrimEnd('\\') + "\\" + moduleName + "\\" + moduleName + "_" + DateTime.Now.ToString("ddMMyyyy");
// TODO: Add your code here
string startPath = s;
string zipPath = s + ".zip";
try
{
File.Delete(zipPath);
ZipFile.CreateFromDirectory(startPath, zipPath);
}
catch (Exception e)
{
}
Dts.TaskResult = (int)ScriptResults.Success;
}
How can I solve this?
Make sure you are using .NET version 4.5. Reference the Compression DLL - here is the path:
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.IO.Compression.FileSystem.dll
Reference it in the class by adding using System.IO.Compression.FileSystem. If the class is inherited from another class, make sure to reference it in the parent class too. (This is what I have to do to make it compile)
To use the ZipFile class, you must add a reference to the System.IO.Compression.FileSystem assembly in your project; otherwise, you'll get the following error message when trying to compile:
The name 'ZipFile' does not exist in the current context.
For more information on how to add a reference to your project in Visual Studio, see How to: Add or remove references by using the Reference Manager.
I found that the ZipFile class would not cooperate only using System.IO.Compression, it asked to see a Reference to System.IO.Compression.FileSystem.
If you're using Visual Basic, adding a reference is fairly easy. In the solution explorer, one of the tabs under the project is called References. Right click there and select Add Reference. Scroll down a bit an check the checkbox next to System.IO.Compression.FileSystem. Once you click OK, you shouldn't even need to explicitly reference System.IO.Compression.FileSystem in your code!
Good luck (:
Just for Update: -
With .Net 4.6.1 version
Adding reference to System.IO.Compression.FileSystem and using System.IO.Compression is enough.
using System.IO.Compression.FileSystem is giving below error.
Related
I have a project A in which I am writing code to be compiled internally using C# Script objects.
I have created another project in a different solution (external project), project B. I have already added a reference to the ProjectB.DLL inside Project A in the "references" list. What I want is to add Project B's reference on the internal Script code that I want to compile. To better explain, my code is as follows:
My "using statements" are:
APPROVED_USING_STATEMENTS = new HashSet<string>();
APPROVED_USING_STATEMENTS.Add("System.Text");
APPROVED_USING_STATEMENTS.Add("System.Data");
APPROVED_USING_STATEMENTS.Add("System.Text.RegularExpressions");
APPROVED_USING_STATEMENTS.Add("System");
APPROVED_USING_STATEMENTS.Add("System.Linq");
APPROVED_USING_STATEMENTS.Add("System.Collections");
APPROVED_USING_STATEMENTS.Add("System.Security.Cryptography");
APPROVED_USING_STATEMENTS.Add("Project.ProjectB");
The compiler code is as follows:
foreach (var apprvUsingStatements in DataTransformationScript.GetApprovedUsingStatements())
{
usingStatements.Append("using " + apprvUsingStatements + "; \n");
}
string transformCode = usingStatements.ToString();
transformCode += "object returnObject = currentData;";
transformCode += schemaMap.transform_script;
transformCode += ";returnObject";
ScriptOptions references = ScriptOptions.Default.AddReferences(DataTransformationScript.GetApprovedUsingStatements());
//Adding my own personal references from Connector
var asm = typeof(Project.ProjectB.TestTransformation).Assembly;
references.AddReferences(asm);
//HTMLEncodeLogMessage.Info(Logger, "Assmebly added: " + asm.FullName + " Location " + asm.Location + " Given Name " + asm.GetName().Name);
//===============================================//
var transformScript = CSharpScript.Create(transformCode, references, globalsType: typeof(DataTransformationScript.Globals));
transformScript.Compile();
As you can see, I add the reference to Project B using the following code extract:
var asm = typeof(Project.ProjectB.TestTransformation).Assembly;
references.AddReferences(asm);
And I already have the using statement above for project as "using Project.ProjectB". (TestTransformation is just a method inside ProjectB. It seems I had to use the method name as well to get the reference dll.
I am still getting an error: The type or namespace name 'Project' could not be found (are you missing a using directive or an assembly reference?).
Am I missing any other kind of reference that I need to add? I noticed I am not getting this error for all the "System" references that I have. Is it possible that C# Script objects only get data from the folders inside C:\Windows\assembly?
I have looked at the following stackoverflow question and it DID NOT solve my problem:
Link
I would really appreciate any kind of guidance and assistance. I am still learning.
Try using costura fody/ fody library
I can't use "Zipfile" class in the name space "System.IO.Compression" my code is :
using System;
using System.IO;
using System.IO.Compression;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
string startPath = #"c:\example\start";
string zipPath = #"c:\example\result.zip";
string extractPath = #"c:\example\extract";
ZipFile.CreateFromDirectory(startPath, zipPath, CompressionLevel.Fastest,true);
ZipFile.ExtractToDirectory(zipPath, extractPath);
}
}
}
the error is :
The name 'zipfile' does not exist in the current context
How I can solve it ?
You need an extra reference for this; the most convenient way to do this is via the NuGet package System.IO.Compression.ZipFile
<!-- Version here correct at time of writing, but please check for latest -->
<PackageReference Include="System.IO.Compression.ZipFile" Version="4.3.0" />
If you are working on .NET Framework without NuGet, you need to add a dll reference to the assembly, "System.IO.Compression.FileSystem.dll" - and ensure you are using at least .NET 4.5 (since it doesn't exist in earlier frameworks).
For info, you can find the assembly and .NET version(s) from MSDN
For those who are green programmers in .NET, to add the DLL reference as MarcGravell noted, you follow these steps:
To add a reference in Visual C#
In Solution Explorer, right-click the project node and click Add Reference.
In the Add Reference dialog box, select the tab indicating the type of component you want to reference.
Select the components you want to reference, and then click OK.
From the MSDN Article, How to: Add or Remove References By Using the Add Reference Dialog Box.
you can use an external package if you cant upgrade to 4.5. One such is Ionic.Zip.dll from DotNetZipLib.
using Ionic.Zip;
you can download it here, its free. http://dotnetzip.codeplex.com/
Just go to References and add "System.IO.Compression.FileSystem".
In solution explorer, right-click References, then click to expand assemblies, find System.IO.Compression.FileSystem and make sure it's checked. Then you can use it in your class - using System.IO.Compression;
Add Reference Assembly Screenshot
A solution that helped me:
Go to Tools > NuGet Package Manager > Manage NuGet Packaged for Solution... > Browse >
Search for System.IO.Compression.ZipFile and install it
System.IO.Compression is now available as a nuget package maintained by Microsoft.
To use ZipFile you need to download System.IO.Compression.ZipFile nuget package.
I know this is an old thread, but I just cannot steer away from posting some useful info on this. I see the Zip question come up a lot and this answers nearlly most of the common questions.
To get around framework issues of using 4.5+... Their is a ZipStorer class created by jaime-olivares: https://github.com/jaime-olivares/zipstorer, he also has added an example of how to use this class as well and has also added an example of how to search for a specific filename as well.
And for reference on how to use this and iterate through for a certain file extension as example you could do this:
#region
/// <summary>
/// Custom Method - Check if 'string' has '.png' or '.PNG' extension.
/// </summary>
static bool HasPNGExtension(string filename)
{
return Path.GetExtension(filename).Equals(".png", StringComparison.InvariantCultureIgnoreCase)
|| Path.GetExtension(filename).Equals(".PNG", StringComparison.InvariantCultureIgnoreCase);
}
#endregion
private void button1_Click(object sender, EventArgs e)
{
//NOTE: I recommend you add path checking first here, added the below as example ONLY.
string ZIPfileLocationHere = #"C:\Users\Name\Desktop\test.zip";
string EXTRACTIONLocationHere = #"C:\Users\Name\Desktop";
//Opens existing zip file.
ZipStorer zip = ZipStorer.Open(ZIPfileLocationHere, FileAccess.Read);
//Read all directory contents.
List<ZipStorer.ZipFileEntry> dir = zip.ReadCentralDir();
foreach (ZipStorer.ZipFileEntry entry in dir)
{
try
{
//If the files in the zip are "*.png or *.PNG" extract them.
string path = Path.Combine(EXTRACTIONLocationHere, (entry.FilenameInZip));
if (HasPNGExtension(path))
{
//Extract the file.
zip.ExtractFile(entry, path);
}
}
catch (InvalidDataException)
{
MessageBox.Show("Error: The ZIP file is invalid or corrupted");
continue;
}
catch
{
MessageBox.Show("Error: An unknown error ocurred while processing the ZIP file.");
continue;
}
}
zip.Close();
}
Add System.IO.Compression.ZipFile as nuget reference it is working
The issue here is that you just Added the reference to System.IO.Compression it is missing the reference to System.IO.Compression.Filesystem.dll
And you need to do it on .net 4.5 or later (because it doesn't exist on older versions).
I just posted a script on TechNet Maybe somebody would find it useful it requires .net 4.5 or 4.7
https://gallery.technet.microsoft.com/scriptcenter/Create-a-Zip-file-from-a-b23a7530
okay, here is the question. I have two projects one is C# Console and other is Class library.
I am accessing/calling Class library method from the console app.
There is a folder called Files within the class library project.
I need to get the path of the Class library's files folder but whenever I use
System.IO.Directory.GetCurrentDirectory();
and
Environment.CurrentDirectory;
it is giving me path of the Console project which I am using to call the method.
Above methods are giving me path like
C:\\ConsolePro\\bin\\Debug
but I need the path of Class library project
C:\\ClassLibPro\\bin\\Debug
Please advise
Once the code is compiled and running, 'Project Path' has no meaning. All you can determine are the file locations of the compiled assemblies. And you can only do what you are asking if your Console project references the built 'class library' DLL directly, rather than via a Project Reference.
Then, you can make use of Reflection to get Assembly paths like;
string path = Assembly.GetAssembly(typeof (SomeClassInOtherProject)).Location;
You should be able to use Directory.GetParent(Directory.GetCurrentDirectory()) a few times to get higher level directories and then add the path of the lib directory to the end of that.
I believe the problem is:
Since the Console project has the DLL file reference it is using DLL to call any methods.
At this time it is returning the class library projct's DLL location which is located in console project's bin directory and it doesn't know about the physical location of class library project.
so essentially it is returning the same project path. I will have to move both projects in same directory in order to solve this issue.
If you loading the class library from another assembly.
string Path = System.Reflection.Assembly.GetAssembly(typeof({LibraryClassName})).Location;
string PathToClassLibPro = Path.GetDirectoryName( Path);
Replace {LibraryClassName} with the class name of your library.
I hope I understand u corretly:
Path.GetDirectoryName(typeof(Foo.MyFooClass).Assembly.Location);
I would recommend one of two options.
If the files are small include them in the class library and stream them to a temp location when needed
Other option is to copy the files during the build to the output directory and use them that way. In cases of multiple shared projects it is best to have a common bin folder that you copy assemblies to and run from that location.
Despite i cant find a good solution i use this trick :
as long as you want to come back to your ideal path u should add Directory.GetParent() instead of ...
Directory.GetParent(...(Directory.GetParent(Directory.GetCurrentDirectory()).ToString()...).ToString()
I use the following approach to get the current project path at runtime:
public static class ProjectInfo {
public static string appDirectory = AppDomain.CurrentDomain.BaseDirectory;
public static string projectPath = appDirectory.Substring(0, appDirectory.IndexOf("\\bin"));
}
I had this exact issue as well where I couldn't access the file in my namespace's bin/debug folder. My solution was to manipulate the string using Split() then construct a new string which is the absolute path to the json file I have in my namespace.
private static string GetFilePath()
{
const char Escape = '\\'; //can't have '\' by itself, it'll throw the "Newline in constant" error
string directory = Environment.CurrentDirectory;
string[] pathOccurences = directory.Split(Escape);
string pathToReturn = pathOccurences[0] + Escape; //prevents index out of bounds in upcoming loop
for(int i = 1; i < pathOccurences.Length; i++)
{
if (pathOccurences[i] != pathOccurences[i - 1]) //the project file name and the namespace file name are the same
pathToReturn += pathOccurences[i] + Escape;
else
pathToReturn += typeof(thisClass).Namespace + Escape; //In the one occurrence of the duplicate substring, I replace it with my class Namespace name
}
return pathToReturn + "yourFile.json";
}
I personally don't like this solution, but it was the only answer I could think of.
To add a new .NET reference to your project in Visual Studio you just click "Add reference..." on References of the current project, switch to the ".NET" tab and go for it.
Now, is there a way to get this list programmatically?
//You need to access GAC
List<string> gacFolders = new List<string>() {
"GAC", "GAC_32", "GAC_64", "GAC_MSIL",
"NativeImages_v2.0.50727_32",
"NativeImages_v2.0.50727_64"
};
foreach (string folder in gacFolders)
{
string path = Path.Combine(#"c:\windows\assembly", folder);
if(Directory.Exists(path))
{
Response.Write("<hr/>" + folder + "<hr/>");
string[] assemblyFolders = Directory.GetDirectories(path);
foreach (string assemblyFolder in assemblyFolders)
{
Response.Write(assemblyFolder + "<br/>");
}
}
}
Source: enumerating assemblies in GAC
Either access the global assembly cache with the gacutil or use a wrapper like introduced on this msdn page.
I would go for fixed path, cause it can be subject of change, but insted for or use
GacUtil
example, from command line can use
gacutil /l > assemblylist.txt
and assemblylist.txt will have a list of all assemblies in GAC with all information you need.
or can try to use
GAC Api (not documented one) You will need to do some interop on this, it's not C#.
Can try to use this C# warpper for it
GAC API Interface
My task: Find all Forms (WindowsForm or WPF, doesn't matter) in a dll or exe file and return that list. In theory that works (meaning: if I've an assembly with a WPF or WindowsForm my code manages to get all Forms, TextBoxes, Labels etc. ). When it comes to "real" assemblies it fails. I get FileNotFound exceptions when calling GetExportedTypes() for every "custom" assembly (.NET assemblies are found, no problems there). I already use GetReferencedAssemblies() to load the referenced assemblies (Reflection.Assembly.LoadFrom) and yes it does work (all assemblies are found and loaded into the AppDomain) but it doesn't help.
I checked the version numbers (they match), I copied my executable and the assembly into one directory with all referenced assemblies, doesn't work.
Here is my code, maybe someone figures out what I'm (obviously) doing wrong:
foreach (AssemblyName reference in selectedAssembly.GetReferencedAssemblies())
{
if (System.IO.File.Exists(
System.IO.Path.GetDirectoryName(selectedAssembly.Location) +
#"\" + reference.Name + ".dll"))
{
System.Reflection.Assembly.LoadFrom(
System.IO.Path.GetDirectoryName(selectedAssembly.Location) +
#"\" + reference.Name + ".dll");
}
else if (System.IO.File.Exists(#"C:\dll\" + reference.Name + ".dll"))
{
System.Reflection.Assembly.LoadFrom(#"C:\dll\" + reference.Name + ".dll");
}
else
{
System.Reflection.Assembly.ReflectionOnlyLoad(reference.FullName);
}
selectedAssembly.GetExportedTypes();
}
at first check if the referenced dll exists in the directory where the assembly is, if not check if it exists in C:\dll and if it's not there try and use the GAC. it does work and I've no errors from there but as soon as I come to GetExportedTypes it fails with a FileNotFound exception on the first custom library.
*edit 1 what do I mean by "real assemblies": I mean assemblies which are more complex and have references to non-standard-.NET libraries/assemblies
Thanks for the hint to fuslogvw.exe Hans Passant but what do you mean by "with code like this"?
okay I used fuslogvw.exe and I get two exceptions for every single dll that is referenced by the "selectedAssembly".
The first one says something like
"The binding starts in LoadFrom-context
The image owned by the system isn't searched in LoadFrom-Context"
the other logentry says that the dll referenced by the selectedAssembly couldn't be found and it tried to download it from application's base path and all directories below...but not from it's actual location...so, key question: how do I change the Load-context to LoadFrom? And why is .NET so stubborn on this? I mean the assemblies are loaded in the AppDomain, it shouldn't care about the actual location of the assembly.
okay problem solved. Here is the solution:
http://ayende.com/blog/1376/solving-the-assembly-load-context-problem
I implemented that into my existing class (removed the static-keyword and put the body of the Init method into my method), compiled it and it worked.
Thanks for your help guys.
okay problem solved. Here is the solution: http://ayende.com/blog/1376/solving-the-assembly-load-context-problem
I implemented that into my existing class (removed the static-keyword and put the body of the Init method into my method), compiled it and it worked.
Thanks for your help guys.
just in case the website will someday be unavailable, here is the sourcecode from ayende
static Dictionary<string, Assembly>assemblies;
public static void Init()
{
assemblies = new Dictionary<string, Assembly>();
AppDomain.CurrentDomain.AssemblyLoad += new AssemblyLoadEventHandler(CurrentDomain_AssemblyLoad);
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
Assembly assembly = null;
assemblies.TryGetValue(args.Name, out assembly);
return assembly;
}
static void CurrentDomain_AssemblyLoad(object sender, AssemblyLoadEventArgs args)
{
Assembly assembly = args.LoadedAssembly;
assemblies[assembly.FullName] = assembly;
}
I would recommend using Reflector to see which references you may not have loaded. For instance, you are only loading the referenced assemblies that the current assembly is looking at. Do you step down through each child to find their referenced assemblies as well? The FileNotFound error is probably pointing you in the direction of a type that is declared in another assembly that isn't loaded.