Can I use a variable to set a path in FileStream? - c#

I have a test script in Selenium Webdriver using C# in which I read data from a .txt external file.
The path is fixed on the script, indicating a folder on my computer. But in the future other people will run this script in other computers and they will have to adjust the path manually directly on the script.
Is it possible to set the path C:\Users\...\myData.txt like a kind of a variable, I mean, not being permanent on the body of the script?
This is the part of the script:
using System;
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using System.IO;
using System.Collections;
using System.Text;
namespace SeleniumTests
{
[TestFixture]
public class Principal
{
IWebDriver driver = null;
[SetUp]
public void SetUp()
{
ChromeOptions options = new ChromeOptions();
options.AddArguments("--disable-infobars");
options.AddArguments("start-maximized");
driver = new ChromeDriver(options);
}
public class DataTXT
{
public string example1{ get; set; }
public string example2{ get; set; }
public string example3{ get; set; }
public string example4{ get; set; }
}
public static IEnumerable DataTXT
{
get
{
string linha;
using (FileStream readFile =
new FileStream(#"C:\Users\...\myData.txt", FileMode.Open, FileAccess.Read))
{
var reader = new StreamReader(readFile, Encoding.GetEncoding("iso-8859-1"));
while ((line = reader.ReadLine()) != null)
{
var column = line.Split(';');
yield return new DataTXT
{
example1 = column[0],
example2 = column[1],
example3 = column[2],
example4 = column[3]
};
}
reader.Close();
readFile.Close();
}
}
}

Did you try? It is just a string.
public string FilePath { get; set: }
using (FileStream readFile =
new FileStream(FilePath, FileMode.Open, FileAccess.Read))
{
You can pass data in a command line
static int Main(string[] args)

I may be misunderstanding your question a bit as I'm slightly new here. But if you are just wanting a path variable that isn't statically defined and can be changed by the users; you could use the config file to define it and point to the config instead. (Or ConfigurationManager MSDN-ConfigManager)

There are a number of ways you can do this.
You can create the path inside your project and know where it is relative to \bin.
I see you are using NUnit. NUnit has TestContext.CurrentContext.TestDirectory that will return the path of the test dll. If you add the txt file to your solution and copy it in with the dll with a post-build event, it will always be in the TestDirectory.

Question solved by making the relative path, same, adding my .txt from each project in Solution Explorer, in the respective csprojs.
Imagining that the solution is the root and placed my .txt in the same relative path used in the new FileStream (path).
In Solution Explorer, right-clicked the .txt and went to Properties. Under Copy To Output Directory > Copy if newer.
#Kaj & #papparazzo, I'd be glad if you took off the negative votes of this question, if you want.

Related

Performance of a program that uses System.Reflection.Metadata varies for unknow reasons

The below program is a command line tool that takes a directory path as input, recursively scans it for files with .dll as extension and verifies whether those files are valid .NET assemblies. To do that verification, it uses the System.Reflection.Metadata NuGet package. Eventually, the name and version of all valid .NET assemblies is printed to the console.
The program works as intended but its performance strikes me as odd. Sometimes, if I let the program scan a directory with thousands of files it just takes dozens of seconds. During that time, there is a lot of disk load and both the first and the second time measurement of the program are unusually high. But running the program again with the same directory argument executes it very quickly, measured typically in a couple of 100 milliseconds.
I do not really understand that behavior. A possible explanation would be that the disk went sleeping but I have looked into this and it does not seem to explain the behavior. The program itself doesn't cache anything and terminates after the content has been printed to the console.
Is there a mechanism in Windows that explains why var dllFilePaths = new DirectoryInfo(args[0]).GetFiles("*.dll", SearchOption.AllDirectories) runs quicker when executed multiple times?
And why would the code that invokes readers from System.Reflection.Metadata run quicker when executed multiple times?
namespace AssemblyFinder
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
public static class Program
{
public static int Main(string[] args)
{
if (args.Length != 1)
{
Console.Error.WriteLine("Please specify the path of the directory to be scanned for .NET assemblies.");
return 1;
}
if (!Directory.Exists(args[0]))
{
Console.Error.WriteLine($"The specified argument \"{args[0]}\" is not an existing directory.");
return 2;
}
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
var assemblies = new List<AssemblyInfo>();
var dllFilePaths = new DirectoryInfo(args[0])
.GetFiles("*.dll", SearchOption.AllDirectories)
.Select(dllFileInfo => dllFileInfo.FullName)
.ToList();
stopWatch.Stop();
Console.WriteLine($"Found {dllFilePaths.Count} dlls in {(long)stopWatch.Elapsed.TotalMilliseconds} milliseconds");
stopWatch.Restart();
foreach (var dllFilePath in dllFilePaths)
{
if (IsAssembly(dllFilePath, out var assemblyInfo))
{
assemblies.Add(assemblyInfo);
}
}
stopWatch.Stop();
foreach (var assembly in assemblies)
{
Console.WriteLine($"{assembly.FilePath} -> {assembly.AssemblyName}, {assembly.AssemblyVersion}");
}
Console.WriteLine($"Found {dllFilePaths.Count} dlls, identified {assemblies.Count} assemblies in {(long)stopWatch.Elapsed.TotalMilliseconds} milliseconds");
return 0;
}
private static bool IsAssembly(string filePath, out AssemblyInfo assemblyInfo)
{
using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var peReader = new PEReader(fileStream))
{
if (!peReader.PEHeaders.IsDll || !peReader.HasMetadata)
{
assemblyInfo = null;
return false;
}
var metadataReader = peReader.GetMetadataReader();
if (!metadataReader.IsAssembly)
{
assemblyInfo = null;
return false;
}
var assemblyDefinition = metadataReader.GetAssemblyDefinition();
assemblyInfo = new AssemblyInfo()
{
AssemblyName = assemblyDefinition.Name.IsNil ? null : metadataReader.GetString(assemblyDefinition.Name),
AssemblyVersion = assemblyDefinition.Version,
FilePath = filePath,
};
return true;
}
}
}
public class AssemblyInfo
{
public string AssemblyName
{
get;
set;
}
public Version AssemblyVersion
{
get;
set;
}
public string FilePath
{
get;
set;
}
}
}

A string Variable in SSIS is not populating with the value generated in a C# script

I have a fairly simple requirement to read the filename from a location and populate a variable with the filename. I am using a script task for this task. No matter what I try, the value of the filename is not populating in the variable.
I'm using a Script task Editor. There is only one ReadWriteVariables which will hold the full name of the file.
Here is the script that I'm using:
namespace ST_f8fd828f11b64932b15f2681e86c8d94
{
using System;
using System.Data;
using System.IO;
using Microsoft.SqlServer.Dts.Runtime;
[Microsoft.SqlServer.Dts.Tasks.ScriptTask.SSISScriptTaskEntryPointAttribute]
public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
{
public void Main()
{
string p = "C:\\Users\\nthaku01\\Desktop\\NewEXPOLD.txt";
FileInfo fi = new FileInfo(p);
String fileName = fi.FullName;
Dts.Variables["User::vLastFilename"].Value = fileName.ToString();
MessageBox.Show(Dts.Variables["User::vLastFilename"].Value.ToString());
Dts.TaskResult = (int)ScriptResults.Success;
}
enum ScriptResults
{
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};
#endregion
}
}
The MessageBox displays the name(and path) of the file. However, the variable is empty.
This issue has been discussed in detail previously as well and I tried every trick. However, it is just not working for me. Please help!!
Thanks,
Navneet
The only problem with your script task that I could see is that ScriptResults was already defined for the script. I renamed your enum section and the enumerators, and I have no problem using the variable to insert the text into a db table. Here's the script task I used:
public void Main()
{
string p = "C:\\Users\\nthaku01\\Desktop\\NewEXPOLD.txt";
FileInfo fi = new FileInfo(p);
String fileName = fi.FullName;
Dts.Variables["User::vLastFilename"].Value = fileName.ToString();
MessageBox.Show(Dts.Variables["User::vLastFilename"].Value.ToString());
Dts.TaskResult = (int)eScriptResults.enumSuccess;
}
enum eScriptResults
{
enumSuccess = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
enumFailure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};
I got it resolved.
Actually, as an SSIS newbie, I was not aware that the value is assigned to the variable during the run-time does not show up in the variable window.
In the variable window, only the value mentioned at the design time shows up. I had to create a derived column and I assigned the value of the user variable to this newly created derived column. This resolved the issue I was facing.
In the Derived column transformation:
output_LastFileName <-- User::vLastFilename

SQLite.Net Won't Create In Win IoT Library

I have been struggling to find a way of persisting an SQLite database on a Pi under Win IoT which can be accessed by different background applications (not concurrently).
I thought I had the answer when I discovered Libraries (Music, Pictures, Videos - but perversely not Documents, without more work). I can create a text file in one app and write it to the Pictures library's default folder. I can then read the text file with another app. File.Exists returns true. Bingo (I thought)!
However, SQLite will not create a database in the folder or open an existing database that I copy to the folder. SQLite.Net.SQLiteConnection returns an SQLite exception: "Could not open database file: C:\Data\Users\DefaultAccount\Pictures\MyDb.db (CannotOpen)" - no further clues.
The folder appears to grant full permissions. Does anyone have any ideas, please?
Creating and Writing a text file:
using System;
using Windows.ApplicationModel.Background;
using System.IO;
using System.Diagnostics;
//*** NOTE: Pictures Library checked in Package.appxmanifest 'Capabilities'
namespace LibraryTest
{
public sealed class StartupTask : IBackgroundTask
{
private BackgroundTaskDeferral Deferral;
public async void Run (IBackgroundTaskInstance taskInstance)
{
Deferral = taskInstance.GetDeferral ();
var myPictures = await Windows.Storage.StorageLibrary.GetLibraryAsync
(Windows.Storage.KnownLibraryId.Pictures);
string path = myPictures.SaveFolder.Path;
Debug.WriteLine ($"'Pictures' Folder: {path}");
string newFilePath = Path.Combine (path, "TestTextFile.txt");
Debug.WriteLine ($"New File Path: {newFilePath}");
try {
using ( var stream = File.OpenWrite (newFilePath) ) {
using ( var writer = new StreamWriter (stream) ) {
writer.Write ("This is some test text.");
}
}
Debug.WriteLine ($"File created OK");
}
catch (Exception ex) { Debug.WriteLine ($"Exception: {ex.Message}"); }
}
}
}
Produced:
'Pictures' Folder: C:\Data\Users\DefaultAccount\Pictures
New File Path: C:\Data\Users\DefaultAccount\Pictures\TestTextFile.txt
File created OK
Reading:
using System;
using Windows.ApplicationModel.Background;
using System.IO;
using System.Diagnostics;
//*** NOTE: Pictures Library checked in Package.appxmanifest 'Capabilities'
namespace ReadLibraryTest
{
public sealed class StartupTask : IBackgroundTask
{
private BackgroundTaskDeferral Deferral;
public async void Run (IBackgroundTaskInstance taskInstance)
{
Deferral = taskInstance.GetDeferral ();
var myPictures = await Windows.Storage.StorageLibrary.GetLibraryAsync
(Windows.Storage.KnownLibraryId.Pictures);
string path = myPictures.SaveFolder.Path;
Debug.WriteLine ($"'Pictures' Folder: {path}");
string newFilePath = Path.Combine (path, "TestTextFile.txt");
Debug.WriteLine ($"New File Path: {newFilePath}");
try {
using ( var stream = File.OpenRead (newFilePath) ) {
using ( var reader = new StreamReader (stream) ) {
string fileContents = reader.ReadLine ();
Debug.WriteLine ($"First line of file: '{fileContents}'");
}
}
Debug.WriteLine ($"File read OK");
}
catch ( Exception ex ) { Debug.WriteLine ($"Exception: {ex.Message}"); }
}
}
}
Produced:
'Pictures' Folder: C:\Data\Users\DefaultAccount\Pictures
New File Path: C:\Data\Users\DefaultAccount\Pictures\TestTextFile.txt
First line of file: 'This is some test text.'
File read OK
However, SQLite will not create a database in the folder or open an
existing database that I copy to the folder.
SQLite.Net.SQLiteConnection returns an SQLite exception: "Could not
open database file: C:\Data\Users\DefaultAccount\Pictures\MyDb.db
(CannotOpen)" - no further clues.
Yes, I reproduced this issue. It seems this folder does not work with SQLite file operations but I don't know where the problem is.
As a workaround, you can use PublisherCacheFolder. I create the .db file and write data in one background app. And read the data from another background app. It works.
Contact class:
public sealed class Contact
{
public int Id { get; set; }
public string Name { get; set; }
}
Create and write file:
StorageFolder sharedFonts = Windows.Storage.ApplicationData.Current.GetPublisherCacheFolder("test");
var sqlpath = System.IO.Path.Combine(sharedFonts.Path, "MyDb.db");
using (SQLite.Net.SQLiteConnection conn = new SQLite.Net.SQLiteConnection(new SQLite.Net.Platform.WinRT.SQLitePlatformWinRT(), sqlpath))
{
conn.CreateTable<Contact>();
for (var i = 0; i < 100; i++)
{
Contact contact = new Contact()
{
Id = i,
Name = "A"
};
conn.Insert(contact);
}
}
Read file:
StorageFolder sharedFonts = Windows.Storage.ApplicationData.Current.GetPublisherCacheFolder("test");
var sqlpath = System.IO.Path.Combine(sharedFonts.Path, "MyDb.db");
using (SQLite.Net.SQLiteConnection conn = new SQLite.Net.SQLiteConnection(new SQLite.Net.Platform.WinRT.SQLitePlatformWinRT(), sqlpath))
{
var query = conn.Table<Contact>().Where(v => v.Name.Equals("A"));
foreach (var stock in query)
Debug.WriteLine("contact: " + stock.Id);
}
To use this publisher folder you need add the following lines in Package.appxmanifest:
<Extensions>
<Extension Category="windows.publisherCacheFolders">
<PublisherCacheFolders>
<Folder Name="test" />
</PublisherCacheFolders>
</Extension>
</Extensions>
Thanks, Rita. Worked very well. For the benefit of anyone reading, I am using the async version of SqlLite and create the connection as follows:
const string FileName = "MyFile.db";
string DbDir;
string DbPath;
Constructor:
DbDir = Windows.Storage.ApplicationData.Current.GetPublisherCacheFolder("test").Path;
DbPath = Path.Combine (DbDir, DbFileName);
public SQLite.Net.Async.SQLiteAsyncConnection GetConnectionAsync ()
{
var connectionFactory = new Func<SQLite.Net.SQLiteConnectionWithLock>(()=>
new SQLite.Net.SQLiteConnectionWithLock(new SQLitePlatformWinRT(),
new SQLite.Net.SQLiteConnectionString(DbPath, storeDateTimeAsTicks: false)));
var asyncConnection = new SQLiteAsyncConnection(connectionFactory);
return asyncConnection;
}
Then, for instance, read a table of type Parms:
public async Task<Parms> ReadParmsAsync ()
{
var db = GetConnectionAsync ();
var query = db.Table<Parms> ().Where (p => p.Id == 1);
return await query.FirstOrDefaultAsync ();
}
My concern about the SQLite async connection is that it is not IDisposable. Therefore, will the 'factory' eventually run out of steam (memory, handles)? But I guess that is a subject for another thread.

Changing the base path of an assembly from the bin directory to a different directory

I have a Test.cs file in C:\ This test file reads from an input file and writes the same to an output file.
Test.cs
public class Test
{
public static int Main(string[] args)
{
var reader = new StreamReader("in.txt");
string input = reader.ReadLine();
var writer = new StreamWriter("out.txt");
writer.WriteLine(input);
return 0;
}
}
Here it should be noted that the code only uses the filename and not the full file path, which means the file is expected to be in the directory where the program is running. And I have created the in.txt in C:\
Now, there is a c# code called Runner.cs in a solution in C:\Project\Runner.cs, that dynamically compiles the Test.cs code and runs it using reflection. Now, when the Test.cs runs, it expects the in.txt file to be in C:\Project\bin\Debug\in.txt , but it is actually present in C:\in.txt
So, my question is, is there a way to make the code to get the file from C:\in.txt and not from the bin directory without changing the path of the file in the Test.cs code file.
Edit: It is my bad that I forgot to mention why I am in need of this requirement.
The Test.cs file comes from over the wire. And I felt it will not be a good choice to edit this file and set the file path accordingly. I want to compile it and run it as it is.
I hope I am clear. If not, please feel free to ask for more information.
If it is as simple as you show in your code switching the CurrentDirectory works for this example:
var mainMembers = new CSharpCodeProvider()
.CreateCompiler()
.CompileAssemblyFromSource(
new CompilerParameters { GenerateInMemory = true }
, #"
using System;
using System.IO;
public class M {
public static int Main() {
Console.WriteLine(""CurDir = ""+ Environment.CurrentDirectory);
var reader = new StreamReader(""in.txt"");
string input = reader.ReadLine();
var writer = new StreamWriter(""out.txt"");
writer.WriteLine(input);
return 0;
}
}")
.CompiledAssembly
.GetType("M")
.GetMember("Main");
// inspect
Environment.CurrentDirectory.Dump("current");
// keep
var oldcd = Environment.CurrentDirectory;
// switch
Environment.CurrentDirectory = "c:\\temp";
// invoke external code
((MethodInfo) mainMembers[0]).Invoke(null,null);
// restore
Environment.CurrentDirectory = oldcd;
In a multi threaded scenario this becomes unreliable.

How do I compile a C# solution with Roslyn?

I have a piece of software that generates code for a C# project based on user actions. I would like to create a GUI to automatically compile the solution so I don't have to load up Visual Studio just to trigger a recompile.
I've been looking for a chance to play with Roslyn a bit and decided to try and use Roslyn instead of msbuild to do this. Unfortunately, I can't seem to find any good resources on using Roslyn in this fashion.
Can anyone point me in the right direction?
You can load the solution by using Roslyn.Services.Workspace.LoadSolution. Once you have done so, you need to go through each of the projects in dependency order, get the Compilation for the project and call Emit on it.
You can get the compilations in dependency order with code like below. (Yes, I know that having to cast to IHaveWorkspaceServices sucks. It'll be better in the next public release, I promise).
using Roslyn.Services;
using Roslyn.Services.Host;
using System;
using System.Collections.Generic;
using System.IO;
class Program
{
static void Main(string[] args)
{
var solution = Solution.Create(SolutionId.CreateNewId()).AddCSharpProject("Foo", "Foo").Solution;
var workspaceServices = (IHaveWorkspaceServices)solution;
var projectDependencyService = workspaceServices.WorkspaceServices.GetService<IProjectDependencyService>();
var assemblies = new List<Stream>();
foreach (var projectId in projectDependencyService.GetDependencyGraph(solution).GetTopologicallySortedProjects())
{
using (var stream = new MemoryStream())
{
solution.GetProject(projectId).GetCompilation().Emit(stream);
assemblies.Add(stream);
}
}
}
}
Note1: LoadSolution still does use msbuild under the covers to parse the .csproj files and determine the files/references/compiler options.
Note2: As Roslyn is not yet language complete, there will likely be projects that don't compile successfully when you attempt this.
I also wanted to compile a full solution on the fly. Building from Kevin Pilch-Bisson's answer and Josh E's comment, I wrote code to compile itself and write it to files.
Software Used
Visual Studio Community 2015 Update 1
Microsoft.CodeAnalysis v1.1.0.0 (Installed using Package Manager Console with command Install-Package Microsoft.CodeAnalysis).
Code
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.MSBuild;
namespace Roslyn.TryItOut
{
class Program
{
static void Main(string[] args)
{
string solutionUrl = "C:\\Dev\\Roslyn.TryItOut\\Roslyn.TryItOut.sln";
string outputDir = "C:\\Dev\\Roslyn.TryItOut\\output";
if (!Directory.Exists(outputDir))
{
Directory.CreateDirectory(outputDir);
}
bool success = CompileSolution(solutionUrl, outputDir);
if (success)
{
Console.WriteLine("Compilation completed successfully.");
Console.WriteLine("Output directory:");
Console.WriteLine(outputDir);
}
else
{
Console.WriteLine("Compilation failed.");
}
Console.WriteLine("Press the any key to exit.");
Console.ReadKey();
}
private static bool CompileSolution(string solutionUrl, string outputDir)
{
bool success = true;
MSBuildWorkspace workspace = MSBuildWorkspace.Create();
Solution solution = workspace.OpenSolutionAsync(solutionUrl).Result;
ProjectDependencyGraph projectGraph = solution.GetProjectDependencyGraph();
Dictionary<string, Stream> assemblies = new Dictionary<string, Stream>();
foreach (ProjectId projectId in projectGraph.GetTopologicallySortedProjects())
{
Compilation projectCompilation = solution.GetProject(projectId).GetCompilationAsync().Result;
if (null != projectCompilation && !string.IsNullOrEmpty(projectCompilation.AssemblyName))
{
using (var stream = new MemoryStream())
{
EmitResult result = projectCompilation.Emit(stream);
if (result.Success)
{
string fileName = string.Format("{0}.dll", projectCompilation.AssemblyName);
using (FileStream file = File.Create(outputDir + '\\' + fileName))
{
stream.Seek(0, SeekOrigin.Begin);
stream.CopyTo(file);
}
}
else
{
success = false;
}
}
}
else
{
success = false;
}
}
return success;
}
}
}

Categories