RavenDb increased startup time of winform app - c#

I use ravendb as embedded database in my winforms project. Everything works as it should but I do need to check with someone startup time of winform main window. When I'm added IDocumentStore initialization startup time is increased by 5,6 seconds.
inside MainForm.cs I have
private IDocumentStore store = new EmbeddableDocumentStore {
RunInMemory = false };
public MainForm()
{
InitializeComponent();
store.Initialize();
}
am I doing something wrong here with IDocumentStore instance ?

If you don't need to access the database right away, you might consider launching the application first, and then initializing it in a separate thread. You'd have to have some kind of "loading..." indicator in your UI, and a flag to check if the initialization is complete so you don't attempt to access the database before it is fully initialized.

No, this an Embedded instance and it takes RavenDB a few seconds to initialize the store, that is expected.

Related

Settings don't appear on windows startup

I have a c# application that launches during startup with the next code below.
On the first windows form I have two textboxes that should be filled with data from Properties.Settings.Default, but they are empty.
If I close the app and start it again, the textboxes are filled with the correct values.
What can be the issue?
RegistryKey rk = Registry.CurrentUser.OpenSubKey
("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
rk.SetValue("", Application.ExecutablePath);
I set the values in the constructor of the form with the following code:
if (Properties.Settings.Default.dbusername != string.Empty)
{
textBoxLoginUsername.Text = Properties.Settings.Default.dbusername;
string readable = EncryptionHelper.Decrypt(Properties.Settings.Default.dbpassword);
textBoxLoginPassword.Text = readable;
}
Your code shows a registry key assignment that is potentially problematic.
First, it attempts to set the default ("") value of
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run
It should be making named key for your startup app e.g.
Second, is it being set in the startup app itself? This is contrary to Microsoft documentation.
Run and RunOnce Registry Keys -
A program that is run from any of these keys should not write to the key during its execution because this will interfere with the execution of other programs registered under the key.
Instead, we'll "do the right thing" by establishing this key in the installer project for the app:
Moving on...
Settings
Showing a "mystery line" like:
string readable = EncryptionHelper.Decrypt(Properties.Settings.Default.dbpassword)
makes it more difficult to diagnose the question that you actually asked. The points made by Panagiotis Kanavos are excellent, but notice that we're talking about that now instead of your original ask. I suggest you solve the main issue first using a Minimal Reproducible Example leaving out the authentication scheme. Then we take the straightforward case of two startup settings:
The textboxes are initialized here:
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
textBoxLoginUsername.Text = Properties.Settings.Default.dbusername;
textBoxLoginPassword.Text = Properties.Settings.Default.dbpassword;
}
}
And after installing the app and restarting the PC we see that things are "so far so good".
Things to check
Without seeing more code, I can only make general suggestions.
Consider writing a startup log file to your app's AppData folder tracing values at various execution points.
Look for uncaught or "swallowed" exceptions that might skip your textbox initialization code.
Check for race condition where Properties.Settings.Default.Save() might be being called before textboxes are initialized.
Since there's "probably" a mechanism for saving login changes, make sure any event handlers are attached after the InitializeComponents has run. For example:
Initializing a Persist scheme
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
textBoxLoginUsername.Text = Properties.Settings.Default.dbusername;
textBoxLoginPassword.Text = Properties.Settings.Default.dbpassword;
buttonLogin.Click += onClickLogin;
}
private void onClickLogin(object? sender, EventArgs e)
{
if(tryLoginWithCredentials())
{
Properties.Settings.Default.dbusername = textBoxLoginUsername.Text;
Properties.Settings.Default.dbpassword = textBoxLoginUsername.Text;
Properties.Settings.Default.Save();
Text = $"Logged in as {Properties.Settings.Default.dbusername}";
}
}
private bool tryLoginWithCredentials() => true; // Succeeded (for testing purposes).
}

WPF cannot close Application instance for running it a second time

I have an Console Application started as [STAThread].
That application should open a seperate Wpf UI for entering some settings.
The functions for that:
private static void openUI()
{
var application = new System.Windows.Application();
//referenced project in the same solution
var ui = new ManagerUI.MainWindow();
//blocks execution
application.Run(ui);
application.Shutdown();
}
Opening the UI for the first time works as expected.
The problem occurs when opening the UI for the second time.
I get an System.InvalidOperationException, saying that I cannot run more than one Application-Instance in the same AppDomain.
For saving ram, it must be closed between the operations.
I also tried to create the System.Windows.Application in the constructor.
But as soon as I run the application the second time, I get a very similiar exception.
The InitializeComponents() method of the UI throws an System.InvalidOperationException, saying that the Object is going to be terminated.
The StackTraces shows that the error appears when the xaml is parsed, so I conclude it cannot open it, because it is still opened by the first execution.
Neither calling ui.Close() nor calling application.Shutdown() solves the problem (Environment.Exit() closes everything, including my Console Application).
The ram profiler indicates, not everything was closed correctly because it shows an higher use after the Window was closed, than before it was opened in the firts place.
How do I properly close the Application instance, or how do I re-use it to run an Wpf Application multiple times?
Having looked at the source code for the Application class, it doesn't look like you will be able to work around this, as various static fields are initialized by the class constructor:
public Application()
{
...
lock(_globalLock)
{
if (_appCreatedInThisAppDomain == false)
{
...
_appInstance = this;
...
_appCreatedInThisAppDomain = true;
}
else
{
throw new InvalidOperationException(...);
}
}
}
...
static private object _globalLock;
static private bool _appCreatedInThisAppDomain;
static private Application _appInstance;
...
Basically the constructor sets _appCreatedInThisAppDomain to true, and as that field is private you have no way of setting it back*.
I think the only way of achieving something similar to what you want is to write a separate WPF application, then use the Process class to launch that from your console application. Alternatively, you could theoretically create a separate AppDomain to host your WPF stuff but that would be a lot more complicated.
[*] other than using Reflection, but let's not go there!
You may create a class that derives from MarshalByRefObject:
public class AppDomainWrapper : MarshalByRefObject
{
public void openUI()
{
var application = new System.Windows.Application();
var ui = new Window();
application.Run(ui);
application.Shutdown();
}
}
...and execute its openUI() method in its own application domain:
[STAThread]
static void Main(string[] args)
{
const int n = 2;
for (int i = 0; i < n; ++i)
{
AppDomain appDomain = AppDomain.CreateDomain("AppDomain");
AppDomainWrapper application = appDomain.CreateInstanceAndUnwrap(typeof(AppDomainWrapper).Assembly.FullName, typeof(AppDomainWrapper).FullName) as AppDomainWrapper;
application.openUI();
AppDomain.Unload(appDomain);
}
}
Have a look at this question:Does a WPF Application Actually Need Application.Run?.
Basically it says, that you can open windows using window.ShowDialog() method without Application instance
The think is that Application.Run does not do anything important but run Dispatcher loop. ShowDialog have its own Dispatcher. You can create Application singleton instance however, since it contains some shared resources.
Hack(run it after application.Shutdown()). I use this in tests:
var field = typeof(Application).GetField(
"_appCreatedInThisAppDomain",
BindingFlags.Static | BindingFlags.NonPublic) ??
throw new InvalidOperationException(
"Field is not found: _appCreatedInThisAppDomain.");
field.SetValue(null, false);
Steven Rands shows the problem.
I have the same problem in an external add-in. But I need an application object for xaml resources and a valid Application.Current.
In my eyes this is a bug. If you call Shutdown() this member should also be reset to false.

How do I prevent two instances of my application from loading after updating using ClickOnce?

I have an application that I am deploying using ClickOnce. I am using the default InstallUpdateUpdateSyncWithInfo() method provided here. I made two changes though; I made the method public and static as I am calling it from a static class. I know bad practices. This is some lazy code just to try out ClickOnce.
Everytime the application updates it loads two instances, the old one and the new one.
Other than that though I am calling the method in my app.xaml.cs like this:
public partial class App : Application
{
private void Application_Startup(object sender, StartupEventArgs e)
{
MainWindow window = new MainWindow();
CheckForUpdates.InstallUpdateSyncWithInfo();
window.Show();
}
}
I thought if I call Window.Show() after checking for an Update it would call the Application.Restart() method in InstallUpdateUpdateSyncWithInfo() before the old version could load, but this is not the case.
Does anyone know how I can prevent two instances of my application from loading after the application is updated?
There was another post on Stack Overflow which from the title, I thought would directly address this question, but I did not see how the poster modified his code to prevent two instances from loading.
There's no need to write the auto-update code yourself. First, I would remove your update code.
Next right-click on your C# project and select Properties. Then go to Publish and click Updates.... Tick the checkbox so your application checks for updates and ClickOnce will handle the rest.

know when a new thread was created in the AppDomain your application is running after?

I would like to know if there is any way to get an event (or something else) that tells you when a new thread was created on your appdomain (C# application)? The basic idea is that when a new thread is created I need to "initialize" the thread with some settings.
I do not want to go all over my code and do that, as I don't know what future will hold.
Create a thread static variable, and initialize anything you need in the constructor.
class ThreadEnvironmentSettings
{
[ThreadStatic]
public static readonly ThreadEnvironmentSettings Settings =
new ThreadEnvironmentSettings();
public ThreadEnvironmentSettings()
{
SetupJavaEnvironment();
}
public void EnsureSetup(){
// Doesn't do anything but required to 'touch' the thread variable
}
}
Then before calling any methods that require an established environment:
ThreadEnvironmentSettigns.Settings.EnsureSetup();
I assume that java loaders execute on the other process. And .NET code just specifies correct arguments for the command line - then you can use environment variables for the whole process.
Environment variables are global to the whole process (that is all threads will have access to them even newly created ones). Here's how to set a variable in C#.

A question about making a C# class persistent during a file load

Apologies for the indescriptive title, however it's the best I could think of for the moment.
Basically, I've written a singleton class that loads files into a database. These files are typically large, and take hours to process. What I am looking for is to make a method where I can have this class running, and be able to call methods from within it, even if it's calling class is shut down.
The singleton class is simple. It starts a thread that loads the file into the database, while having methods to report on the current status. In a nutshell it's al little like this:
public sealed class BulkFileLoader {
static BulkFileLoader instance = null;
int currentCount = 0;
BulkFileLoader()
public static BulkFileLoader Instance
{
// Instanciate the instance class if necessary, and return it
}
public void Go() {
// kick of 'ProcessFile' thread
}
public void GetCurrentCount() {
return currentCount;
}
private void ProcessFile() {
while (more rows in the import file) {
// insert the row into the database
currentCount++;
}
}
}
The idea is that you can get an instance of BulkFileLoader to execute, which will process a file to load, while at any time you can get realtime updates on the number of rows its done so far using the GetCurrentCount() method.
This works fine, except the calling class needs to stay open the whole time for the processing to continue. As soon as I stop the calling class, the BulkFileLoader instance is removed, and it stops processing the file. What I am after is a solution where it will continue to run independently, regardless of what happens to the calling class.
I then tried another approach. I created a simple console application that kicks off the BulkFileLoader, and then wrapped it around as a process. This fixes one problem, since now when I kick off the process, the file will continue to load even if I close the class that called the process. However, now the problem I have is that cannot get updates on the current count, since if I try and get the instance of BulkFileLoader (which, as mentioned before is a singleton), it creates a new instance, rather than returning the instance that is currently in the executing process. It would appear that singletons don't extend into the scope of other processes running on the machine.
In the end, I want to be able to kick off the BulkFileLoader, and at any time be able to find out how many rows it's processed. However, that is even if I close the application I used to start it.
Can anyone see a solution to my problem?
You could create a Windows Service which will expose, say, a WCF endpoint which will be its API. Through this API you'll be able to query services' status and add more files for processing.
You should make your "Bulk Uploader" a service, and have your other processes speak to it via IPC.
You need a service because your upload takes hours. And it sounds like you'd like it to run unattended if necessary,, and you'd like it to be detached from the calling thread. That's what services do well.
You need some form of Inter-Process Communication because you'd like to send information between processes.
For communicating with your service see NetNamedPipeBinding
You can then send "Job Start" and "Job Status" commands and queries whenever you feel like to your background service.

Categories

Resources