ASP.NET Opening File in Zip Folder [duplicate] - c#

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

Related

Get default namespace from existing csproj (Microsoft.NET.Sdk format)

So, I am writing a code generator tool and I want to get the default namespace from an existing csproj that the user will have to specify. Essentially I want to be able to load the csproj from a path and get some configuration from it.
I also want to be able to get all existing projects from a solution, from which I would use the solution file from a path.
I've looked into code analyzers and believe that's the way to go, but I haven't found a single example of what I want to achieve so far.
I do not wish to give support to older format csproj, just the Microsoft.NET.Sdk format that came with VS2017.
So the solution as stated in the comments was to use an MSBuildWorkspace.
My code looks something like this:
using Microsoft.CodeAnalysis.MSBuild;
using Microsoft.CodeAnalysis;
public class ProjectLoader : IProjectLoader
{
public string GetVSProjectDefaultNamespace(string projectPath)
{
var workspace = MSBuildWorkspace.Create();
Project project;
try
{
project = workspace.OpenProjectAsync(projectPath).Result;
}
catch(Exception e)
{
throw new Exception("The requested project failed to load. Make sure the path to the project file is correct.", e);
}
var defaultNamespace = project.DefaultNamespace ?? project.Name;
return defaultNamespace;
}
}
It's important to install the following nuget packages:
Microsoft.CodeAnalysis
Microsoft.CodeAnalysis.Workspaces.MSBuild
For the previous snippet to work.
Hope this helps anybody else!

How to read the list of NuGet packages in packages.config programatically?

What's the best way to read (ideally via C#) the packages listed in packages.config files?
Within our source code repository I have a lot of solutions and projects and equally a lot of packages.config files. I'm trying to build a consolidated list of packages (and versions) in use across my source code repository.
I can see there is a NuGet.Core package available - how could I use this to achieve my goal?
Thanks
If you do not want to read the XML directly you can install the NuGet.Core NuGet package and then use the PackageReference class.
Here is some example code that uses this class to print out the package id and its version.
string fileName = #"c:\full\path\to\packages.config";
var file = new PackageReferenceFile(fileName);
foreach (PackageReference packageReference in file.GetPackageReferences())
{
Console.WriteLine("Id={0}, Version={1}", packageReference.Id, packageReference.Version);
}
You will need to find the packages.config files yourself which you can probably do with a directory search, something like:
foreach (string fileName in Directory.EnumerateFiles("d:\root\path", "packages.config", SearchOption.AllDirectories))
{
// Read the packages.config file...
}
An alternative and more up to date way of doing this is to install the NuGet.Packaging NuGet package and use code similar to:
var document = XDocument.Load (fileName);
var reader = new PackagesConfigReader (document);
foreach (PackageReference package in reader.GetPackages ())
{
Console.WriteLine (package.PackageIdentity);
}
As suggested you will need to install NuGet.Core, your solution may have several projects in it, so it's good to know how to specify the project name when installing. Let's say your Solution is MySolution and you have two projects Project01 & Project02 and you only want to install in Project02.
Install-Package NuGet.Core -ProjectName Project02
Next you will need to add a using statement in the whatever.cs page you are going to do your work to target the package and let's say you just want to get the version number so that you can print it out somewhere on your website. That is actually what I wanted to do.
using NuGet;
next I wanted to get at a specific package and read it's version number so that when we release my software I have a visual identifier at a certain place on my website that I can go to and see the version that is in production.
here is the code I wrote to populate a webforms label on my page.
protected void Page_Load(Object sender, EventArgs e)
{
var pkgRefpath = Server.MapPath("~/packages.config");
PackageReferenceFile nugetPkgConfig = new PackageReferenceFile(pkgRefpath);
IEnumerable<PackageReference> allPackages = nugetPkgConfig.GetPackageReferences();
var newtonsoftPkg = (
from pkg in allPackages
where pkg.Id == "Newtonsoft.Json"
select pkg
).FirstOrDefault();
if (newtonsoftPkg== null) return;
var newtonsoftPkg_Version = newtonsoftPkg.Version;
ltrNewtonsoftVer.Text = newtonsoftPkg_Version.ToString();
}
This is a slightly different answer to the question, but this shows the solution that I ended up with for my needs after finding this Question/Answer and modifying what I learned to suit my own needs. I hope it can help someone else out.

The name 'zipfile' does not exist in the current context

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.

How to enforce same nuget package version across multiple c# projects?

I have a bunch of small C# projects which use a couple of NuGet packages. I'd like to be able to update version of a given package automatically. More then that: I'd like to be warned if a project uses different version from the others.
How do I enforce same version dependency across multiple C# projects?
As I haven't found another way to enforce this, I've written a unit test which will fail if different package versions are being found in any packages.config in any subfolder.
As this might be useful for others, you'll find the code below. You'll have to adapt the resolution of the root folder done in GetBackendDirectoryPath().
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml;
using NUnit.Framework;
namespace Base.Test.Unit
{
[TestFixture]
public class NugetTest
{
private const string PACKAGES_CONFIG_FILE_NAME = "packages.config";
private const string BACKEND_DIRECTORY_NAME = "DeviceCloud/";
private const string PACKAGES_NODE_NAME = "packages";
private const string PACKAGE_ID_ATTRIBUTE_NAME = "id";
private const string PACKAGE_VERSION_ATTRIBUTE_NAME = "version";
/// <summary>
/// Tests that all referenced nuget packages have the same version by doing:
/// - Get all packages.config files contained in the backend
/// - Retrieve the id and version of all packages
/// - Fail this test if any referenced package has referenced to more than one version accross projects
/// - Output a message mentioning the different versions for each package
/// </summary>
[Test]
public void EnforceCoherentReferences()
{
// Act
IDictionary<string, ICollection<PackageVersionItem>> packageVersionsById = new Dictionary<string, ICollection<PackageVersionItem>>();
foreach (string packagesConfigFilePath in GetAllPackagesConfigFilePaths())
{
var doc = new XmlDocument();
doc.Load(packagesConfigFilePath);
XmlNode packagesNode = doc.SelectSingleNode(PACKAGES_NODE_NAME);
if (packagesNode != null && packagesNode.HasChildNodes)
{
foreach (var packageNode in packagesNode.ChildNodes.Cast<XmlNode>())
{
if (packageNode.Attributes == null)
{
continue;
}
string packageId = packageNode.Attributes[PACKAGE_ID_ATTRIBUTE_NAME].Value;
string packageVersion = packageNode.Attributes[PACKAGE_VERSION_ATTRIBUTE_NAME].Value;
if (!packageVersionsById.TryGetValue(packageId, out ICollection<PackageVersionItem> packageVersions))
{
packageVersions = new List<PackageVersionItem>();
packageVersionsById.Add(packageId, packageVersions);
}
//if (!packageVersions.Contains(packageVersion))
if(!packageVersions.Any(o=>o.Version.Equals(packageVersion)))
{
packageVersions.Add(new PackageVersionItem()
{
SourceFile = packagesConfigFilePath,
Version = packageVersion
});
}
if (packageVersions.Count > 1)
{
//breakpoint to examine package source
}
}
}
}
List<KeyValuePair<string, ICollection<PackageVersionItem>>> packagesWithIncoherentVersions = packageVersionsById.Where(kv => kv.Value.Count > 1).ToList();
// Assert
string errorMessage = string.Empty;
if (packagesWithIncoherentVersions.Any())
{
errorMessage = $"Some referenced packages have incoherent versions. Please fix them by adapting the nuget reference:{Environment.NewLine}";
foreach (var packagesWithIncoherentVersion in packagesWithIncoherentVersions)
{
string packageName = packagesWithIncoherentVersion.Key;
string packageVersions = string.Join("\n ", packagesWithIncoherentVersion.Value);
errorMessage += $"{packageName}:\n {packageVersions}\n\n";
}
}
Assert.IsTrue(packagesWithIncoherentVersions.Count == 0,errorMessage);
//Assert.IsEmpty(packagesWithIncoherentVersions, errorMessage);
}
private static IEnumerable<string> GetAllPackagesConfigFilePaths()
{
return Directory.GetFiles(GetBackendDirectoryPath(), PACKAGES_CONFIG_FILE_NAME, SearchOption.AllDirectories)
.Where(o=>!o.Contains(".nuget"));
}
private static string GetBackendDirectoryPath()
{
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
var uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
return Path.GetDirectoryName(path.Substring(0, path.IndexOf(BACKEND_DIRECTORY_NAME, StringComparison.Ordinal) + BACKEND_DIRECTORY_NAME.Length));
}
}
public class PackageVersionItem
{
public string SourceFile { get; set; }
public string Version { get; set; }
public override string ToString()
{
return $"{Version} in {SourceFile}";
}
}
}
I believe I have found a setup which solves this (and many other) problem(s).
I just realized one can use a folder as nuget source. Here is what I did:
root
+ localnuget
+ Newtonsoft.Json.6.0.1.nupkg
+ nuget.config
+ packages
+ Newtonsoft.Json.6.0.1
+ src
+ project1
nuget.config looks like this:
<configuration>
<config>
<add key="repositoryPath" value="packages" />
</config>
<packageSources>
<add key="local source" value="localnuget">
</packageSources>
</configuration>
You can add Nuget server to nuget.config to get access to updates or new dependencies during development time:
<add key="nuget.org" value="https://www.nuget.org/api/v2/" />
Once you're done, you can copy .nupkg from cache to localnuget folder to check it in.
There are 3 things I LOVE about this setup:
I'm now able to use Nuget features, such as adding props and targets. If you have a code generator (e.g. protobuf or thrift) this becomes pricesless.
It (partially) solves the problem of Visual Studio not copying all DLLs, because you need to specify dependencies in .nuspec file and nuget loads indirect dependencies automatically.
I used to have a single solution file for all projects so updating nuget packages was easier. I haven't tried yet but I think I solved that problem too. I can have nuget packages for the project I want to export from a given solution.
I don't know how to enforce it, but I've found the "Consolidate" tab to help.
This tab shows you packages that have different versions throughout the solution. From there you can select projects and use the install button to install the same package version across them. This tab can be found under "Manage NuGet for solution".
See Consolidate tab in Microsoft documentation.
Thank you for asking this - so I am not alone. I put considerable time into ensuring all projects in my solution use the same package version. The NuGet user interface (and also the command line interface) also contribues to having different versions among the projects within a solution. In particular when a new project is added to the solution and package X shall be added to the new project, NuGet is overly greedy to download the latest version from nuget.org instead of using the local version first, which would be the better default handling.
I completely agree with you, that NuGet should warn if different versions of a package are used within a solution. And it should help avoiding this and fixing such version maze.
The best I found to do now is to enumerate all packages.config files within the solution folder (your projects-root) which look like
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="6.0.6" targetFramework="net451" />
...
</packages>
then sorting the xml-nodes by id and analysing the version numbers.
If any package occurs with different version numbers, making them all equal and afterwards running the NuGet command
Update-Package -ProjectName 'acme.lab.project' -Reinstall
should fix wrong package versions.
(Since NuGet is open source it would certainly be a cool thing to get our hands dirty and implement the missing version-conflict avoidance utility.)
Additionally to the "Consolidate" tab in VS, you can use powershell Sync-Package
https://learn.microsoft.com/en-us/nuget/reference/ps-reference/ps-ref-sync-package.
Examples:
# Sync the Elmah package installed in the default project into the other projects in the solution
Sync-Package Elmah
# Sync the Elmah package installed in the ClassLibrary1 project into other projects in the solution
Sync-Package Elmah -ProjectName ClassLibrary1
# Sync Microsoft.Aspnet.package but not its dependencies into the other projects in the solution
Sync-Package Microsoft.Aspnet.Mvc -IgnoreDependencies
# Sync jQuery.Validation and install the highest version of jQuery (a dependency) from the package source
Sync-Package jQuery.Validation -DependencyVersion highest

c# Class Library Project - Load DLL from same folder?

I'm working on a plugin for a existing C# .NET Program. It's structured in a manner where you put your custom .dll file in Program Root/Plugins/your plugin name/your plugin name.dll
This is all working well, but now I'm trying to use NAudio in my project.
I've downloaded NAudio via Nuget, and that part works fine, but the problem is that it looks for the NAudio.dll in Program Root, and not in the folder of my plugin.
This makes it hard to distribute my plugin, because it would rely on users dropping the NAudio.dll in their Program Root in addition to putting the plugin into the "Plugins" folder.
Source:
SettingsView.xaml:
<Button HorizontalAlignment="Center"
Margin="0 5"
Width="120"
Command="{Binding SoundTestCommand,
Source={StaticResource SettingsViewModel}}"
Content="Sound Test" />
SettingsViewModel.cs:
using NAudio.Wave;
.
.
.
public void SoundTest()
{
IWavePlayer waveOutDevice;
WaveStream mainOutputStream;
WaveChannel32 inputStream;
waveOutDevice = new WaveOut();
mainOutputStream = new Mp3FileReader(#"E:\1.mp3");
inputStream = new WaveChannel32(mainOutputStream);
inputStream.Volume = 0.2F;
waveOutDevice.Init(mainOutputStream);
waveOutDevice.Play();
}
How can I get C# to look for NAudio in Program Root/Plugins/my plugin name/NAudio.dll instead of looking for it in Program Root/NAudio.dll ?
I'm using VS Express 2013, Target Framework is 4.5 and Output type is Class Library.
Edit:
I found 2 ways to make this work ( I'm not sure what the pros and cons of both methods are - if anyone knows I would appreciate additional information ).
Using the NuGet Package Costura.Fody.
After installing the NuGet package, I simply had to set all other References "Copy Local" to "False" and then set "Copy Local" for NAudio to "True".
Now when I build, the NAudio.dll is compressed and added to my own DLL.
Using the AssemblyResolver outlined below.
It didn't work right away though, so here is some additional information that may help anyone facing the same issue:
I put Corey's code as he posted it into the Helpers folder.
My entry point is Plugin.cs, the class is public class Plugin : IPlugin, INotifyPropertyChanged
In there, the entry method is public void Initialize(IPluginHost pluginHost), but simply putting PluginResolver.Init(path) did not work.
The host program uses WPF and is threaded and I had to use a dispatcher helper function of the host program to get it to work: DispatcherHelper.Invoke(() => Resolver.Init(path));
As mentioned, I'm currently unsure which method to use, but I'm glad I got it to work. Thanks Corey!
You can use the PATH environment variable to add additional folders to the search path. This works for native DLLs, but I haven't tried to use it for .NET assemblies.
Another option is to add a hook to the AssemblyResolve event on the current application domain and use a custom resolver to load the appropriate assembly from wherever you find it. This can be done at the assembly level - I use it in NAudio.Lame to load an assembly from a resource.
Something along these lines:
public static class PluginResolver
{
private static bool hooked = false;
public static string PluginBasePath { get; private set; }
public static void Init(string BasePath)
{
PluginBasePath = BasePath;
if (!hooked)
{
AppDomain.CurrentDomain.AssemblyResolve += ResolvePluginAssembly;
hooked = true;
}
}
static Assembly ResolvePluginAssembly(object sender, ResolveEventArgs args)
{
var asmName = new AssemblyName(args.Name).Name + ".dll";
var assemblyFiles = Directory.EnumerateFiles(PluginBasePath, "*.dll", SearchOption.AllDirectories);
var asmFile = assemblyFiles.FirstOrDefault(fn => string.Compare(Path.GetFileName(fn), asmName, true) == 0);
if (string.IsNullOrEmpty(asmFile))
return null;
return Assembly.LoadFile(asmFile);
}
}
(Usings for the above: System.IO, System.Reflection, System.Linq)
Call Init with the base path to your plugins folder. When you try to reference an assembly that isn't loaded yet it will search for the first file that matches the base name of the assembly with dll appended. For instance, the NAudio assembly will match the first file named NAudio.dll. It will then load and return the assembly.
No checking is done in the above code on the version, etc. and no preference is given to the current plugin's folder.

Categories