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.
Related
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.
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#
This question already has an answer here:
Automatically refresh ASP.NET Output Cache on expiry
(1 answer)
Closed 5 years ago.
I have a website with a lot of data in it.
I use C# .NET MVC4 for development.
I have a big slow page loading problem when the cache is empty.
currently I'm using a cache that contains all the data that I need and when the cache is on the pages loads right away, but when the cache expires it takes about 10s the page to be fully loaded.
I'm looking for an option to auto refresh the cache when it expires,
I've been searching over goolge, but couldn't find anything in that matter
How is it should be done?
Or are there other options to solve this problem?
Thanks
You could cache it on the first call with a TTL, let it invalidate, and then the next call will get it and cache it back again. The problem with this is that you are slowing down your thread while it has to go fetch the data as it is unavailable, and multiple threads will wait for it (assuming you lock the read to prevent flooding).
One way to get around the first load issue is to prime your cache on application start up. This assures that when your application is ready to be used, the data is already loaded up and will be fast. Create a quick interface like ICachePrimer { void Prime() }, scan your assemblies for it, resolve them, then run them.
The way I like to get around the empty cache on invalidation issue is to refresh the data before it is removed. To easily do this in .Net, you can utilize the MemoryCache's CacheItemPolicy callbacks.
UpdateCallback occurs before the item is removed, and allows you to refresh the item.
RemovedCallback occurs after the item has been removed.
In the example below, my CachedRepository will refresh the cached item when it is invalidated. Other threads will continue to receive the "old" value until the refresh completes.
public class MyCachedRepository : IMyRepository
{
private readonly IMyRepository _baseRepository;
private readonly ObjectCache _cache;
public MyCachedRepository(IMyRepository baseRepository, ObjectCache cache)
{
_baseRepository = baseRepository;
_cache = cache;
}
public string GetById(string id)
{
var value = _cache.Get(id) as string;
if (value == null)
{
value = _baseRepository.GetById(id);
if (value != null)
_cache.Set(id, value, GetPolicy());
}
return value;
}
private CacheItemPolicy GetPolicy()
{
return new CacheItemPolicy
{
UpdateCallback = CacheItemRemoved,
SlidingExpiration = TimeSpan.FromMinutes(0.1), //set your refresh interval
};
}
private void CacheItemRemoved(CacheEntryUpdateArguments args)
{
if (args.RemovedReason == CacheEntryRemovedReason.Expired || args.RemovedReason == CacheEntryRemovedReason.Removed)
{
var id = args.Key;
var updatedEntity = _baseRepository.GetById(id);
args.UpdatedCacheItem = new CacheItem(id, updatedEntity);
args.UpdatedCacheItemPolicy = GetPolicy();
}
}
}
Source: http://pdalinis.blogspot.in/2013/06/auto-refresh-caching-for-net-using.html
There is no mechanism to auto refresh a cache when the keys expire. All caching systems employ passive expiration. The keys are invalidated the first time they are requested after the expiration, not automatically at that exact expiration time.
What you're talking about is essentially a cache that never expires, which is easy enough to achieve. Simply either pass no expiration (if the caching mechanism allows it) or a far-future expiration. Then, your only problem is refreshing the cache on some schedule, so that it does not become stale. For that, one option is to create a console application that sets the values in the cache (importantly, without caring if there's something there already) and then use Task Scheduler or similar to schedule it to run at set intervals. Another option is to use something like Revalee to schedule callbacks into your web application at defined intervals. This basically the same as creating a console app, only the code could be integrated into your same website project.
You can also use Hangfire to perform the scheduling directly within your web application, and could use that to run a console application, hit a URL, whatever. The power of Hangfire is that it allow you pretty much schedule any process you want, but that also means you have to actually provide the code for what should happen, i.e. actually connect with HttpClient and fetch the URL, rather than just telling Revallee to hit a particular URL.
I am using C# 5.0, VS 2012, MVC4. I have a scenario where I need to cache employees data and query the cache when performing a search on employees info.
I am not displaying all employees initially but wanted to initiate a thread to cache all employees. So in index method when view is displayed, I am doing this
//Starting a thread to load the cache if its null
if (HttpRuntime.Cache["AllEmployees"] == null)
{
thCacheAllEmployees = new Thread(new ThreadStart(CacheAllEmployees));
thCacheAllEmployees.Name = "CacheAllEmployees";
thCacheAllEmployees.Start();
}
CacheAllEmployees is a separate method which will query LDAP and stores all employees in Cache. It will take about 15 secs for LDAP query. But within these first 15 secs after view is loaded and cache is not yet loaded, then when user starts typing in search box, I am making a ajax method call to GetFilteredEmployees action method. I want to access previously started thread, check if its alive, then to wait for that thread to complete so that I don't need to do a fresh LDAP query again.
if (thCacheAllEmployees.IsAlive)
{
thCacheAllEmployees.Join();
if (HttpRuntime.Cache["AllEmployees"] != null)
return (List<CMSUser>)HttpRuntime.Cache["AllEmployees"];
}
But the problem is, when its ajax call seems like it will be a new Main Thread and doesn't know about thCacheAllEmployees. So thCacheAllEmployees will be null object. So I need to get the instance of this thread from currently all active threads in application.
I can store thread id of thCacheAllEmployees when view is loaded first time in a session variable, but how can I access that thread from pool of threads when making ajax method call ?
Is there any better way of doing this ? please give ur suggestions.
When you think threads think actions not data. When you want to store data you do not put that data on a thread, you put it into memory, then that memory is accessible by one ore more threads depending on the scope.
There are lots of ways you can store that data. I'm not sure if the data to cache is unique for different user sessions or if you want just one global cache. Anything that you want to access from anywhere you can put in a static variable. You just have to be sure to use locks so that multiple threads do not try to access that data at the same time which is never safe.
Model
public static class MyCache
{
private static object LockToken = new object();
private static List<CMSUser> _Users { get; set; }
static MyCache()
{
_Users = GetUsers();
}
public static List<CMSUser> Users
{
lock (LockToken)
{
return _Users;
}
}
}
Controller
public class UsersController : ApiController
{
public List<CMSUser> Get()
{
return MyCache.Users;
}
}
View
$.ajax({
url: '/api/users',
dataType: 'json',
success: function(users) {
// do something with users here
}
});
Why wait for the first call to cache data? You could do this during the application start by adding it to the Application_Start function in Global.asax.
This will mean you will have a 15 sec overhead when your application starts, but after that you are good to go.
If you do want to use a thread here too, you could put its id in a static variable, and use that to check if the list has loaded.
This link http://msdn.microsoft.com/en-us/library/aa772153(VS.85).aspx says:
You can register up to five notification requests on a single LDAP connection. You must have a dedicated thread that waits for the notifications and processes them quickly. When you call the ldap_search_ext function to register a notification request, the function returns a message identifier that identifies that request. You then use the ldap_result function to wait for change notifications. When a change occurs, the server sends you an LDAP message that contains the message identifier for the notification request that generated the notification. This causes the ldap_result function to return with search results that identify the object that changed.
I cannot find a similar behavior looking through the .NET documentation. If anyone knows how to do this in C# I'd be very grateful to know. I'm looking to see when attributes change on all the users in the system so I can perform custom actions depending on what changed.
I've looked through stackoverflow and other sources with no luck.
Thanks.
I'm not sure it does what you need, but have a look at http://dunnry.com/blog/ImplementingChangeNotificationsInNET.aspx
Edit: Added text and code from the article:
There are three ways of figuring out things that have changed in Active Directory (or ADAM). These have been documented for some time over at MSDN in the aptly titled "Overview of Change Tracking Techniques". In summary: Polling for Changes using uSNChanged. This technique checks the 'highestCommittedUSN' value to start and then performs searches for 'uSNChanged' values that are higher subsequently. The 'uSNChanged' attribute is not replicated between domain controllers, so you must go back to the same domain controller each time for consistency. Essentially, you perform a search looking for the highest 'uSNChanged' value + 1 and then read in the results tracking them in any way you wish. Benefits This is the most compatible way. All languages and all versions of .NET support this way since it is a simple search. Disadvantages There is a lot here for the developer to take care of. You get the entire object back, and you must determine what has changed on the object (and if you care about that change). Dealing with deleted objects is a pain. This is a polling technique, so it is only as real-time as how often you query. This can be a good thing depending on the application. Note, intermediate values are not tracked here either. Polling for Changes Using the DirSync Control. This technique uses the ADS_SEARCHPREF_DIRSYNC option in ADSI and the LDAP_SERVER_DIRSYNC_OID control under the covers. Simply make an initial search, store the cookie, and then later search again and send the cookie. It will return only the objects that have changed. Benefits This is an easy model to follow. Both System.DirectoryServices and System.DirectoryServices.Protocols support this option. Filtering can reduce what you need to bother with. As an example, if my initial search is for all users "(objectClass=user)", I can subsequently filter on polling with "(sn=dunn)" and only get back the combination of both filters, instead of having to deal with everything from the intial filter. Windows 2003+ option removes the administrative limitation for using this option (object security). Windows 2003+ option will also give you the ability to return only the incremental values that have changed in large multi-valued attributes. This is a really nice feature. Deals well with deleted objects. Disadvantages This is .NET 2.0+ or later only option. Users of .NET 1.1 will need to use uSNChanged Tracking. Scripting languages cannot use this method. You can only scope the search to a partition. If you want to track only a particular OU or object, you must sort out those results yourself later. Using this with non-Windows 2003 mode domains comes with the restriction that you must have replication get changes permissions (default only admin) to use. This is a polling technique. It does not track intermediate values either. So, if an object you want to track changes between the searches multiple times, you will only get the last change. This can be an advantage depending on the application. Change Notifications in Active Directory. This technique registers a search on a separate thread that will receive notifications when any object changes that matches the filter. You can register up to 5 notifications per async connection. Benefits Instant notification. The other techniques require polling. Because this is a notification, you will get all changes, even the intermediate ones that would have been lost in the other two techniques. Disadvantages Relatively resource intensive. You don't want to do a whole ton of these as it could cause scalability issues with your controller. This only tells you if the object has changed, but it does not tell you what the change was. You need to figure out if the attribute you care about has changed or not. That being said, it is pretty easy to tell if the object has been deleted (easier than uSNChanged polling at least). You can only do this in unmanaged code or with System.DirectoryServices.Protocols. For the most part, I have found that DirSync has fit the bill for me in virtually every situation. I never bothered to try any of the other techniques. However, a reader asked if there was a way to do the change notifications in .NET. I figured it was possible using SDS.P, but had never tried it. Turns out, it is possible and actually not too hard to do. My first thought on writing this was to use the sample code found on MSDN (and referenced from option #3) and simply convert this to System.DirectoryServices.Protocols. This turned out to be a dead end. The way you do it in SDS.P and the way the sample code works are different enough that it is of no help. Here is the solution I came up with:
public class ChangeNotifier : IDisposable
{
LdapConnection _connection;
HashSet<IAsyncResult> _results = new HashSet<IAsyncResult>();
public ChangeNotifier(LdapConnection connection)
{
_connection = connection;
_connection.AutoBind = true;
}
public void Register(string dn, SearchScope scope)
{
SearchRequest request = new SearchRequest(
dn, //root the search here
"(objectClass=*)", //very inclusive
scope, //any scope works
null //we are interested in all attributes
);
//register our search
request.Controls.Add(new DirectoryNotificationControl());
//we will send this async and register our callback
//note how we would like to have partial results
IAsyncResult result = _connection.BeginSendRequest(
request,
TimeSpan.FromDays(1), //set timeout to a day...
PartialResultProcessing.ReturnPartialResultsAndNotifyCallback,
Notify,
request);
//store the hash for disposal later
_results.Add(result);
}
private void Notify(IAsyncResult result)
{
//since our search is long running, we don't want to use EndSendRequest
PartialResultsCollection prc = _connection.GetPartialResults(result);
foreach (SearchResultEntry entry in prc)
{
OnObjectChanged(new ObjectChangedEventArgs(entry));
}
}
private void OnObjectChanged(ObjectChangedEventArgs args)
{
if (ObjectChanged != null)
{
ObjectChanged(this, args);
}
}
public event EventHandler<ObjectChangedEventArgs> ObjectChanged;
#region IDisposable Members
public void Dispose()
{
foreach (var result in _results)
{
//end each async search
_connection.Abort(result);
}
}
#endregion
}
public class ObjectChangedEventArgs : EventArgs
{
public ObjectChangedEventArgs(SearchResultEntry entry)
{
Result = entry;
}
public SearchResultEntry Result { get; set;}
}
It is a relatively simple class that you can use to register searches. The trick is using the GetPartialResults method in the callback method to get only the change that has just occurred. I have also included the very simplified EventArgs class I am using to pass results back. Note, I am not doing anything about threading here and I don't have any error handling (this is just a sample). You can consume this class like so:
static void Main(string[] args)
{
using (LdapConnection connect = CreateConnection("localhost"))
{
using (ChangeNotifier notifier = new ChangeNotifier(connect))
{
//register some objects for notifications (limit 5)
notifier.Register("dc=dunnry,dc=net", SearchScope.OneLevel);
notifier.Register("cn=testuser1,ou=users,dc=dunnry,dc=net", SearchScope.Base);
notifier.ObjectChanged += new EventHandler<ObjectChangedEventArgs>(notifier_ObjectChanged);
Console.WriteLine("Waiting for changes...");
Console.WriteLine();
Console.ReadLine();
}
}
}
static void notifier_ObjectChanged(object sender, ObjectChangedEventArgs e)
{
Console.WriteLine(e.Result.DistinguishedName);
foreach (string attrib in e.Result.Attributes.AttributeNames)
{
foreach (var item in e.Result.Attributes[attrib].GetValues(typeof(string)))
{
Console.WriteLine("\t{0}: {1}", attrib, item);
}
}
Console.WriteLine();
Console.WriteLine("====================");
Console.WriteLine();
}