1

I have a base Document DB repository in the infrastructure layer of my solution. I based this repository on this GitHub project, which is a static class that is utilized by my other domain model repositories.

In my API layer I have config.json files that are environment specific. I would like to use dependency injection to be able to use my configuration class that reads the DocumentDB settings defined in the API layer in the deeper Infrastructure layer. This StackOverflow answer details how to use DI with an API controller, however I can't figure out how to use DI in this case, as a static class, I don't have a constructor. Is it possible to use DI with my static repository? If not, how should I read config settings into the infrastructure layer?

My ConfigurationOptions class (in Infrastructure layer):

public class ConfigurationOptions
{
    public string EndpointUri { get; set; }
}

My DocumentDbRepository class (in Infrastructure layer):

public static class DocumentDbRepository<T>
{
    // I want to read these strings from my config.json files
    private static string EndpointUri { get; } = ConfigurationOptions.EndpointUri;

    //...


    private static Document GetDocument(string id)
    {
        return Client.CreateDocumentQuery(Collection.DocumentsLink)
            .Where(d => d.Id == id)
            .AsEnumerable()
            .FirstOrDefault();
    }
}

Part of my Startup class (in my API layer)

public class Startup
{
    public IConfiguration Configuration { get; set; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<ConfigurationOptions>(options =>
            options.EndpointUri = Configuration.Get("EndpointUri"));

    // ...

    }

// ...

}
Community
  • 1
  • 1
08Dc91wk
  • 4,254
  • 8
  • 34
  • 67
  • Ivan, if you want to use DI, you shouldn't declare the repository class as static. What you could do is inject the dependency as a singleton, in that way you use the same instance in the app. – lopezbertoni Aug 20 '15 at 14:03

1 Answers1

0

I believe you are almost there.

The first step you have to take is almost done.

in your startup.cs, you have

services.Configure<ConfigurationOptions>(options =>
        options.EndpointUri = Configuration.Get("EndpointUri"));

you can just call

services.Configure<ConfigurationOptions>(Configuration);

the services will map the EndpointUri attribute of your class. With this step 1 is done.

Now, following the post you linked, you can send your configurationOptions to the controller like:

    public class SomeController
{
    private string _endpointUrl;
    public SomeController(IOptions<ConfigurationOptions> options)
    {
        _endpointUrl = options.Options.EndpointUri;
    }
}

but, from what i assume, you want to have the EndpointUri in the DocumentDbRepository. You can do that in 2 ways:

1 --------------------------------------------------

You can create a constructor in your DocumentDbRepository to receive the EndpointUri and call it in your controller like such:

    public class SomeController
{
    private DocumentDbRepository _documentDbRepositoy
    public SomeController(IOptions<ConfigurationOptions> options)
    {
        _documentDbRepositoy = new DocumentDbRepository (options.Options.EndpointUri);
    }
}

2 ---------------------------------------------------

You can inject the DocumentDbRepository to all your controllers. For that i suggest that you create an interface IDocumentDbRepository and then configure it at startup making it a singleton or scoped or trasiend (for more info, see this link)

To do so, lets start with your DocumentDbRepository

public static class DocumentDbRepository<T> : IDocumentDbRepository<T>
{
    private string EndpointUri { get; private set;}

    public DocumentDbRepository(IOptions<ConfigurationOptions> options){
        EndpointUri = options.Options.EndpointUri;
    }

    //...


}

then, at startup.cs you set it as singleton (in this example)

public void ConfigureServices(IServiceCollection services){
    services.Configure<ConfigurationOptions(Configuration);
    services.AddSingleton<IDocumentDbRepository, DocumentDbRepository>();
    // ...

}

by doing this, if your controllers have a dependency on a IDocumentDbRepository, the singleton will be provided:

    public class SomeController
{
    private DocumentDbRepository _documentDbRepositoy
    public SomeController(IDocumentDbRepository documentDbRepository)
    {
        _documentDbRepositoy = documentDbRepository
    }
}
C-JARP
  • 1,028
  • 14
  • 16
  • Thanks for your answer Spike! I can't do your step 1 because the repository is static and can't take a constructor. I can't do your step 2 since my controllers are not using the DocumentDB repository, they read from domain models which are pre-loaded from the repository, which is why the answer I linked is not helpful for me. I tried creating a non-static wrapper for the DocumentDB repository which can accept the DI, and then passing through the config settings in every static method, but the repo no longer works (no error, the async methods just don't execute). – 08Dc91wk Aug 20 '15 at 11:04
  • It was my fault for not reading everything. However, by seeing the git repository you linked, you can create a singleton on startup and then do the following: private static string endpointUri; private static String EndpointUri; { get { if (string.IsNullOrEmpty(endpointUri)) { endpointUri= singleton.EndpointUri; } return endpointUri; } – C-JARP Aug 20 '15 at 11:23