I am developing an ASP.NET MVC 5 application and I need to manage some global parameters, which are basically just a set of key-value-pairs. My requirements are the following:
Initial values are read from a server config file.
Parameters are available in every controller for both reading/writing and adding/deleting (like a new parameter can be added if certain controller is executed).
Parameters should surface subsequent request (either residing in Session or serialized in QueryString).
I should be possible to see and easily manage them (CRUD) using a special admin webpage.
My "brute force" approach for this would be just to implement a static class with List<Tuple<string,string>> to keep the settings, use System.Web.Configuration.WebConfigurationManager to populate initial values, use static properties to store and retrieve the list in a session variable and design a separate controller and view for managing the settings.
But this looks like re-inventing the wheel to me. Is there any (not necessarily full-fledged) pre-existing solution (in ASP.NET, or as a NuGet package) I might rest my efforts upon? Or maybe I am missing something fundamental in ASP.NET?
UPDATE: Depending on the nature of the parameter, some of them might have the lifetime of the Application, whereas some of them are bound to the current user session. Therefore they need to be either preserved in a Session object or "passed through" in every request.
That sounds like the most common approach, I don't see anything wrong with using session variables.
Related
I am new to working with state management. Currently I am working on a blazor application and I stumbled across the "fluxor" framework which allows state management via the flux pattern.
Fluxor is working perfectly for me, however I can't seem to figure out where the State of a page is actually stored.
Is it in cache, a db or some other fancy way? Is there a way for me to see that stored data in the browser?
I use fluxor on the client side of my application by the way.
Thanks for helping me out!
State is kept in memory. You can view the state with a nice GUI by enabling Redux Devtools with .UseReduxDevTools() like this:
services.AddFluxor(o => o
.ScanAssemblies(typeof(SomeType).Assembly)
.UseReduxDevTools());
Then use the redux devtools addin:
https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?hl=en
If you wish to save the state to localstorage or a database I made a library to persist the state called Fluxor.Persist:
https://github.com/Tailslide/fluxor-persist
An IStore is instantiated as a Scoped dependency. Ultimately this is the root of everything for the current user.
When you inject IStore, IState<Whatever> IDispatcher, IActionSubscriber they will ultimately come from the state that is stored within that IStore instance.
If you inject IStore into something you can iterate through its Features property, which is a dictionary of IFeature keyed by name (the name being from IFeature.GetName).
The IFeature has an object GetState() method you can use to grab the state.
This is the non-generic way of accessing the state. The state is actually stored using generics.
Look at the ReduxDevTools code and you will see an example of how to get all state (to send to ReduxDevTools browser plugin) using IStore.Features and GetState
https://github.com/mrpmorris/Fluxor/blob/master/Source/Fluxor.Blazor.Web.ReduxDevTools/ReduxDevToolsMiddleware.cs#L67
and in the OnJumpToState method it shows how I restore historical states from the browser plugin
https://github.com/mrpmorris/Fluxor/blob/master/Source/Fluxor.Blazor.Web.ReduxDevTools/ReduxDevToolsMiddleware.cs#L92
For starters, please forgive me and please correct me on my terminology. I am quite sure of the correct words to use for what I am trying to accomplish.
I have been given the task of building an ASP.Net Razor web site. It is something new to me. I am very proficient in PHP and ASP Classic. What I need to be able to figure out is how to declare a variable that is accessible everywhere. I do not know if in the .net world you call it a global variable or application variable or something else. But, here is how I would do this in Classic ASP.
In Classic ASP, I would have a file named VarFunct.asp. It would be the file that I declare my variables and have various functions I would access from anywhere. I would include the VarFunct.asp file on all of my pages. Anyway this is what I am really trying to do (written in how I would do it in Classic ASP)…
SelLoc = Request("SelLoc")
If Len(Trim(SelLoc)) = 0 Then
SelLoc = "All"
End If
In this case, Request("SelLoc") could be Request.QueryString or Request.Form. Then anywhere in my website I could use the variable SelLoc. So, in short... I need to be able to set a variable. Check to see if it is set by Request.Form, if not, check Request.QueryString, if not set the value to “All”. How do I write this? And where do I put it?
When I created the website using Visual Studio 2012, I selected ASP.NET Web Site (Razor V2).
This seems like it should be such a basic fundamental task of any website that has any kind of server side programming, but trying to find information and documentation online is near impossible, but probably because I am not using the correct terms for my question. I have not found any Razor tutorials that talk about setting variables that can be used globally across the website.
If someone could please help me out here by either telling me what I need to do or point me to a good tutorial, that would be great.
what you are looking for is called Static Class/Member
This will allow you to store and share data for the whole application.
BUT! since web server is multi-threaded, you wouldn't want to do this or else you might run into the case where the data is overwritten by another request before you finished the current one.
If you need to pass data from controller to your View you can use ViewBag dynamic object
If you need to use the data anywhere else (for example in a helper class) then do
HttpContext.Current.Application["VariableName"] = something
It is basically a dictionary and each request will have a different Application object
There are several ways of doing this.
For your example I would assume that this particular variable can be different for different users that are using the application at the same time. This is more of a Session scope than Application scope.
In this case you could simply use inheritance and make a base controller and/or base view model class that all your other controllers and/or view models inherit from. This way you can pass it back and forth between the view and controller and read/update it whenever you need to.
You could also use the Request and HttpContext and Session objects that are built into asp.net, if they fit your need. A brief overview of some of their functionality can be found here: https://learn.microsoft.com/en-us/aspnet/web-pages/overview/api-reference/asp-net-web-pages-api-reference --- google searching specific ones yields tons of results.
If you truly want Application scope, you can of course use a static class for you utilize static methods. Then you don't need to include the class in every other class, but you would need to fully name qualify the method when you call it.
I would not recommend static variables at this level though. I can't imagine very many things that would need to change for every single user that you would change while the application instance is running. Most of these sorts of items that we use are caches (generally db lookups and such, that we don't want to retrieve from the db each time, and RARELY get updated). If you utilize caches, be very aware of your thread safety when updating them. Here is an msdn on caching: https://msdn.microsoft.com/en-us/library/aa478965.aspx --- Or application configuration settings, like the application environment. We pull most of those from a config file, and they are read only, we don't change them within a running instance of the application.
My project group and I are to develop a generic workflow system, and have decided to implement a single Node (a task in the workflow) as a C# Visual Studio Web API project (Using the ASP.NET MVC structure).
In the process of implementing a Node's logic, we've come across the trouble of how to store data in our Node. Our Node specifically consists of a few lists of Uri's leading to other Nodes as well as some status/state boolean values. These values are currently stored in a regular class but with all the values as internal static fields.
We're wondering if there's a better way to do this? Particularly, as we'd like to later apply a locking-mechanism, it'd be prefereable to have an object that we can interact with, however we are unsure of how we can access this "common" object in various Controllers - or rather in a single controller, which takes on the HTTP requests that we receive for ou Node.
Is there a way to make the Controller class use a modified constructor which takes this object? And if so, the next step: Where can we provide that the Controller will receive the object in this constructor? There appears to be no code which instantiates Web API controllers.
Accessing static fiels in some class seems to do the trick, data-wise, but it forces us to implement our own locking-mechanism using a boolean value or similar, instead of simply being able to lock the object when it is altered.
If I am not making any sense, do tell. Any answers that might help are welcome! Thanks!
Based on your comments, I would say the persistence mechanism you are after is probably one of the server-side caching options (System.Runtime.Caching or System.Web.Caching).
System.Runtime.Caching is the newer of the 2 technologies and provides the an abstract ObjectCache type that could potentially be extended to be file-based. Alternatively, there is a built-in MemoryCache type.
Unlike a static method, caches will persist state for all users based on a timeout (either fixed or rolling), and can potentially have cache dependencies that will cause the cache to be immediately invalidated. The general idea is to reload the data from a store (file or database) after the cache expires. The cache protects the store from being hit by every request - the store is only hit after the timeout is reached or the cache is otherwise invalidated.
In addition, you can specify that items are "Not Removable", which will make them survive when an application pool is restarted.
More info: http://bartwullems.blogspot.com/2011/02/caching-in-net-4.html
We like to have a global instance of a class and would like to access across the application (in different forms etc)
What are the different possiblities? (other than static class).
It sounds like you want the Singleton pattern. Depending on your application you want to be careful though. You only get one instance of it, and this can cause unexpected behaviors with multiple threads etc. (there are other drawbacks too, my main point is that you have to look at the downsides of the pattern also).
C# patterns: http://www.dofactory.com/Patterns/Patterns.aspx
singleton.
Or perhaps (singletons are frowned upon) you could do something with an IoC.
This generally hints that you're doing something wrong though.
You could use ASP.NET Application State.
Application state is a data repository
available to all classes in an ASP.NET
application. Application state is
stored in memory on the server and is
faster than storing and retrieving
information in a database. Unlike
session state, which is specific to a
single user session, application state
applies to all users and sessions.
Therefore, application state is a
useful place to store small amounts of
often-used data that does not change
from one user to another.
I want to store a small list of a simple object (containing three strings) in my ASP.NET MVC application. The list is loaded from the database and it is updated rarely by editing some values in the site's admin area.
I'm thinking of using HttpContext.Current.Application to store it. This way I can load it in the Global.asax:
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
HttpContext.Current.Application["myObject"] = loadDataFromSql(); // returns my object
}
And then can easily reference it from any controllers or views as needed. Then in the event, the admin area calls the updateMyObject controller action, I can just update the DB and load it in again and replace HttpContext.Current.Application["myObject"].
Are there any cons to doing this? It seems like it will work fine for what I am trying to achieve, however does anyone know of a better way to do this, assuming there is some major disadvantage to the method I've laid out?
What you actually do is Caching, and it's great, since you reduce calls to an external storage (a database or a file, whatever). The trade-off is memory usage, of course. Now, almost any modern web framework, including ASP.NET, includes some kind of a caching mechanism. Either you use it, or you use some kind of a global variable.
Storing data in ASP.NET's built-in Cache object has some significant advantages, since this mechanism actually checks the memory usage and removes the cached data according to some rules.
However, if the data you want to cache is intensively used across the application, and its size is not too large (say, smaller than 1 MB), you may want to store it in as a global variable.
In ASP.NET, global variables are achieved by either using the Application object, like you described in your question, or by writing public static properties/fields in an internal/public class.
Here's my solution to static properties. Note that I use a locking object, to protect the inner data from corruption. It looks like this:
public class WhateverClass
{
private static object theLocker = new object();
private static YourDataType theData;
public static YourDataType TheData
{
get
{
lock (theLocker)
{
return theData;
}
}
set
{
lock (theLocker)
{
theData = value;
}
}
}
}
The usage is very simple:
First time, in Application_Start:
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
WhateverClass.TheData = loadDataFromSql();
}
In any controller:
var myData = WhateverClass.TheData;
This approach is better because you have type safety, since this public static property can be explicitly declared with the exact type. In addition, this kind of storage is more testable since it doesn't depend on the web context.
HTH!
HttpContext.Current.Application is essentially a hangover that is needed for backwards compatibility with classic ASP. It's essentially a static Hashtable with classic ASP locking semantics (Application.Lock / Application.UnLock).
As a weakly-typed Hashtable, you will need to cast objects you retrieve:
MyObject myObject = (MyObject) HttpContext.Current.Application["myObject"];
In an ASP.NET application that is not a migration from classic ASP, I would prefer using other standard .NET stuff, such as:
A static field, using .NET locking semantics if you need locking (e.g. the C# lock keyword, or a ReaderWriterLockSlim instance, depending on your requirements):
static MyObject myObject = LoadFromSql();
The ASP.NET Cache - which has rich functionality for managing expiration, dependencies, ...
Yes, using HttpContext.Current.Application will work fine for what you are doing. No problems.
HttpContext.Current.Application is simply a reference to the static global HttpApplicationState object in .NET for your Web Application, of which there should be one global instance per web application. By storing data there, you provide fast, thread-safe access to your global variables. Be sure to lock them when updating values, as in this example:
System.Web.HttpContext.Current.Application.Lock();
System.Web.HttpContext.Current.Application["WebApplicationPath"] = MyWebApplicationPath;
System.Web.HttpContext.Current.Application.UnLock();
As others have mentioned, you can also create a series of static classes in your App_Code or other folder and there store global static values as well as your HttpContext.Current.Application values, where they can be safely checked for values or updated from the database, or update and check each other, working in tandem. I usually create a static global class to assist in the management and retrieval of the Application variables I store. In this way you have both the state dictionary of the HttpApplicationState class and the web application static objects working together to share and maintain global values. (Keep in mind each static class is assigned per worker process and there may be as many as 10 WP on average by default on many IIS web servers/web applications. So keep data in static types to a minimum.)
Keep in mind as some mentioned server farms do not share Application state. There are many ways to manage this. I'm not a fan of cache because of the ways in which it can expire, fail, become stale, or get corrupted. A simpler solution is to simply use use the database and URL querystrings to communicate across servers and maintain state. Good luck!
If you're deploying to a single web server the approach would work. Consider the Cache object for this as it provides more options for expiration if you need such functionality. (See a comparison, albeit an aged one, here.)
If you're ever going to deploy to a web server farm or equivalent you should use memcached or another web farm friendly caching mechanism. Both the Application and Cache objects only typically exist in a single server context; if your user could be hitting multiple web servers during their session (and the cache needs to be identical) you'll need a shared cache that can be seen from each of the potential web servers.
Regardless of which path you take you will need to invalidate/reload your cache whenever the underlying data changes, which is custom code that varies by app.
This approach works well and can speed things considerably but it's a bit more work than you may realize at first glance...
Application_Start really only gets fired on App Pool Recylce's, IIS Resets or reboots. If your updating these values that infrequently, why not store them in your web.config and access them that way?
That being said, I don't think there is anything wrong with your approach. Though more typically I've seen people using config files for rarely changed values.