I am working in a multi-layered web application that has ASP.NET MVC as its front-end client. A particular page of this web application is taking a very long time to load. Around 30 seconds.
I downloaded dotTrace and ran it on my application (following this tutorial). I found out that the reason my application is slow.
It turns out it is because one particular method that I have does a load of work (takes time), and that same method gets called a total of 4 times.
Here is a screenshot from dotTrace showing the above:
The method in question is GetTasks(). So in order to improve the speed of the web application I want to cache the data returned from GetTasks() for each request.
If my thinking is correct, this would really improve on the speed issues I am having.
My question is, how can I achieve this? I have never done such a thing before. For each new request, how can I cache the data returned from GetTasks(), and use that for all subsequent calls to GetTasks().
Have you considered the Cache Aside pattern?
You can implement it easily using LazyCache
//probably in my constructor (or use dependency injection)
this.cache = new CachingService()
public List<MyTasks> GetTasks()
{
return cache.GetOrAdd<List<MyTasks>>("get-tasks", () = > {
//go and get the tasks here.
});
}
For more information see https://alastaircrabtree.com/the-easy-way-to-add-caching-to-net-application-and-make-it-faster-is-called-lazycache/
One of the most popsular solution is to cache results. I can shouw you my solution.
First of all install Nuget package: LazyCache
Then you can use wrapper that I've created wrapper: code. You can extract and interface or whatever.
Then you can use it like this:
private readonly CacheManager cacheManager = new CacheManager();
// or injected via ctor
public IEnumerable<Task> GetTasks()
{
return this.cacheManager.Get("Tasks", ctx => this.taskRepository.GetAll());
}
public void AddTask(Task task)
{
this.taskRepository.Create(task);
/// other code
// we need to tell the cache that it should get fresh collectiion
this.cacheManager.Signal("Tasks");
}
Related
This is a practice ASP.NET project I'm using to better understand a few techniques, and while I've got Dependency Injection working, its not working quite as I want it to. I have a class that I want to use to store a history, so every time the user hits a submit button, it displays a result, and after the second time it starts displaying the history. Anyway I added the history to the DI as a scoped service, thinking that would mean it would be created and then remain the same instance for the duration of the session for that user. However according to the debugger it looks like the list never gets bigger than one, and thats at the point of adding the item to the list. So the code.
The object
{
public class RollHistory : IRollHistory
{
public List<IRollMessage> Entries { get; set; } = new List<IRollMessage>();
}
}
The DI
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddTransient<IDiceTray, DiceTray>();
services.AddTransient<IRollMessage, RollMessage>();
services.AddScoped<IRollHistory, RollHistory>();
}
The Controller constructor
public HomeController(ILogger<HomeController> logger, IDiceTray diceTray, IRollMessage rollMessage, IRollHistory rollHistory)
{
_logger = logger;
_diceTray = diceTray;
_rollMessage = rollMessage;
_rollHistory = rollHistory;
}
And the code for when the button gets clicked
[HttpPost]
public IActionResult Index(DiceRollModel diceRoll)
{
_diceTray.DiceRoll(diceRoll.DiceType, diceRoll.DiceCount, diceRoll.Bonus, diceRoll.VantageType);
_rollMessage.RollMessages(_diceTray);
diceRoll.RollResult = _rollMessage;
_rollHistory.Entries.Add(_rollMessage);
diceRoll.History = _rollHistory.Entries;
return View(diceRoll);
}
It's worth noting I've tried to code this at least 4 different ways with and without DI, the only way it works is if I use AddSingleton, while this might not be an issue because this app is unlikely to ever be live, its a poor excuse not to do it right.
I believe “scope” is by default per request which would explain that each submit gets is own service.
“Doing stuff right” is of course to some extend a matter of opinion. But my opinion would clearly be that I would avoid server-side session to avoid problems with scaling to more than one instance. There are also ways to support shared state, but this is difficult. To me singletons are not a code smell either, but they have their own problems.
Your problem might be solved by storing whatever state you need in the browser either in a cookie or localStorage. Your service would then have request scope, but it would read user state from browser causing “user scope” for the data. (But don’t rely on browser state to persist and remember it is modifiable to the user.)
So I have a website written in .NET Core C# and I would like to run a process in the background that would make API calls to other website and save the data in database.
I have created ApiAccessor class and would like to invoke the method from the controller (which uses dependency injections for it's database connection), but if I pass them to the ApiAccessor (it would be async) the connection is already disposed of. I've tried injecting it from the get go, but it will still say that the interfaces are disposed, by the time it finishes. I can only do await on it, but this would cause user to wait for too long. What approach should I take with this one? I am a newbie at DI. Maybe some Singleton class? I would still don't know how to pass dependency injections to singleton
ApiAccessor:
IUserAccount _userAccounts;
public ApiAccessor(IConfiguration configuration, IUserAccount userAccounts)
{
_configuration = configuration;
_userAccounts = userAccounts;
}
//...
MethodToPollApi(){
var newUserIdToAdd = // just some kind of new data from api
_userAccounts.Add(newUserIdToAdd) // accessing DB, that causes errors
}
Controller:
void Index(){
MethodToPollApi();
return View();
}
I would consider an idea of using as called background jobs. There are a few popular frameworks for this type of solutions. Within them: custom implementation based on IHostedService, Quartz.NET, Hangfire, and many more available.
I used to play with many of them, personally prefer Hangfire as it self bootstrapped, provide nice UI for jobs dashboard, and really easy to use - for instance, that is how triggering jobs light look like with it:
Run once immediately:
var jobId = BackgroundJob.Enqueue(() => Console.WriteLine("Fire-and-forget!"));
Run delayed:
BackgroundJob.Schedule(() => Console.WriteLine("Delayed!"), TimeSpan.FromDays(7));
Run repeating:
var jobId = RecurringJob.AddOrUpdate(() => Console.WriteLine("Recurring!"), Cron.Daily);
Pick up completed job and continue:
BackgroundJob.ContinueWith(jobId, () => Console.WriteLine("Continuation!"));
Continuing the answer from #Dmitry. With Hangfire you can do something like this.
services.AddHangfire(x => x.UseSqlServerStorage("<Your connection string>"));
Hope this helps.
I have a member of my controller
private Lazy<MyCache> loadedComponentCache = new Lazy<MyCache>(() =>
{
MyCache instance = MyCacheb.Instance;
instance.LoadStuffAsync().Wait();
return instance;
}, LazyThreadSafetyMode.PublicationOnly);
that I'm using to lazy-call a long-running method LoadAsync() that will only need called if a certain API endpoint is hit after the user goes to the page.
[HttpGet]
public ActionResult GetStuff()
{
var results = from component in loadedComponentCache.Value.All()
// ...
}
Any idea why it's re-loading every time the API endpoint is hit? My understanding is that an instance of my controller is created only when the user goes to the page and thus this will only be hit once per API call per user visiting the page.
You could make loadedComponentCache static but that's not ideal. If you are using an IoC container you could register it as a singleton. These long lived objects are generally to be avoided though if possible.
If you you truely need this long lived cache then you should probably consider using something like Redis which is designed and optimised for this sort of scenario and can be distributed across multiple nodes. https://redis.io/topics/introduction
I have desktop application, that uses WCF services. I have got great usability improve when I implemented async WCF calls.
My question is: what is the best practice to initialize service client?
In previous realization there was single static object with credentials and a public method GetClient(), that was creating new ServiceClient before every call. In application there was commonly used such construction:
using (var svc = ServiceClientFactory.GetClient()) {
var data = svc.CallMethod(...);
some_application_context.specific_attribute = data;
}
so, before any call, was created new client, that was destroyed immediately after operation was finished and received data was used.
My question is: is it the best practice to call client constructor before every call?
I've tried to create single static client object, that is initialized once at startup and destroyed once on application closing, but I haven't got any notional performance gain.
Seems like it works fine, but I wonder if there any not very obvious obstacles in using single client? And what is recommended?
It's kind of a broad question, it depens on a lot of factors and also on style I guess.
When using reliable sessions or sessions in general you have to store the reference of course.
When calling the service many times it might be better to store the reference, or it might not. Better profile it then and there.
I always store a reference and create a property which check if the client is null or in the Faulted State.
Service.ServiceClient ShippingService
{
get
{
if (mService == null || mService.State == CommunicationState.Faulted)
{
mService = new Service.ServiceClient("netTcpService");
mShippingService.Open();
}
return mService;
}
}
You should look at dependency injection for getting your service references. Effectively it would be similar if not the same performance to what your doing now but it would make long term management easier and allow easier unit testing.
Most of the WCF overhead is connection negotiation so singleton vs new on each call won't really end up making a huge difference.
Is this a nice way to use the LINQ context during one http request? In almost every request i have some selects from the database and some inserts/updates. It seams to work but I dont know how this will work with heavy traffic to the servers and on load balanced servers, anyone have any opinions/ideas about this way to keep the Context during the entire lifespan of the Request?
public static AccountingDataContext Accounting
{
get
{
if (!HttpContext.Current.Items.Contains("AccountingDataContext"))
{
HttpContext.Current.Items.Add("AccountingDataContext", new AccountingDataContext(ConfigurationManager.ConnectionStrings["SQLServer.Accounting"].ConnectionString));
}
return HttpContext.Current.Items["AccountingDataContext"] as AccountingDataContext;
}
}
This is a generally good idea on some levels. But you probably want to push instantiation back from the Begin_Request event. With the integrated pipeline, you will be initializing a rather expensive DB Context for every single request to your site. Including favicon.ico, all your stylesheets and all your images.
Best, simple implementation of something that only instantiates it when something asks for the context is Ayende's example for NHibernate's ISession; you can just replace it with the appropriate bits to instantiate your L2S context.
I'm using Unity for dependency injection, but the idea is the same:
protected void Application_BeginRequest() {
var childContainer = this.Container.CreateChildContainer();
HttpContext.Current.Items["container"] = childContainer;
this.ControllerFactory.RegisterTypes(childContainer);
}
protected void Application_EndRequest() {
var container = HttpContext.Current.Items["container"] as IUnityContainer;
if (container != null) {
container.Dispose();
}
}
The container is responsible for setting up a number of things, one of which is the data context. Works like a charm. I haven't done load balancing, but can't imagine you'd run into issues there either. The request gets its own context, which is wrapping a single user connecting to a database. No different that using old school ADO .NET for data access.