Unresponsive UI using background worker, processing files are very slow.
Two different issues encountered here. GDpicture SDK is used for image processing. CPU Utilization is bare minimum, how can I maximize performance, ultimately have responsive and fast wpf application.
namespace OCR
{
public partial class MainWindow : Window
{
BackgroundWorker bw;/*= new BackgroundWorker();*/
private SynchronizationContext threadSyn = null;
string log_cap = string.Empty;
List<string> log_list = new List<string>();
string value = "Merged";
public MainWindow()
{
try
{
InitializeComponent();
InitializeBackgroundWorker();
File_process();
string configpath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"path.txt");
string[] configfile = File.ReadAllLines(configpath);
if (configfile.Length > 1)
{
ip.Text = configfile[0];
op.Text = configfile[1];
ex_tb.Text = configfile[2];
Protb.Text = configfile[3];
}
cbPDFConform.Items.Clear();
for (int i = 0; i < Enum.GetNames(typeof(PdfConformance)).Length - 1; i++)
{
ComboBoxItem cbi = new ComboBoxItem();
cbi.Content = Enum.GetName(typeof(PdfConformance), (PdfConformance)i);
PdfConformance test = (PdfConformance)i;
cbi.Tag = (PdfConformance)i;
cbPDFConform.Items.Add(cbi);
}
cbPDFConform.SelectedIndex = 0;
cbProcessorCount.Items.Clear();
for (int i = 1; i <= Environment.ProcessorCount; i++)
{
cbProcessorCount.Items.Add(i.ToString());
if (Environment.ProcessorCount / 2 == i) { cbProcessorCount.SelectedIndex = i - 1; }
}
LicenseManager oLicenseManager = new LicenseManager();
oLicenseManager.RegisterKEY("");
configpath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"path.txt");
configfile = File.ReadAllLines(configpath);
if (configfile.Length > 1)
{
ip.Text = configfile[0];
op.Text = configfile[1];
ex_tb.Text = configfile[2];
Protb.Text = configfile[3];
}
GrantAccess(ip.Text);
GrantAccess(op.Text);
GrantAccess(ex_tb.Text);
GrantAccess(Protb.Text);
threadSyn = SynchronizationContext.Current;
}
catch (Exception e1)
{ MessageBox.Show("e1" + e1.Message); }
}
private void InitializeBackgroundWorker()
{
bw = new BackgroundWorker();
bw.DoWork += Bw_DoWork;
bw.WorkerSupportsCancellation = true;
}
public async void File_process()
{
await Task.Run(() => converttiffpdfreducer());
}
private void Bw_DoWork(object sender, DoWorkEventArgs e)
{
this.Dispatcher.Invoke(() =>
{
try
{
using (StreamWriter sw = new StreamWriter(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"path.txt"), false))
{
sw.WriteLine(ip.Text);
sw.WriteLine(op.Text);
sw.WriteLine(ex_tb.Text);
sw.WriteLine(Protb.Text);
sw.Close();
}
ParallelOptions parallelOptions = new ParallelOptions();
parallelOptions.MaxDegreeOfParallelism = int.Parse(cbProcessorCount.SelectedItem.ToString());
var watch1 = new System.Diagnostics.Stopwatch();
watch1.Start();
converttiffpdfreducer();
//deletenew();
watch1.Stop();
TimeSpan ts1 = watch1.Elapsed;
ts1.ToString("mm\\:ss");
if (MergeChk.IsChecked == false)
{
value = "OCRed";
}
WriteLn("All documents have been successfully " + value + " " + ts1 + " " + DateTime.Now +" "+Environment.UserName);
}
catch (Exception DOwork)
{ MessageBox.Show("e2 " + DOwork.Message); }
});
}
private void GrantAccess(string fullPath)
{
DirectoryInfo dInfo = new DirectoryInfo(fullPath);
DirectorySecurity dSecurity = dInfo.GetAccessControl();
dSecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.FullControl, InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.NoPropagateInherit, AccessControlType.Allow));
dInfo.SetAccessControl(dSecurity);
}
private string[] mutliocr(string[] arr)
{
string box = string.Empty;
string box1 = string.Empty;
try
{
string filepath = string.Empty;
string outpath = ex_tb.Text;
if (MergeChk.IsChecked == true)
{ filepath = op.Text; }
else if (MergeChk.IsChecked == false)
{ filepath = Protb.Text; }
System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke((Action)(() =>
{
Thread.CurrentThread.IsBackground = true;
var watch2 = new System.Diagnostics.Stopwatch();
watch2.Start();
string[] getfilearray = arr;
for (int f = 0; f < getfilearray.Length; f++)
{
string dirName = Directory.GetParent(getfilearray[f]).FullName;
string folder = Directory.GetParent(getfilearray[f]).FullName;
box = Path.GetDirectoryName(getfilearray[f]);
box1 = Path.GetDirectoryName(box);
string getextension = Path.GetExtension(getfilearray[f]);
string[] newF = Directory.EnumerateFiles(dirName, "*.*", SearchOption.AllDirectories).ToArray();
string FN = Directory.GetParent(getfilearray[f]).Name;
string ocrfolder = (new FileInfo(getfilearray[f]).Directory.FullName);
string filen = Path.Combine(ocrfolder, folder, FN + "-ocr" + getextension);
string dict = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Redist", "OCR");
if (!Directory.Exists(ocrfolder))
{
Directory.CreateDirectory(ocrfolder);
}
GrantAccess(ocrfolder);
GdPicturePDF oGdPicturePDF = new GdPicturePDF();
oGdPicturePDF.OcrPagesDone += OcrPagesDone;
void OcrPagesDone(GdPictureStatus status1)
{
if (oGdPicturePDF.SaveToFile(filen) == GdPictureStatus.OK)
{ }
else
MessageBox.Show("PDF: The OCR-ed file has failed to save. Status: " + oGdPicturePDF.GetStat().ToString());
}
GdPictureStatus status = GdPictureStatus.OK;
if (oGdPicturePDF.LoadFromFile(getfilearray[f], false) == GdPictureStatus.OK)
if (status == GdPictureStatus.OK)
{
if (oGdPicturePDF.OcrPages_4("*", 0, "eng", dict, "", 300, OCRMode.FavorSpeed, 1, true) == GdPictureStatus.OK)
if (status == GdPictureStatus.OK)
{ }
else
{ MessageBox.Show("PDF: The OCR process has failed. Status: " + status.ToString()); }
}
else
{ MessageBox.Show("PDF: The PDF file has failed to load. Status: " + status.ToString()); }
oGdPicturePDF.Dispose();
GrantAccess(getfilearray[f]);
File.Delete(getfilearray[f]);
watch2.Stop();
TimeSpan ts2 = watch2.Elapsed;
ts2.ToString("mm\\:ss");
WriteLn(" OCR pages " + filen.Replace(op.Text, "") + " " + ts2 + " " + DateTime.Now);
}
if (MergeChk.IsChecked == true)
{
foreach (string str in Directory.EnumerateFiles(op.Text, "*.pdf", SearchOption.AllDirectories).ToArray())
{
if (Path.GetFileNameWithoutExtension(str).EndsWith("-ocr"))
File.Move(str, Path.Combine(Path.GetDirectoryName(str), Path.GetFileNameWithoutExtension(str).Substring(0, Path.GetFileNameWithoutExtension(str).Length - 4) + ".pdf"));
}
}
if (MergeChk.IsChecked == false)
{
FileSystem.MoveDirectory(Protb.Text, op.Text, UIOption.AllDialogs);
Directory.CreateDirectory(Protb.Text);
string FF = string.Empty;
foreach (string str in Directory.EnumerateFiles(op.Text, "*.pdf", SearchOption.AllDirectories))
{
if (Path.GetFileNameWithoutExtension(str).EndsWith("-ocr"))
File.Move(str, Path.Combine(Path.GetDirectoryName(str), Path.GetFileNameWithoutExtension(str).Substring(0, Path.GetFileNameWithoutExtension(str).Length - 4) + ".pdf"));
}
}
}));
}
catch (Exception mul)
{
}
return arr;
}
public static string browseFolder()
{
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
System.Windows.Forms.FolderBrowserDialog fbd = new System.Windows.Forms.FolderBrowserDialog();
System.Windows.Forms.DialogResult result = fbd.ShowDialog();
string path = string.Empty;
if (result == (System.Windows.Forms.DialogResult)MessageBoxResult.OK)
{
path = fbd.SelectedPath;
if (path[path.Length - 1] != '\\')
{
path = path + "\\";
}
}
return path;
}
private string[] converttiffpdfreducer()
{
string[] dir = null;
string box = string.Empty;
string box1 = string.Empty;
string[] gg = null;
try
{
string filepath = ip.Text;
string outpath = Protb.Text;
System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke((Action)(() =>
{
PdfConformance optPDFConform = PdfConformance.Unknown;
dir = Directory.EnumerateDirectories(filepath, "*.*", SearchOption.AllDirectories).Where(l => l.Length != 0).OrderBy(f => f).ToArray();
for (int ad = 0; ad < dir.Length; ad++)
{ string[] getfilearray = Directory.EnumerateFiles(dir[ad], "*.*", SearchOption.AllDirectories).ToArray();
if (getfilearray.Length == 0)
break;
if (getfilearray.Length != 0)
for (int f = 0; f < getfilearray.Length; f++)
{
string getext = Path.GetExtension(getfilearray[f]);
string fd = Path.GetDirectoryName(getfilearray[f]);
string op_path = fd.Replace(filepath, Protb.Text);
string getextension = Path.GetExtension(getfilearray[f]);
string dict = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Redist", "OCR");
string outputPath = fd.Replace(filepath, outpath);
string FNAME = Path.GetFileNameWithoutExtension(getfilearray[f]);
string fn = Path.GetDirectoryName(getfilearray[f]).Replace(filepath, outpath);
string filen = Path.Combine(outputPath, fn, FNAME + ".pdf");
string savefile = Path.Combine(op_path, filen);
string pathString = getfilearray[f];
box = Path.GetDirectoryName(getfilearray[f]);
box1 = Path.GetDirectoryName(box);
using (GdPictureDocumentConverter oConverter = new GdPictureDocumentConverter()) {
GdPictureStatus status = new GdPictureStatus();
if (Path.GetExtension(getfilearray[f]).ToUpper() == ".PDF")
{
status = oConverter.LoadFromFile(getfilearray[f], GdPicture14.DocumentFormat.DocumentFormatPDF);
}
else if (Path.GetExtension(getfilearray[f]).ToUpper() == ".TIF" || Path.GetExtension(getfilearray[f]).ToUpper() == ".TIFF")
{
status = oConverter.LoadFromFile(getfilearray[f], GdPicture14.DocumentFormat.DocumentFormatTIFF);
}
else if (Path.GetExtension(getfilearray[f]).ToUpper() == ".JPG")
{
status = oConverter.LoadFromFile(getfilearray[f], GdPicture14.DocumentFormat.DocumentFormatJPEG);
}
if (status == GdPictureStatus.OK)
{
if (!Directory.Exists(op_path))
{
Directory.CreateDirectory(op_path);
}
GrantAccess(op_path);
optPDFConform = (PdfConformance)((ComboBoxItem)cbPDFConform.SelectedItem).Tag;
status = oConverter.SaveAsPDF(savefile, optPDFConform);
if (status == GdPictureStatus.OK)
{ }
else
{ }
}
else
{ }
}
}
string BOXX = box.Replace(ip.Text, Protb.Text);
string[] Arr = Directory.EnumerateFiles(BOXX, "*.pdf", SearchOption.AllDirectories).ToArray();
if (MergeChk.IsChecked == true)
{ merge(Arr); }
else if (MergeChk.IsChecked == false)
{
mutliocr(Arr);
}
}
}));
}
catch (Exception ee)
{ }
return dir;
}
private string[] merge(string[] arr)
{
string box = string.Empty;
string box1 = string.Empty; string[] gg = null;
System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke((Action)(() =>
{
box = Path.GetDirectoryName(arr[0]);
box1 = Path.GetDirectoryName(box);
string dirName = Directory.GetParent(arr[0]).FullName;
string BOXFILES = Path.GetDirectoryName(dirName);
string folder = Directory.GetParent(arr[0]).FullName.Replace(Protb.Text, op.Text);
string ocrfolder = (new FileInfo(arr[0]).Directory.FullName).Replace(Protb.Text, op.Text);
string fn = Directory.GetParent(arr[0]).Name;
string filen = Path.Combine(ocrfolder, folder, fn + ".pdf");
if (!Directory.Exists(ocrfolder))
{
Directory.CreateDirectory(ocrfolder);
}
GrantAccess(ocrfolder);
using (GdPicturePDF oGdPicturePDF = new GdPicturePDF())
{
GdPictureStatus status = oGdPicturePDF.MergeDocuments(ref arr, filen);
if (status == GdPictureStatus.OK)
{ }
else
{ }
oGdPicturePDF.Dispose();
}
Directory.Delete(box, true);
string BOXX = box.Replace(Protb.Text, op.Text);//op
string[] files = Directory.EnumerateFiles(BOXX, "*.pdf", SearchOption.AllDirectories).ToArray();
if (MergeChk.IsChecked == true)
{ mutliocr(files); }
}));
return gg;
}
private void inbtn_Click(object sender, RoutedEventArgs e)
{
try
{ ip.Text = browseFolder(); }
catch (Exception e7)
{ MessageBox.Show("e7" + e7.Message); }
}
private void obtn_Click(object sender, RoutedEventArgs e)
{
try
{ op.Text = browseFolder(); }
catch (Exception e8)
{ MessageBox.Show("e8" + e8.Message); }
}
private void start_btn_Click(object sender, RoutedEventArgs e)
{
if (!bw.IsBusy)
{
// Cancel the asynchronous operation.
this.bw.CancelAsync();
// Disable the Cancel button.
bw.RunWorkerAsync();
start_btn.Content = "Stop";
//this.Status.Content = "Running....";
}
else
{
bw.CancelAsync();
start_btn.Content = "Start";
//this.Status.Content = "Stopped....";
}
}
private void pro_btn_Click(object sender, RoutedEventArgs e)
{
try
{ Protb.Text = browseFolder(); }
catch (Exception e10)
{ MessageBox.Show("e10" + e10.Message); }
}
private void excep_Click(object sender, RoutedEventArgs e)
{
try
{ ex_tb.Text = browseFolder(); }
catch (Exception e11)
{ MessageBox.Show("e111" + e11.Message); }
}
private void WriteLn(string text)
{
logtb.Dispatcher.BeginInvoke(new Action(() =>
{
logtb.Text += text + Environment.NewLine;
}));
log_list.Add(text);
log_cap = text + Environment.NewLine + log_cap;
using (StreamWriter sw = new StreamWriter(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"FileProcessing_log.txt"), false))
{
foreach (string l in log_list)
sw.WriteLine(l);
sw.Close();
}
}
}
}
The point of a BackgroundWorker is to push things off the UI thread. You do that, but then in Bw_DoWork you immediately push things back the UI thread, with this.Dispatcher.Invoke, which blocks the worker thread until the work now running on the UI thread completes.
Basically: remove that this.Dispatcher.Invoke call, and just run the code on the worker. If you need to touch the UI, then you'll need to be on the UI thread for those bits, but only those buts.
Likewise, I doubt that mutliocr should be using dispatch invoke, and it certainly shouldn't change the UI thread to being a background thread (Thread.CurrentThread.IsBackground = true;).
Your code is very very smelly and ugly. You seem to follow absolutely no naming convention at all. Locals and class members are camelCase and PascalCase and some use no casing at all and others use underscores. You should really review you code carefully with many aspects in mind and clean it up. There are some redundancies too.
A really bad habbit of yours is the excessive use of the Dispatcher. For example, you create a background thread and post the complete! work of this thread back to the Dispatcher/UI thread. A huge waste of resources and elimination of any multithreading benefit.
You don't want to put all your work on the Dispatcher. You want to offload CPU intensive eork to a background thread. You want to make use of asynchronous APIs where possible. Because you want to keep the UI responsive. Dispatcher means UI thread.
Some highly important points of interest
GrantAccess implementation is a severe security violation of user rights. Don't modify access rules. Rather filter and ignore resources where the current user is not authorized for access. What is especially critical, is that you never revert the access rights to the original state.
As a general rule: don't execute IO related code (e.g., database, HTTP streams, file IO) on a background thread. Use async APIs instead. Use threading only for CPU bound work (e.g. computations, conversions).
File has an async API you should always use. For example File.OpenRead returns a FileStream which exposes a FileStream.ReadAsnyc member. if you need more convenience when handling files like read line by line, then wrap the FileStream into a StreamReader/StreamWriter and use members like StreamReader.ReadLineAsync
To avoid Dispatcher calls, pass the required UI values to the concurent methods as argument. Better use data binding (which won't eliminate the cross threading issues writing, but would make your code more readable and eliminates Dispatcher invocation to read the values). Take alook at the refactored File_process method below. It shows how to pass UI values as argument to the converttiffpdfreducer method which is then executed on a background thread.
Consider to add cancellation support to to the longrunning converttiffpdfreducer()
Avoid calling ToArray or ToList on an IEnumerable. Those methods are finalizers that immediately execute the originally deferred LINQ queries.
Don't call ToArray or ToList on the result of EnumerateFiles and its likes. Those methods are used to improve performance as they return the filesystem objects item by item. This is especially important if you recursively iterate over the complete filesystem structure. If the filesystem tree is very deep and broad, calling ToArray will force the itereation to complete and then to return all results at once. ToArray on EnumerateFiles is like using GetFiles. You should review your complete code and refactor it properly. You always use EnumerateXYZ wrong!
"The EnumerateFiles and GetFiles methods differ as follows: When you
use EnumerateFiles, you can start enumerating the collection of names
before the whole collection is returned. When you use GetFiles, you
must wait for the whole array of names to be returned before you can
access the array. Therefore, when you are working with many files and
directories, EnumerateFiles can be more efficient."
Use data binding instead of directly accessing UI elements. This allows you to read the properties on the background thread without using the Dispatcher.
Never execute long running operation from the constructor
Never call async code from the constructor
Always keep object instantiation cheep and fast and without hidden performance/resource costs
Never catch Exception. Always catch a specialized exception type.
Don't use empty catch blocks. Either handle the exception if you can or laet it crash your application to give you a chance to fix bugs. When you swallow exceptions bugs will silently creep into your application. You will have a really hard time to discover them. Logging exceptions is not considered handling - rethrow in such case.
You don't have to close a resource explicitly if you declare the resource using the using statement. The implicit call to Dispose once the instruction pointer leaves the using scope will close the resource automatically.
Implementing all the suggestion will significantly speed up your application.
I have refactored only some of your code to show how to properly use async APIs and Task.Run instead of the BackgroundWorker. I have removed every Dispatcher invocation. Instead of direct access to UI elements in order to read their values from the background thread, I have extracted those values before invoking the concurent method and passed those prefetched values as method arguments. If you would use data binding you could read the property values directly and therefore ommit the method parameters.
The MainWindow should be shown manually from App.xaml.cs to allow asynchronous and longrunning initialization of the instance. For this pattern let the class that requires such initialization implement a public InitializeAsync method that can be awaited from the caller's context. Alternatively use Lazy<T> to defer initialization when required e.g., when initialization is depending on explicit access to members.
Although the refactored code will significantly improve the applicatoin's performance, you will have do to do some important refactoring yourself (following the pattern of the already refactored code sections).
Take a look at
InitializeAsync and WriteLnAsync to learn how to use the async file IO API.
converttiffpdfreducer to learn how to use the EnumerateFiles and EnumerateDirectories methods properly in order to significantly improve the performance.
mutliocr, merge and converttiffpdfreducer to learn how pass UI element values as argument in order to avoid Dispatcher invocations.
start_btn_Click and converttiffpdfreducer to learn how to implemnent cancellation and to guard your API against calls during an uninitialized state
App.xaml
<Application Startup="Application_Startup">
</Application>
App.xaml.cs
class App : Application
{
private async void Application_Startup(object sender, StartupEventArgs e)
{
var mainWindow = new MainWindow();
// Because InitializeAsync depends on UI elements,
// we have to wait until the Ui is loaded.
mainWindow.Loaded += OnMainWindowLoaded;
// Either call Show() before initialization or after.
// If before, ensure access to uninitialized members and resources is denied
// e.g. by querying the MainWindow.IsInitialized property in public members and event handlers.
mainWindow.Show();
}
private async void OnMainWindowLoaded(object sender, EventArgs args)
=> await mainWindow.InitializeAsync();
}
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public bool IsInitialized { get; private set; }
private bool IsBusy { get; set; }
private CancellationTokenSource CancellationTokenSource { get; set; }
public MainWindow()
{
InitializeComponent();
CancellationTokenSource = new CancellationTokenSource();
}
// Execute blocking initialization routines asynchronously
public async Task InitializeAsync()
{
if (IsInitialized)
{
return;
}
// Will execute the intesive CPU bound work on a background thread.
await File_process(Cancellationtoken.None);
string configpath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"path.txt");
// Use async API to read/write from/to files and other IO resources
using (FileStream configfile = File.OpenRead(configpath))
{
using (var fileReader = new StreamReader(configfile))
{
var configFileContent = new List<string>();
while (!fileReader.EndOfStream)
{
string lineOfFile = await fileReader.ReadLineAsync();
configFileContent.Add(lineOfFile);
}
if (configFileContent.Any())
{
ip.Text = configFileContent[0];
GrantAccess(configFileContent[0]);
op.Text = configFileContent[1];
GrantAccess(configFileContent[1]);
ex_tb.Text = configFileContent[2];
GrantAccess(configFileContent[2]);
Protb.Text = configFileContent[3];
GrantAccess(configFileContent[3]);
}
}
}
cbPDFConform.Items.Clear();
for (int i = 0; i < Enum.GetNames(typeof(PdfConformance)).Length - 1; i++)
{
ComboBoxItem cbi = new ComboBoxItem();
cbi.Content = Enum.GetName(typeof(PdfConformance), (PdfConformance)i);
PdfConformance test = (PdfConformance)i;
cbi.Tag = (PdfConformance)i;
cbPDFConform.Items.Add(cbi);
}
cbPDFConform.SelectedIndex = 0;
cbProcessorCount.Items.Clear();
for (int i = 1; i <= Environment.ProcessorCount; i++)
{
cbProcessorCount.Items.Add(i.ToString());
if (Environment.ProcessorCount / 2 == i) { cbProcessorCount.SelectedIndex = i - 1; }
}
LicenseManager oLicenseManager = new LicenseManager();
oLicenseManager.RegisterKEY("");
threadSyn = SynchronizationContext.Current;
IsInitialiezd = true;
}
public async Task File_process(CancellationToken cancellationToken)
{
// Read UI values to avoid Dispatcher calls from the background thread
string ipText = ip.Text;
string protbText = Protb.Text;
string opText = op.Text;
// Execute the intesive CPU bound work on a background thread.
await Task.Run(() => converttiffpdfreducer(ipText, protbText, opText, cancellationToken), cancellationToken);
}
private async Task DoWorkAsync(CancellationToken cancellationToken)
{
IsBusy = true;
using (var sw = new StreamWriter(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"path.txt"), false))
{
await sw.WriteLineAsync(ip.Text);
await sw.WriteLineAsync(op.Text);
await sw.WriteLineAsync(ex_tb.Text);
await sw.WriteLineAsync(Protb.Text);
}
try
{
cancellationToken.ThrowIfCancellationRequested();
var watch1 = new System.Diagnostics.Stopwatch();
watch1.Start();
// Consider to add cancellation support to File_process
await File_process(cancellationToken);
watch1.Stop();
TimeSpan ts1 = watch1.Elapsed;
ts1.ToString("mm\\:ss");
if (MergeChk.IsChecked == false)
{
value = "OCRed";
}
await WriteLnAsync("All documents have been successfully " + value + " " + ts1 + " " + DateTime.Now + " " + Environment.UserName, cancellationToken);
IsBusy = false;
}
catch (OperationCanceledException)
{
IsBusy = false;
throw;
}
}
private async Task WriteLnAsync(string text, CancellationToken cancellationToken)
{
logtb.Text += text + Environment.NewLine;
log_list.Add(text);
log_cap = text + Environment.NewLine + log_cap;
using (var sw = new StreamWriter(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"FileProcessing_log.txt"), false))
{
foreach (string l in log_list)
{
cancellationToken.ThrowIfCancellationRequested();
await sw.WriteLineAsync(l);
}
}
}
private async void start_btn_Click(object sender, RoutedEventArgs e)
{
if (!IsInitialized)
{
return;
}
if (IsBusy)
{
// Cancel the longrunning operation.
this.CancellationTokenSource.Cancel();
}
start_btn.Content = "Start";
try
{
await DoWorkAsync(CancellationTokenSource.Token);
}
catch (OperationCanceledException)
{
CancellationTokenSource?.Dispose();
CancellationTokenSource = new CancellationTokenSource();
}
}
private void converttiffpdfreducer(
string ipText,
string protbText,
string opText,
CancellationToken cancellationToken)
{
string[] dir = null;
string box = string.Empty;
string box1 = string.Empty;
string[] gg = null;
PdfConformance optPDFConform = PdfConformance.Unknown;
foreach (var directoryPath in Directory.EnumerateDirectories(ipText, "*.*", SearchOption.AllDirectories).Where(l => l.Length != 0))
{
cancellationToken.ThrowIfCancellationRequested();
foreach (var filePath in Directory.EnumerateFiles(directoryPath, "*.*", SearchOption.AllDirectories))
{
cancellationToken.ThrowIfCancellationRequested();
string getext = Path.GetExtension(filePath);
string fd = Path.GetDirectoryName(filePath);
string op_path = fd.Replace(ipText, protbText);
string getextension = Path.GetExtension(filePath);
string dict = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Redist", "OCR");
string outputPath = fd.Replace(ipText, protbText);
string FNAME = Path.GetFileNameWithoutExtension(filePath);
string fn = Path.GetDirectoryName(filePath).Replace(ipText, protbText);
string filen = Path.Combine(outputPath, fn, FNAME + ".pdf");
string savefile = Path.Combine(op_path, filen);
box = Path.GetDirectoryName(filePath);
box1 = Path.GetDirectoryName(box);
using (GdPictureDocumentConverter oConverter = new GdPictureDocumentConverter())
{
GdPictureStatus status = new GdPictureStatus();
if (Path.GetExtension(filePath).ToUpper() == ".PDF")
{
status = oConverter.LoadFromFile(filePath, GdPicture14.DocumentFormat.DocumentFormatPDF);
}
else if (Path.GetExtension(filePath).ToUpper() == ".TIF" || Path.GetExtension(filePath).ToUpper() == ".TIFF")
{
status = oConverter.LoadFromFile(filePath, GdPicture14.DocumentFormat.DocumentFormatTIFF);
}
else if (Path.GetExtension(filePath).ToUpper() == ".JPG")
{
status = oConverter.LoadFromFile(filePath, GdPicture14.DocumentFormat.DocumentFormatJPEG);
}
if (status == GdPictureStatus.OK)
{
if (!Directory.Exists(op_path))
{
Directory.CreateDirectory(op_path);
}
GrantAccess(op_path);
optPDFConform = (PdfConformance)((ComboBoxItem)cbPDFConform.SelectedItem).Tag;
status = oConverter.SaveAsPDF(savefile, optPDFConform);
if (status == GdPictureStatus.OK)
{ }
else
{ }
}
else
{ }
}
}
}
string BOXX = box.Replace(ipText, protbText);
// TODO::Refactor 'merge' and replace 'ToArray' with 'foreach'
string[] Arr = Directory.EnumerateFiles(BOXX, "*.pdf", SearchOption.AllDirectories).ToArray();
if (MergeChk.IsChecked == true)
{ merge(Arr, protbText); }
else if (MergeChk.IsChecked == false)
{
mutliocr(Arr);
}
}
private string[] merge(string[] arr, string protbText, string opText)
{
string box = string.Empty;
string box1 = string.Empty; string[] gg = null;
System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke((Action)(() =>
{
box = Path.GetDirectoryName(arr[0]);
box1 = Path.GetDirectoryName(box);
string dirName = Directory.GetParent(arr[0]).FullName;
string BOXFILES = Path.GetDirectoryName(dirName);
string folder = Directory.GetParent(arr[0]).FullName.Replace(protbText, opText);
string ocrfolder = (new FileInfo(arr[0]).Directory.FullName).Replace(protbText, opText);
string fn = Directory.GetParent(arr[0]).Name;
string filen = Path.Combine(ocrfolder, folder, fn + ".pdf");
if (!Directory.Exists(ocrfolder))
{
Directory.CreateDirectory(ocrfolder);
}
GrantAccess(ocrfolder);
using (GdPicturePDF oGdPicturePDF = new GdPicturePDF())
{
GdPictureStatus status = oGdPicturePDF.MergeDocuments(ref arr, filen);
if (status == GdPictureStatus.OK)
{ }
else
{ }
oGdPicturePDF.Dispose();
}
Directory.Delete(box, true);
string BOXX = box.Replace(protbText, opText);//op
string[] files = Directory.EnumerateFiles(BOXX, "*.pdf", SearchOption.AllDirectories).ToArray();
if (MergeChk.IsChecked == true)
{ mutliocr(files, protbText, opText); }
}));
return gg;
}
private string[] mutliocr(string[] arr, string protbText, string opText)
{
string box = string.Empty;
string box1 = string.Empty;
try
{
string filepath = string.Empty;
if (MergeChk.IsChecked == true)
{ filepath = opText; }
else if (MergeChk.IsChecked == false)
{ filepath = protbText; }
System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke((Action)(() =>
{
Thread.CurrentThread.IsBackground = true;
var watch2 = new System.Diagnostics.Stopwatch();
watch2.Start();
string[] getfilearray = arr;
for (int f = 0; f < getfilearray.Length; f++)
{
string dirName = Directory.GetParent(getfilearray[f]).FullName;
string folder = Directory.GetParent(getfilearray[f]).FullName;
box = Path.GetDirectoryName(getfilearray[f]);
box1 = Path.GetDirectoryName(box);
string getextension = Path.GetExtension(getfilearray[f]);
string[] newF = Directory.EnumerateFiles(dirName, "*.*", SearchOption.AllDirectories).ToArray();
string FN = Directory.GetParent(getfilearray[f]).Name;
string ocrfolder = (new FileInfo(getfilearray[f]).Directory.FullName);
string filen = Path.Combine(ocrfolder, folder, FN + "-ocr" + getextension);
string dict = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Redist", "OCR");
if (!Directory.Exists(ocrfolder))
{
Directory.CreateDirectory(ocrfolder);
}
GrantAccess(ocrfolder);
GdPicturePDF oGdPicturePDF = new GdPicturePDF();
oGdPicturePDF.OcrPagesDone += OcrPagesDone;
void OcrPagesDone(GdPictureStatus status1)
{
if (oGdPicturePDF.SaveToFile(filen) == GdPictureStatus.OK)
{ }
else
MessageBox.Show("PDF: The OCR-ed file has failed to save. Status: " + oGdPicturePDF.GetStat().ToString());
}
GdPictureStatus status = GdPictureStatus.OK;
if (oGdPicturePDF.LoadFromFile(getfilearray[f], false) == GdPictureStatus.OK)
if (status == GdPictureStatus.OK)
{
if (oGdPicturePDF.OcrPages_4("*", 0, "eng", dict, "", 300, OCRMode.FavorSpeed, 1, true) == GdPictureStatus.OK)
if (status == GdPictureStatus.OK)
{ }
else
{ MessageBox.Show("PDF: The OCR process has failed. Status: " + status.ToString()); }
}
else
{ MessageBox.Show("PDF: The PDF file has failed to load. Status: " + status.ToString()); }
oGdPicturePDF.Dispose();
GrantAccess(getfilearray[f]);
File.Delete(getfilearray[f]);
watch2.Stop();
TimeSpan ts2 = watch2.Elapsed;
ts2.ToString("mm\\:ss");
WriteLn(" OCR pages " + filen.Replace(opText, "") + " " + ts2 + " " + DateTime.Now);
}
if (MergeChk.IsChecked == true)
{
foreach (string str in Directory.EnumerateFiles(opText, "*.pdf", SearchOption.AllDirectories).ToArray())
{
if (Path.GetFileNameWithoutExtension(str).EndsWith("-ocr"))
File.Move(str, Path.Combine(Path.GetDirectoryName(str), Path.GetFileNameWithoutExtension(str).Substring(0, Path.GetFileNameWithoutExtension(str).Length - 4) + ".pdf"));
}
}
if (MergeChk.IsChecked == false)
{
FileSystem.MoveDirectory(protbText, opText, UIOption.AllDialogs);
Directory.CreateDirectory(protbText);
string FF = string.Empty;
foreach (string str in Directory.EnumerateFiles(opText, "*.pdf", SearchOption.AllDirectories))
{
if (Path.GetFileNameWithoutExtension(str).EndsWith("-ocr"))
File.Move(str, Path.Combine(Path.GetDirectoryName(str), Path.GetFileNameWithoutExtension(str).Substring(0, Path.GetFileNameWithoutExtension(str).Length - 4) + ".pdf"));
}
}
}));
}
catch (Exception mul)
{
}
return arr;
}
}
I have a calculation that does I/O I want to send to another thread so on the web site the user can goto the next page without waiting for the calculation to finish. From what I understand are I need to do is call the method like this
var backgroundTask = Task.Run(() => CalculateSet(uow, profile, userId, specialtyCode ));
But when I do this is seems to call one line in the method and goes away.. non of the work is done.
Am I missing something ?
[Fact]
public void Calculation_Xls()
{
string currentDirectory = Directory.GetCurrentDirectory();
string filesDirectory = currentDirectory + "\\Files";
System.Text.Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
var builder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json");
Configuration = builder.Build();
var optionsBuilder = new DbContextOptionsBuilder<RetContext>();
optionsBuilder.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
int i = 0; //outer loop
UnitOfWork uow = new UnitOfWork(new RetContext(optionsBuilder.Options));
using (var stream = System.IO.File.Open(filesDirectory + "\\t2UserProfileDataTwoUserPerSpecialty.xlsx",
FileMode.Open, FileAccess.Read))
{
using (var reader = ExcelReaderFactory.CreateReader(stream))
{
do
{
while (reader.Read())
{
if (i != 0)
{
var userId = reader.GetString(0);
var specialtyCode = reader.GetString(1);
var userProfileElement1_WorkExp = reader.GetValue(2);
var userProfileElement2_VolExp = reader.GetValue(3);
var userProfileElement3_ResExp = reader.GetValue(4);
var userProfileElement4_Pubs = reader.GetValue(5);
var userProfileElement5_AOA = reader.GetValue(6);
var userProfileElement6_Nspecialties = reader.GetValue(7);
var userProfileElement7_PercentApps = reader.GetValue(8);
//Create profile
UserProfileData profile = new UserProfileData();
profile.UserProfileElement1_WorkExp = Convert.ToInt32(userProfileElement1_WorkExp);
profile.UserProfileElement2_VolExp = Convert.ToInt32(userProfileElement2_VolExp);
profile.UserProfileElement3_ResExp = Convert.ToInt32(userProfileElement3_ResExp);
profile.UserProfileElement4_Pubs = Convert.ToInt32(userProfileElement4_Pubs);
profile.UserProfileElement5_Aoa = Convert.ToBoolean(userProfileElement5_AOA);
profile.UserProfileElement6_Nspecialties = Convert.ToInt32(userProfileElement6_Nspecialties);
profile.UserProfileElement7_PercentApps = Convert.ToInt32(userProfileElement7_PercentApps);
//Calculate for set of programs. Selects one row at a time from XLS. BulkInsert into DB
//THIS ONLY RUNS ONE LINE OF THE METHOD
var backgroundTask = Task.Run(() => CalculateSet(uow, profile, userId, specialtyCode ));
//THIS WORKS
//CalculateSet(uow, profile, userId, specialtyCode);
}
i++;
Debug.WriteLine("Bulkcreate complete " + i);
//only process xxx rows
if (i > 1)
{
break;
}
}
} while (reader.NextResult());
}
}
Debug.WriteLine("Should get here quickly and not wait until task is done");
}
private void CalculateSet(UnitOfWork uow, UserProfileData profile, string userId, string specialtyCode)
{
//I CAN HIT THIS BREAKPOINT!
//get specialtyId from code
var specialtyId = uow.RefMedicalSpecialtyRepository
.Find(x => x.Code == specialtyCode).FirstOrDefault().Id;
//NEVER GET TO THIS BREAKPOINT
//loop through all programs for speciality
var programsForSpecialty = uow.RefProgramDetailDataRepository
.Find(x => x.RefMedicalSpecialtyId == specialtyId);
//List for bulk insert
// List<UserProgram> userPrograms = new List<UserProgram>();
//Write a row for each program
foreach (RefProgramDetailData rpdd in programsForSpecialty.ToList())
{
//Get program info
var programProfile = LoadData.Load_RefProgramProfileData(rpdd.Code);
//Calculate results
var userProgram = _calculator.CalculateAll(programProfile, profile, specialtyId, userId);
//If the Program can not be found in program detail then skip insert
if (userProgram == null)
{
Debug.WriteLine("Program NULL");
}
else
{
//Write results to UserProgram
uow.UserProgramRepository.Create(userProgram);
//userPrograms.Add(userProgram);
Debug.WriteLine("Program " + programProfile.ProgramCode);
}
}
//bulk insert
// uow.UserProgramRepository.BulkCreate(userPrograms);
}
}
EDIT 1: I put this in my controller. But it is waiting for the Task to finish before it redirects. Why isn't it redirecting immediately ?
await Task.Run(() => _calculator.CalculateAllSet(_unitOfWork, userProfileData, msId, null));
return RedirectToAction("Index", "Home");
Can you try like that.
[Fact]
public async Task Calculation_Xls()
{
string currentDirectory = Directory.GetCurrentDirectory();
string filesDirectory = currentDirectory + "\\Files";
System.Text.Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
var builder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json");
Configuration = builder.Build();
var optionsBuilder = new DbContextOptionsBuilder<RetContext>();
optionsBuilder.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
int i = 0; //outer loop
UnitOfWork uow = new UnitOfWork(new RetContext(optionsBuilder.Options));
using (var stream = System.IO.File.Open(filesDirectory + "\\t2UserProfileDataTwoUserPerSpecialty.xlsx",
FileMode.Open, FileAccess.Read))
{
using (var reader = ExcelReaderFactory.CreateReader(stream))
{
do
{
while (reader.Read())
{
if (i != 0)
{
var userId = reader.GetString(0);
var specialtyCode = reader.GetString(1);
var userProfileElement1_WorkExp = reader.GetValue(2);
var userProfileElement2_VolExp = reader.GetValue(3);
var userProfileElement3_ResExp = reader.GetValue(4);
var userProfileElement4_Pubs = reader.GetValue(5);
var userProfileElement5_AOA = reader.GetValue(6);
var userProfileElement6_Nspecialties = reader.GetValue(7);
var userProfileElement7_PercentApps = reader.GetValue(8);
//Create profile
UserProfileData profile = new UserProfileData();
profile.UserProfileElement1_WorkExp = Convert.ToInt32(userProfileElement1_WorkExp);
profile.UserProfileElement2_VolExp = Convert.ToInt32(userProfileElement2_VolExp);
profile.UserProfileElement3_ResExp = Convert.ToInt32(userProfileElement3_ResExp);
profile.UserProfileElement4_Pubs = Convert.ToInt32(userProfileElement4_Pubs);
profile.UserProfileElement5_Aoa = Convert.ToBoolean(userProfileElement5_AOA);
profile.UserProfileElement6_Nspecialties = Convert.ToInt32(userProfileElement6_Nspecialties);
profile.UserProfileElement7_PercentApps = Convert.ToInt32(userProfileElement7_PercentApps);
//Calculate for set of programs. Selects one row at a time from XLS. BulkInsert into DB
//THIS ONLY RUNS ONE LINE OF THE METHOD
var backgroundTask = await Task.Run(() => CalculateSet(uow, profile, userId, specialtyCode ));
//THIS WORKS
//CalculateSet(uow, profile, userId, specialtyCode);
}
i++;
Debug.WriteLine("Bulkcreate complete " + i);
//only process xxx rows
if (i > 1)
{
break;
}
}
} while (reader.NextResult());
}
}
Debug.WriteLine("Should get here quickly and not wait until task is done");
}
private void CalculateSet(UnitOfWork uow, UserProfileData profile, string userId, string specialtyCode)
{
//I CAN HIT THIS BREAKPOINT!
//get specialtyId from code
var specialtyId = uow.RefMedicalSpecialtyRepository
.Find(x => x.Code == specialtyCode).FirstOrDefault().Id;
//NEVER GET TO THIS BREAKPOINT
//loop through all programs for speciality
var programsForSpecialty = uow.RefProgramDetailDataRepository
.Find(x => x.RefMedicalSpecialtyId == specialtyId);
//List for bulk insert
// List<UserProgram> userPrograms = new List<UserProgram>();
//Write a row for each program
foreach (RefProgramDetailData rpdd in programsForSpecialty.ToList())
{
//Get program info
var programProfile = LoadData.Load_RefProgramProfileData(rpdd.Code);
//Calculate results
var userProgram = _calculator.CalculateAll(programProfile, profile, specialtyId, userId);
//If the Program can not be found in program detail then skip insert
if (userProgram == null)
{
Debug.WriteLine("Program NULL");
}
else
{
//Write results to UserProgram
uow.UserProgramRepository.Create(userProgram);
//userPrograms.Add(userProgram);
Debug.WriteLine("Program " + programProfile.ProgramCode);
}
}
//bulk insert
// uow.UserProgramRepository.BulkCreate(userPrograms);
}
}
Is there a way for me to link my module in all of my form i'm using c# app and this is my code. This is actually a notification bell that will notify users if he/she has/have notifications. I already linked it on homepage how am i able to do that in all other pages
private void systemNotificationREXS(HomePage module)
{
TextBox Username = (TextBox)module.FindControl("Hide_user");
Label Fullname = (Label)module.FindControl("userfullname");
Label notifLabel = (Label)module.FindControl("notifLabel");
using (con = new SqlConnection(EXCUSESLPCON))
{
using (cmd = new SqlCommand("SYSTEMNOTIFICATIONEXSLIP", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#userfullname", Fullname.Text);
con.Open();
using(adp = new SqlDataAdapter(cmd))
{
using(dt = new DataTable())
{
adp.Fill(dt);
for (int i = 0; i < dt.Rows.Count; i++ )
{
int notifcount = int.Parse(dt.Rows[i]["notifcount"].ToString());
string modulename = dt.Rows[i]["modulename"].ToString();
string modulebody = modulename + "Body";
string moduleLabel = modulename + "Label";
Label namebox = (Label)module.FindControl(modulename);
if (notifcount > 0)
{
namebox.Visible = true;
namebox.Text = notifcount.ToString();
module.FindControl(modulebody).Visible = true;
try
{
module.FindControl(moduleLabel).Visible = true;
}
catch
{
notifLabel.Visible = false;
}
}
else
{
namebox.Visible = false;
module.FindControl(modulebody).Visible = false;
try
{
module.FindControl(moduleLabel).Visible = false;
}
catch
{
notifLabel.Visible = false;
}
}
}
}
}
con.Close();
}
}
}
internal void notificationSystemREXS(string fullname, string hide_user, HomePage modulename)
{
systemNotificationREXS(modulename);
}
Code to linked on homepage:
private void systemNotificationREXS()
{
Notification moduleacc = new Notification();
moduleacc.notificationSystemREXS(userfullname.Text, Hide_user.Text, this);
}
Your method does very simple job, but you have made it complicated and over dependent on the module and other stuff.
The method should return only the notification data for the user and let the caller of the method to decide what to do with the data.
Consider doing following.
public class NotificationData
{
public int NotificationCount {get;set;}
public int ModuleName {get;set;}
}
public class NotificationService
{
public static List<NotificationData> GetNotificationData(string username)
{
var notificationList = new List<NotificationData>();
using (con = new SqlConnection(EXCUSESLPCON))
{
using (cmd = new SqlCommand("SYSTEMNOTIFICATIONEXSLIP", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#userfullname", Fullname.Text);
con.Open();
using(adp = new SqlDataAdapter(cmd))
{
using(dt = new DataTable())
{
for (int i = 0; i < dt.Rows.Count; i++ )
{
var notification = new NotificationData();
notification.NotificationCount = int.Parse(dt.Rows[i]["notifcount"].ToString());
notification.ModuleName = dt.Rows[i]["modulename"].ToString();
}
}
}
}
}
return notificationList
}
}
Now you should use this method from whichever page you want as following.
Let say you want to use it from HomePage. So you may write following code in Page_Load event of HomePage. (I am assuming here that HomePage is a web page and it has all the controls loaded before this code gets executed).
Label userNameLabel = (Label)this.FindControl("userfullname");
var userName = userNameLabelText;
var notificationList = NotificationService.GetNotificationData(userName);
foreach(var notification in notificationList)
{
var modulename = notification.ModuleName;
var notifcount = notification.Count;
string modulebody = modulename + "Body";
string moduleLabel = modulename + "Label";
Label namebox = (Label)this.FindControl(modulename);
if (notifcount > 0)
{
namebox.Visible = true;
namebox.Text = notifcount.ToString();
this.FindControl(modulebody).Visible = true;
try
{
this.FindControl(moduleLabel).Visible = true;
}
catch
{
notifLabel.Visible = false;
}
}
else
{
namebox.Visible = false;
this.FindControl(modulebody).Visible = false;
try
{
this.FindControl(moduleLabel).Visible = false;
}
catch
{
notifLabel.Visible = false;
}
}
}
I hope this should help you resolve your issue.
I am using a recursive function that has a transaction in it, however the transaction causes a "callback requested query abort
abort due to ROLLBACK" error. Here is my code:
public Dictionary<int, string> GetFolders(string connectstring)
{
var connection = new SQLiteConnection(connectstring);
connection.Open();
Dictionary<int, string> folderdictionary = new Dictionary<int, string>();
using (var transaction = connection.BeginTransaction())
{
using (SQLiteCommand command = connection.CreateCommand())
{
command.CommandText = "select * from moz_bookmarks AS bookmarks WHERE type=2";
SQLiteDataReader commandread = command.ExecuteReader();
int current_id = 0;
List<string> currentfolders = new List<string>();
while (commandread.Read()) // <--------------- thrown here
{
var title = commandread.GetString(5);
current_id = commandread.GetInt32(0);
var parent = commandread.GetInt32(3);
List<string> folders = new List<string>();
folder = GetChild(connection, (string)commandread["title"], commandread.GetInt32(3), ref folders, true);
currentfolders.Add(folder);
folderdictionary.Add(current_id, folder);
folder = "";
}
}
transaction.Commit();
}
connection.Close();
return folderdictionary;
}
The recursion itself is in the GetChild function:
private static string GetChild(SQLiteConnection sqlite_connection2, string title, int id, ref List<string> folder, bool recursive, SQLiteTransaction transaction)
{
if (recursive)
folder.Add(title);
using (SQLiteCommand folder_get = sqlite_connection2.CreateCommand())
{
folder_get.Connection = sqlite_connection2;
folder_get.CommandText = "SELECT * FROM moz_bookmarks WHERE id = " + id;
SQLiteDataReader get_folders = folder_get.ExecuteReader();
while (get_folders.Read())
{
if (get_folders.GetInt32(1) == 1)
{
break;
}
else if (get_folders.GetInt32(1) == 2 && get_folders.GetInt32(0) != 1)
{
folder.Add(get_folders["title"].ToString());
if (get_folders.GetInt32(3) != 0 && get_folders.GetInt32(0) != 1)
{
GetChild(sqlite_connection2, (string)get_folders["title"], get_folders.GetInt32(3), ref folder, false);
}
break;
}
}
if (recursive)
folder.Reverse();
get_folders.Close();
}
return string.Join("\\", folder);
}
Without the SQLiteTransaction, the GetChild is a huge memory leak and eventually throws a OutOfMemoryException.