Application Variables in ASP.NET Core 2.0 - c#

How would I go about setting and accessing application-wide variables in ASP.NET Core 2.0?
Details:
I have a variable, let's call it CompanyName, which resides in the database and is used on literally every page. I don't want to hit the database every time I need to display the CompanyName. 100 years ago, I would have set Application["CompanyName']=CompanyName but I understand that this is not the way to do things in .NET Core. What would be the alternative?

A lot has progressed in the last 100 years. Some time ago, I believe in ASP.NET 1.0, the Application object in ASP classic was superseded with caching (although the Application object was left in for backward compatibility with ASP classic).
AspNetCore has replaced the caching mechanism of ASP.NET and made it DI-friendly, but it is still very similar to how the state of things was in ASP.NET. The main difference is that you now need to inject it instead of using the static HttpContext.Current.Cache property.
Register the cache at startup...
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMemoryCache();
services.AddMvc();
}
public void Configure(IApplicationBuilder app)
{
app.UseMvcWithDefaultRoute();
}
}
And you can inject it like...
public class HomeController : Controller
{
private IMemoryCache _cache;
public HomeController(IMemoryCache memoryCache)
{
_cache = memoryCache;
}
public IActionResult Index()
{
string companyName = _cache[CacheKeys.CompanyName] as string;
return View();
}
Then to make it work application wide, you can use a filter or middleware combined with some sort of cache refresh pattern:
Attempt to get the value from the cache
If the attempt fails
Lookup the data from the database
Repopulate the cache
Return the value
public string GetCompanyName()
{
string result;
// Look for cache key.
if (!_cache.TryGetValue(CacheKeys.CompanyName, out result))
{
// Key not in cache, so get data.
result = // Lookup data from db
// Set cache options.
var cacheEntryOptions = new MemoryCacheEntryOptions()
// Keep in cache for this time, reset time if accessed.
.SetSlidingExpiration(TimeSpan.FromMinutes(60));
// Save data in cache.
_cache.Set(CacheKeys.CompanyName, result, cacheEntryOptions);
}
return result;
}
Of course, you could clean that up and make a service with strongly typed properties as a wrapper around your cache that is injected into controllers, but that is the general idea.
Note also there is a distributed cache in case you want to share data between web servers.
You could alternatively use a static method or a statically registered class instance, but do note if hosting on IIS that the static will go out of scope every time the application pool recycles. So, to make that work, you would need to ensure your data is re-populated using a similar refresh pattern.
The primary difference is that with caching there are timeout settings which can be used to optimize how long the data should be stored in the cache (either a hard time limit or a sliding expiration).

You could create a Singleton-class called ApplicationWideSettings. Give that class public Properties. Initialize all the values you need one time and then use them by accesing the only instance of your class via:
ApplicationWideSettings.Instance.PropertyName;
Just make sure the namespace of the ApplicationWideSettings-class is referenced when you want to access it.
I prefer this over global/static settings because you have one class to save all your globally available data.
If you are unsure what a Singleton is I can just suggest you look into this article from Jon Skeet:
C# In Depth: Implementing the Singleton Pattern in C#

Related

EC Core Lazy Database Connection

I'm using EF Core with .NET Core 5 and have a database connection that is dependency injected into my different controllers. Here's how the database context is created via ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<MyDbContext>(opt =>
{
opt.UseMySql(Settings.Instance.SQLConnectionString, ServerVersion.AutoDetect(Settings.Instance.SQLConnectionString), b =>
{
b.UseNewtonsoftJson();
})
});
}
This works great, but I've realized this code runs for every API method that gets called, even those that don't need a database context. For example, this controller has an empty constructor and no database context usage, but still calls UseMySql:
[Produces("application/json")]
[Route("client")]
public class SimpleClientController : Controller
{
[HttpPost("GetTime")]
public IActionResult GetTime([FromBody] GetTimeRequest request)
{
// return the current UTC server time
return Json(new GetTimeResponse()
{
Time = DateTime.UtcNow
});
}
}
In general this isn't a big deal, but some issues were highlighted during the recent us-east-2 AWS outage, which showed that methods that do not rely on the database were blocked by the lack of database connection. My redis/dynamodb methods do not suffer the same fate if there is a redis or dynamodb outage, as they are handled via a singleton service and only used lazily by methods that require them.
Is there a way to do something similar with EF Core and the database context? Ideally we only initialize EF/the database if the controller has to use the context.
Looks like my issue was actually with the automatic version detection, which is creating a connection to MySQL every single time to detect the version. I've now cached the version and it seems to have fixed the issue.

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.

How to Per-Request caching in ASP.net core

My old code looks like this:
public static class DbHelper {
// One conection per request
public static Database CurrentDb() {
if (HttpContext.Current.Items["CurrentDb"] == null) {
var retval = new DatabaseWithMVCMiniProfiler("MainConnectionString");
HttpContext.Current.Items["CurrentDb"] = retval;
return retval;
}
return (Database)HttpContext.Current.Items["CurrentDb"];
}
}
Since we don't have HttpContext anymore easily accesible in core, how can I achieve the same thing?
I need to access CurrentDb() easily from everywhere
Would like to use something like MemoryCache, but with Request lifetime. DI it's not an option for this project
There are at least 3 options to store an object per-request in ASP.NET Core:
1. Dependency Injection
You could totally re-design that old code: use the built-in DI and register a Database instance as scoped (per web-request) with the following factory method:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<Database>((provider) =>
{
return new DatabaseWithMVCMiniProfiler("MainConnectionString");
});
}
Introduction to Dependency Injection in ASP.NET Core
.NET Core Dependency Injection Lifetimes Explained
2. HttpContext.Items
This collection is available from the start of an HttpRequest and is discarded at the end of each request.
Working with HttpContext.Items
3. AsyncLocal<T>
Store a value per a current async context (a kind of [ThreadStatic] with async support). This is how HttpContext is actually stored: HttpContextAccessor.
What's the effect of AsyncLocal<T> in non async/await code?
ThreadStatic in asynchronous ASP.NET Web API
Will not the database or connection string would be same across the
requests?
If so then you could do it by a static variable and middleware.
The middleware would check and set the info on each request start and static variable would store the value then your method could read it from the static variable.
Other simpler approach would be to inject/pass the IHttpContextAccessor as parameter. With this you could do with minimal changes but you have the pass the IHttpContextAccessor service from each calling method.

NHibernate: Configure() in every page request?

I have been reading many books on NHibernate and have noticed how the Configure() is implemented. In the books that method is called every time the application is run in a console application. Most of the ASP.NET examples online call Configure() on every page request. I think this will have alot of overhead since NHibernate must be configured on every request. Does it matter if NHibernate is configured on every page request? If not, how would someone save the configuration - application wide in asp.net mvc?
NHibernate is designed to be configured once per application start. In the case of a console program, that's every time you run the program. In the case of an ASP.NET application, that's every time the application starts, firing the Application.Start event.
The SessionFactory NHibernate creates from Configure() is safe to be cached for the lifetime of the application and is thread-safe to create sessions repeatedly. There is no need to configure on every request.
In the most basic way, you can use a lazy-initialized static property to safely give you a singleton for your application to use:
public static class NHibernateSessions
{
private static readonly Lazy<SessionFactory> lazyFactory;
static NHibernateSessions
{
lazyFactory = new Lazy<SessionFactory >(
() => NHibernateSessions.CreateSessionFactory());
}
public static SessionFactory Factory
{
get
{
return NHibernateSessions.lazyFactory.Value;
}
}
public static void Initialize()
{
if(!NHibernateSessions.lazyFactory.IsValueCreated)
{
// Access the value to force initialization.
var factory = lazyFactory.Value;
}
}
private static SessionFactory CreateSessionFactory()
{
// Add code here to configure and create factory.
}
}
This code uses the Lazy<T> type, to ensure the initialization is thread-safe. You can then call NHibernateSessions.Factory to get the singleton factory with which to re-use throughout your application.
By default the factory is initialized on the first get of the Factory property. This means that for an ASP.NET application, the first request to attempt to use NHibernate will be a slow one. If this is a problem, you can force initialization when the application starts by calling the Initialize() method in an Application.Start event-handler.

Categories

Resources