Best practice with lifetime of IMongoDatabase object in C#? - c#

I'm brand new to NoSQL and I have a question. I've created a DatabaseHandler that allows me to grab a collection globally across my solution. I then noticed that I'm using 1 instance of IMongoDatabase for the entire lifetime of my application, is this correct?
Obviously coming form a MySQL background I'm used to using and opening a new connection on each call to DatabaseHandler
I'm just asking for someone to check if this is okay, as I'm really new and It's sort of confusing me.
internal sealed class DatabaseHandler : IDisposable
{
private static readonly ILogger Logger = LogManager.GetCurrentClassLogger();
public IMongoDatabase MongoDatabase;
public DatabaseHandler()
{
var config = Program.Server.ConfigHandler;
var databaseHost = config.GetValue("database.hostname");
var databasePort = config.GetValue("database.port");
var mongoClient = new MongoClient(new MongoClientSettings
{
Server = new MongoServerAddress(databaseHost, databasePort.ToInteger()),
ServerSelectionTimeout = TimeSpan.FromSeconds(3)
});
MongoDatabase = mongoClient.GetDatabase(config.GetValue("database.name"));
var isMongoLive = MongoDatabase.RunCommandAsync((Command<BsonDocument>)"{ping:1}").Wait(1000);
if (!isMongoLive)
{
Logger.Error("We couldn't establish a connection with the database.");
}
}
public IMongoCollection<T> GetCollection<T>(string name)
{
return MongoDatabase.GetCollection<T>(name);
}
public void Dispose()
{
MongoDatabase.D
}
}

Related

C# Repositories and Http responses not returning expected data using same dbContext XUnit

I've been trying to implement integration tests with a database per test strategy, but I haven't been able to make it work as needed.
This is the factory class that uses WebApplicationFactory:
public class TestFactory<TProgram, TDbContext> : WebApplicationFactory<TProgram>
where TProgram : class where TDbContext : DbContext
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureTestServices(services =>
{
services.RemoveDbContext<TDbContext>();
services.AddDbContext<TDbContext>(options =>
{
options.UseInMemoryDatabase(Guid.NewGuid().ToString());
});
services.EnsureDbCreated<TDbContext>();
});
}
}
This is the TestClass:
public class RolesControllerTest : IDisposable
{
private readonly TestFactory<Program, ADbContext> _factory;
private IServiceScope _scope;
private ADbContext_dbContext;
private readonly HttpClient _client;
private IRoleRepository _rolesRepository;
public RolesControllerTest()
{
_factory = new TestFactory<Program, ADbContext>();
_client = _factory.CreateClient();
_scope = _factory.Services.CreateScope();
var scopedServices = _scope.ServiceProvider;
_dbContext = scopedServices.GetRequiredService<ADbContext>();
_dbContext.Database.EnsureCreated();
}
public void Dispose()
{
_factory.Dispose();
_scope.Dispose();
}
// Tests ...
}
This is the test:
[Fact(DisplayName = "GetAsync returns a list of role models")]
public async Task GetAsync_ReturnsTaskOfRoleModelList()
{
var roleModelInDb = new RoleModel
{
Id = Guid.NewGuid(),
Name = "Role A",
Description = "Role A Description"
};
_rolesRepository = new RoleRepository(_dbContext, TestMapperHelper.GenerateTestMapper());
var roleModel = await _rolesRepository.CreateAsync(roleModelInDb);
var responseData = await _client.GetFromJsonAsync<List<RoleModel>>("/api/roles");
responseData.ShouldNotBeNull();
responseData.ShouldBeOfType<List<RoleModel>>();
responseData.Count.ShouldBe(1);
responseData[0].Id.ShouldBe(roleModel.Id);
responseData[0].Name.ShouldBe(roleModelInDb.Name);
}
The repository returns the expected data: the new roleModel that's been added to the db.
The responseData is a list as expected, but it's empty, so the test fails.
If I try to use a client instead of the repository to create the initial roleModel:
var createdResponse = await _client.PostAsJsonAsync("/api/roles", roleModelInDb);
var createdByClient = await TestResponseHelper.GetResponseContent<RoleModel>(createdResponse);
The createdResponse is a 200 OK Http response, and the role model createdByClient is a valid RoleModel, but the test fails, the list is still empty.
If I use a roleRepository to find the previously created roleModel by Id, the result is null.
If I'm using the same database context for the web factory and repositories, why is this happening?

WPF SimpleInjector call to client.GetAsync hanging

I am trying to use SimpleInjector in a WPF Application (.NET Framework). We use it in exactly the same way in many of our Services but for some reason when I am attempting to implement the same logic in this WPF Application, the call to the HttpClient().GetAsync is hanging. We think it is because for some reason the Task is not executing.
I am registering the objects from the OnStartUp element of App.xaml.cs as below. Inside the SetupService Constructor we call a SetupService URL (set in the SetupConfiguration Section of the App.Config) to get the SetupResponse to use in the app.
It is ultimately hanging in the ServiceClient.GetAsync method, I have tried to show the flow below:
All classes appear to have been injected correctly, and the ServiceClient is populated in exactly the same way as the same point in one of our working services. We're at a loss as to what is happening, and how to fix this.
Finally, SetupService is being injected in other Classes - so I would rather get it working like this, rather than remove the call from the SimpleInjector mechanism.
Any help is very much appreciated.
public partial class App : Application
{
private static readonly Container _container = new Container();
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
RegisterDependencies();
_container.Verify();
}
private void RegisterDependencies()
{
var serviceConfigSection = ServiceConfigurationSection.Get();
_container.RegisterSingle<ILoggingProvider, LoggingProvider>();
_container.RegisterSingle<IServiceClient>(() => new ServiceClient(_container.GetInstance<ILoggingProvider>()));
_container.RegisterSingle<IConfigurationSection>(() => SetupConfigurationSection.Get());
_container.RegisterSingle<ISetupService, SetupService>();
}
}
public class SetupService: ISetupService
{
private static readonly Dictionary<string, string> AcceptType = new Dictionary<string, string>
{
{"Accept", "application/xml"}
};
private const string AuthenticationType = "Basic";
private readonly IServiceClient _serviceClient;
private readonly ILoggingProvider _logger;
private readonly IConfigurationSection _configuration;
public SetupService(IConfigurationSection configuration, IServiceClient serviceClient, ILoggingProvider logger)
{
_serviceClient = serviceClient;
_logger = logger;
_configuration = kmsConfiguration;
RefreshSetup();
}
public void RefreshSetup()
{
try
{
var token = BuildIdentityToken();
var authHeaderClear = string.Format("IDENTITY_TOKEN:{0}", token);
var authenticationHeaderValue =
new AuthenticationHeaderValue(AuthenticationType, Convert.ToBase64String(Encoding.ASCII.GetBytes(authHeaderClear)));
_serviceClient.Url = _configuration.Url;
var httpResponse = _serviceClient.GetAsync(string.Empty, authenticationHeaderValue, AcceptType).Result;
var responseString = httpResponse.Content.ReadAsStringAsync().Result;
_response = responseString.FromXML<SetupResponse>();
}
catch (Exception e)
{
throw
}
}
public class ServiceClient : IServiceClient
{
private const string ContentType = "application/json";
private string _userAgent;
private ILoggingProvider _logger;
public string Url { get; set; }
public string ProxyAddress { get; set; }
public int TimeoutForRequestAndResponseMs { get; set; }
public int HttpCode { get; private set; }
public ServiceClient(ILoggingProvider logger = null)
{
_logger = logger;
}
public async Task<HttpResponseMessage> GetAsync(string endpoint, AuthenticationHeaderValue authenticationHeaderValue = null, IDictionary<string, string> additionalData = null, IDictionary<string, string> additionalParams = null)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(Url);
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(ContentType));
if (authenticationHeaderValue != null)
client.DefaultRequestHeaders.Authorization = authenticationHeaderValue;
ProcessHeader(client.DefaultRequestHeaders, additionalData);
var paramsQueryString = ProcessParams(additionalParams);
if (!string.IsNullOrEmpty(paramsQueryString))
endpoint = $"{endpoint}?{paramsQueryString}";
return await client.GetAsync(endpoint); **// HANGS ON THIS LINE!**
}
}
}
}
If you block on asynchronous code from a UI thread, then you can expect deadlocks. I explain this fully on my blog. In this case, the cause of the deadlock is Result. There's a couple of solutions.
The one I recommend is to rethink your user experience. Your UI shouldn't be blocking on an HTTP call to complete before it shows anything; instead, immediately (and synchronously) display a UI (i.e., some "loading..." screen), and then update that UI when the HTTP call completes.
The other is to block during startup. There's a few patterns for this. None of them work in all situations, but one that usually works is to wrap the asynchronous work in Task.Run and then block on that, e.g., var httpResponse = Task.Run(() => _serviceClient.GetAsync(string.Empty, authenticationHeaderValue, AcceptType)).GetAwaiter().GetResult(); and similar for other blocking calls.
Blocking before showing a UI is generally considered a bad UX. App stores generally disallow it. So that's why I recommend changing the UX. You may find an approach like this helpful.
Thanks for your Responses, I just wanted to sync the solution I've gone for.
It was risky for me to change the code in SetupService to remove the .Result, even though this was probably the correct solution, as I did not want to affect the other working Services using the SetupService library already there.
I ended up moving the regsitrations off the UI Thread by embedding the SimpleInjector code in a Code library, Creating a Program.cs and Main() and setting that as my Entry point.
static class Program
{
public static readonly Container _container = new Container();
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
public static void Main(){
var app = new MyApp.App();
Register();
app.Run(_container.GetInstance<MainWindow>());
}
static void Register()
{
_container.Register<MainWindow>();
MySimpleInjector.Register(_container);
_container.Verify();
}
}
and then, in a Separate .dll project, MyApp.Common
public class MySimpleInjector
{
private readonly Container _container;
public static void Register(Container container)
{
var injector = new MySimpleInjector(container);
}
private void RegisterDependencies()
{
var serviceConfigSection = ServiceConfigurationSection.Get();
_container.RegisterSingle<ILoggingProvider, LoggingProvider>();
_container.RegisterSingle<IServiceClient>(() => new ServiceClient(_container.GetInstance<ILoggingProvider>()));
_container.RegisterSingle<IConfigurationSection>(() => SetupConfigurationSection.Get());
_container.RegisterSingle<ISetupService, SetupService>();
}
}
I appreciate that this may not be the ideal solution - but it suits my purposes.
Again, thanks for your help and comments!
Andrew.

C# fetch connection details inside a constructor

I have my DB class defined as below:
public class DbAdapterService : DbAdapterService
{
private readonly AppSettings _settings;
public DbAdapterService(IOptions<AppSettings> settings)
{
_settings = settings?.Value;
DbConnectionStringBuilder builder = new DbConnectionStringBuilder();
builder.ConnectionString = _settings.ConnectionString;
}
}
In the above class I am fetching my connection string from my appsettings.json and it works fine.
Now we need to fetch the connecting strings username and password from another method defined in our class. This method fetches these details from our stored vault. Example as below:
public class CredentialsService : ICredentialsService
{
public Credentials GetDetails()
{
//return credentials
}
}
My questions is can I call this method in my DbAdapterService constructor above or if there is a better way to handle this.
Thanks
--Updated--
public class DbAdapterService : DbAdapterService
{
private readonly AppSettings _settings;
public ICredentialsService _credentialsService;
private bool isInitialized = false;
public DbAdapterService(IOptions<AppSettings> settings, ICredentialsService credentialsService)
{
_settings = settings?.Value;
_credentialsService = credentialsService;
if (!isInitialized)
{
Initialize(_credentialsService);
}
DbConnectionStringBuilder builder = new DbConnectionStringBuilder();
builder.ConnectionString = _settings.ConnectionString;
}
public void Initialize(ICredentialsService credentialsService)
{
if (isInitialized)
return;
else
{
//credentialsService.GetDetails();
isInitialized = true;
}
}
}
You seem to want to initialize the connection string in the constructor. If you're reaching out to some external component (file system, database, or API for example) to retrieve a value, that's possibly going to be an async operation. There's no reliable way of calling an async method in a constructor.
So, what can we do? Well, there's no rule saying we must do it in the constructor. The constructor was a convenient place, because it ensures that by the time you invoke any other methods, the initialization will have taken place. But there are other patterns to accomplish this. Here's one:
public class DbAdapterService : IDbAdapterService
{
string _connectionString;
readonly AppSettings _settings;
readonly ICredentialsService _credentialsService;
public DbAdapterService(IOptions<AppSettings> settings,
ICredentialsService credentialsService)
{
_settings = settings.Value;
_credentialsService = credentialsService;
}
async Task EnsureInitializedAsync()
{
if (!string.IsNullOrEmpty(_connectionString))
{
//no need to reinitialize
//unless the credentials might change during the lifecycle of this object
return;
}
var credentials = await _credentialsService.GetDetailsAsync();
var builder = new DbConnectionStringBuilder(_settings.ConnectionString);
builder.Username = credentials.Username;
builder.Password = credentials.Password;
_connectionString = builder.ConnectionString;
}
public async Task DoSomethingAsync()
{
await EnsureInitializedAsync();
//now you can use _connectionString here
}
}
The key part is remembering to invoke EnsureInitializedAsync() in any method that needs to make use of the connection string. But at least code that consumed DbAdapterService won't have to know whether to initialize the connection string or not.
While this pattern isn't as necessary for non-async code, it's great for operations that might become async in the future, and the pattern makes more sense if the details of the connection might actually change at runtime, but your objects are constructed when you configure IoC container.
you can try this
public class DbAdapterService : DbAdapterService
{
private readonly AppSettings _settings;
private readonly ICredentialsService _credentialsService ;
public DbAdapterService(
IOptions<AppSettings> settings,
ICredentialsService credentialsService )
{
_credentialsService= credentialsService ;
_settings = settings?.Value;
DbConnectionStringBuilder builder = new DbConnectionStringBuilder();
builder.ConnectionString = _settings.ConnectionString;
}
}
after this you can call any method from the credentialService
or a little shorter if you only need credentials
private readonly AppSettings _settings;
private readonly Credentials _credentials;
public DbAdapterService(
IOptions<AppSettings> settings,
ICredentialsService credentialsService )
{
_credentials= credentialsService.GetDetails();
_settings = settings?.Value;
DbConnectionStringBuilder builder = new DbConnectionStringBuilder();
builder.ConnectionString = _settings.ConnectionString;
}

Dependency Injection containers - how do I get a specific instance of an object?

For example, I have a Repository class for getting data from a database, and there are several service classes, let's say Service1, Service2, Service3.
I will have multiple Repository instances, for example, for two or three databases. And, you should be able to configure services to work with a specific database.
I can't figure out how to implement these dependencies using the Dependency Injection container.
As far as I understand, I can register the Repository service either as a Singleton, or a new instance will be created for each dependency.
But, I only need two repositories, Repository ("DB1") and Repository ("DB2"), and when creating a service instance, I should be able to choose which database to work with. That is, as an option-Service1(Repository ("DB1")), Service2 (Repository ("DB1")), Service1 (Repository ("DB2")).
For example:
public class Program
{
static void Main()
{
var connectionStringDb1 = "DB1 connection string";
var connectionStringDb2 = "DB2 connection string";
var repositoryDb1 = new Repository(connectionStringDb1);
var repositoryDb2 = new Repository(connectionStringDb2);
var smsSendService1 = new SmsSendService(repositoryDb1);
var smsSendService2 = new SmsSendService(repositoryDb2);
var emailSendService1 = new EmailSendService(repositoryDb1);
smsSendService1.Run();
var tasks = new Task[]
{
smsSendService1.Run(),
smsSendService2.Run(),
emailSendService1.Run()
};
Task.WaitAll(tasks);
}
}
public class Repository
{
private string _connectionString;
public Repository(string connectionString)
{
_connectionString = connectionString;
}
public object GetData()
{
// Getting data from the Database
var data = ...;
return data;
}
}
public class SmsSendService
{
private readonly Repository _repository;
public SmsSendService(Repository repository)
{
_repository = repository;
}
public Task Run()
{
return Task.Run(() =>
{
// Sending SMS in a loop
while (true)
{
var data = _repository.GetData();
// ...
Task.Delay(1000);
}
});
}
}
public class EmailSendService
{
private readonly Repository _repository;
public EmailSendService(Repository repository)
{
_repository = repository;
}
public Task Run()
{
return Task.Run(() =>
{
// Sending Email in a loop
while (true)
{
var data = _repository.GetData();
// ...
Task.Delay(1000);
}
});
}
}
Try to take a look at autofac named instances

Async method that calls in ViewModel causes deadlock

I do requests to Github Api so I have async methods, these do this job. Before it, I always called they in method, that calls from command(actually DelegateCommand). But now I wanna do request in ViewModel because I need to display list on page. I am using Prism to wire view and viewmodel.
Because I can't make viewmodel async, I can't use await word, so I tried to do something like gets result from task, or task.wait. But with this I have the same result. My app stop works with white display when it did request. I read some info about that and I understood that call async method in not async method is bad, and it causes deadlock, but I don't know what to do with this. And I think deadlock causes that app stop works.
Here is method where app die:
public async Task<IEnumerable<RepositoryModel>> GetRepositoriesAsync()
{
try
{
var reposRequest = new RepositoryRequest { Sort = RepositorySort.FullName };
var gitHubRepos = await _gitHubClient.Repository.GetAllForCurrent(reposRequest); //async request, don't say about name convention, it is not my method.
var gitRemoteRepos = new List<RepositoryModel>();
foreach ( var repository in gitHubRepos )
{
var repos = new RepositoryModel();
repos.RepositoryTypeIcon = GetRepositoryTypeIcon(repository);
gitRemoteRepos.Add(repos);
}
return gitRemoteRepos;
}
catch ( WebException ex )
{
throw new Exception("Something wrong with internet connection, try to On Internet " + ex.Message);
}
catch ( Exception ex )
{
throw new Exception("Getting repos from github failed! " + ex.Message);
}
}
And here is viewmodel:
public class RepositoriesPageViewModel : BindableBase
{
private INavigationService _navigationService;
private readonly Session _session;
public ObservableCollection<RepositoryModel> Repositories { get; }
private readonly RepositoriesManager _repositoriesManager;
public RepositoriesPageViewModel(INavigationService navigationService, ISecuredDataProvider securedDataProvider)
{
_navigationService = navigationService;
var token = securedDataProvider.Retreive(ConstantsService.ProviderName, UserManager.GetLastUser());
_session = new Session(UserManager.GetLastUser(), token.Properties.First().Value);
var navigationParameters = new NavigationParameters { { "Session", _session } };
_repositoriesManager = new RepositoriesManager(_session);
var task = _repositoriesManager.GetRepositoriesAsync();
//task.Wait();
Repositories = task.Result as ObservableCollection<RepositoryModel>;
}
}
I recommend using my NotifyTask<T> type, which provides a data-bindable wrapper around Task<T>. I explain this pattern more completely in my article on async MVVM data binding.
public class RepositoriesPageViewModel : BindableBase
{
private INavigationService _navigationService;
private readonly Session _session;
public NotifyTask<ObservableCollection<RepositoryModel>> Repositories { get; }
private readonly RepositoriesManager _repositoriesManager;
public RepositoriesPageViewModel(INavigationService navigationService, ISecuredDataProvider securedDataProvider)
{
_navigationService = navigationService;
var token = securedDataProvider.Retreive(ConstantsService.ProviderName, UserManager.GetLastUser());
_session = new Session(UserManager.GetLastUser(), token.Properties.First().Value);
var navigationParameters = new NavigationParameters { { "Session", _session } };
_repositoriesManager = new RepositoriesManager(_session);
Repositories = NotifyTask.Create(GetRepositoriesAsync());
}
}
private async Task<ObservableCollection<RepositoryModel>> GetRepositoriesAsync()
{
return new ObservableCollection<RepositoryModel>(await _repositoriesManager.GetRepositoriesAsync());
}
Note that with this approach, your data binding would use Repositories.Result to access the actual collection. Other properties are also available, most notably Repositories.IsCompleted and Respositories.IsNotCompleted for showing/hiding busy spinners.

Categories