I am experiencing a problem with the cacheManager in NopCommerce
I have a list of nopCommerce products, in the form of an IPagedList<Product>
I add them to my cachemanager as such:
_cacheManager.Set("SearchResult", products.ToList(), 5);
Now whenever i try to retrieve them like this:
var searchresults = new List<Product>();
if (_cacheManager.IsSet("SearchResult"))
{
searchresults = _cacheManager.Get<List<Product>>("SearchResult");
}
It is just empty, like, the isSet evaluates to false.
I tried to _cacheManager.Clear() before i add them, but that also doesn't work. I am running out of ideas here. Anyone got a clue?
I used this as a source for the retrieval:
http://www.nopcommerce.com/boards/t/12290/getting-an-item-on-the-cachemanager-requires-a-function-param-.aspx
I suppose that the problem is that you can't cache data between http requests, but I'm sure that you can retrieve that data during the same request.
NopCommerce has two cache managers. Both are declared at DependencyRegistrar.cs:
builder.RegisterType<MemoryCacheManager>().As<ICacheManager>().Named<ICacheManager>("nop_cache_static").SingleInstance();
builder.RegisterType<PerRequestCacheManager>().As<ICacheManager>().Named<ICacheManager>("nop_cache_per_request").InstancePerHttpRequest();
The default cache manager, only holds data for the current HTTP request. The second one, the static cache, spans to other HTTP requests.
If you want to use the static cache, you need to instruct Autofac to inject it when you configure the dependencies for your service. Look at DependencyRegistrar.cs, there are several examples for this, for instance:
builder.RegisterType<ProductTagService>().As<IProductTagService>()
.WithParameter(ResolvedParameter.ForNamed<ICacheManager>("nop_cache_static"))
.InstancePerHttpRequest();
I encourage you to use this approach instead of adding an static reference to MemoryCacheManager.
I solved it by adding this._cacheManager = new MemoryCacheManager() instead of
this._cacheManager = cacheManager, where cachemanager is an instance of ICacheManager
Related
I'm currently working on a webserver in asp.net core.
I want the server to process the users input and data and am looking for a good solution to save complex Objects for the runtime.
So my first approach was to use Sessions. In Asp.net, sessions used to work like Session["key"] = new ValueObject()
In asp.net core however you can only use the methods SetString, SetInt32 and Set for byte arrays. I found a lot of solutions which basically converted the objects into Json strings. However in my case this isn't possible due to the objects containing other object references and more.
My second idea was to create a list of objects with the SessionId as identifier. Problem with this is that every time I would make request to the server, it needs to go through all existing Sessions to find the matching one, so this would probably drastically increase the time for the request.
So my question is what would be the best way to save user related objects?
Is using Sessions even the best way for solving this problem or am I missing something?
Note: Request are handled by JQuery AJAX, so reloading the page for accessing data is not an option.
You could try using the MemoryCache that can hold any .net type. It is not a problem but given it is a shared structure, it will be shared to all users, so, you have to carefull manage it. To do it, you could use HttpContext.Session.Id to define the keys on the memory cache instance. For sample (pseudo-code I didn't test):
public class HomeController : Controller
{
private IMemoryCache _cache;
public HomeController(IMemoryCache memoryCache)
{
_cache = memoryCache;
}
public async Task<IActionResult> CacheGetOrCreateAsynchronous()
{
string cacheKey = $"{HttpContext.Session.Id}_data";
var cacheEntry = await
_cache.GetOrCreateAsync(cacheKey , entry =>
{
entry.SlidingExpiration = TimeSpan.FromSeconds(3);
return Task.FromResult(DateTime.Now);
});
return View("Cache", cacheEntry);
}
}
I'm attempting to add caching to our IS4 implementation using their Caching methods. However, my implementation does not appear to be having any impact on the speed of login or the number of queries hitting my database per login (which I would expect caching to reduce both).
The changes I made to implement caching are as follows:
Added the following to Startup.cs ConfigureServices
Updated the services.AddIdenttiyServer() call to include the lines:
.AddInMemoryCaching()
.AddClientStoreCache<IClientStore>()
.AddResourceStoreCache<IResourceStore>()
.AddCorsPolicyCache<ICorsPolicyService>();
Updated ConfigureServices to also have the following:
services.AddScoped<ICorsPolicyService, DefaultCorsPolicyService>();
services.AddScoped<IClientStore, ClientStore>();
services.AddScoped<IResourceStore, ResourceStore>();
That appeared to be the only things I needed to implement, and while the application runs normally, the caching does not seem to be doing anything. What am I missing?
Basically you need to do 2 things:
First implement the IClientStore:
public class ClientStore : IClientStore
{
private readonly IClientService clientService;
public ClientStore(IClientService clientService)
{
this.clientService = clientService;
}
public Task<Client> FindClientByIdAsync(string clientId)
{
var client = this.clientService.GetById(clientId);
return Task.FromResult(client);
}
}
The ClientService is my implementation for getting the client from the db, so there you need to put your own.
Then in the Startup.cs you need:
services.AddIdentityServer(options =>
{
options.Caching.ClientStoreExpiration = new TimeSpan(0, 5, 0);
})
.AddInMemoryCaching()
.AddClientStoreCache<ClientStore>()
.// More stuff that you need
This is for the Client Caching but for the Cors and the ResourceStore is quite the same.
I think that you are missing the options.Caching.ClientStoreExpiration part. Start from there.
Hope that this helps.
PS: Forgot to mention - you don't need to explicitly inject your implementation of the IClientStore. By adding it to the .AddClientStoreCache<ClientStore>() it gets injected. But (as in my example) if you have other services, used by the store, you need to inject them.
There is no standard way to cache users.
It caches only:
Clients - AddClientStoreCache
Resources - AddResourceStoreCache
CorsPolicy - AddCorsPolicyCache
More details you can get from documentations
I have an ASP.NET MVC application using StructureMap.
I have created a service called SecurityContext which has a static Current property. A simplified version looks like this:
public class SecurityContext : ISecurityContext
{
public bool MyProperty { get; private set; }
public static SecurityContext Current
{
get
{
return new SecurityContext() { MyProperty = true };
}
}
}
I've hooked this up in my StructureMap registry as follows:
For<ISecurityContext>().Use(() => SecurityContext.Current);
My understanding of this Linq expression overload of the Use method is that the returned concrete object is the same for the entire HTTP request scope.
However, I've set up a test case where my context interface is injected in two places, once in the controller's constructor and again using the SetterProperty attribute in the base class my view inherits from.
When debugging I observe the Current static method being hit twice so clearly my assumptions are wrong. Can anyone correct what I'm doing here? The reason I want this request-scoped is because I'm loading certain data into my context class from the database so I don't want this to happen multiple times for a given page load.
Thanks in advance.
The default lifecycle for a configuration is Transient, thus each request for an ISecurityContext will create a new instance of SecurityContext. What I think you want is to use the legacy HttpContext lifecycle.
Include the StructureMap.Web nuget package. Then change your configuration to the following:
For<ISecurityContext>()
.Use(() => SecurityContext.Current)
.LifeCycleIs<HttpContextLifecycle>();
More information on lifecyles can be found here.
The HttpContextLifecycle is obsolete, however I do not know if or when it will be removed. The StructureMap team does recommend against using this older ASP.Net lifecycle. They state in the documentation that most modern web frameworks use a nested container per request to accomplish the same scoping. Information about nested containers can be found here.
I don't know if the version of ASP.Net MVC you are using is considered a modern web framework. I doubt it is because ASP.Net Core 1.0 is the really the first in the ASP.Net line to fully embrace the use of DI. However, I will defer to #jeremydmiller on this one.
I need to somehow attach my custom data to the HttpRequest being handled by my IIS custom modules - so that code that runs in earlier stages of IIS pipeline attaches an object and code that runs in later stages can retrieve the object and use it and no other functionality of IIS pipeline processing is altered by adding that object.
The data needs to persist within one HTTP request only - I don't need it to be stored between requests. I need it to be "reset" for each new request automatically - so that when a new request comes it doesn't contain objects my code attached to the previous request.
Looks like HttpContext.Items is the way to go, although MSDN description of its purpose is not very clear.
Is using HttpContext.Current.Items the way to solve my problem?
This should work - I have done this in a project before.
I have a class which has a static property like this -
public class AppManager
{
public static RequestObject RequestObject
{
get
{
if (HttpContext.Current.Items["RequestObject"] == null)
{
HttpContext.Current.Items["RequestObject"] = new RequestObject();
}
return (RequestObject)HttpContext.Current.Items["RequestObject"];
}
set { HttpContext.Current.Items["RequestObject"] = value; }
}
}
And then RequestObject contains all my custom data so then in my app I can do
AppManager.RequestObject.CustomProperty
So far I have not come across any issues in the way HttpContext.Items works.
So we have a webservice that is called from different applications and it runs an extraction of data which takes a while and we don't want it to run multiple times. So we thought we could set an HttpContext.Current.Application["isRunning"] to be persistent through all the requests like :
if ((bool)HttpContext.Current.Application["isRunning"])
And it doesn't work, since a new HttpContext is created when an other application call the webmethod.
Except writing onto the disk or in AppSettings I don't see how I can persist data through every request to only have one instance of my webmethod running at a time. I've tried with Application, Cache and static variables but they all do not persist across requests. It seems it creates a new instance each time.
Preventing a new instance to be created or persist data through instances would fix the issue. Any hint?
You could use EnterpriseLibraries Caching Block to cache the data following extraction.
http://www.codeproject.com/KB/web-cache/CachingApplicationBlock.aspx
Once you have the Enterprise Library assemblies referenced, it's just a case of adding a few lines to your web.config and then using code such as the following inside your service.
//Create Instance of CacheManager
ICacheManager _objCacheManager = CacheFactory.GetCacheManager();
AbsoluteTime timeToExpire = new AbsoluteTime(TimeSpan.FromMinutes(60));
MyData myData = null;
myData = (MyData)cacheManager.GetData("ref");
if (myData == null)
{
//get the data
cacheManager.Add("ref", myData, CacheItemPriority.Normal, null, timeToExpire);
}
return myData;
Take a look at the following links, which provide useful information on wanting to use the Singleton pattern with web services.
http://forums.asp.net/t/881617.aspx/1
http://social.msdn.microsoft.com/Forums/en-US/asmxandxml/thread/72274741-dbbe-4a64-a360-6bbe60026ec9/
http://msdn.microsoft.com/en-us/library/ff650316.aspx