Developer forum

Forum » Dynamicweb 10 » HttpContext in TableScripts (and maybe other backend code)

HttpContext in TableScripts (and maybe other backend code)

Imar Spaanjaars Dynamicweb Employee
Imar Spaanjaars
Reply

How do I access HttpContext from a table script? In 9 I had code like this:

if (!Dynamicweb.Context.Current.Items.Contains("SomeKey"))

But now in 10 Context.Current is null.

I tried injecting an IHttpContextAccessor like I normally would in core:

public MyTableScript(IHttpContextAccessor context)
{
}

That works and my constructor gets called, but context is still null.

Imar


Replies

 
Kevin Steffer
Kevin Steffer
Reply

Have you tried using the DependencyResolver.Current.GetRequriedService<IHttpContextAccessor>() ?

 
Imar Spaanjaars Dynamicweb Employee
Imar Spaanjaars
Reply

Same thing; HttpContext is null. I guess that's because it runs as a background thread where there is no context. I just remembered a similar issue from an index builder: https://doc.dynamicweb.com/forum/development/development/httpcontext-in-an-indexbuilderextender

For the dev team: Would it be an option to have some kind of storage (like a Dictionary<string, object> on a TableScript and other background tasks that exist for the lifetime of a single invocation? With HttpContext we had that; data would live for exactly one context which would mean my full lifecycle of the table script, index builder or what not.

With other solutions, I run the risk of storing data for too long or too short. I could for example cache my data for 10 minutes. If my job takes 20, I need to fetch the data twice. If I cache it for longer but the job runs quicker, I run the risk of stale data that has been updated by a previous run.

Any input would be highly appreciated.

Imar

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply

Hi

What about using AsyncLocal<T>: https://learn.microsoft.com/en-us/dotnet/api/system.threading.asynclocal-1

using Dynamicweb.Extensibility.AddIns;
using Dynamicweb.Data;
using System;
using System.Collections.Generic;
using System.Threading;

public class MyTableScript : TableScript
{
    private static AsyncLocal<Dictionary<string, object>> _asyncCache = new AsyncLocal<Dictionary<string, object>>();

    private static Dictionary<string, object> AsyncCache
    {
        get
        {
            if (_asyncCache.Value == null)
                _asyncCache.Value = new Dictionary<string, object>();
            return _asyncCache.Value;
        }
    }

    public override void Execute(DataRow row)
    {
        // Store per async context
        AsyncCache["Now"] = DateTime.Now;

        // Use the stored value
        row["MyField"] = $"Cached timestamp: {AsyncCache["Now"]}";

    }
}
 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply
This post has been marked as an answer

Or more old school thread static:

using Dynamicweb.Extensibility.AddIns;
using Dynamicweb.Data;
using System;
using System.Collections.Generic;

public class MyTableScript : TableScript
{
    [ThreadStatic]
    private static Dictionary<string, object> _threadCache;

    private static Dictionary<string, object> ThreadCache
    {
        get
        {
            if (_threadCache == null)
                _threadCache = new Dictionary<string, object>();
            return _threadCache;
        }
    }

    public override void Execute(DataRow row)
    {
        // Store per-thread value
        ThreadCache["Now"] = DateTime.Now;

        // Use the stored value
        row["MyField"] = $"Cached timestamp: {ThreadCache["Now"]}";

    }
}
Votes for this answer: 1
 
Imar Spaanjaars Dynamicweb Employee
Imar Spaanjaars
Reply
// Important: clear when done
ThreadCache.Clear();

I guess that's where the complexity comes in: I don't want to clear it; I want to keep my data for the entire execution of the import job. Here's my flow

1. Job starts

2. I fetch expensive data once

3. ProcessRow is called for each row in my set; I use the locally stored data

4. Job ends; I clear my cache

Years ago you and I had a design session to implement something like an IJobRunner where we could implement custom logic for different steps of the job, without having to rely on subscribers like JobFinished and so on. Did that ever make it into the product?

Imar

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply
This post has been marked as an answer

Hi Imar

You should not call the clear - you can also use ThreadLocal - both will die automatically when out of the job runner context.

Votes for this answer: 1

 

You must be logged in to post in the forum