Moving ClientContext to external call

Hi in order to use complete request caching with Fastly, we need to move the ClientContext from the header and load in this information via ajax.

So I’m simply trying to convert that block to a api call like so:

    [RoutePrefix("api/client")]
public class ClientController : ApiControllerBase
{
    private readonly ClientContextViewModelBuilder _clientContextViewModelBuilder;

    public ClientController(ClientContextViewModelBuilder clientContextViewModelBuilder)
    {
        _clientContextViewModelBuilder = clientContextViewModelBuilder;
    }

    [HttpGet]
    public IHttpActionResult Get()
    {
        var viewModel = _clientContextViewModelBuilder.Build();
        var clientContext = this.RenderViewToString("Framework/ClientContext", viewModel);
        return Ok(clientContext);
    }

}

But _clientContextViewModelBuilder.Build() fails, because it can’t build the SiteSettingViewModel because _routeRequestInfoAccessor.RouteRequestInfo is null in the SiteSettingViewModelBuilder.

How can I load all the data needed to do this tasks in a api call?

RequestModelAccessor seam to be needed for all the builders, is there an easier way to do what I want maybey?

Litium version: 7

I think you need to restructure the code so in the html you need to write out the basic information in the client context to the html but skip the preloadState and then by the api-request only load the preloadState parameters. The basic information is the same for all request for that page so that is something you should be able to cache with the html.

The requestContext need to be sent to the api endpoint as an http header to correctly create the RequestModel (and other classes).

When using fastly and if you plan to cache the full html-page like that, ensure that you have a Surrogate-Key assigned to so you can purge only the page-html data instead of using Purge All that also will purge all media.

Oki so the requestVerificationToken is ok to be cached?

Also, could you expand on this one? c# is not my first language :wink: (I think I read somewhere that context was not allowed in api calls)

The requestContext need to be sent to the api endpoint as an http header to correctly create the RequestModel (and other classes).`

Should i just inject RequestContext requestContext in the constructor?

I didn’t see the requestVerificationToken that not was set on the window.__litium.-object. But no, that should not either be cached and need to be included in the request header for every api-controller endpoint that is decorated with the [ApiValidateAntiForgeryToken]-attribute. The value ini the header need to match the value in the cookie with the same name, otherwise the request will be denied.

requestContext is only a name of the parameter and the header, it is not the same as the RequestContext that exists in ASP.NET WebAPI and is only in this case an json-formatted string that will be serialized into an SiteSettingViewModel in the RequestModelHandler-class so that the request knows the channel/page/product/category the user currently is browsing.

I see the parameter:

litium-request-context: {“channelSystemId”:“4f231060-96ef-4e9e-b1f3-d4066b6065b8”,“currentPageSystemId”:“dab845c0-8bf9-4cdd-80d5-e826cfeb9337”}

On the normal Cart api call, is this the one I need to add? This would mean that I cant create a “mock .js file” and load the data using a script tag?

I need to load the data using js adding in the litium-request-context header?

It is that data, but that data is the same for the same page for all users so that can be cached together with the html. I don’t think you can manage to load that with a script tag.

You instead need:

  • Include the request context in the html-on the page
  • include the script tag that load the javascript files
  • the javascript files load this data from the loaded html-page and will use for all the additional api-calls.
1 Like

Thank you! Now I got it working, but am not loving the solution. I really would love to have it in a script tag like this:

<script src="/api/client/?channelSystemId=4f231060-96ef-4e9e-b1f3-d4066b6065b8&currentPageSystemId=dab845c0-8bf9-4cdd-80d5-e826cfeb9337"></script>

Where are the litium-request-context first processed? Can i override it?

Edit: This seam to work, could this be a ok solution?

   public static class RequestHeaderExtension
{
    public static SiteSettingViewModel GetSiteSettingViewModel(this HttpRequestHeaders httpHeaders, HttpRequestMessage request)
    {

        if (httpHeaders.TryGetValues("litium-request-context", out var items))
        {
            var json = items.First();
            var jObject = JObject.Parse(json);
            return jObject.ToObject<SiteSettingViewModel>();
        }
        else
        {

            /*
             * If the litium-request-context header is not set we we load the value from
             * the query string if possible.
             */
            Guid csi;
            Guid cpi;

            if (
                Guid.TryParse(request.GetQueryString("channelSystemId"), out csi) &&
                Guid.TryParse(request.GetQueryString("currentPageSystemId"), out cpi))
            {
                return new SiteSettingViewModel() { ChannelSystemId = csi, CurrentPageSystemId = cpi };
            }
        }
        return null;
    }
}

Thanks

That will work in my opinion. Please note SietSettingViewModel also contains ProductCategorySystemId.

1 Like