Azure Functions: binding to DocumentClient versus static instance - what's recommended? - c#

I know how to bind queries directly to an Azure Function and use Cosmos DB triggers in functions.
However, I'm looking for direction around using DocumentClient (Nuget package Microsoft.Azure.Cosmos) directly.
There's documentation that explains how to reuse a static client instance between executions.
It is also possible to get a DocumentClient instance as a binding by adding [DocumentDB("test", "test", ConnectionStringSetting = "CosmosDB")] DocumentClient client to the function's parameters.
Finally, it is possible to create a DocumentClient instance in the function's body: var client = new DocumentClient(...).
I do not find a clear recommendation when to use what approach except that number 3 never is a good option because of performance, memory usage and connection limits. Also, I understand that using a static instance has advantages.
Questions
Azure functions have a connection limit (discussed here). Does this also apply when using approach 2 (bind to client)?
What are the pros and cons of using approach 2 (binding) versus 1 (static)?
What's the advantage of binding to a SQL query compared to binding to a DocumentClient and creating the query in the function's body?

There is another way to use DocumentClient.
Starting Version 1.0.28 of Microsoft.NET.Sdk.Functions, one can now use a FunctionsStartup class to initialize DocumentClient once, and then register it for DI (dependency injection), and then use the same instance every time.
The FunctionsStartup class is documented here. And a better explanation is here.
In your Startup's configure method, build your client.
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
[assembly: FunctionsStartup(typeof(MyApp.Startup))]
namespace MyApp
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
IDocumentClient client = GetCustomClient();
builder.Services.AddSingleton<IDocumentClient>(client);
}
}
This can be then injected into the function constructor and used by the methods.
public class MyFunction
{
private IDocumentClient _client;
public MyFunction(IDocumentClient client)
{
_client = client;
}
[FunctionName("MyFunction")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
// use _client here.
}
}
When Azure creates an instance of this class to serve a request, it passes the IDocumentClient instance that was created in FunctionsStartup class.
This strategy allows one to reuse the same instance of DocumentClient. Singeton-ness of this client is not forced by making it static, but by making sure we only create it once. This also helps with testability as tests can inject a different instance of IDocumentClient.

This article makes a good case for a static client.
We all know the woes of this approach for the HttpClient (and if you
don’t, please read it right after this article!), and it has the exact
same effect here: If the Function is getting a high volume of
triggers, we not only will be penalizing the performance of our
database calls with the initialization overhead but the memory
consumption will raise and we might even incur in socket exhaustion
scenarios.
To your questions 2 and 3:
The big pro of using the binding is simplicity. All the creation of the clients etc is abstracted away from you. Con of this is of course control. Here is a good example of using a custom client.
Using the SQL query instead of the DocumentClient is one step further up in regards to abstraction.

Related

Dependency injection using both AddSingleton and AddTransient C#

I'm having a huge problem with the configuration/dependency injection of an application.
I have a singleton class added through DI with AddSingleton, that has in its constructor a IRequestClient, that is scoped because
busConfigurator.AddRequestClient()
which among other things, has the same effect as AddScoped.
When I start the app, it says
"Cannot consume scoped service 'MassTransit.IRequestClient`1[...]' from singleton '...'.)"
Which absolutely makes sense.
The weirdest thing is that I have another app set up the exact same way, but it just works and I would really like for that class to remain singleton.
My colleague and I spent an entire day trying to find the differences between the two applications, but they are virtually the same in their configurations, so we are having trouble in understanding why one works while the other doesn't.
I'm not entirely sure on what details could be important to better define the problem, so feel free to ask.
We've looked all around the internet trying to find a solution, but it was always "Change singleton to transient", but that's not an option, first because it HAS to be a singleton, otherwise it wouldn't make sense in our app, as that thing is what caches lots of date from our db so we can't just go around keeping on collecting heaps of data, second because the first app works with singleton, not with transient and we'd like to keep it that way
// This method is called in Main()
private static void ConfigureMassTransit(IServiceCollection services)
{
services.AddMassTransit(busConfigurators =>
{
busConfigurators.AddRequestClient<ICacheRepository>();
busConfigurators.AddConsumers(typeof(Program).GetTypeInfo().Assembly);
busConfigurators.UsingRabbitMq((context, cfg) =>
{
cfg.Host(new Uri($"rabbitmq://{Config.Settings.RabbitMq_Host}"), hostConfigurator =>
{
hostConfigurator.Username(Config.Settings.RabbitMq_User);
hostConfigurator.Password(Config.Settings.RabbitMq_Password);
});
cfg.ReceiveEndpoint("myApp", e =>
{
e.ConfigureConsumers(context);
});
});
});
// CacheRepository
public class CacheRepository : ICacheRepository
{
private readonly IClient Client;
public CacheRepository(ICacheRepository client, ILogger<CacheRepository> logger)
{
this.client = client;
this.logger = logger;
}
}
When a dependency is scoped, the implication is that a new instance is needed for each scope (which is usually an incoming HTTP request or message.) It implies that the instance should not be re-used for multiple requests.
If you have a singleton that depends on that scoped dependency, that singleton will be created using an instance of that dependency (the request client.) Because that singleton "lives forever," so does the instance of the request client it contains.
The result is that the request client is not supposed to be re-used across different scopes, but now it is. One instance is used forever.
A likely solution is to modify the class that depends on that client so that it doesn't need to be a singleton. You mentioned that it has to be a singleton because it caches data.
How does it cache data? Does it do so by storing data in a private field? If so, perhaps you could make that field static. Now the class instance isn't re-used, but those fields are shared between instances. (Verify that interaction with those fields is thread safe if they may be accessed concurrently.)
Or if there's some other cache mechanism, you could move that into its own dependency and make that a singleton.
Then your class can be scoped. It will depend on the singleton cache, always using the same instance. It will also depend on the scoped request client, using a new instance for each scope.
You could inject IServiceProvider instead, and create a scope when the singleton needs to perform a request. That way, you're sticking to the expected use of the request client.
await using var scope = provider.CreateAsyncScope();
var client = scope.ServiceProvider.GetRequiredService<IRequestClient<T>>();
await client.GetResponse(...);

Why using HttpClient in a using block IS WRONG in WebApi context?

So, the question is why the usage of HttpClient in using block is WRONG, BUT in WebApi context?
I've been reading this article Don't Block on Async Code. In it we have the following example:
public static async Task<JObject> GetJsonAsync(Uri uri)
{
// (real-world code shouldn't use HttpClient in a using block; this is just example code)
using (var client = new HttpClient())
{
var jsonString = await client.GetStringAsync(uri);
return JObject.Parse(jsonString);
}
}
// My "top-level" method.
public class MyController : ApiController
{
public string Get()
{
var jsonTask = GetJsonAsync(...);
return jsonTask.Result.ToString();
}
}
The comment // (real-world code shouldn't use HttpClient in a using block; this is just example code) just triggered me. I've been always using HttpClient in this way.
The next thing I've checked is Microsoft's documentation on HttpClient Class.
In it, we have the following statement with provided source sample:
HttpClient is intended to be instantiated once and re-used throughout
the life of an application. Instantiating an HttpClient class for
every request will exhaust the number of sockets available under heavy
loads. This will result in SocketException errors. Below is an example
using HttpClient correctly.
public class GoodController : ApiController
{
private static readonly HttpClient HttpClient;
static GoodController()
{
HttpClient = new HttpClient();
}
}
So isn't the constructor called on each request and thus a new HttpClient will be created every time?
Thanks!
There's a bit of a long answer to this...
Originally, the official recommendation was to use HttpClient in a using block. But this caused problems at scale, essentially using up lots of connections in the TIME_WAIT state.
So, the official recommendation changed to use a static HttpClient. But this caused problems where it would never correctly handle DNS updates.
So, the ASP.NET team came up with IHttpClientFactory in .NET Core 2.1, so code (or at least code running on modern platforms) can reuse HttpClient instances (or, more properly, the message handlers of those instances), avoiding the TIME_WAIT problem, but also periodically closing those connections to avoid the DNS problem.
But, at the same time, the .NET team came up with SocketsHttpHandler also in .NET Core 2.1, which also does connection pooling.
So, on modern platforms, you can either use IHttpClientFactory or a static/singleton HttpClient. On older platforms (including .NET Framework), you would use a static/singleton HttpClient and either live with the DNS issue or use other workarounds.
Actually writing this question I noticed the static constructor in the code sample provided from Microsoft. This all makes sense now.
The Static Constructors are used to initialize any static data, or to perform a particular action that needs to be performed only once. It is called automatically before the first instance is created or any static members are referenced.
In the context of WebAPI the static constructor is called one time only thus creating only one HttpClient and reusing it for all other requests.
I'll never use using(HttpClient....) in production code again.
This is a great article on the wrong usage of HttpClient - YOU'RE USING HTTPCLIENT WRONG AND IT IS DESTABILIZING YOUR SOFTWARE

What is the best approach to define an HttpClient instance in a base class of a class library project?

There is an application which has 3 interfaces and whoever wants to use this app needs to implement these interfaces. I have created a class library project which has these interface implementations that I have inherited all from the same base class to be able to have a single HttpClient. Here is what I have done so far:
public class BaseProxy
{
protected static readonly HttpClient Client;
static BaseProxy()
{
Client = new HttpClient();
}
}
and I have used this Client in all derived classes to make GetAsync and PostAsync requests as follows:
public class XProxyImplementation
{
var response = Client.GetAsync(BaseUrl + "XXXApi/GetClientSettings/").Result;
response.EnsureSuccessStatusCode();
}
None of the methods in Web API are async by the way and I chose singleton solution because I don't want to use using block for each request. My question is should I go for a DI solution or is this code enough for an app which will be used internally? All suggestions for improvement are welcome.
I have read many answers regarding to using DI containers but this is just a class library with proxy implementations.
My other concern is even if I want to use DI, currently I am not able to introduce DI in my constructor classes because the other application that uses my implementations is looking for an empty constructor. When I try to pass HttpClient parameter to the constructor I get the following error:
The current type, System.Net.Http.HttpMessageHandler, is an abstract
class and cannot be constructed
The application which uses my dlls doesn't allow me to pass any parameters to constructor that uses any abstract classes. I guess this application uses Unity to make the handshake and in some way it looks for an empty constructor. Once I try to do the following changes I am getting the error:
public BaseProxy() : this(Service.HttpClient)
{
}
public XProxyImplementation(HttpClient client) : base(client)
{
}
That's why I actually prefered singleton instance to DI implementation.
DI? Yes
DI will enable testability of your proxy classes, whereas your current implementation cannot be unit-tested. It will also improve separation of concerns: remove the responsibility of controlling HttpClient lifetime from the proxy.
Typically, you would do something like this:
public abstract class BaseProxy
{
protected readonly HttpClient Client;
protected BaseProxy(HttpClient client)
{
Client = client;
}
// ... other members
}
public class XProxyImplementation : BaseProxy
{
public XProxyImplementation(HttpClient client) : base(client)
{
}
// ... other members
public Task SendRequest() // for example
{
return Client.GetAsync("....");
}
}
During the tests, you would initialize a different instance of HttpClient, injecting a test-friendly implementation of HttpMessageHandler:
// you implement TestHttpMessageHandler that aids your tests
var httpClient = new HttpClient(new TestHttpMessageHandler());
var proxyUnderTest = new XProxyImplementation(httpClient);
See this blog post for explanation of unit testing with HttpClient and HttpMessageHandler.
DI container? No
Now that we introduced dependency injection into your code, next question is, what injection mechanism should be used.
In your specific case, I would vote against coupling to any specific DI container, because you want your library to be consumed by many different applications, and you don't want to bloat their dependencies (an application might already be using a different DI container).
Moreover, since the code you posted is very simple, a full-blown DI container would be an overkill. In production code, you can just move your singleton HttpClient to a "service locator":
public static class SingletonServices
{
public static readonly HttpClient HttpClient;
static SingletonServices()
{
HttpClient = new HttpClient();
}
}
So that when you instantiate a proxy in production code, you do this:
var proxy = new XProxyImplementation(SingletonServices.HttpClient);
I would definitely go with a DI solution for this using the Microsoft.Extensions.DependencyInjection package.
https://dzone.com/articles/dependency-injection-in-net-core-console-applicati
And you should also be very aware how you use your async methods like GetAsync.
Using .Result almost never gives the desired result and you would be better off making the method async and using an await keyword like so:
var response = await Client.GetAsync(BaseUrl + "XXXApi/GetClientSettings/");
https://montemagno.com/c-sharp-developers-stop-calling-dot-result/
is a good resource for the whys and hows of this best practice
DI is the answer. If you do not want to use ID there is an HttpClientFactory that you can implement.
You can read more here
https://learn.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests

HttpClient DocumentClient What Happens With Different Threads. Azure Functons

I read in an article about HttpClient/DocumentClient that it can be best practice to create a singleton for apps and inject it into object so that underlying resources are not exhausted by continued re-creating.How does this work? If an HttpClient is being accessed by various threads and making simultaneous calls to possibly different endpoints I can't see how this can work.
I read this
https://medium.com/#nuno.caneco/c-httpclient-should-not-be-disposed-or-should-it-45d2a8f568bc
with interest. If I have an Azure Function making use of a DocumentClient calling cosmosDb how should I use the DocumentClient? Should it be a static instance?
I have my Azure function set up like this. I presume a new instance of DocmentClient is being created with every request which under high load could cause resource problems.
[FunctionName("MyGetFunc")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
[CosmosDB("ct","ops", ConnectionStringSetting ="cosmosConn")]
DocumentClient docClient,
ILogger log)
//use docClient here...
{
For the DocumentClient part of your question see here: https://learn.microsoft.com/en-us/sandbox/functions-recipes/cosmos-db?tabs=csharp#customize-a-documentclient-and-reuse-it-between-executions
They talk about the different scenarios. So yes, if you have many Function invocations, I would use one static instance - which is also thread-safe.
private static DocumentClient client = GetCustomClient();
private static DocumentClient GetCustomClient()
{
DocumentClient customClient = new DocumentClient(
new Uri(ConfigurationManager.AppSettings["CosmosDBAccountEndpoint"]),
ConfigurationManager.AppSettings["CosmosDBAccountKey"],
new ConnectionPolicy
{
ConnectionMode = ConnectionMode.Direct,
ConnectionProtocol = Protocol.Tcp,
// Customize retry options for Throttled requests
RetryOptions = new RetryOptions()
{
MaxRetryAttemptsOnThrottledRequests = 10,
MaxRetryWaitTimeInSeconds = 30
}
});
// Customize PreferredLocations
customClient.ConnectionPolicy.PreferredLocations.Add(LocationNames.CentralUS);
customClient.ConnectionPolicy.PreferredLocations.Add(LocationNames.NorthEurope);
return customClient;
}
[FunctionName("CosmosDbSample")]
public static async Task<HttpResponseMessage> Run(
If an HttpClient is being accessed by various threads and making simultaneous calls to possibly different endpoints I can't see how this can work.
Why? The HttpClient is thread-safe which means that it can be used from several concurrent threads simultaneously.
Is HttpClient safe to use concurrently?
If you're using .NET Core, please also refer to Use HttpClientFactory to implement resilient HTTP requests.
HttpClient is intended to be instantiated once and reused throughout the life of an application. Instantiating an HttpClient class for every request will exhaust the number of sockets available under heavy loads. That issue will result in SocketException errors. Possible approaches to solve that problem are based on the creation of the HttpClient object as singleton or static, as explained in this Microsoft article on HttpClient usage.
But there’s a second issue with HttpClient that you can have when you use it as singleton or static object. In this case, a singleton or static HttpClient doesn't respect DNS changes, as explained in this issue at the .NET Core GitHub repo.
To address those mentioned issues and make the management of HttpClient instances easier, .NET Core 2.1 introduced a new HttpClientFactory that can also be used to implement resilient HTTP calls by integrating Polly with it.
[CosmosDB("ct","ops", ConnectionStringSetting ="cosmosConn")]
DocumentClient docClient,
That is using the Cosmos DB Binding. The Binding does not create multiple instances of the DocumentClient, it will create one and reuse it in all executions.
You can check the source code here: https://github.com/Azure/azure-webjobs-sdk-extensions/blob/dev/src/WebJobs.Extensions.CosmosDB/Bindings/CosmosDBClientBuilder.cs.
It calls GetService and obtains the DocumentClient instance for that particular connection string if one already was created in a previous execution.
Similarly to maintaining your own static/Lazy DocumentClient (see https://learn.microsoft.com/en-us/azure/azure-functions/manage-connections#documentclient-code-example-c).

What is the best way to pass runtime constructor parameters to Autofac?

I am building a generic piece of middleware software (a windows service) that will perform many jobs.. such as:
Sync Inventory
Import Orders
etc
I am using C# with a Windows Service, and Quartz.NET to schedule the jobs to run.
I am also using AutoFac.
From what I understand, AutoFac dependencies should be built at the composition root. This is fine..however, I have certain services that get injected which require runtime parameters (configuration values that come from the database).
For example:
Some jobs will connect to an SFTP server whereby the connection details are stored as key value pairs in the database
Some jobs will connect to a remote API whereby those API authentication details are stored against the job in the database.
I've done some research on this and some alternatives basically suggest removing the constructor of some of these services (such as an SFTP client) and passing these as configuration methods..
Instead of the client have a constructor such as
SftpClient(string host, string username, string password, int timeoutInSeconds)
It would have a default constructor, and a configure method that you pass these in.
I don't like this at all- it goes against what I've learnt in that you should try and configure your object so it is in a consistent state through the constructor.
What are the best options?
My JobFactory method currently takes on a dependancy on IComponentContext.
I've seen there are ways to pass parameters to AutoFac to construct the object, but things I've read suggest that it is not ideal.
Is it better to just use my Factory to
The simplest solution is to inject a factory instead of an instance. Do not inject the AutoFac container itself (that hides dependencies). Just write a simple class.
class SftpClientFactory : ISftpClientFactory
{
public SftpClient GetClient(string host, string userName, string password, int timeout)
{
return new SftpClient(host, userName, password, timeout);
}
}
Then register it like this:
container.RegisterType<ISftpFactory, SftpFactory>();
And in your class
class Example
{
private readonly ISftpClientFactory _clientFactory;
public Example(ISftpClientFactory injectedFactory)
{
_clientFactory = injectedFactory;
}
public void DoTheWork()
{
var client = _clientFactory.GetClient(host, userName, password, timeout);
}
}
As a bonus, you now have complete control of the object life cycle, which sounds like it could be important with an sftp client, which might hold a non-managed resource and be Disposable:
public void DoTheWork()
{
using (var client = _clientFactory.GetClient(host, userName, password, timeout))
{
client.DownloadFile();
}
}
This scheme preserves the inversion of control, you still keep a single composition root, the client can still be stubbed by your unit test project, and you still get compile-time resolution of dependencies. The only down side is it is slightly more work to write the stub, since you have to write a stub factory too.
You could take advantage of delegate factories to pass custom parameters in runtime. In that case you do not have to create any custom factories and it would be quite easy to mock in your tests as well.
You cannot use built-in Func<X,Y,T> delegate, because parameters you have to pass are of the same type. But you could introduce your own delegate. If you have a separate interface for SmtpClient, it would look like this
public delegate ISmtpClient SmtpClientFactory(string host, string username, string password, int timeout);
Then, instead of injecting ISmtpClient, you should inject SmptClientFactory. No additional registration is needed there.
If you do not have ISmtpClient interface it would look pretty much the same, although it would be harder to test later.

Categories