No console output during call WSL/WSL2 command in Powershell from C# - c#

I have Pengwin (Linux distro optimalized for working with WSL - surely everybody know) with installed github-linguist, set up by tutorial in https://github.com/github/linguist/blob/master/README.md . Even I have use my Insider Windows instance, change version WSL for upcoming 2, but everything keep like before.
In Pengwin and Powershell cmd is everything OK:
wsl bash -c "github-linguist '/mnt/d/Documents/Visual Studio 2017/Projects/LearnCss/LearnCss/Program.cs'"
But by calling in C# is output empty (any other commmand like dir works):
static PowershellBuilder builder = new PowershellBuilder();
/// <summary>
/// Tested, working
/// For every command return at least one entry in result
/// </summary>
/// <param name="commands"></param>
/// <returns></returns>
public async static Task<List< List<string>>> InvokeAsync(IEnumerable<string> commands)
{
List<List<string>> returnList = new List<List<string>>();
PowerShell ps = null;
// After leaving using is closed pipeline, must watch for complete or
using (ps = PowerShell.Create())
{
foreach (var item in commands)
{
ps.AddScript(item);
var async = ps.BeginInvoke();
// Return for SleepWithRandomOutputConsole zero outputs
var psObjects = ps.EndInvoke(async);
returnList.Add(ProcessPSObjects(psObjects));
}
}
return returnList;
}
/// <summary>
/// Tested, working
/// For every command return at least one entry in result
/// </summary>
/// <param name="commands"></param>
/// <returns></returns>
public static List<List<string>> Invoke(IEnumerable<string> commands)
{
var result = InvokeAsync(commands);
result.Wait();
return result.Result;
}
private static List<string> ProcessPSObjects(ICollection<PSObject> pso)
{
List<string> output = new List<string>();
foreach (var item in pso)
{
if (item != null)
{
output.Add(item.ToString());
}
}
return output;
}
public static List<string> InvokeSingle(string command)
{
return Invoke(CA.ToListString(command))[0];
}
But with calling with Process.Start all works like a charm:
/// <summary>
/// If in A1 will be full path specified = 'The system cannot find the file specified'
/// A1 if dont contains extension, append exe
/// </summary>
/// <param name="exeFileNameWithoutPath"></param>
/// <param name="arguments"></param>
/// <returns></returns>
public static List<string> InvokeProcess(string exeFileNameWithoutPath, string arguments)
{
FS.AddExtensionIfDontHave(exeFileNameWithoutPath, AllExtensions.exe);
//Create process
System.Diagnostics.Process pProcess = new System.Diagnostics.Process();
// Must contains only filename, not full path
pProcess.StartInfo.FileName = exeFileNameWithoutPath;
//strCommandParameters are parameters to pass to program
pProcess.StartInfo.Arguments = arguments;
pProcess.StartInfo.UseShellExecute = false;
//Set output of program to be written to process output stream
pProcess.StartInfo.RedirectStandardOutput = true;
//Optional, recommended do not enter, then old value is not deleted and both paths is combined
//pProcess.StartInfo.WorkingDirectory = ;
//Start the process
pProcess.Start();
W32.EnableWow64FSRedirection(true);
//Get program output
string strOutput = pProcess.StandardOutput.ReadToEnd();
//Wait for process to finish
pProcess.WaitForExit();
var result = SH.GetLines(strOutput);
return result;
}
Calling code:
const string lang = "language:";
public static string DetectLanguageForFileGithubLinguist(string windowsPath)
{
string command = null;
string arguments = null;
// With WSL or WSL 2 not working. In both cases Powershell returns right values but in c# everything empty. Asked on StackOverflow
StringBuilder linuxPath = new StringBuilder();
linuxPath.Append("/mnt/");
linuxPath.Append(windowsPath[0].ToString().ToLower());
var parts = SH.Split(windowsPath, AllStrings.bs);
for (int i = 1; i < parts.Count; i++)
{
linuxPath.Append("/" + parts[i]);
}
command = "wsl";
arguments = " bash -c \"github-linguist '" + linuxPath + "'\"";
W32.EnableWow64FSRedirection(false);
// empty
var pc = PowershellRunner.InvokeSingle("cmd /c bash -c 'ruby -v'");
// empty
var pc2 = PowershellRunner.InvokeSingle("wsl bash -c whoami");
// with content
var pc3 = PowershellRunner.InvokeSingle("dir");
//command = #"c:\Windows\System32\wsl.exe";
//arguments = " -- github-linguist \"/mnt/d/Documents/Visual Studio 2017/Projects/LearnCss/LearnCss/Program.cs\"";
// empty
var pc4 = PowershellRunner.InvokeSingle(command + arguments);
PowershellRunner.InvokeProcess(command + ".exe", arguments);
var lines = PowershellRunner.InvokeSingle(command);
var line = CA.ReturnWhichContains(lines, lang).FirstOrNull();
if (line == null)
{
return null;
}
var result = line.ToString().Replace(lang, string.Empty).Trim();
return result;
}
Why calling with PowerShell class is not working?

Related

Read All Value From Cache

i am using .netcore with Microsoft.Extensions.Caching.Distributed , i have a scenario to get all the keys and also i need to flush all the values.
I have searched many articles no one gives the exact idea to get all values or Flush values. IDistributedCache don't have flush the redis cache.
Can anyone help on this.
For my project ,the follow function return all matched keys:
//using StackExchange.Redis;
/// <summary>
/// 搜索所有与<see cref="keyStr"/>相匹配的缓存的key
/// </summary>
/// <param name="keyStr">搜索词,*表示任意字符</param>
/// <param name="dbIndex">redis中查找db</param>
/// <param name="trimRedisInstanceName">是否在查询前及返回前去除<see cref="Extension.RedisInstanceName"/>前缀</param>
/// <returns>redis中的key列表,<see cref="trimRedisInstanceName"/>参数设置是否包括<see cref="Extension.RedisInstanceName"/></returns>
protected async Task<List<string>> FilterByKey(string keyStr, int dbIndex = 0, bool trimRedisInstanceName = true)
{
//创建连接
var conn = await ConnectionMultiplexer.ConnectAsync(_configuration.GetSection("Cache")["Redis"]);
//获取db
var db = conn.GetDatabase(dbIndex);
var listResult = new List<string>();
//遍历集群内服务器
foreach (var endPoint in conn.GetEndPoints())
{
//获取指定服务器
var server = conn.GetServer(endPoint);
//在指定服务器上使用 keys 或者 scan 命令来遍历key
foreach (var key in server.Keys(dbIndex, Extension.RedisInstanceName + keyStr))
{
if (trimRedisInstanceName)
{
listResult.Add(key.ToString().Replace(Extension.RedisInstanceName, ""));
}
else
{
listResult.Add(key);
}
//获取key对于的值
//var val = db.StringGet(key);
Console.WriteLine($"key: {key}, value:");
}
}
return listResult;
}
In the method,Extension.RedisInstanceName used in
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = config.GetSection("Cache")["Redis"];
options.InstanceName = RedisInstanceName;
});
it used by this:
//刷新缓存
var allCacheCompany = await FilterByKey("xxxx.*");
foreach (var companyKey in allCacheCompany)
{
await _cache.RemoveAsync(companyKey);
}

.NET Core : IFileProvider.GetDirectoryContents recursive not working

I would like to scan a directory ("C:/test") and get all files .pdf recursively
I create a provider like this :
IFileProvider provider = new PhysicalFileProvider("C:/test"); // using config in my code and also tried with "C:/test/"
I placed some pdf in directories and subdirectories
There's a file with this path : C:/test/pdf59.pdf
Another with C:/test/testComplexe/pdf59.pdf
Where I try these lines, they all return "NotFoundDirectoryException" :
provider.getDirectoryContents(#"**")
provider.getDirectoryContents(#"*")
provider.getDirectoryContents(#"*.*")
provider.getDirectoryContents(#"**.*")
provider.getDirectoryContents(#"pdf59.pdf")
provider.getDirectoryContents(#"*.pdf")
Exception this line :
provider.getDirectoryContents(#"testComplexe")
How could i query these recursive directories and files ? Thank you
You can write your own recursive function.
var files = new List<IFileInfo>();
GetFiles("C:/Tests", files);
private void GetFiles(string path, ICollection<IFileInfo> files)
{
IFileProvider provider = new PhysicalFileProvider(path);
var contents = provider.GetDirectoryContents("");
foreach (var content in contents)
{
if (!content.IsDirectory && content.Name.ToLower().EndsWith(".pdf"))
{
files.Add(content);
}
else
{
GetFiles(content.PhysicalPath, files);
}
}
}
For my future self (and others) to copy-paste...
public static class Demo
{
public static void FindPdfs()
{
var provider = new PhysicalFileProvider("c:\\temp");
var pdfs = new List<IFileInfo>();
provider.FindFiles(
directory: "/",
match: file => file.Name.EndsWith(".pdf"),
process: pdfs.Add,
recursive: true);
foreach (var pdf in pdfs)
{
using (var stream = pdf.CreateReadStream())
{
// etc...
}
}
}
}
public static class FileProviderExtensions
{
/// <summary>
/// Searches for files matching some <paramref name="match"/>, and invokes <paramref name="process"/> on them.
/// </summary>
/// <param name="provider">File provider</param>
/// <param name="directory">parent directory for the search, a relative path, leading slashes are ignored,
/// use "" or "/" for starting at the root of <paramref name="provider"/></param>
/// <param name="match">the match predicate, if this returns true the file is passed to <paramref name="process"/></param>
/// <param name="process">this action is invoked on <paramref name="match"/>ing files </param>
/// <param name="recursive">if true directories a</param>
/// <returns>the number of files <paramref name="match"/>ed and <paramref name="process"/>ed</returns>
public static int FindFiles(this IFileProvider provider, string directory, Predicate<IFileInfo> match, Action<IFileInfo> process, bool recursive = false)
{
var dirsToSearch = new Stack<string>();
dirsToSearch.Push(directory);
var count = 0;
while (dirsToSearch.Count > 0)
{
var dir = dirsToSearch.Pop();
foreach (var file in provider.GetDirectoryContents(dir))
{
if (file.IsDirectory)
{
if (!recursive)
continue;
var relPath = Path.Join(dir, file.Name);
dirsToSearch.Push(relPath);
}
else
{
if (!match(file))
continue;
process(file);
count++;
}
}
}
return count;
}
}
This is the simplest version if you just want a list of IFileInfo objects. It uses an extension method. Assumes you already have a IFileProvider, such as one that has been injected.
var files = FileProvider.GetRecursiveFiles("/images").ToArray();
 
using Microsoft.Extensions.FileProviders;
using System.Collections.Generic;
using System.IO;
public static class FileProviderExtensions
{
public static IEnumerable<IFileInfo> GetRecursiveFiles(this IFileProvider fileProvider, string path, bool includeDirectories = true)
{
var directoryContents = fileProvider.GetDirectoryContents(path);
foreach (var file in directoryContents)
{
if (file.IsDirectory)
{
if (includeDirectories)
{
yield return file;
}
// recursively call GetFiles and return each one
// file.Name is the directory name alone (eg. images)
foreach (var f in fileProvider.GetRecursiveFiles(Path.Combine(path, file.Name), includeDirectories))
{
yield return f;
}
}
else
{
// return file
yield return file;
}
}
}
}
To get the content of your root folder ("C:/test/"), use the provider this way :
var contents = provider.getDirectoryContents("")
Then, you have to enumerate results in contents, and do what ever you want with each one.
Documentation : https://learn.microsoft.com/en-us/aspnet/core/fundamentals/file-providers?view=aspnetcore-2.1

How to kill the application that is using a TCP port in C#?

I want to free a TCP port during startup of my application (asking confirmation to user), how to get the PID number and then, if the user confirm, kill it?
I know I can get this information by netstat, but how to do it in a script or better in a C# method.
You can run netstat then redirect the output to a text stream so you can parse and get the info you want.
Here is what i did.
Run netstat -a -n -o as a Process
redirect the standard out put and capture the output text
capture the result, parse and return all the processes in use
check if the port is being used
find the process using linq
Run Process.Kill()
you will have to do the exception handling.
namespace test
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
Console.WriteLine("Port number you want to clear");
var input = Console.ReadLine();
//var port = int.Parse(input);
var prc = new ProcManager();
prc.KillByPort(7972); //prc.KillbyPort(port);
}
}
public class PRC
{
public int PID { get; set; }
public int Port { get; set; }
public string Protocol { get; set; }
}
public class ProcManager
{
public void KillByPort(int port)
{
var processes = GetAllProcesses();
if (processes.Any(p => p.Port == port))
try{
Process.GetProcessById(processes.First(p => p.Port == port).PID).Kill();
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
else
{
Console.WriteLine("No process to kill!");
}
}
public List<PRC> GetAllProcesses()
{
var pStartInfo = new ProcessStartInfo();
pStartInfo.FileName = "netstat.exe";
pStartInfo.Arguments = "-a -n -o";
pStartInfo.WindowStyle = ProcessWindowStyle.Maximized;
pStartInfo.UseShellExecute = false;
pStartInfo.RedirectStandardInput = true;
pStartInfo.RedirectStandardOutput = true;
pStartInfo.RedirectStandardError = true;
var process = new Process()
{
StartInfo = pStartInfo
};
process.Start();
var soStream = process.StandardOutput;
var output = soStream.ReadToEnd();
if(process.ExitCode != 0)
throw new Exception("somethign broke");
var result = new List<PRC>();
var lines = Regex.Split(output, "\r\n");
foreach (var line in lines)
{
if(line.Trim().StartsWith("Proto"))
continue;
var parts = line.Split(new char[]{' '}, StringSplitOptions.RemoveEmptyEntries);
var len = parts.Length;
if(len > 2)
result.Add(new PRC
{
Protocol = parts[0],
Port = int.Parse(parts[1].Split(':').Last()),
PID = int.Parse(parts[len - 1])
});
}
return result;
}
}
}

C#: split file path [duplicate]

My path is \\server\folderName1\another name\something\another folder\
How do I extract each folder name into a string if I don't know how many folders there are in the path and I don't know the folder names?
Many thanks
string mypath = #"..\folder1\folder2\folder2";
string[] directories = mypath.Split(Path.DirectorySeparatorChar);
Edit:
This returns each individual folder in the directories array. You can get the number of folders returned like this:
int folderCount = directories.Length;
This is good in the general case:
yourPath.Split(#"\/", StringSplitOptions.RemoveEmptyEntries)
There is no empty element in the returned array if the path itself ends in a (back)slash (e.g. "\foo\bar\"). However, you will have to be sure that yourPath is really a directory and not a file. You can find out what it is and compensate if it is a file like this:
if(Directory.Exists(yourPath)) {
var entries = yourPath.Split(#"\/", StringSplitOptions.RemoveEmptyEntries);
}
else if(File.Exists(yourPath)) {
var entries = Path.GetDirectoryName(yourPath).Split(
#"\/", StringSplitOptions.RemoveEmptyEntries);
}
else {
// error handling
}
I believe this covers all bases without being too pedantic. It will return a string[] that you can iterate over with foreach to get each directory in turn.
If you want to use constants instead of the #"\/" magic string, you need to use
var separators = new char[] {
Path.DirectorySeparatorChar,
Path.AltDirectorySeparatorChar
};
and then use separators instead of #"\/" in the code above. Personally, I find this too verbose and would most likely not do it.
I see your method Wolf5370 and raise you.
internal static List<DirectoryInfo> Split(this DirectoryInfo path)
{
if(path == null) throw new ArgumentNullException("path");
var ret = new List<DirectoryInfo>();
if (path.Parent != null) ret.AddRange(Split(path.Parent));
ret.Add(path);
return ret;
}
On the path c:\folder1\folder2\folder3 this returns
c:\
c:\folder1
c:\folder1\folder2
c:\folder1\folder2\folder3
In that order
OR
internal static List<string> Split(this DirectoryInfo path)
{
if(path == null) throw new ArgumentNullException("path");
var ret = new List<string>();
if (path.Parent != null) ret.AddRange(Split(path.Parent));
ret.Add(path.Name);
return ret;
}
will return
c:\
folder1
folder2
folder3
Realise this is an old post, but I came across it looking - in the end I decided apon the below function as it sorted what I was doing at the time better than any of the above:
private static List<DirectoryInfo> SplitDirectory(DirectoryInfo parent)
{
if (parent == null) return null;
var rtn = new List<DirectoryInfo>();
var di = parent;
while (di.Name != di.Root.Name)
{
rtn.Add(di);
di = di.Parent;
}
rtn.Add(di.Root);
rtn.Reverse();
return rtn;
}
There are a few ways that a file path can be represented. You should use the System.IO.Path class to get the separators for the OS, since it can vary between UNIX and Windows. Also, most (or all if I'm not mistaken) .NET libraries accept either a '\' or a '/' as a path separator, regardless of OS. For this reason, I'd use the Path class to split your paths. Try something like the following:
string originalPath = "\\server\\folderName1\\another\ name\\something\\another folder\\";
string[] filesArray = originalPath.Split(Path.AltDirectorySeparatorChar,
Path.DirectorySeparatorChar);
This should work regardless of the number of folders or the names.
public static IEnumerable<string> Split(this DirectoryInfo path)
{
if (path == null)
throw new ArgumentNullException("path");
if (path.Parent != null)
foreach(var d in Split(path.Parent))
yield return d;
yield return path.Name;
}
Inspired by the earlier answers, but simpler, and without recursion. Also, it does not care what the separation symbol is, as Dir.Parent covers this:
/// <summary>
/// Split a directory in its components.
/// Input e.g: a/b/c/d.
/// Output: d, c, b, a.
/// </summary>
/// <param name="Dir"></param>
/// <returns></returns>
public static IEnumerable<string> DirectorySplit(this DirectoryInfo Dir)
{
while (Dir != null)
{
yield return Dir.Name;
Dir = Dir.Parent;
}
}
Either stick this in a static class to create a nice extension method, or just leave out the this (and static).
Usage example (as an extension method) to access the path parts by number:
/// <summary>
/// Return one part of the directory path.
/// Path e.g.: a/b/c/d. PartNr=0 is a, Nr 2 = c.
/// </summary>
/// <param name="Dir"></param>
/// <param name="PartNr"></param>
/// <returns></returns>
public static string DirectoryPart(this DirectoryInfo Dir, int PartNr)
{
string[] Parts = Dir.DirectorySplit().ToArray();
int L = Parts.Length;
return PartNr >= 0 && PartNr < L ? Parts[L - 1 - PartNr] : "";
}
Both above methods are now in my personal library, hence the xml comments. Usage example:
DirectoryInfo DI_Data = new DirectoryInfo(#"D:\Hunter\Data\2019\w38\abc\000.d");
label_Year.Text = DI_Data.DirectoryPart(3); // --> 2019
label_Entry.Text = DI_Data.DirectoryPart(6);// --> 000.d
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/// <summary>
/// Use to emulate the C lib function _splitpath()
/// </summary>
/// <param name="path">The path to split</param>
/// <param name="rootpath">optional root if a relative path</param>
/// <returns>the folders in the path.
/// Item 0 is drive letter with ':'
/// If path is UNC path then item 0 is "\\"
/// </returns>
/// <example>
/// string p1 = #"c:\p1\p2\p3\p4";
/// string[] ap1 = p1.SplitPath();
/// // ap1 = {"c:", "p1", "p2", "p3", "p4"}
/// string p2 = #"\\server\p2\p3\p4";
/// string[] ap2 = p2.SplitPath();
/// // ap2 = {#"\\", "server", "p2", "p3", "p4"}
/// string p3 = #"..\p3\p4";
/// string root3 = #"c:\p1\p2\";
/// string[] ap3 = p1.SplitPath(root3);
/// // ap3 = {"c:", "p1", "p3", "p4"}
/// </example>
public static string[] SplitPath(this string path, string rootpath = "")
{
string drive;
string[] astr;
path = Path.GetFullPath(Path.Combine(rootpath, path));
if (path[1] == ':')
{
drive = path.Substring(0, 2);
string newpath = path.Substring(2);
astr = newpath.Split(new[] { Path.DirectorySeparatorChar }
, StringSplitOptions.RemoveEmptyEntries);
}
else
{
drive = #"\\";
astr = path.Split(new[] { Path.DirectorySeparatorChar }
, StringSplitOptions.RemoveEmptyEntries);
}
string[] splitPath = new string[astr.Length + 1];
splitPath[0] = drive;
astr.CopyTo(splitPath, 1);
return splitPath;
}
Maybe call Directory.GetParent in a loop? That's if you want the full path to each directory and not just the directory names.
The quick answer is to use the .Split('\\') method.
I use this for looping folder ftp server
public List<string> CreateMultiDirectory(string remoteFile)
var separators = new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar };
string[] directory = Path.GetDirectoryName(remoteFile).Split(separators);
var path = new List<string>();
var folder = string.Empty;
foreach (var item in directory)
{
folder += $#"{item}\";
path.Add(folder);
}
return path;
Or, if you need to do something with each folder, have a look at the System.IO.DirectoryInfo class. It also has a Parent property that allows you to navigate to the parent directory.
I wrote the following method which works for me.
protected bool isDirectoryFound(string path, string pattern)
{
bool success = false;
DirectoryInfo directories = new DirectoryInfo(#path);
DirectoryInfo[] folderList = directories.GetDirectories();
Regex rx = new Regex(pattern);
foreach (DirectoryInfo di in folderList)
{
if (rx.IsMatch(di.Name))
{
success = true;
break;
}
}
return success;
}
The lines most pertinent to your question being:
DirectoryInfo directories = new DirectoryInfo(#path);
DirectoryInfo[] folderList = directories.GetDirectories();
DirectoryInfo objDir = new DirectoryInfo(direcotryPath);
DirectoryInfo [] directoryNames = objDir.GetDirectories("*.*", SearchOption.AllDirectories);
This will give you all the directories and subdirectories.
I am adding to Matt Brunell's answer.
string[] directories = myStringWithLotsOfFolders.Split(Path.DirectorySeparatorChar);
string previousEntry = string.Empty;
if (null != directories)
{
foreach (string direc in directories)
{
string newEntry = previousEntry + Path.DirectorySeparatorChar + direc;
if (!string.IsNullOrEmpty(newEntry))
{
if (!newEntry.Equals(Convert.ToString(Path.DirectorySeparatorChar), StringComparison.OrdinalIgnoreCase))
{
Console.WriteLine(newEntry);
previousEntry = newEntry;
}
}
}
}
This should give you:
"\server"
"\server\folderName1"
"\server\folderName1\another name"
"\server\folderName1\another name\something"
"\server\folderName1\another name\something\another folder\"
(or sort your resulting collection by the string.Length of each value.
Here's a modification of Wolf's answer that leaves out the root and fixes what seemed to be a couple of bugs. I used it to generate a breadcrumbs and I didn't want the root showing.
this is an extension of the DirectoryInfo type.
public static List<DirectoryInfo> PathParts(this DirectoryInfo source, string rootPath)
{
if (source == null) return null;
DirectoryInfo root = new DirectoryInfo(rootPath);
var pathParts = new List<DirectoryInfo>();
var di = source;
while (di != null && di.FullName != root.FullName)
{
pathParts.Add(di);
di = di.Parent;
}
pathParts.Reverse();
return pathParts;
}
I just coded this since I didn't find any already built in in C#.
/// <summary>
/// get the directory path segments.
/// </summary>
/// <param name="directoryPath">the directory path.</param>
/// <returns>a IEnumerable<string> containing the get directory path segments.</returns>
public IEnumerable<string> GetDirectoryPathSegments(string directoryPath)
{
if (string.IsNullOrEmpty(directoryPath))
{ throw new Exception($"Invalid Directory: {directoryPath ?? "null"}"); }
var currentNode = new System.IO.DirectoryInfo(directoryPath);
var targetRootNode = currentNode.Root;
if (targetRootNode == null) return new string[] { currentNode.Name };
var directorySegments = new List<string>();
while (string.Compare(targetRootNode.FullName, currentNode.FullName, StringComparison.InvariantCultureIgnoreCase) != 0)
{
directorySegments.Insert(0, currentNode.Name);
currentNode = currentNode.Parent;
}
directorySegments.Insert(0, currentNode.Name);
return directorySegments;
}
I'd like to contribute using this options (without split method)
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace SampleConsoleApp
{
class Program
{
static void Main(string[] args)
{
var filePaths = new[]
{
"C:/a/b/c/d/files-samples/formdata.bmp",
#"\\127.0.0.1\c$\a\b\c\d\formdata.bmp",
"/usr/home/john/a/b/c/d/formdata.bmp"
};
foreach (var filePath in filePaths)
{
var directorySegments = GetDirectorySegments(filePath);
Console.WriteLine(filePath);
Console.WriteLine(string.Join(Environment.NewLine,
directorySegments.Select((e, i) => $"\t Segment#={i + 1} Text={e}")));
}
}
private static IList<string> GetDirectorySegments(string filePath)
{
var directorySegments = new List<string>();
if (string.IsNullOrEmpty(filePath))
return directorySegments;
var fileInfo = new FileInfo(filePath);
if (fileInfo.Directory == null)
return directorySegments;
for (var currentDirectory = fileInfo.Directory;
currentDirectory != null;
currentDirectory = currentDirectory.Parent)
directorySegments.Insert(0, currentDirectory.Name);
return directorySegments;
}
}
}
if everything goes well, an output will be like:
C:/a/b/c/d/files-samples/formdata.bmp
Segment#=1 Text=C:\
Segment#=2 Text=a
Segment#=3 Text=b
Segment#=4 Text=c
Segment#=5 Text=d
Segment#=6 Text=files-samples
\\127.0.0.1\c$\a\b\c\d\formdata.bmp
Segment#=1 Text=\\127.0.0.1\c$
Segment#=2 Text=a
Segment#=3 Text=b
Segment#=4 Text=c
Segment#=5 Text=d
/usr/home/john/a/b/c/d/formdata.bmp
Segment#=1 Text=C:\
Segment#=2 Text=usr
Segment#=3 Text=home
Segment#=4 Text=john
Segment#=5 Text=a
Segment#=6 Text=b
Segment#=7 Text=c
Segment#=8 Text=d
You can still perform additional filters to GetDirectorySegments (since you have an instance of DirectoryInfo you can check atributes or use the Exist property)

The remote host closed the connection. The error code is 0x800703E3

I am currently trying to generate a CSV using nhibernate. This error does not occur on my development enviroment but it does on the live site that it's being used on. I have tried fiddling with time out's but this does not seem to have any effect as it's timing out way before it should. The timing is completely random, sometimes it'll be 3 seconds before it times out the next it will be 10 seconds. There doesn't seem to be any real consistancy in the timing.
Stack Trace:
System.Web.HttpException: The remote host closed the connection. The error code is 0x800703E3.
at System.Web.Hosting.IIS7WorkerRequest.RaiseCommunicationError(Int32 result, Boolean throwOnDisconnect)
at System.Web.Hosting.IIS7WorkerRequest.ExplicitFlush()
at System.Web.HttpResponse.Flush(Boolean finalFlush)
at Reports.CustomCSVWriter.WritetoHttpStream(String filename, Boolean header)
The code is as follows:
public class ProductSpreadSheetDownload : CustomCSVWriter
{
protected override string[] GetCollection()
{
Page.Server.ScriptTimeout = 300;
IList<Product> products = new List<Product>();
IStockScheme stockScheme = Fabric.ObjectProvider.Get<IStockScheme>();
ICriteria criteria = CoreHttpModule.Session.CreateCriteria(typeof(Product))
.Add(NHibernate.Expression.Expression.IsNotNull(Product.STOCK_CODE))
.Add(NHibernate.Expression.Expression.Eq(Product.IS_VISIBLE_ON_WEBSITE, true))
.Add(NHibernate.Expression.Expression.Eq(Product.STOCK_TYPE, StockType.StockItem))
.Add(NHibernate.Expression.Expression.Not(NHibernate.Expression.Expression.Like(Product.NAME, "%*%")));
AddCustomCriteria(criteria);
products = criteria.List<Product>();
products = Product.RemoveOrphanedAndUnrooted((List<Product>)products);
Product[] productArray = new Product[products.Count];
products.CopyTo(productArray, 0);
double?[] levels = stockScheme.GetStock(productArray, false);
List<string> productStringList = new List<string>();
IProductMapper mapper = Fabric.ObjectProvider.Get<IProductMapper>();
var rootUrl = Fabric.SettingsProvider.ReadSetting<string>("RootUrl", string.Empty);
string showOutOfStock = Page.Request.QueryString["ShowOutOfStock"];
int minStockLevel = int.MinValue;
if (showOutOfStock == "False")
minStockLevel = 0;
for (int i = 0; i < productArray.Length; i++)
{
if (levels[i] > minStockLevel && levels[i] != null && productArray[i].Parent != null && productArray[i].Parent.IsVisibleOnWebsite)
{
StringBuilder productStringBuilder = new StringBuilder();
productStringBuilder.AppendFormat("{0}, ", CleanString(productArray[i].Name));
productStringBuilder.AppendFormat("{0}, ", CleanString(productArray[i].StockCode));
productStringBuilder.AppendFormat("{0}, ", levels[i]);
productStringBuilder.AppendFormat("{0}, ", mapper.GetUrl(productArray[i]) );
productStringBuilder.AppendFormat("{0}, ", CleanString(productArray[i].Category));
productStringBuilder.AppendFormat("{0}, ", CleanString(productArray[i].SubCategory));
productStringBuilder.AppendFormat("{0}, ", CleanString(mapper.GetText(productArray[i], "Description")));
productStringBuilder.AppendFormat("{0}, ", mapper.GetImageUrl(productArray[i], "Main"));
AddCustomFields(productStringBuilder, mapper);
productStringList.Add(productStringBuilder.ToString().Trim().TrimEnd(','));
}
}
string[] productstrings = new string[productStringList.Count];
productStringList.CopyTo(productstrings, 0);
return productstrings;
}
/// <summary>
/// Override this method to add custom criteria to the feed
/// </summary>
/// <example>
/// criteria.Add(NHibernate.Expression.Expression.Eq(Product.IS_VISIBLE_ON_WEBSITE, true));
/// </example>
protected virtual void AddCustomCriteria(ICriteria criteria) {}
/// <summary>
/// Override this method to add custom fields to the CSV output
/// </summary>
/// <example>
/// productStringBuilder.AppendFormat("{0}, ", mapper.GetImageUrl(productArray[i], "Main"));
/// </example>
protected virtual void AddCustomFields(StringBuilder productStringBuilder, IProductMapper mapper) { }
protected override string Headers()
{
string headers = "Name, Stockcode, Stock_Level, URL, Category, SubCategory, Description, Main Image URL";
return headers;
}
/// <summary>
/// Removes characters that are not safe in a CSV file.
/// </summary>
protected static string CleanString(string stringToClean)
{
return string.IsNullOrEmpty(stringToClean) ? string.Empty : stringToClean.Replace("\n", " ").Replace(',', ' ');
}
}
}

Categories

Resources