I am working on a Rest API. So far I build a Webview where the user can make inputs and send them to the server. When the server receives the information it will start a program and do some calculations. The problem here is that opening the program needs a lot of time. So the user has to wait for +20 seconds.
The point is that the user will change data of the same object and send them back to the server. When the server gets these data again it has to open the program again so that the user has to wait for another 20 seconds.
The program is referenced as a library. I create an instance of it within the controller class. So each time the server gets a new request it will open an instance, pass the data to the program and return the result to the client.
My question here is: Is there a way to avoid opening an instance for each request and instead open an instance temporarily for each user?
Edit:
The program is written in VBA. It is a configurator which calculates whether an option works out or not. I will access it by creating an instance of it:
Configurator conf = new Configurator
After that you can either create a new position or recall an old one by passing an ID like this:
conf.ID = id;
This process needs a lot of time because the program is collecting a lot of data from a database.
So this is the process I want to skip and instead use the object I created before.
After that you can pass other data to the program/object like height etc.
You can use dependency injection engines like Autofac. Register your program instance onApplicationStart as a singleton instance. Then whenever you want an instance of the program.dll, autofac will give you the same instance according to your defined registration config which is singleton.
Related
I'm working on C# script ConsoleApp with a few dll type projects added.
Overview of the script is this- The script will basically connect to an external ActiveDirectory and do a search on a given OU. Get a list of all users from that OU and then connect via Microsoft Graph API and do 1) Invite the user for B2B and 2) Update some attributes on these invited users in AzureAD.
My solution has a few projects.
ConsoleApp - (this is start of the program)
LogicLayer - DLL. This is where the main logic resides. Such as which users are new in AD, which ones to remove from Azure etc.
DALActiveDirectory - DLL. This is where script will connect to AD and return data back to LogicLayer.
DALGraphAPI - DLL. This is where the script will connect to GraphAPI. Contains functions to get all users, get user by Id, update user attributes etc. Mainly methods here are called from LogicLayer.
PasswordCrypto - Dll. contains function to retrieve encrypted text from a file and decrypt it to get the passwords. Both DALGraphAPI and DALActiveDirectory use respective passwords.
LogFile - dll This is where I have defined a class to create a logfile with its name formatted with timestamp. eg "Log-yyyy_MM_dd_HH_mm_ss_ffff.txt".
Now I want to use LogFile instance to log certain things (such as errors, some debug messages) as control passes from ConsoleApp to LogicLayer to DALActiveDirectory to PasswordCrypto ...and so on. However, I only want one instance of this LogFile class. And no matter where the control is, the app should use that one instance to log to that one log file. If I do this in every class:
LogFile logFile = new LogFile();
then, it creates a new log file (with new name because of the timestamp). I want only one logfile created per full run of the console app. How can I achieve this? One way is to create one instance in ConsoleApp (which is the startup project) and then pass it other classes. I think it will work but is not very elegant solution. I've read something called Singleton pattern on internet but not sure if it applies to this.
Any suggestions?
Here is an example of a singleton pattern.
Private Shared objLoggerTool As LoggerTool
Public Shared Function GetLoggerToolInstance(ByVal strLogPath As String, ByVal iLogLevel As Integer) As LoggerTool
If (objLoggerTool Is Nothing) Then
objLoggerTool = New LoggerTool(strLogPath, iLogLevel)
End If
Return objLoggerTool
End Function
you instantiate the logger as
'instantiate the logger
_loggerTool = LoggerTool.GetLoggerToolInstance(config.LogFilePath, config.LogLevel)
This is a vb.net example from an app I did but it should help you understand how to create the logger and use it.
I am developing a web services project using the ServiceStack framework.
I would like to create a global object(in my case, a SessionManager object for a GDS system I am working against, it has no relation to ASP.NET sessions) to be accessed by all incoming requests.
However, I am facing a problem whereby ASP.NET will create a new instance of my application and thereby create a new instance of my SessionManager a few times in it's life cycle. I verified this by putting a debugging line on Application_Start and Application_End protected methods in the Global.asax class and realized that the Global.asax class starts and end a number of times in its life cycle. I tried declaring my SessionManager in a static class and used it via a static construct but it still creates new instances of my SessionManager. Not sure why.
So my question is how can I create a proper global (in memory) object that can be access by all requests?
Initially I thought that by using the IoC container and specifying its singleton scope that I could achieve a singleton object, but it doesn't seems like this is the case in the ASP.NET world. So please pardon me for my knowledge in the ASP.NET area as i come from a front end development background. Hope to gain some knowledge in this area from some of the experts in this community. May thanks in advance!
I am facing a problem whereby ASP.NET will create a new instance of my application and thereby create a new instance of my SessionManager a few times in it's life cycle. I verified this by putting a debugging line on Application_Start and Application_End protected methods in the Global.asax class and realized that the Global.asax class starts and end a number of times in its life cycle.
IIS Application Pool Recycling:
What you are seeing here is IIS recycling the application pool. IIS does this to try and prevent memory leaks. You can configure the recycling to occur at specific intervals.
I tried declaring my SessionManager in a static class and used it via a static construct but it still creates new instances of my SessionManager. Not sure why.
Unfortunately static variables don't survive recycling, so if your application is recycled you have to create a new instance of your SessionManager class. Which means you will need to handle persisting and restoring its state across application instances.
By default the recycling process uses an overlapped mechanism, whereby it starts an new instance of your application before terminating the old instance. This means there is no downtime to users while the application instance is shutdown and started. Unfortunately this means that you can't save the state of SessionManager in Application_End and restore it in Application_Start in the new instance because Application_End of the current instance will be called after the other application is up and running. So if you were going to do it that way, you would need to disable overlapping. But remember if you disable overlapping, there may be a small downtime then while the recycling occurs.
This article explains the recycling and the considerations.
How I would handle this:
Disable application pool recycling overlapping
Create a static instance of SessionManager that is created once when the application starts, in Application_Start.
In Application_End save the state of SessionManager to persistent storage so it can be restored in the same state when initialised in Application_Start. Perhaps serialise the state of JSON or XML.
Initially I thought that by using the IoC container and specifying its singleton scope that I could achieve a singleton object, but it doesn't seems like this is the case in the ASP.NET world.
Once you have solved the recycling issues, you don't need to use IoC to access the static object in ServiceStack as long as it is in global scope.
Maintaining the interval schedule after application restart
I have two solutions to maintaining the interval schedule. Solution 1, is simple and requires no external dependencies, though it does require to persist a date value, but this could be to a simple text file. Solution 2, is generic in that most platforms have support for it, with little configuration.
I would use a timer to run the event every 10 minutes, then record the time of the last successful check of the sessions in persistent storage (i.e. a text file, database or external cache). Then if your application is restarted, when it starts up simply determine how long it should be until the next check. This will mean that IIS application pool recycling restarts shouldn't effect the interval.
Pseudo Code:
const int interval = 10; // Run every 10 minutes
double timerInverval = 60 * interval; // In seconds
// Get last run from peristent storage
DateTime? lastRun = GetLastRunTime(); // Substitute with appropriate call from storage
// Determine elapsed time
if(lastRun.HasValue) {
var secondsRemainingUntilNextRun = (lastRun.Value.AddMinutes(interval) - DateTime.Now).TotalSeconds;
if(secondsRemainingUntilNextRun <= 0){
// Run immediately, the web application has been down and missed running the SessionManager job
SessionManager.CheckSessions(); // Substitute with appropriate call
} else {
timerInterval = secondsRemainingUntilNextRun;
}
}
// Set a timer to trigger the SessionManager job after timerInterval seconds
timer.interval = timerInterval;
Alternatively you could create a scheduled task that calls your web application and triggers this action. If the task is triggered independently of the web application, then it doesn't have to worry about maintaining the schedule if the application is restarted. I believe Azure has a scheduler service, or if you run a cloud instance then you can create a system scheduled task.
Your requirements are contradicting: you want in-memory store and you want it to be reliable and persistent and survive IIS application pool recycles. The system memory just isn't such a reliable store. If you need some persistent data you should consider using what is designed for this purpose: a database or even a file on the hard drive for example.
And of course to optimize the performance you could use an in-memory caching layer to avoid hitting your persistent layer every time you need to access the information. Another advantage to using a persistent store is that if your application is hosted in a webfarm across multiple nodes, all those nodes will be able to share the same data.
Just don't rely on IIS recycling. No matter what options you are tweaking in the IIS console, the AppPool might someday simply die wiping everything you have stored in memory and there's nothing you could do about it.
ServiceStack supports redis out of the box, as well as several other caching providers: Memcached, Azure, Disk... so the choice of where to locate your global session provider is still up to you!
You should combine caching mechanism and the singleton pattern. So you define a class that has access to the underlying cache provider, all request have once single entry point to your session manager, and use this cache provider as your data repository.
It will survive recycling, crashes and it will make your life easy, once you have to scale your application.
I have an application that can be launched from the explorer context menu for a Windows drive. When you click the menu item the drive letter is passed to the new instance. I want to make sure that any old instance is closed.
I also want to make sure that the last drive that was selected is persisted, so that when I start the application again from the start-menu, it will remember the drive I originally selected.
It would be best if the already running application would receive an event so that it can update without having to kill and restart.
I tried the following, but that doesn't seem to be working:
This is my Class library method(it is just a line that define a variable so just i have a DLL that there a variable in it and no more)
namespace Dispatch
{
public class cls_get_drive_letter
{
public static string drive_letter;
}
}
This is my loading form code: (Here i will fill the DLL's variable)
private void Frm_loading_Load(object sender, EventArgs e)
{
Dispatch.cls_get_drive_letter.drive_letter = "XXX";
Process currentProcess = Process.GetCurrentProcess();
if (Process.GetProcessesByName(currentProcess.ProcessName, currentProcess.MachineName).Length >1)
{
currentProcess.Kill();
}
}
So when i run this for first time the "XXX" will be stored in DLL but when the current instance of application is running and i am going to run next instance of it the application will be closed because of this code:
Process currentProcess = Process.GetCurrentProcess();
if (Process.GetProcessesByName(currentProcess.ProcessName, currentProcess.MachineName).Length >1)
{
currentProcess.Kill();
}
So when closing code occurs with this code the new "XXX" will not stored in DLL and the last string will be in dll.
All variables, in this case a static field, will only remain the same for the running instance of your application.
When the application is started again the field is empty
A static variable is not stored 'inside a dll' but is stored inside the memory of the application that loads the dll. When a second instance of the application starts, it will have its own memory space and it will have its own version of the string variable. The variable is also not kept between instances, so as soon as you start a new instance it will have its own, empty string variable.
When the application is stopped, the memory for that instance is released and the variable is 'forgotten'.
If you want to share state between applications, there are all kinds of solutions, one could be the System.Configuration.Settings API, a file somewhere, a memory mapped file shared between multiple processes, a Named Pipe, a Kernel Semaphore. Options aplenty.
Until we understand exactly what it is you're trying to accomplish with this shared state, we can't provide you with a better alternative than the explanation that what you're doing right now, will not work do to the way static variables work.
Update based on new information:
You can store your currently selected drive in a Settings file for your project. You can add such file from the project properties in Visual Studio. There's a tab called settings. Create a new setting for "Selected Drive" and make it a User setting (that way you can update it without Admin rights).
To communicate a new drive letter to your already running application, you have a number of options.
For one, you could check whether your executable is already running (like you're doing now) and in that case update the settings file and exit the new instance. Your already running instance could periodically refresh the settings to pick up new values.
When your application starts, you can open a named pipe on your machine on which you listen for drive changes. When the 2nd instance starts, it can detect that the pipe is already there, write the new drive to the pipe and close. The already running application can pick up this message and change its configuration.
You can send a WindowMessage to the other application
You can host a simple WCF service to receive the notification
You can write the new drive letter to a file stored in a known location and have the other instance use a FileSystemWatcher to detect the changes to that file.
As I said the possibilities are endless.
If I were you I'd first make sure that the value is persisted between relaunches by implementing the Settings file in your application. Then investigate the options I described above, do some experimentation and then ask new questions when you cannot figure out how to make it work.
I have an issue. I'd have a video player that takes in simple parameters as a c# form app. As an experiment to better understand programming, I'd like to have only one instance of the app running and have it refresh with the new args if the open command is given. I could program it so that when it gets the signal, to refreshVideo() or something like that.
Pseudo example:
//app is started from cmd line
//open app for first time
vidViewer.exe("lotr.avi", "44:44");
//keep instance open but have it refresh with new movie
vidViewer.exe("star_wars.avi", "22:32")
As it stands right now a new app with embedded video player will open, so I could have 100 open flicks if I passed it enough args. I'd just like to keep it at one.
Can provide more info if needed.
Thanks all,
Kevin
My suggestion would be to design your application such that, when launched, it would attempt to acquire a system resource that is mutually exclusive (meaning that only the first instance would succeed). Since, in your scenario, you will also require a means of interprocess communication (to transmit the name and start-time of new videos), you may use the same mechanism for achieving this.
You could, for example, use a self-hosted WCF service, bound to a fixed TCP port, that each application instance attempts to register upon being started. Due to the way ports work, only the first instance will succeed; subsequent instances would fail with a “port already in use” exception.
If an instance manages to register the WCF service, then you may assume it to be the “principal” instance and proceed to play the video on it. It should, however, listen for incoming messages from the WCF service and update the video being played accordingly (see below).
If an instance finds that the port is already in use, it should assume that another instance is already running. It would then initialize a WCF client that sends the name and start-time of the new video to be played to the WCF service. Finally, it should terminate itself without displaying any window, assuming that the principal instance will take care of playing its video.
I need to write program that will be given some path as a parameter, and play audiofile, located in that path. But after i call that program second time-i need first one to finish playing file and after that-play second file, that was passed as a parameter to second instance. How to pass second parameter as queue to first program instance if its possible..?
I guess you're describing the following strategy:-
instance A of your app is open and playing track X.
the user double clicks track Y in explorer
windows starts instance B of your app, passing in the filename as a parameter
instance B detects instance A
instance B sends a message to instance A to play track Y
instance B shuts down
instance A receives the message, stops playing track X and starts playing track Y
Evidently this is the way VLC media player works. If you try the above, you will see a new VLC process appear for a short time before your current instance starts playing the new track.
This kind of very simple cross process communication can be achieved using something like System.Threading.Mutex. E.g. you could use one mutex to indicate the existence of a currently running instance and another for passing the new track name to the current instance.
In fact, this article describes something quite similar.
I don't think you need second instance of program for this purpose. You can simply ask the first program to play the new audio file once it has finished playing the first. You can achieve this via several ways.
You can host a WCF Service inside your program which plays the audio file. It will be playing audio and will be listening to WCF Service in parallel. Program that sends the second parameter will pass the new path via WCF Service.
Similarly you can use sockets for communication
A third way could be to use Windows Message Queues. Audio player will be continuously pooling the queue for the new paths. The second program will send the new file path via adding a message in Windows Message Queue
You can also use files for communication. Audio player can look for changes in file and other program can write paths to that file