I am trying to debug code from https://nunrar.codeplex.com/. In branch DOCUMENTATION -> Basic Usage there is the following code:
RarArchive archive = RarArchive.Open(source);
foreach (RarArchiveEntry entry in archive.Entries)
{
string path = Path.Combine(destination, Path.GetFileName(entry.FilePath));
entry.ExtractToFile(path);
}
Well.. I 've downloaded source code, find RarArchiveEntry class and started to looking for method ExtractToFile(), but there isn't any method there neither in class, nor in project!
Please help me to find this method or method which i can call to look through how this programm can unpack rar files step-by-step?
It looks like the documentation is obsolete and the name of the method was changed, there is an extension method found in RarArchiveEntry.Exensions.cs called WriteToFile.
/// <summary>
/// Extract to specific file
/// </summary>
public static void WriteToFile(this RarArchiveEntry entry, string destinationFileName, ExtractOptions options = ExtractOptions.Overwrite)
{
entry.WriteToFile(destinationFileName, new NullRarExtractionListener(), options);
}
Related
I'm fairly rusty when it comes to C#. I've been poking my nose around internet trying to find a solution to my question without success.
I created a test project using MSTest. Some tests use files, that I added to my project test under the folder TestData, and they are copied when executing the test by using the attribute DeploymentItem.
Example: [DeploymentItem(#"TestData\test.txt")]
This copies test.txt at the execution folder and it works. However, when I want to use this file in the test, I then have to work on "test.txt" instead of #"TestData\test.txt". Thus, if I want to factorize my code, I have to have two variables:
const string testFileName = "test.txt";
const string testFilePath = #"TestData\test.txt";
and then use them as
[DeploymentItem(testFilePath)]
public void TestFunction()
{
[...]testFileName[...]
}
Ideally, I want instead to write:
[DeploymentItem(testFilePath)]
public void TestFunction()
{
[...]testFilePath[...]
}
This way I would only need one variable.
It would work if I use the second argument of DeploymentItem as such:
const string testFilesFolder = "TestData";
const string testFilePath = #"TestData\test.txt";
[DeploymentItem(testFilePath, testFilesFolder)]
public void TestFunction()
{
[...]testFilePath[...]
}
However, that forces me and everyone to think about passing the second argument every time we use DeploymentItem. But it has the merit of working.
Here are the different things I tried to do to address the issue:
Inheriting from DeploymentItem to simply add my own constructor: DeploymentItem is sealed so this is not possible.
Creating my own attribute, by copying the code of DeploymentItem. The file is not copied at all:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
class DeployFileAttribute : Attribute
{
public DeployFileAttribute(string path)
{
Path = path;
OutputDirectory = System.IO.Path.GetDirectoryName(path);
}
public string Path { get; }
public string OutputDirectory { get; }
}
[DeployFile(testFilePath)] // testFilePath is not copied at all, even though the constructor is correctly executed.
Creating a method that would return the attribute. It does not seem like it is possible to use the result of a method as an attribute:
public static DeploymentItemAttribute DeployFile(string path)
{
return new DeploymentItemAttribute(path, System.IO.Path.GetDirectoryName(path));
} // No compilation error
[DeployFile(testFilePath)] // DeployFileAttribute type does not exist
Creating something like a C++ style using statement or C style macro, I can't seem to find a syntax that works
using DeployFile(string toto) = DeploymentItemAttribute(toto, System.IO.Path.GetDirectoryName(path)); // Syntax is wrong, could not find one that works
Any hindsight would be welcome!
From my point of view, there are only two possibilities:
You use DeploymentItem in the way it was created by Microsoft.
[DeploymentItem(testFilePath, testFilesFolder)] as you manshioned in your post
You can combine source path:
const string testFileName = "test.txt";
[DeploymentItem(#"TestData\" + testFileName)]
public void TestFunction()
{
[...]testFileName[...]
}
In this case, you'll have just one variable :)
You can write your own extension for MSTest and create an attribute you need. But this is not the easy way. As key words for this approach, you could google for TestExtensionExecution, ITestMethodInvoker and TestClassExtensionAttribute
On the other hand, this is very understandable, why DeploymentItem is implemented as it is. Do not forget, that the source folder can be an absolute path as well. So assume, that you have the following attribute [DeploymentItem(#"S:\Shared\TestFiles\AAA\BBB\test.txt")] What should be the destination folder? But even with relative paths: [DeploymentItem(#"..\..\..\TestFiles\AAA\BBB\test.txt")] - can say the name of the destination folder in this case?
I'm trying to read an xlsx file, and I got a basic overview from This Codeproject Link
Now, I'm getting the following exception message:
The code segment related to this exception is given below:
public static sst SharedStrings;
/// <summary>
/// All worksheets in the Excel workbook deserialized
/// </summary>
/// <param name="ExcelFileName">Full path and filename of the Excel xlsx-file</param>
/// <returns></returns>
public static IEnumerable<worksheet> Worksheets(string ExcelFileName)
{
worksheet ws;
using (ZipArchive zipArchive = ZipFile.Open(ExcelFileName, ZipArchiveMode.Read))
{
SharedStrings = DeserializedZipEntry<sst>(GetZipArchiveEntry(zipArchive, #"xl/sharedStrings.xml"));
foreach (var worksheetEntry in (WorkSheetFileNames(zipArchive)).OrderBy(x => x.FullName))
{
ws = DeserializedZipEntry<worksheet>(worksheetEntry);
ws.NumberOfColumns = worksheet.MaxColumnIndex + 1;
ws.ExpandRows();
yield return ws;
}
}
}
After some searching, I figured out that I needed to target .NET 4.5 or above version, (I'm targetting 4.6.1, but I also have tried 4.5, still same results). Also, as far as the dependencies are concerned, my references look like this:
After doing all this, I'm still getting the exception mentioned above, and have no idea why this is happening.
EDIT 1: I've been through This StackOverflow Link, where I figured that I need the latest DLLs. I went to the Nuget Package Manager, and there were "No Packages Found" which were available for the updates.
I have tried .NET 4.6.1 and 4.6.2. Both work OK for me.
My Visual Studio is Community Edition 2017
The project references:
Note that System.IO.Compression.ZipFile is not referenced. It was not possible to reference it in my environment.
Use Workbook.Worksheets() or declare the calling class as sub-class of Excel.Workbook.
Excel is the namespace of the CodeProject article source which provides the necessary classes.
using Excel;
using System;
namespace akExcelAsZipDemo
{
class Program : Workbook
{
// from
// https://www.codeproject.com/tips/801032/csharp-how-to-read-xlsx-excel-file-with-lines-ofthe
//
// inspired:
// https://github.com/ahmadalli/ExcelReader
static void Main(string[] args)
{
const string fileName = #"E:\AK\export.xlsx";
var worksheets = Worksheets(fileName);
foreach (worksheet ws in worksheets)
{
Console.WriteLine($"cols={ws.NumberOfColumns} rows={ws.Rows.Length}");
}
Console.WriteLine();
}
}
}
I'm using SwaggerResponse attributes to decorate my api controller actions, this all works fine, however when I look at the generated documentation the description field for parameters is empty.
Is a there an attribute based approach to describe action parameters (rather than XML comments)?
With the latest Swashbuckle, or better said at least the Swashbuckle.AspNetCore variant which I'm using, the Description field for parameters can now be displayed correctly as output.
It does require the following conditions to be met:
XML comments must be enabled and configured with Swagger
Parameters should be explicitly decorated with either [FromRoute], [FromQuery], [FromBody] etc.
The same for the method type (get/post/put etc.), which should be decorated with [Http...]
Describe the parameter as usual with a <param ...> xml comment
A full sample looks like this:
/// <summary>
/// Short, descriptive title of the operation
/// </summary>
/// <remarks>
/// More elaborate description
/// </remarks>
/// <param name="id">Here is the description for ID.</param>
[ProducesResponseType(typeof(Bar), (int)HttpStatusCode.OK)]
[HttpGet, Route("{id}", Name = "GetFoo")]
public async Task<IActionResult> Foo([FromRoute] long id)
{
var response = new Bar();
return Ok(response);
}
Which produces the following output:
You should confirm you are allowing Swagger to use XML comments
httpConfig.EnableSwagger(c => {
if (GetXmlCommentsPath() != null) {
c.IncludeXmlComments(GetXmlCommentsPath());
}
...
...
);
protected static string GetXmlCommentsPath() {
var path = HostingEnvironment.MapPath("path to your xml doc file");
return path;
}
You should also check you are generating XML doc for your desired project. Under your desired project Properties (Alt + Enter on top of the project or Right Click -> Properties) -> Build -> Check XML documentation file
For completeness sake, when using latest version of Swashbuckle.AspNetCore (2.1.0) and Swashbuckle.SwaggerGen/Ui (6.0.0), enable Xml documentation file generation in your project's Build
Then the following to your ConfigureServices() method:
services.ConfigureSwaggerGen(options =>
{
options.SingleApiVersion(new Info
{
Version = "v1",
Title = "My API",
Description = "API Description"
});
options.DescribeAllEnumsAsStrings();
var xmlDocFile = Path.Combine(AppContext.BaseDirectory, $"{_hostingEnv.ApplicationName}.xml");
if (File.Exists(xmlDocFile))
{
var comments = new XPathDocument(xmlDocFile);
options.OperationFilter<XmlCommentsOperationFilter>(comments);
options.ModelFilter<XmlCommentsModelFilter>(comments);
}
});
I have application 1 and application 2. App2 needs to verify that App1 is installed, and if it is it needs to access a property from the App1 Settings.
What would be the best way to go about this?
UPDATE
First, my apologies for never accepting an answer to this, I know it's over a year old now, but I got sidetracked immediately after asking this and then the project was changed, blah blah blah. Mea culpa...
I'm back on it now and I still need to solve this problem, but now the applications are deployed via ClickOnce, so I don't actually know where they are located. Any suggestions would be appreciated. I promise I'll select an answer this time.
The docs for ConfigurationManager.OpenExeConfiguration have an example of reading the .config file of another exe and accessing the AppSettings. Here it is:
// Get the application path.
string exePath = System.IO.Path.Combine(
Environment.CurrentDirectory, "ConfigurationManager.exe");
// Get the configuration file.
System.Configuration.Configuration config =
ConfigurationManager.OpenExeConfiguration(exePath);
// Get the AppSetins section.
AppSettingsSection appSettingSection = config.AppSettings;
As far as checking that App1 is installed, you could write a value in the Registry during installation and check it in App2 (and remove the value during uninstall).
This is a pain, I can tell you that much. I've found that the best way to do this is that you serialize the Settingsclass and use XML(code below). But try this page first:
http://cf-bill.blogspot.com/2007/10/visual-studio-sharing-one-file-between.html
public class Settings
{
public static string ConfigFile{get{return "Config.XML";}}
public string Property1 { get; set; }
/// <summary>
/// Saves the settings to the Xml-file
/// </summary>
public void Save()
{
XmlSerializer serializer = new XmlSerializer(typeof(Settings));
using (TextWriter reader = new StreamWriter(ConfigFile))
{
serializer.Serialize(reader, this);
}
}
/// <summary>
/// Reloads the settings from the Xml-file
/// </summary>
/// <returns>Settings loaded from file</returns>
public static Settings Load()
{
XmlSerializer serializer = new XmlSerializer(typeof(Settings));
using (TextReader reader = new StreamReader(ConfigFile))
{
return serializer.Deserialize(reader) as Settings;
}
}
}
I am storing a PNG as an embedded resource in an assembly. From within the same assembly I have some code like this:
Bitmap image = new Bitmap(typeof(MyClass), "Resources.file.png");
The file, named "file.png" is stored in the "Resources" folder (within Visual Studio), and is marked as an embedded resource.
The code fails with an exception saying:
Resource MyNamespace.Resources.file.png cannot be found in class MyNamespace.MyClass
I have identical code (in a different assembly, loading a different resource) which works. So I know the technique is sound. My problem is I end up spending a lot of time trying to figure out what the correct path is. If I could simply query (eg. in the debugger) the assembly to find the correct path, that would save me a load of headaches.
This will get you a string array of all the resources:
System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceNames();
I find myself forgetting how to do this every time as well so I just wrap the two one-liners that I need in a little class:
public class Utility
{
/// <summary>
/// Takes the full name of a resource and loads it in to a stream.
/// </summary>
/// <param name="resourceName">Assuming an embedded resource is a file
/// called info.png and is located in a folder called Resources, it
/// will be compiled in to the assembly with this fully qualified
/// name: Full.Assembly.Name.Resources.info.png. That is the string
/// that you should pass to this method.</param>
/// <returns></returns>
public static Stream GetEmbeddedResourceStream(string resourceName)
{
return Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
}
/// <summary>
/// Get the list of all emdedded resources in the assembly.
/// </summary>
/// <returns>An array of fully qualified resource names</returns>
public static string[] GetEmbeddedResourceNames()
{
return Assembly.GetExecutingAssembly().GetManifestResourceNames();
}
}
I'm guessing that your class is in a different namespace. The canonical way to solve this would be to use the resources class and a strongly typed resource:
ProjectNamespace.Properties.Resources.file
Use the IDE's resource manager to add resources.
I use the following method to grab embedded resources:
protected static Stream GetResourceStream(string resourcePath)
{
Assembly assembly = Assembly.GetExecutingAssembly();
List<string> resourceNames = new List<string>(assembly.GetManifestResourceNames());
resourcePath = resourcePath.Replace(#"/", ".");
resourcePath = resourceNames.FirstOrDefault(r => r.Contains(resourcePath));
if (resourcePath == null)
throw new FileNotFoundException("Resource not found");
return assembly.GetManifestResourceStream(resourcePath);
}
I then call this with the path in the project:
GetResourceStream(#"DirectoryPathInLibrary/Filename");
The name of the resource is the name space plus the "pseudo" name space of the path to the file. The "pseudo" name space is made by the sub folder structure using \ (backslashes) instead of . (dots).
public static Stream GetResourceFileStream(String nameSpace, String filePath)
{
String pseduoName = filePath.Replace('\\', '.');
Assembly assembly = Assembly.GetExecutingAssembly();
return assembly.GetManifestResourceStream(nameSpace + "." + pseduoName);
}
The following call:
GetResourceFileStream("my.namespace", "resources\\xml\\my.xml")
will return the stream of my.xml located in the folder-structure resources\xml in the name space: my.namespace.