0

My ASP.NET Core application is using dotliquid. I am creating my own custom dotliquid tag and I want to inject IHttpContextAccessor in my custom tag. Based on my research i have to create ITagFactory to create tag and inject IHttpContextAccessor.

my custom factory

public class LiquidTagFactory : DotLiquid.ITagFactory
{
    private readonly Type _tagType;
    private readonly string _tagName;
    private readonly IHttpContextAccessor _contextAccessor;

    public string TagName { get { return _tagName; } }

    public LiquidTagFactory(Type tagType, string tagName, IHttpContextAccessor contextAccessor)
    {
        _tagType = tagType;
        _tagName = tagName;
        _contextAccessor = contextAccessor;
    }

    public Tag Create()
    {
        return (Tag)Activator.CreateInstance(_tagType, _contextAccessor);
    }
}

my custom tag

public class TextBox : DotLiquid.Tag
{
    private string _html = null;
    private readonly IHttpContextAccessor _contextAccessor;

    public TextBox(IHttpContextAccessor contextAccessor)
    {
        _contextAccessor = contextAccessor;
    }

    public override void Initialize(string tagName, string markup, List<string> tokens)
    {
        // here i want to store some values into HttpContext.Items
        _contextAccessor.HttpContext.Items.Add("key","somedata");           

        base.Initialize(tagName, markup, tokens);
    }

    public override void Render(Context context, TextWriter result)
    {
       _html = CreateHtml();
        result.Write(_html);
        base.Render(context, result);
    }
}

Then i would register this factory as

 Template.RegisterTagFactory(new LiquidTagFactory(typeof(TexBox), "textbox", _httpContextAccessor));

However, i am using ASP.NET Core. I am not sure how do i register custom tag factory using .NET Core's dependency injection?

looking at dotliquid's template code it stores the ITagFactory in private static field

  private static Dictionary<string, Tuple<ITagFactory, Type>> Tags { get; set;}

In my case, every request will have its own IHttpContextAccessor, and i don't want to create factory for each request

LP13
  • 30,567
  • 53
  • 217
  • 400

1 Answers1

0

I think i found it. As per SO we can register IHttpContextAccessor singleton. As of .NET Core 2.1 there is an extension method that has been added to correctly register an IHttpContextAccessor as a singleton. Simply add as follows in your ConfigureServices() method:

         services.AddHttpContextAccessor();

This is equivalent to:

         services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();

and then register the factory in Configure() method in startup. Make sure to pass IHttpContextAccessor as parameter

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, IOptions<DomainOptions> domainOps, IHttpContextAccessor httpContextAccessor)
    {


        Template.RegisterTagFactory(new LiquidTagFactory(typeof(TextBox), "textbox", httpContextAccessor));
    }
LP13
  • 30,567
  • 53
  • 217
  • 400