I have the following configured within my IContainer Initialize routine:
x.For<IDbConnection>().Use<SqlConnection>().Ctor<string>().Is(MY_SQL_CONNECTION_STRING);
Here's the constructor for my service:
private readonly IForumRepository _repo;
public ForumService(IForumRepository repo)
{
_repo = repo;
}
And here's the constructor for my repository:
private readonly IDbConnection _cn;
public ForumRepository(IDbConnection connection)
{
_cn = connection;
}
In one of my service routines, I am calling a method to get an object in my repository, then upon returning to the service layer I call a 2nd method in my repository - however, on this second call to the repository, my connection (_cn) no longer has a connection string associated with it (it appears to be wiped upon exiting the using {} block the first time my service called a method in the repository.
Here's the first method that I call in the repository.
public Tag GetTag(int id)
{
Tag o;
const string q = #"select * from tags where id = #pId";
using (_cn)
{
_cn.Open();
o = _cn.Query<Tag>(q, new { pId = id }).SingleOrDefault();
} *** AT THIS POINT THE CONN STRING PROPERTY OF _CN IS CLEARED?!
return o;
}
I 'd have thought this should work fine seeing as the constructor for my service instantiates a SQL Connection which the first call to the repo utilizes fine, and seeing as subsequent calls to my repo are in the same service scope I'd have thought that repository's SqlConnection dependency should still retain the original connection string details.
Can someone please shed some light on where I'm going wrong with this?
After the using block is finished, the object being used will be disposed. Does the connection string get removed on disposal? In any case, you likely shouldn't use the object after is has been disposed.
Based on the code in your post, I would think you don't want to use the using block? I think you will want to manually close the connection, though (I think using will do that automatically as part of disposal).
Related
(I am writing a processor that handles requests in a queue (console app).
I would like to use the .NET Core DI.
So far my code looks like this:
...
var connectionString = exportConfiguration.ConnectionString;
using (var scope = _serviceProvider.CreateScope())
{
var provider = scope.ServiceProvider;
var service = provider.GetRequiredService<MyContext>();
service.SqlConnectionString = sqlConnectionString; // I don't think property injection on a dbcontext will work, it takes its connection string in via the constructor
}
I have read how to assign parameters to the object as shown above, but how do I create a new context based on the connection string that is used in all the objects that the service uses (using constructor injection because thats why dbcontexts take - connection string in constructor)?
(I am not storing my connection string in the queue by the way, a code comes down the queue and my app then chooses the connection string to use).
I have managed to work this out. The key was that when you use CreateScope(), then GetRequiredService(), the DI system will provide new objects. So I just had to provide the correct information. This is now what my code looks like:
// Prior code gets information from a queue, which could be different every time.
// This needs passing as a constructor to the DbContext and possibly other information from the queue to other methods constructors
// (constructor injection not property injection)
var connectionString = queueItem.ConnectionString;
// save the connection string so the DI system (startup.cs) can pick it up
Startup.ConnectionString = connectionString;
using (var scope = _serviceProvider.CreateScope())
{
var provider = scope.ServiceProvider;
var service = provider.GetRequiredService<IMyService>();
// go off and get data from the correct dbcontext / connection string
var data = service.GetData();
// more processing
}
/// The Service has the DbContext in its constructor:
public class MyService : IMyService {
private DbContext _dbContext;
public MyService(DbContext dbContext) {
_dbContext = dbContext;
}
// more stuff that uses dbcontext
}
/// In startup.cs:
public static string ConnectionString {get;set;}
...
builder.Services.AddScoped<IMyService, MyService>();
builder.Services.AddScoped<DbContext>(options => options.UseSqlServer(Startup.ConnectionString));
// Also the following code will work if needed:
// Parameter1 is something that comes from the queue and could be different for each
// CreateScope()
build.Services.AddScoped<IMyOtherService>((_) =>
new MyOtherService(Startup.Parameter1));
I hope this helps somebody, because when I was googling around I couldn't find out how to do this.
Before posting this question I have gone through multiple posts that are similar. My question focuses on "why is it happening despite applying the common and possibly right solution?".
I am developing a .NET Core 3.1 web app. I have a DbContext named 'SkipQContext'. I am trying to access the connection string from appsettings.json in the SkipQContext file using Configuration object.
For that, I have injected IConfiguration as a service to the SkipQContext constructor.
Constructor:
private readonly string ConnectionString;
public SkipQContext()
{
}
public SkipQContext(DbContextOptions<SkipQContext> options, IConfiguration configuration)
: base(options)
{
ConnectionString = configuration.GetConnectionString("DefaultConnection");
}
I have also registered in ConfigureServices method of Startup class.
services.AddSingleton(Configuration);
Now when I instantiate SkipQContext in one of my repository classes, the default constructor of SkipQContext is called. When I try to fetch data using it, I get the "IConfiguration object is null."
I applied breakpoints in ConfigureServices method and can see that the IConfiguration object has the connection string value.
My first question is, why is it null in SkipQContext when I am registering it in ConfigureServices and also injecting it in SkipQContext constructor? Multiple answers online state this as the right method.
Also, I am thinking, I might not be instantiating the SkipQContext rightly. As my statement :
SkipQContext db = new SkipQContext();
hits the default constructor of SkipQContext which is empty and not the overloaded constructor where IConfiguration is injected.
P.S. If the last question is dumb. I am still a bit unclear about how dependency injection works in .NET Core.
Also, I am thinking, I might not be instantiating the SkipQContext rightly. As my statement:
SkipQContext db = new SkipQContext();
hits the default constructor of SkipQContext which is empty and not the overloaded constructor where IConfiguration is injected.
You are right, this is not how dependency injection is supposed to work. Whenever you do new Something, then you are explicitly going around dependency injection. The main point about dependency injection is that a component that has a dependency (e.g. a database context) does not need to create that dependency itself, or even know how to create that dependency itself.
When you call new SkipQContext(), you are explicitly creating that depenndency, so you are tightly coupled to that SkipQContext and whatever that context needs in order to work properly (in this case, it needs DbContextOptions and IConfiguration). What you want instead is components to be loosely coupled to their dependencies. So you just declare what dependencies you need and require that someone or something else fulfills these dependencies for you. And that’s exactly where dependency injection comes in:
With dependency injection, you have a “dependency injection container” which takes care of creating all the dependencies that you or some component may require. You configure the container in a central location, in Startup.ConfigureServices, and then you are able to simply declare what dependencies you need via a service’s constructor. But in order for the container to provide these dependencies to that service, the service will have to be created by the container itself.
So what you will see is that you will basically have to consume everything through dependency injection. But this also makes it easy to realize when you are not using dependency injection: Whenever you write new Something, then that something won’t be created by the container and as such won’t have its dependencies automatically fulfilled. Depending on what that something is that might be what you want, or maybe not (e.g. creating a List<string> or a DTO object is something you want to do directly, creating a service or something that has other dependencies likely isn’t).
Coming back to your problem, in order to have the DI container take care of the dependencies in the constructor of SkipQContext, you will have to let the DI container create that context for you. So you cannot create it with new but instead you will have to depend on it by adding it to the constructor of whatever component you need it in.
E.g. if you have a controller, just add it as a dependency there:
public class HomeController : Controller
{
private readonly SkipQContext _db;
public HomeController(SkipQContext db)
{
_db = db;
}
public async Task<IActionResult> Index()
{
var items = await _db.Items.ToListAsync();
return View(new IndexViewModel
{
Items = items,
});
}
}
One final note regarding your database context: If you register the database context correctly with the DI container, then it will already be configured using the DbContextOptions that gets passed to the constructor. These options will also include the connection string the context needs to open the database connection. So you do not need to pass the IConfiguration manually or extract the connection string there. It will be automatically done for you by EF Core.
A proper context setup could look like this (in ConfigureServices):
services.AddDbContext<SkipQContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
There is no need to instantiate the Configuration as a Singleton, the Default builder of WebHost already inject the configuration in the request , your Startup Class should look like this
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
string conn = Configuration.GetConnectionString("NAME OF YOUR CONNECTION STRING IN THE application.json FILE");
services.AddDbContext<CLASSOFURDBCONTEXT>(config =>
{
config.UseSqlServer(conn);
});
}
}
And your dbcontext should have the following constructor
public YourDbContext(DbContextOptions<YourDbContext> options) : base(options)
{
}
Then you only need to call the DbContext in a controller or a service and the DI will do the rest
As per why your IConfiguration throw the null reference exception i can think of 2 possibilities. Either you need to do the other kind instanciation which would be like this
services.AddSingleton<IConfiguration,Configuration>();
Or maybe it is because you are not using DI into the DbContext itself, you shouldnt need to do the new YourContextDbContext(). You should just simply put it in the constructor of the service or controller and it should work "magically" without you actually need to make an instance of it.
I write some tests of created system which worked with PostgreSQL. I create in solution new project with type Class Library (.NET Core). Then, i create class, which testing class DocumentRepository. But in constructor of DocumentRepository is used IConfiguration (for connecting with database), and this IConfiguration i can't call in test class. How i can to imitate connecting with database in UnitTest?
Here class, which i want testing
public class DocumentsRepository : IRepository<Documents>
{
private string connectionString;
public DocumentsRepository(IConfiguration configuration, string login, string password)
{
connectionString = configuration.GetValue<string>("DBInfo:ConnectionString");
connectionString = connectionString.Replace("username", login);
connectionString = connectionString.Replace("userpassword", password);
}
internal IDbConnection Connection
{
get
{
return new NpgsqlConnection(connectionString);
}
}
public void Add(Documents item)
{
using (IDbConnection dbConnection = Connection)
{
dbConnection.Open();
dbConnection.Execute("SELECT addrecuserdocuments(#DocumentName,#Contents,#DocumentIntroNumber)", item);
}
}
Here's test, which i try use
using FluentAssertions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using WebApplication4.Controllers;
using WebApplication4.Entites;
using WebApplication4.ViewModels;
using Xunit;
namespace TestsApp
{
public class UserControllerTest
{
private IConfiguration configuration;
private string connectionString;
[Fact]
public async Task IndexUsers()
{
connectionString = configuration.GetValue<string>("DBInfo:ConnectionString");
var aCon = new AccountController(configuration);
var uCon = new UserController(configuration);
LoginModel model = new LoginModel
{
Login = "postgres",
Password = "111"
};
aCon.Authorization(model);
var result = uCon.Index();
var okResult = result.Should().BeOfType<OkObjectResult>().Subject;
var persons = okResult.Value.Should().BeAssignableTo<IEnumerable<Documents>>().Subject;
persons.Count().Should().Be(7);
}
}
}
Test show my error on
var result = uCon.Index();
And get me NullReferenceException.
How i can resolve this problem?
First and foremost, you're not unit testing, you're integration testing. As soon as you've got something like a database connection in the mix, unit testing is well out the window. If your goal is to write unit tests for your repository class, you should be mocking the data store.
Second, you should not inject IConfiguration, if you need some data from your configuration, such as a connection string, you should bind it to a strongly-typed class, and inject that instead:
services.Configure<MyConnectionStringsClass>(Configuration.GetSection("ConnectionStrings"));
Then, inject IOptionsSnapshot<MyConnectionStringsClass> instead.
Third, you really shouldn't be handling it this way, anyways. If you repository has a dependency on IDbConnection, then you should be injecting that into your repository. In Startup.cs:
services.AddScoped(p => new NpgsqlConnection(Configuration.GetConnectionString("Foo"));
Then, accept NpgsqlConnection in your repo constructor and set it to a private field.
Fourth, if you insist on continuing the way you currently are, you should absolutely not have a custom getter on your Connection property that news up NpgsqlConnection. That means you'll get a new instance every single time you access this property. Instead, you should define it as simple { get; private set; }, and set it in your repo's constructor.
Fifth, you should not be using using with a property defined in either way, as it will be disposed after the first time you do it, making all subsequent queries fail with an ObjectDisposedException. If you're going to new it up in your class, then your class needs to implement IDisposable and you should dispose of your connection in the Dispose method. FWIW, if you inject all dependencies (including your connection) into your class, you don't need to implement IDisposable as there's nothing the class will own that it needs to dispose of - another great reason to use dependency injection all the way down.
Finally, to answer you main question, you should use TestServer. When creating a TestServer you pass it your Startup class as a type param, so you end up with a true replica of your actual app, with all the appropriate services and such. Then, you can issue HTTP requests, like you would with HttpClient to test your controller actions and such. However, again, this is for integration testing only, which is the only time you should actually have a PostreSQL database in-play anyways.
Friends tell me what is the core meaning of init parameter in case of a servlet.
I know that how to initialize it in a web.xml but I don't know what is the actual purpose of it why it is required? Please tell me with a good example.
The Javadoc says: "A convenience method which can be overridden so that there's no need to call super.init(config)."
The init method's main purpose is to allow customization while you are initializing the servlet.
The simplest implementation is when you don't want to do any customization according to your application you can always call super.init method.
To understand meaning of what different init params can be there and how init method is useful:
Imagine a system Of BookManagement system, here for adding books and removing books from db you will be needing Database connection over which you can access the data. Now as Servlet's init method is called for the first request and database connection also needs be created only once(or n number of time if doing connection pooling) then initializing the database connection is something that you should do in init method.
A code snippet from Softlab example , let's assume that getInitParameter method reads the databaseUrl and other properties from web.xml
public class DBServlet ... {
Connection connection = null;
public void init() throws ServletException {
// Open a database connection to prepare for requests
try {
databaseUrl = getInitParameter("databaseUrl");
... // get user and password parameters the same way
connection = DriverManager.getConnection(databaseUrl,
user, password);
} catch(Exception e) {
throw new UnavailableException (this,
"Could not open a connection to the database");
}
}
...
}
One more example of counting the number of time servlet was accessed: https://docstore.mik.ua/orelly/java-ent/servlet/ch03_03.htm
So in Summary: To do customization like read the initial values of variable or to initialize resources(like db connection) you can use init method.
Below is the source code of init methods :
public void init(ServletConfig config)throws ServletException
{
this.config = config;
int();
}
public void init() throws ServletException;
It is recommended to override to init() method, not init(ServletConfig).
When overriding init(ServletConfig), the first thing that must be done is to call:
super.init(config);
If you do this then calling directly to getServletContext() in your method will no longer result in an NPE.
I am pretty new to NUnit (and automated testing in general). I have recently done some Ruby On Rails work and noticed that in my test suite, when I create objects (such as a new user) and commit them during course of the suite, they are never committed to the database so that I can run the test over and over and not worry about that user already existing.
I am now trying to accomplish the same thing in NUnit, but I am not quite sure how to go about doing it. Do I create a transaction in the Setup and Teardown blocks? Thanks.
Why would you talk to the database during unit-tests? This makes your unit-test to integration-tests by default. Instead, create wrappers for all database communication, and stub/mock it during unit-tests. Then you don't have to worry about database state before and after.
Now, if you are not willing to that level of refactoring: The problem with transactions is that you need an open connection. So, if your method targeted for testing handles all communication on its own, it is really difficult to inject a transaction that you can create at setup and roll back at teardown.
Maybe you can use this. It is ugly, but perhaps it can work for you:
namespace SqlServerHandling
{
[TestFixture]
public sealed class TestTransactionRollBacks
{
private string _connectionString = "Data Source = XXXDB; ; Initial Catalog = XXX; User Id = BLABLA; Password = BLABLA";
private SqlConnection _connection;
private SqlTransaction _transaction;
[SetUp]
public void SetUp()
{
_connection = new SqlConnection(_connectionString);
_transaction = _connection.BeginTransaction();
}
[TearDown]
public void TearDown()
{
_transaction.Rollback();
}
[Test]
public void Test()
{
Foo foo = new Foo(_connection);
object foo.Bar();
}
}
internal class Foo
{
private readonly SqlConnection _connection;
object someObject = new object();
public Foo(SqlConnection connection)
{
_connection = connection;
}
public object Bar()
{
//Do your Stuff
return someObject;
}
}
I agree with Morten's answer, but you might want to look at this very old MSDN Magazine article on the subject: Know Thy Code: Simplify Data Layer Unit Testing using Enterprise Services
I use SQLite for unit tests, using NHibenate. Even if you're not using NHibernate it should be possible to do. SQLite has an in memory mode, where you can create a database in memory and persist data there. It is fast, works well, and you can simply throw away and recreate the schema for each test or fixture as you see fit.
You can see the example from Ayende's blog for an overview of how its done. He is using NHibernate, but the concept should work with other ORM or a straight DAL as well.