How can I remove shared variables from legacy code - c#

In the system there is a singleton for currently logged user (our own user not windows user) containing a shared instance.
In a few hundred data access class files this is used to set CreatebyID and EditbyID for each request sent to the database. Nearly all the classes inherit a single base although at the moment the two values are set in each class.
This all worked fine for the companies desktop applications for many years however when the same data access classes were used in a new web application the currently logged user was shared across all users sessions and could not be changed without causing issues.
How can I refactor the code without significantly re-writing the whole DAL and without passing in a current user (or User ID) into every instance or setting an EditbyID property on each class for every save.

You could use a static property which get/set a Session variable via HttpContext.Current.Session.
For example:
public class DAL
{
public static int CreatebyID
{
get
{
return (int)HttpContext.Current.Session["CreatebyID"];
}
set
{
HttpContext.Current.Session["CreatebyID"] = value;
}
}
public static int EditbyID
{
get
{
return (int)HttpContext.Current.Session["EditbyID"];
}
set
{
HttpContext.Current.Session["EditbyID"] = value;
}
}
}

Related

Using a WCF service to share information across clients

I'm trying to develop a system to share information across 2 windows applications with different update loops.
I developed a solution that uses a WCF service to store and retrieve data. However this data is different across clients and therefore showing different values for each applications.
The service I tried to implement are similar to this
namespace TEST_Service_ServiceLibrary
{
[ServiceContract]
public interface TEST_ServiceInterface
{
[OperationContract]
string GetData();
[OperationContract]
void StoreData(string data);
}
}
namespace TEST_Service_ServiceLibrary
{
// Core service of the application, stores and provides data:
public class TEST_Service : TEST_ServiceInterface
{
string TEST_string;
// Used to pull stored data
public string GetData()
{
return TEST_string;
}
// Used to store data
public void StoreData(string data)
{
TEST_string = data;
}
}
}
Each of the applications creates a TEST_Service client.
I tested the GetData and StoreData functions and they work fine independently, however when I use StoreData on one application and test the GetData method from the other the data appears to be empty.
I have looked around but haven't found a solution to this problem, is there a work around for this? or should I change my approach? I thought of using a local data base but I'm not sure this is the best way to solve it
Thanks a lot
You have more than one instance of your service class. If you want to have your data in memory, you will need to run it in single instance mode:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
Now keeping your data in memory might not be the best option anyway. You should look for a data store of some kind and then make that store a persistent instance with a single interface. Then it does not matter how many of your service instances are used.
If your WCF service was storing information in a database, then information stored on one request would go to the database, and when another request retrieved it, the result would come from that database. So if one client stored something, another could retrieve it.
The reason why this isn't working is because in response to each request your application is creating a new instance of the TEST_Service class. That means TEST_string, where you are storing values between requests, is a new string. It doesn't contain the previous value.
For experimentation you could try changing the string to static:
static string TEST_string;
...and then the value would persist between instances of the service class. But that still wouldn't be effective because your WCF service could be deployed to multiple servers, and then each one would have a separate instance of the class. Updating one wouldn't update the others. Or, if the service application restarted then the value would be lost. (From the context I assume that you're just experimenting with this.)
So ultimately you'd want some way to persist data that wouldn't depend on any of those factors, but would "survive" even when the instance of the service class goes out of scope or the application shuts down.

Use static global variable class in ASP.NET MVC web application

I am creating an ASP.NET MVC web application. It has service classes to execute business logic and it access data through Entity Framework.
I want to change some business logic based on application variable. These variables are global variables and load from app config and don't change after the initial loading.
public class BroadcastService : IBroadcastService
{
private static readonly ILog Logger = LogProvider.GetCurrentLogger();
private readonly IUnitOfWork _worker;
private readonly IGlobalService _globalService;
public BroadcastService(IUnitOfWork worker, IGlobalService globalService)
{
_worker = worker;
_globalService = globalService;
}
public IEnumerable<ListItemModel> GetBroadcastGroups()
{
if(Global.EnableMultiTenant)
{
//load data for all tenants
}
else
{
//load data for current tenant only
}
return broadcastGroups ?? new List<ListItemModel>();
}
...
}
public static class Global
{
public static bool EnableMultiTenant{get;set;}
}
For example, EnableMultiTenant will hold application is running in multi-tenant mode or not.
My concerns are:
Is it ok to use a static global variable class to holds those values?
This application is hosting on Azure app service with load balancing. Is there any effect when running multi-instance and when app pool restarts?
To answer your question as to whether it is 'okay' to do this, I think that comes down to you.
I think the biggest thing to know is when that data is going to get refreshed. From experience I believe that static information gets stored in the application pool, so if it is restarted then the information will be refreshed.
Lifetime of ASP.NET Static Variable
Consider how many times you need that information, if you only need it once at startup, is it worth having it as a static. If you are getting that information a lot (and say for example it is stored in a database) then it may be sensible to store that in a cache somewhere such as a static member.
I think my only recommendation with static member variables is asp is keep them simple, booleans seem fine to me. Remember that users do share the same application meaning that static variables are global for all users. If you want a user specific variable then you want to use sessions cache.
Always remember the two hardest thing in programming
Naming things
Cache invalidation
Off by one errors
https://martinfowler.com/bliki/TwoHardThings.html
Even though this is a joke, it holds a lot of truth
Hope this helps
This is thread safe if you initialize these values once and then only read from them. It is also safe in the presence of multiple worker processes and restarts because the multiple processes don't share variables.
As an alternative consider creating an instance of a class holding your settings:
class MySettings {
bool IsEnabled;
}
Then you can use dependency injection to inject a singleton value of this class to your code. This makes it easier to tests and makes the code more uniform.

Azure Functions and Caching

We are planning to develop an Azure function for which the input trigger is a service bus message and the output will be blob storage. The service bus message will contain a image url and the function will resize the image to a predefined resolution and will upload to azure blob storage.
The resolution to which the image should be resized is stored in the database and the Azure function needs to make a call to database to get to know the resolution that is supposed to be used for the image in the input message. The resolution would actually be a master data configured based on the source of the input message.
Making a database call would be a expensive call as it would have to go to the database for each call. Is there any way to cache the data and use it without calling the database. Like in memory caching?
You are free to use the usual approaches that you would use in other .NET applications:
You can cache it in memory. The easiest way is just to declare a static dictionary and put database values inside (use concurrent dictionary if needed). The cached values will be reused for all subsequent Function executions which run on the same instance. If an instance gets idle for 5 minutes, or if App scales out to an extra instance, you will have to read the database again;
You can use distributed cache, e.g. Redis, by using its SDK from Function code. Might be a bit nicer, since you keep the stateless nature of Functions, but might cost a bit more. Table Storage is a viable alternative to Redis, but with more limited API.
There's no "caching" feature of Azure Functions themselves, that would be ready to use without any extra code.
You can use Azure Cache service (https://azure.microsoft.com/en-us/services/cache/) to cache your data. Basically, In your Azure Function instead of calling database all the time, call Azure cache and use if it is not expired and if it is expired or not set then call database to get the value and populate the cache with appropriate expiry logic (timeout after fixed time or some other custom logic).
You could use Durable Functions and make the database call via an activity or sub-Orchestration, the return value is essentially cached for you then and will be returned without making the underlying call again each time the function replays.
Redis is in-memory cache and there is custom output binding that you can use to keep your function clean:
[FunctionName("SetPoco")]
public static async Task<IActionResult> SetPoco(
[HttpTrigger("POST", Route = "poco/{key}")] HttpRequest request,
[Redis(Key = "{key}")] IAsyncCollector<CustomObject> collector)
{
string requestBody;
using (var reader = new StreamReader(request.Body))
{
requestBody = reader.ReadToEnd();
var value = JsonConvert.DeserializeObject<CustomObject>(requestBody);
await collector.AddAsync(value);
}
return new OkObjectResult(requestBody);
}
Link to the project: https://github.com/daulet/Indigo.Functions#redis
However if by in-memory cache you mean in memory of the function I'd strongly recommend otherwise as function are meant to be stateless and you won't be able to share that memory across multiple hosts running your function. This is also not recommended in Azure Functions best practices
Here's a little class I built to simplify the task of storing and re-using objects in the running instance's memory whilst it remains alive. Of course this means each new instance will need to populate itself but this can provide some useful optimisations.
// A simple light-weight cache, used for storing data in the memory of each running instance of the Azure Function.
// If an instance gets idle (for 5 minutes or whatever the latest time period is) or if the Function App scales out to an extra instance then the cache is re-populated.
// To use, create a static readonly instance of this class in the Azure Function class, in the constructor pass a function which populates the object to cache.
// Then simply reference the Data object. It will be populated on the first call and re-used on future calls whilst the same instance remains alive.
public class FunctionInstanceCache<T>
{
public FunctionInstanceCache(Func<T> populate)
{
Populate = populate;
IsInit = false;
}
public Func<T> Populate { get; set; }
public bool IsInit { get; set; }
private T data;
public T Data
{
get
{
if (IsInit == false)
{
Init();
};
return data;
}
}
public void Init()
{
data = Populate();
IsInit = true;
}
}
Then in your Azure Function instance implementation create a static readonly instance of this, passing in a Populate method:
private static readonly FunctionInstanceCache<string[]> Fic = new FunctionInstanceCache<string[]>(PopulateCache);
Then implement this
private static string[] PopulateCache()
{
return DOSOMETHING HERE;
}
Then simply call Fic.Data when needed - it will be populated on first use and then re-used whilst the instance remains alive.

Winforms - MVP Pattern: Using static ApplicationController to coordinate application?

Background
I'm building a two-tiered C# .net application:
Tier 1: Winforms client application using the MVP (Model-View-Presenter) design pattern.
Tier 2: WebAPI RESTful service sitting on top of Entity Framework and SQL Server.
Currently, I have questions relating to the overall architecture of the Winforms client application. I'm new to programming (about a year) but I've made good progress with this application. I want to step back and re-evaluate my current approach to check that I'm generally heading in the right direction.
Application Domain
The Winforms application is a fairly simple security personnel tracking application. The main view (Form) is the focus of the application, and has different sections which group content into functional areas (e.g. a section for tracking personnel schedules, a section for tracking who is assigned where, etc.). A menu on the side of the application launches secondary views (e.g. history, statistics, contacts, etc.). The idea is that the app could be used by a security office to organize daily operations and then keep a detailed history of everything in a database for reporting on in the future.
Technical Details
As mentioned, the Winforms client is built using the MVP pattern (passive view), focusing on using dependency injection as much as possible (via SimpleInjector IoC container). Each view (form) is paired up with a single presenter. The views implement interfaces, allowing the presenter to control the view (regardless of the concrete implementation). The view raises events for the presenter to subscribe to. Currently, presenters are not allowed to directly communicate to another presenter.
An application controller is used to coordinate the application. This is the area of my application architecture where I'm the most shakey (hence the post title). The application controller is currently used to:
Open new views (forms) and manage open forms.
Facilitate communication between application components via an event aggregator. One presenter publishes an event and any number of presenter can subscribe to that event.
Host session information (i.e. security context/logon, config data, etc.)
The IoC container is registered into the application controller at application start-up. This allows the application controller, for example, to create a presenter from the container, and then have all subsequent dependencies (view, services, etc.) to be automatically handled by the container.
Question
In order to make the Application Controller accessible to all presenters, I have created the controller as a static class.
public static class ApplicationController
{
private static Session _session;
private static INavigationWorkflow _workflow;
private static EventAggregator _aggregator;
#region Registrations
public static void RegisterSession(Session session) {}
public static void RegisterWorkflow(INavigationWorkflow workflow) {}
public static void RegisterAggregator(EventAggregator aggregator) {}
#endregion
#region Properties
public static Session Session
{
get { return _session; }
}
#endregion
#region Navigation
public static void NavigateToView(Constants.View view) {}
#endregion
#region Events
public static Subscription<TMessageType> Subscribe<TMessageType>(Action<TMessageType> action) {}
public static void Publish<TMessageType>(TMessageType message) {}
public static void Unsubscribe<TMessageType>(Subscription<TMessageType> subscription) {}
#endregion
}
Is this considered an acceptable practice to make a static class like this? I mean, it certainly works. It just feels... off? Are there any other holes that you can see in my architecture based on what I have described?
-
** EDIT **
This edit is made in response to Ric .Net’s answer posted below.
I have read through all of your suggestions. As I am committed to utilizing dependency injection to the fullest extent I can, I’m onboard with all of your suggestions. That was my plan from the beginning, but when I ran into things I didn’t understand how to accomplish via injection, I turned to the global static controller class to solve my problems (A god class it is becoming, indeed. Yikes!). Some of those questions still exist:
Event Aggregator
The defining line here is what should be considered optional, I think. I’ll provide a bit more context about my app before outlining my problem. Using web terminology, my main form generally acts like a layout view, hosting navigation controls and a notification section in the left menu, and partial views being hosted in the center. Coming back to winforms terminology, the partial views are just custom made UserControls that I treat like views, and each of them are paired up with their own presenter. I have 6 of these partial views hosted on my main form, and they serve as the meat and potatoes of the application.
As an example, one partial view lists available security guards and another lists potential patrol areas. In a typical use case, a user would drag an available security guard from the available list to one of the potential patrol areas, effectively becoming assigned to that area. The patrol area view would then update to show the assigned security guard and the guard would be removed from the available list view. Utilizing drag-and-drop events, I can handle this interaction.
My questions come when I need to handle other types of interactivity between the various partial views. For example, double clicking on guard that is assigned to a location (as seen in one partial view) could highlight that guard’s name on another partial view showing all personnel schedules, or bring up employee details/history on another partial view. I could see the graph/matrix of what partial views are interested in events occurring in other partial views as becoming quite complex, and I’m not sure how to handle that via injection. With 6 partial views, I wouldn’t want to inject the other 5 partial views/presenters into each one. I was planning on accomplishing this via the event aggregator. Another example I could think of is needing to update data on a separate view (its own form) based off an event that occurs on one of the partial views on the main form.
Session & Form Opener
I really like your thoughts here. I’m going to take these ideas and run with them, and see where I end up!
Security
What are your thoughts on controlling user access to certain functionality based on what type of account they have? The recommendations I’ve been reading online say that security could be implemented by modifying the views based on their account type. The thought being, if a user can’t interact with a UI element to kick off a certain task, then the presenter will never be asked to perform that task. I’m curious if you inject the WindowsUserContext into each presenter and do additional checks, especially for http service bound requests?
I haven’t done too much development on the service side of things yet, but for http service bound requests, I imagine you need to send security information along with each request so that the service can authenticate the request. My plan was to inject the WindowsUserContext directly into the winforms service agents that end up making the service requests (i.e. the security validation would not be coming from the presenter). In that case, the service agents could potentially do a last minute security check before sending off a request.
A static class is of course handy in some cases but there are a lot of downsides to this approach.
The tend to grow into something like a God class. You already see this happening. So this class violates SRP
A static class cannot have dependencies and therefore it needs to use the Service Locator anti pattern to get it's dependencies. This is not a problem perse if you consider this class to be part of the composition root, but nevertheless, this often heads the wrong way.
In the supplied code I see three responsibilities of this class.
EventAggregator
What you call Session information
A service to open other views
Some feedback on this three parts:
EventAggregator
Although this is a widely used pattern and sometimes it can be very powerful I myself am not fond of this pattern. I see this pattern as something that provides optional runtime data where in most cases this runtime data is not optional at all. In other words, only use this pattern for truly optional data. For everything that is not really optional, use hard dependencies, using constructor injection.
The ones that need the information in that case depend upon IEventListener<TMessage>. The one that publish the event, depend upon IEventPublisher<TMessage>.
public interface IEventListener<TMessage>
{
event Action<TMessage> MessageReceived;
}
public interface IEventPublisher<TMessage>
{
void Publish(TMessage message);
}
public class EventPublisher<TMessage> : IEventPublisher<TMessage>
{
private readonly EventOrchestrator<TMessage> orchestrator;
public EventPublisher(EventOrchestrator<TMessage> orchestrator)
{
this.orchestrator = orchestrator;
}
public void Publish(TMessage message) => this.orchestrator.Publish(message);
}
public class EventListener<TMessage> : IEventListener<TMessage>
{
private readonly EventOrchestrator<TMessage> orchestrator;
public EventListener(EventOrchestrator<TMessage> orchestrator)
{
this.orchestrator = orchestrator;
}
public event Action<TMessage> MessageReceived
{
add { orchestrator.MessageReceived += value; }
remove { orchestrator.MessageReceived -= value; }
}
}
public class EventOrchestrator<TMessage>
{
public void Publish(TMessage message) => this.MessageReceived(message);
public event Action<TMessage> MessageReceived = (e) => { };
}
To be able to guarantee events are stored in one single location, we extract that storage (the event) into its own class, the EventOrchestrator.
The registration is as follows:
container.RegisterSingleton(typeof(IEventListener<>), typeof(EventListener<>));
container.RegisterSingleton(typeof(IEventPublisher<>), typeof(EventPublisher<>));
container.RegisterSingleton(typeof(EventOrchestrator<>), typeof(EventOrchestrator<>));
Usage is trivial:
public class SomeView
{
private readonly IEventPublisher<GuardChanged> eventPublisher;
public SomeView(IEventPublisher<GuardChanged> eventPublisher)
{
this.eventPublisher = eventPublisher;
}
public void GuardSelectionClick(Guard guard)
{
this.eventPublisher.Publish(new GuardChanged(guard));
}
// other code..
}
public class SomeOtherView
{
public SomeOtherView(IEventListener<GuardChanged> eventListener)
{
eventListener.MessageReceived += this.GuardChanged;
}
private void GuardChanged(GuardChanged changedGuard)
{
this.CurrentGuard = changedGuard.SelectedGuard;
}
// other code..
}
If another view will receive a lot of events you could always wrap all IEventListeners of that View in a specific EventHandlerForViewX class which get all important IEventListener<> injected.
Session
In the question you define several ambient context variables as Session information. Exposing this kind of information through a static class promotes tight coupling to this static class and thus makes it more difficult to unit test parts of your application. IMO all information provided by Session is static (in the sense that it doesn't change throughout the lifetime of the application) data that could just as easily be injected into those parts that actually need this data. So Session should completely be removed from the static class. Some examples how to solve this in a SOLID manner:
Configuration values
The composition root is in charge of reading all information from the configuration source (e.g. your app.config file). This information can there be stored in a POCO class crafted for its usage.
public interface IMailSettings
{
string MailAddress { get; }
string DefaultMailSubject { get; }
}
public interface IFtpInformation
{
int FtpPort { get; }
}
public interface IFlowerServiceInformation
{
string FlowerShopAddress { get; }
}
public class ConfigValues :
IMailSettings, IFtpInformation, IFlowerServiceInformation
{
public string MailAddress { get; set; }
public string DefaultMailSubject { get; set; }
public int FtpPort { get; set; }
public string FlowerShopAddress { get; set; }
}
// Register as
public static void RegisterConfig(this Container container)
{
var config = new ConfigValues
{
MailAddress = ConfigurationManager.AppSettings["MailAddress"],
DefaultMailSubject = ConfigurationManager.AppSettings["DefaultMailSubject"],
FtpPort = Convert.ToInt32(ConfigurationManager.AppSettings["FtpPort"]),
FlowerShopAddress = ConfigurationManager.AppSettings["FlowerShopAddress"],
};
var registration = Lifestyle.Singleton.CreateRegistration<ConfigValues>(() =>
config, container);
container.AddRegistration(typeof(IMailSettings),registration);
container.AddRegistration(typeof(IFtpInformation),registration);
container.AddRegistration(typeof(IFlowerServiceInformation),registration);
}
And where you need some specific information, e.g. information to send an email you can just put IMailSettings in the constructor of the type needing the information.
This will also give you the possibility to test a component using different config values, which would be harder to do if all config information had to come from the static ApplicationController.
For security information, e.g. the logged on User the same pattern can be used. Define an IUserContext abstraction, create a WindowsUserContext implementation and fill this with the logged on user in the composition root. Because the component now depends on IUserContext instead of getting the user at runtime from the static class, the same component could also be used in an MVC application, where you would replace the WindowsUserContext with an HttpUserContext implementation.
Opening other forms
This is actually the hard part. I normally also use some big static class with all kinds of methods to open other forms. I don't expose the IFormOpener from this answer to my other forms, because they only need to know, what to do, not which form does that task for them. So my static class exposes this kinds of methods:
public SomeReturnValue OpenCustomerForEdit(Customer customer)
{
var form = MyStaticClass.FormOpener.GetForm<EditCustomerForm>();
form.SetCustomer(customer);
var result = MyStaticClass.FormOpener.ShowModalForm(form);
return (SomeReturnValue) result;
}
However....
I'm not at all happy with this approach, because over time this class grows and grows. With WPF I use another mechanism, which I think could also be used with WinForms. This approach is based on a message based architecture described in this and this awesome blogposts. Although at first the information looks as it is not at all related, it is the message based concept that let these patterns rock!
All my WPF windows implement an open generic interface, e.g. IEditView. And if some view needs to edit a customer, it just get's this IEditView injected. A decorator is used to actually show the view in pretty much the same way as the forementioned FormOpener does it. In this case I make use of a specific Simple Injector feature, called decorate factory decorator, which you can use to create forms whenever it is needed, just as the FormOpener used the container directly to create forms whenever it needs to.
So I did not really test this, so there could be some pitfalls with WinForms, but this code seems to work on a first and single run..
public class EditViewShowerDecorator<TEntity> : IEditView<TEntity>
{
private readonly Func<IEditView<TEntity>> viewCreator;
public EditViewShowerDecorator(Func<IEditView<TEntity>> viewCreator)
{
this.viewCreator = viewCreator;
}
public void EditEntity(TEntity entity)
{
// get view from container
var view = this.viewCreator.Invoke();
// initview with information
view.EditEntity(entity);
using (var form = (Form)view)
{
// show the view
form.ShowDialog();
}
}
}
The forms and decorator should be registered as:
container.Register(typeof(IEditView<>), new[] { Assembly.GetExecutingAssembly() });
container.RegisterDecorator(typeof(IEditView<>), typeof(EditViewShowerDecorator<>),
Lifestyle.Singleton);
Security
The IUserContext must the base for all security.
For the userinterface I normally hide all controls/buttons that a certain userrole doesn't have access to. The best place is to perform this in the Load event.
Because I use the command/handler pattern as described here for my all actions external of my forms/views I use a decorator to check if a user has permission to perform this certain command (or query).
I would advise you to read this post a few times until you really get the hang of it. Once you get familiar with this pattern you won't do anything else!
If you have any questions about these patterns and how to apply a (permission)decorator, add a comment!

Is there something like SESSION in Windows application?

Is there something like SESSION in Windows application? I want to store a few values to be persistent between forms.
For example: First form has some check boxes and third form process them accordingly. So I need to store the checked checkboxes somewhere.
If you're talking about different Forms within the same Application, then just create some static members on a class, it will be persisted for the lifetime of the executable.
You could only expose your CheckBoxes Checked state through properties of this form where you put your CheckBoxes on, and access these properties from your third or Process form.
public partial class MainForm : Form {
// We assume we have let's say three CheckBoxes named chkFirst, chkSecond and chkThird
public bool IsFirstChecked { get { return chkFirst.Checked; } }
public bool IsSecondChecked { get { return chkSecond.Checked; } }
public bool IsThirdChecked { get { return chkThird.Checked; } }
// Calling this form from where these checked states will be processed...
// Let's suppose we have to click a button to launch the process, for instance...
private void btnLaunchProcess(object sender, EventArgs e) {
ProcessForm f = new ProcessForm();
f.Parent = this;
if (DialogResult.OK == f.ShowDialog()) {
// Process accordingly if desired, otherwise let it blank...
}
}
}
public partial class ProcessForm : Form {
// Accessing the checked state of CheckBoxes
private void Process() {
if ((this.Parent as MainForm).FirstChecked)
// Process according to first CheckBox.Checked state.
else if ((this.Parent as MainForm).SecondChecked)
// Process according to second CheckBox.Checked state.
else if ((this.Parent as MainForm).ThirdChecked)
// Process according to third CheckBox.Checked state.
}
}
Please consider that I picked this code up the top of my head, so it might happen not to compile. Anyway, I hope that this gives you an idea of how to pass your values throughout your forms.
The biggest difference between Web and WinForm programming is that Web is stateless. SESSION and VIEWSTATE are workarounds to allow one to preserve values.
WinForms are stateful, so you don't need to go through SESSION and VIEWSTATE-like variables. A value is preserved as long as the object exists.
You can use app.config (or Settings section in Project's Properties) if you use Visual Studio, or just serialize your values and store them in some file.
If you want to persist data between independent execution of the same app (as in concurrent request serving in a HTTP farm) then just write out some XML or use a mashalling/serializing system with your runtime/plaform (dunno what it would be for C#).
Then import it again. Just watch your concurrency control.
If this is just a regular single-user windows application, create a class to model the state you want to pass around and require it in your form constructors:
internal class ApplicationState
{
// Store the selected checkbox values here, for example
public List<int> SelectedProductIds { get; }
// ... additional state ...
}
internal class EditOrderForm: Form
{
private ApplicationState applicationState;
public EditCustomerForm(ApplicationState applicationState) {
this.applicationState = applicationState;
}
// Rest of the code
}
You could use static variables instead of instances - but those are just global variables that make your code harder to read and maintain.
If you are looking to store data on a per user basis between execution sessions, you should consider Isolated Storage.
Doesn't clutter install directory
Doesn't cause issues with AnitVirus software
Part of the OS including .Net objects, don't need to install anything else
Already works with the Windows security model
Exists on a per user basis, so saved settings are separated for each user
Can serialize/deserialize obects directly into it

Categories

Resources