4

I have a DocumentRenderer class, which calls an external API. The DocumentRenderer requires an AccessKey, which is stored in my appsettings.json config file. I want a newly instantiated DocumentRenderer object to, by default, use the AccessKey specified in the config file. However, I can't figure out how to achieve this outside of startup.cs. (I'm using ASP.NET Core)

Here's what I've tried so far:

Added DocumentRenderer to appsettings.json:

"DocumentRenderer": {
    "AccessKey": "<key>",
    "EndpointUrl": "<url>",
    "OutputFormat" :  "pdf" 
}

Created a "DocumentRendererOptions" POCO:

public class DocumentRendererOptions
{
    public string AccessKey { get; set; }
    public string EndpointUrl { get; set; }
    public string OutputFormat { get; set; }
}

Registered DocumentRendererOptions as a singleton service and bound the options from appsettings.json to it in the ConfigureServices method of startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<DocumentRendererOptions>();
    services.Configure<DocumentRendererOptions>(options => Configuration.GetSection("DocumentRenderer").Bind(options));
}

Finally I have my DocumentRenderer class:

public class DocumentRenderer
{
    private readonly string _endpointUrl;
    private readonly string _accessKey;
    private readonly string _outputFormat;

    public DocumentRenderer()
    {
    }

    public DocumentRenderer(IOptions<DocumentRendererOptions> options)
    {
        _accessKey = options.Value.AccessKey;
        _endpointUrl = options.Value.EndpointUrl;
        _outputFormat = options.Value.OutputFormat;
    }
}

I incorrectly assumed this would allow me to instantiate a new DocumentRenderer object with the default options, but obviously something is missing.

Every article I've read so far just talks about using this method with a controller and allowing DI to do the rest, but the DocumentRenderer isn't a controller.

As a temporary fix I've just made DocumentRendererOptions static, then assigned the values in startup, but this doesn't seem like the best solution

Andy
  • 71
  • 5
  • register the `DocumentRenderer` with services as well so the framework will instantiate it for you – Nkosi Jan 11 '17 at 13:09
  • @Nkosi How do I use the DocumentRenderer from other classes once I've registered it as a service? – Andy Jan 11 '17 at 13:22
  • by using constructor injection. same way you used IOptions in the renderer constructor. I would also advise abstracting the renderer and passing that to dependent classes – Nkosi Jan 11 '17 at 13:24
  • If I understand correctly, this means whichever class instantiates a new DocumentRenderer must also have the IOptions in its constructor? – Andy Jan 11 '17 at 13:36
  • No. the rederer is the one dependent on the options. the DI framework is responsible for instantiating classes and their dependencies. You may need to go back to the documentation https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection – Nkosi Jan 11 '17 at 13:37

1 Answers1

0

register the DocumentRenderer with services as well so the framework will instantiate it for you

public void ConfigureServices(IServiceCollection services)
{
    // Adds services required for using options.
    services.AddOptions();

    // Registers the following lambda used to configure options.
    services.Configure<DocumentRendererOptions>(Configuration.GetSection("DocumentRenderer"));

    //register other services
    services.AddSingleton<DocumentRenderer>();
}

Source: Using Options and configuration objects

Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • I tried this, but when I instantiate a new DocumentRenderer anywhere all of the it's values are null. This even happens when I call app.ApplicationServices.GetService() – Andy Jan 11 '17 at 13:28
  • Or other way, just put the `DocumentRenderer` into a static class. – John Jang May 08 '18 at 03:58