I have a Web Api project which relies heavily on Azure Cosmos DB. Until now, having one Cosmos DB account (one connection string) was sufficient. Now a new requirement is to be able to connect to a different Cosmos (two connection strings) depending on an incoming parameter.
For customerId X we should fetch documents from Cosmos DB 1 and for another customer Y we have to look in Cosmos DB 2.
Until now my Startup.cs file registered a singleton instance of CosmosClient. Which in turn gets instantiated like this
cosmosClient = new CosmosClient(endpointUrl, primaryKey);
And this worked really well. The Web Api was easily able to process all requests. But now that we have to new up a CosmosClient per request, performance is really bad.
So my question is; Is there a way to have multiple instances of the same singleton? As in; can we create a single instance of the combination Class+EndPointUrl? (Would that still be a singleton?)
Right now, we are newing up thousands of CosmosClients every minute. And we really need just one more compared to what we had earlier.
There's multiple ways to do this, but an easy implementation would be to create a wrapper around each CosmosClient you use. The only use of the wrapper will be to allow you to use various instances of the CosmosClient and differentiate them by their types.
//Create your own class for each client inheriting the behaviour of CosmosClient
public class ContosoCosmosClient : CosmosClient
{
public ContosoCosmosClient(string connectionString, CosmosClientOptions clientOptions = null) : base(connectionString, clientOptions)
{
}
public ContosoCosmosClient(string accountEndpoint, string authKeyOrResourceToken, CosmosClientOptions clientOptions = null) : base(accountEndpoint, authKeyOrResourceToken, clientOptions)
{
}
public ContosoCosmosClient(string accountEndpoint, TokenCredential tokenCredential, CosmosClientOptions clientOptions = null) : base(accountEndpoint, tokenCredential, clientOptions)
{
}
}
//In Startup.up add a Singleton for each client
services.AddSingleton(new ContosoCosmosClient(...));
services.AddSingleton(new FabrikamCosmosClient(...));
Then in your business logic you can add both clients and depending on your logic choose which client you want to use:
public class MyService
{
public MyService(ContosoCosmosClient contosoClient, FabrikamCosmosClient fabrikamClient)
{
//...
}
}
Thanks for all comments and answers.
In the end, is this case, the best solution was the approach that was suggested by Mr. T. https://devblogs.microsoft.com/cosmosdb/httpclientfactory-cosmos-db-net-sdk/
I'm now still using one CosmosClient, Scoped. Which allows dynamic use of endpoints.
By injecting the IHttpClientFactory and setting the CosmosClientOptions like this;
{
HttpClientFactory = () => _httpClientFactory.CreateClient("cosmos")
});
we are now making full use of the HttpClient and its ability to reuse ports.
Related
So I'm building an ASP.NET-Core API connecting to a mongoDB instance. I was reading through the official Microsoft tutorial regarding this topic and came across the linked code sample.
Basically they instantiate a BookService and create a new instance of MongoClient in the scope of the constructor.
private readonly IMongoCollection<Book> _books;
public BookService(IBookstoreDatabaseSettings settings)
{
var client = new MongoClient(settings.ConnectionString);
var database = client.GetDatabase(settings.DatabaseName);
_books = database.GetCollection<Book>(settings.BooksCollectionName);
}
As I understand this the _books collection would still work without the MongoClient instance present since it knows which collection it's assigned to and how to communicate with it BUT the mongoDB MongoClient re-use guidelines suggests to store a global/static instance of the client to re-use. (I guess for the same port-exhaustion, etc. reason you would want to re-use HTTPClients? Also it supports internal connection pooling, which is nice!)
Thinking further on what they imply I was quite sure it would be a bad idea to instantiate and immediately drop an instance for a client for each of my services. But I dont't know anything about MongoDB on this scope.
I know it's just a tutorial and they tend to be the "quick and dirty" way of coding but since I'm new to this whole topic I just wanted to make sure I would start out properly.
So is it OK doing it the "Microsoft way" or should I just create a global instance for the client or a factory altogether?
//Edit:
For clarification: Would it be better to register the MongoClient as a Singleton on Startup and inject it into classes that need it OR use the method described above?
This is how I typically add Mongo to my pipelines:
services.AddSingleton<IMongoClient>(sp =>
{
var connectionString = "";
return new MongoClient(connectionString);
});
services.AddScoped(sp =>
{
var client = sp.GetRequiredService<IMongoClient>();
var database = "";
return client.GetDatabase(database);
});
This gives me a scoped IDatabase instance I can inject anywhere I need it (while using just one singleton IMongoClient instance).
NOTE: This example has been simplified
I have got a Client's Contact table and wanted to retrieve specific client contact information from DB. The code I typed belove brings me all contact details. I wanted to use a parameter to only bring me specific client contacts.
I used IClientContactRepository interface like this
public interface IClientContactRepository
{
IQueryable<ClientContactModel> ClientContacts { get; }
}
And i used this class to retrive data from database with dapper
public class ClientContactRepository : IClientContactRepository
{
private readonly IConfiguration configuration;
private List<ClientContactModel> ClientContactList {get;set;}
public ClientContactRepository(IConfiguration config)
{
configuration = config;
SqlConnection conn = new SqlConnection(configuration["ConnectionString"]);
using (var connection = conn)
{
ClientContactList = connection.Query<ClientContactModel>("Select * FROM ContactTable ").ToList();
}
}
public IQueryable<ClientContactModel> ClientContacts => ClientContactList;
}
In my Startup class
services.AddTransient<IClientContactRepository, ClientContactRepository>();
My QUESTION is: can I pass the client's id parameter to the constructor.
I tried this: add a parameter to the constructor
public ClientContactRepository(IConfiguration config, int clientId)
and tried to start up class.
services.AddTransient<IClientContactRepository, ClientContactRepository(int,i)>()
Didn't work....
Can someone help me how to pass parameter please?
Yes, but where are you getting the client ID from - is it a configured value that will be static for the lifetime of the application? If so, you can use the AddTansient method overload that accepts a factory delegate to create the objects.
The better way (will cover all use cases) is registering the type that can provide that information (create one if no such type exists) with the DI container and use that as a parameter in the constructor of your repo.
As an example, let’s say you get your client ID from a claim, so the type you need to inject is IPrincipal:
services.AddScoped<IPrincipal>(
provider => provider.GetService<IHttpContextAccessor>()
.HttpContext
.User);
You would then inject the IPrincipal into your repo constructor and retrieve the client ID. An even better way would be to create your own type “ClientIdAccessor” which is responsible for providing the client ID. You would then not have a dependency on IPrincipal when testing your repo and the implementation of this new type would only depend on external libraries for your asp.net core implementation.
Side note: are you certain you want to use AddTransient for your repo? Usually you’d want to use the same repo object for the lifetime of the request (I.e. AddScoped).
I have an application (IJobInit) that uses a list from JSON settings to create multiple instances of a class (IJob). This class does some work using two other dependencies, IInputClient and IOutputClient. It uses M.Extensions.DependencyInjection to create a container which is handed off to AutoFac to create an IContainer.
IJobInit(IContainer container)
I would like IInputClient to be configured different for each instance of IJob. Speficially, I'd like to pass in a secret for it to use. The result would be:
IInputClient(HttpClient client)
where HttpClient is configured using ConfigureHttpClient such that IJob does not know that it is pre-authenticated. This would also be suitable:
IInputClient(ISecretProvider secretsProvider, string secretName)
The end result is three instances of IJob with IInputClient configured differently.
IJob(IInputClient inputClient1, IOutputClient outputClient)
IJob(IInputClient inputClient2, IOutputClient outputClient)
IJob(IInputClient inputClient3, IOutputClient outputClient)
How do I achieve this? I was looking at Autofac scopes but those controlwhen an instance is created without any control over its configuration (unless I missed it).
A colleague suggested that I could host each instance of IJob in its own process with its own configuration which is possible but I'm trying to host all the jobs in a single Azure Function and use the list in config to create the inner jobs.
Thanks!
I'm not totally happy with this solution but it works for now.
private async Task<IInputClient> GetClientAsync(string secretId)
{
HttpClient httpClient = this.httpClientFactory.CreateClient();
string secret = await this.secretsProvider.GetSecretAsync(secretId);
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Concat(":", secret))));
return this.scope.Resolve<IInputClient>(new TypedParameter(typeof(HttpClient), httpClient));
}
In ServiceStack application, I have Funq configured to inject a session per request like this:
container.Register<NHibernate.ISessionFactory>(sessionFactoryForDB1);
container.Register<NHibernate.ISession>(c => c.Resolve<NHibernate.ISessionFactory>()
.OpenSession())
.ReusedWithin(Funq.ReuseScope.Request);
My service looks like this, and it works just fine:
public class MyNhAwareService : Service
{
public ISession Session { get; set; }
public object Any(DoSomething request)
{
...
}
}
Now, the problem comes in when I want to add a second NHibernate database into the mix with its own session factory:
container.Register<NHibernate.ISessionFactory>(sessionFactoryForDB1);
container.Register<NHibernate.ISession>(c => c.Resolve<NHibernate.ISessionFactory>()
.OpenSession())
.ReusedWithin(Funq.ReuseScope.Request);
// add a different session factory
container.Register<NHibernate.ISessionFactory>(sessionFactoryForDB2);
I've been experimenting with a variety of ways Funq can be used, and I thought I had found the way forward when I discovered the 'RegisterNamed()" method, but that still doesn't help, as I can't use anything except TryResolve() from within my service.
This seems like it should be possible, but I'm beating my head against the wall trying to work it out...Any advice would be greatly appreciated.
You have a couple ways of going about this.
Option 1: Unique Interfaces
This option is to create a distinct interface for each NHibernate database so that they can be uniquely resolved by Funq.
For example:
interface FactoryA : NHibernate.ISessionFactory
{
}
interface FactoryB : NHibernate.ISessionFactory
{
}
You could then proceed as you are now. The same applies for the session. See here for a little more detail about the process:
How to register multiple IDbConnectionFactory instances using Funq in ServiceStack.net
Option 2: Named Instance
This option I am less familiar with, but you can name your instances using Funq:
container.Register<NHibernate.ISessionFactory>("FactoryA",sessionFactoryForDB1);
And then in your service, resolve it thusly:
ServiceStackHost.Instance.Container.ResolveNamed<NHibernate.ISessionFactory>("FactoryA");
This option uses Service Location, which I personally find less attractive.
I've recently refactored my MVC application to use Unity dependency injection to resolve dependencies, which is great. It's much more decomposable, etc., etc.
What I'm doing now is adding the capability for multiple tenants to use it. The approach I'm using (so that the rest of the code doesn't have to know much about the tenants) is creating things like a tenant-filtered version of my repository interface (which is just a proxy for another repository... so it will call one of the underlying methods, then check if the record has the right tenant and behave accordingly). This lets me basically emulate having a totally separate store for each tenant even though under the hood the data is not segregated, so relatively little of the client code needs to change.
The problem with all of this is how it fits into the DI way of doing things. What I'm planning to do is, at the beginning of the request, detect the host name, then use that to determine the tenant (each tenant will have a list of hostnames in the DB). Although I'm using per-request lifetimes for most objects Unity is constructing and resolving I don't really get how Unity can "know" what tenant to use since it would need both the data about the request (which I suppose the controller will have, but I don't think is available in my container configuration method) and access to the database to know which host (and it hardly seems desirable to have my container configuration making database calls). I can solve #2 by only passing in a host name and making the classes with tenants go figure out which tenant is being referenced, but that doesn't help with #1.
Right now I'm using "property injection" (also known as "a public property" in less high-falutin' circles), but I don't see how I'm going to avoid having my controller be the one that actually feeds the tenant data in, so now I don't really have just the one composition root controlling everything.
Is there a way I can do this in the composition root, or should I just resign myself to having the controller do this work?
For some reason you seem to forget about injection factories. Registering interface/type against a factory lets you execute arbitrarily complicated code upon resolving, including consulting the request, tenant database, whatever.
container.RegisterType<IRepository>(
new InjectionFactory(
c => {
// whatever, consult the database
// whatever, consult the url
return ...;
} );
The factory composition is transparent so that whenever you need it, the target doesn't even know that the factory code has been executed rather than a type instance from simple mapping.
Somewhere it needs to make a database call. Maybe the simplest place would be in global.ascx if it's needed system wide.
private static ConcurrentDictionary<string, string> _tenantCache = new ConcurrentDictionary<string, string>();
protected virtual void Application_BeginRequest(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)source;
var tenantId = _tenantCache.GetOrAdd(app.Context.Request.Url.Host, host =>
{
// Make database call in this class
var tenant = new TenantResolver();
return tenant.GetTenantId(host);
})
app.Context.Items["TenantID"] = tenantId ;
}
You will want to cache the result as Application_BeginRequest is called alot. You can then configure Unity to have child containers. Put all the common/default mappings in the parent container then create a child container per tenant and register the correct implementation for each tenant in it's own child container.
Then implement IDependencyResolver to return the correct child container.
public class TenantDependencyResolver : IDependencyResolver
{
private static IUnityContainer _parentContainer;
private static IDictionary<string, IUnityContainer> _childContainers = new Dictionary<string, IUnityContainer>();
public TenantDependencyResolver()
{
var fakeTenentID = "localhost";
var fakeTenentContainer = _parentContainer.CreateChildContainer();
// register any specific fakeTenent Interfaces to classes here
//Add the child container to the dictionary for use later
_childContainers[fakeTenentID] = fakeTenentContainer;
}
private IUnityContainer GetContainer()
{
var tenantID = HttpContext.Current.Items["TenantID"].ToString();
if (_childContainers.ContainsKey(tenantID)
{
return _childContainers[tenantID];
}
return _parentContainer;
}
public object GetService(Type serviceType)
{
var container = GetContainer();
return container.Resolve(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
var container = GetContainer();
return container.ResolveAll(serviceType);
}
}
Then set ASP.NET MVC DependecyResolver to be the TenantDependencyResolver. I didn't run this code but it should give you an idea of what you would need to do. If your implementations are set then you might be able to do it in the static constructor of TenantDependecyResolver.