Using two different databases with my model - crash on constructor - c#

I have a project that works for a single database. Now I need to get it to work with a second (within the same project) that has the same data structure. So I am using the same model and am trying to pass in the Data Connection name upon calling my Data Context Class. Unfortunately I am receiving the following error:
The type String cannot be constructed. You must configure the
container to supply this value.
Here is the code that I tried:
public UniversityContext(string context)
: base(context){
}
When I looked for answers I found this answer for that error and it recommends, having a parameter-less constructor as well. I tried that and still the same issue.
Here it is with the parameter-less constructor:
public UniversityContext()
: base("UniversityConnection")
{
}
public UniversityContext(string context)
: base(context)
{
}
In case it matters I am using Unity.

Unity automatically tries to use the most greedy constructor. In your case this is:
public UniversityContext(string context)
You can configure this with an injection constructor, without seeing your code something like this:
container.RegisterType<UniversityContext>(
new InjectionConstructor("UniversityContext"));

Related

What is the problem with using directive and SQLite in the following situation? I got ObjectDisposedException, but just here?

I do not have any problems for example here:
using FooContext context = new FooContext();
context.RemoveRange(context.FooTable);
context.SaveChanges();
But I DO get ObjectDisposedException here when I use 'using directive' either with block (with {}, as before C# 8.0) either by writing the new form, without {}.
DbSet<FooThing> allResults;
using (FooContext context = new FooContext())
{
allResults = context.FooTable;
}
return allResults;
And again, no problems with the following:
FooContext context = new FooContext();
return context.FooTable;
What is the problem with my code and how could I use using directive without exceptions?
EDIT:
Now I'm trying to use DI.
I created a scaffolded item by choosing "...using Entity Framwork" in the menu in VS.
In the class that was created by VS, I have an instance of the DbContext class at the top:
private readonly FooContext _context;
public FooController(FooContext context)
{
_context = context;
}
I can use this object, it seems there is no problem with it.
But now I get:
System.InvalidOperationException: Unable to resolve service for type '<Namespaces of my app here>.FooContext' while attempting to activate '<Namespaces of my app here>.FooController'.
I think that is because I did not injected the type to the appropriate container.
Where should I do this?
Should I do something here?
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
}
A DbSet<T>, which is what FooTable is an instance of, is a table accessor. You return this instance is (which then used by something we assume) but the associated DbContext instance on which this instance relies on was disposed by your using block.
If you are using asp.net you should look into using a Dependency Injection framework (like AutoFac). You can then register your DbContext type, have it injected in your Controller, and AutoFac will dispose the DbContext instance at the end of the request.
Your context is disposed when it exits the using statement. There would normally be no problem with your allResults, but I would guess that you are trying to use a navigation property or related item on the results. Your code will attempt to retrieve the data, but then it gets blocked because the context that was used to retrieve the data has been disposed.
So far it seems that this solves my current problem:
EF Core how to get a DBContext in a class instance?
Thank you, Igor for mentioning DI!
Finally I found this:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.0

Entity Framework Core Context Instance Options

I am new on EF Core.
I have created my context which refers from appsettings.json
public APITestDBContext(DbContextOptions<APITestDBContext> options):base(options)
{
}
Working well. I able to update DB in Code First approach. But when I tried to make an instance from dbcontext, it's expecting option. I don't know what options that expecting.
private APITestDBContext db = new APITestDBContext();
There is no argument given that corresponds to the required formal
parameter 'options' of
'APITestDBContext.APITestDBContext(DbContextOptions)'
What I need to write there?
What you did is fine that you supported dependency injection for your class, and In the ConfigureService Method in Startup.cs you mentioned how the injection to be resolved.
So now when you need to create new like that. Your class requires a constructor parameter which you need to provide which will be the same parameter value in your startup class.
or create another overload for the constructor as below which accepts no parameters :
public APITestDBContext():base()
{
}
But to do that it will call DBContext.OnConfiguring() method to setup your db which you need to implement.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Your Connection String");
}

EF6 and multiple configurations (SQL Server and SQL Server Compact)

Update: Problem solved, see end of this question.
The problem:
We are trying to use Entity Framework 6 and code-based configuration in a scenario were we have use both a SQL Server and SQL Server CE in the same AppDomain.
This quite simple scenario seems not to be supported "by design". From the EF team:
Note: We do not support having multiple configuration classes used in
the same AppDomain. If you use this attribute to set different
configuration classes for two contexts an exception will be thrown.
More information here: Code-based Configuration (Codeplex)
The question:
How do we move forward from here? Any help would be greatly appreciated! Is there a more flexible way to connect a configuration to a context instead of an AppDomain?
(Our context classes are located in different assemblies. We have tried the DbConfigurationType attribute but the problem is EF itself)
Configuration files:
Configuration for normal SQL server
public class EfConfiguration : DbConfiguration
{
public EfConfiguration()
{
SetProviderServices(
SqlProviderServices.ProviderInvariantName,
SqlProviderServices.Instance);
SetDefaultConnectionFactory(new SqlConnectionFactory());
}
}
Configuration for SQL Server Compact Edition
public class EfCeConfiguration : DbConfiguration
{
public EfCeConfiguration()
{
SetProviderServices(
SqlCeProviderServices.ProviderInvariantName,
SqlCeProviderServices.Instance);
SetDefaultConnectionFactory(
new SqlCeConnectionFactory(SqlCeProviderServices.ProviderInvariantName));
}
}
UPDATE:
The error which we get is:
System.TypeInitializationException : The type initializer for
'MyProject.Repositories.Base.DataContext'
threw an exception. ----> System.InvalidOperationException : An
instance of 'EfCeConfiguration' was set but this type was not
discovered in the same assembly as the 'DataContext' context. Either
put the DbConfiguration type in the same assembly as the DbContext
type, use DbConfigurationTypeAttribute on the DbContext type to
specify the DbConfiguration type, or set the DbConfiguration type in
the config file. See http://go.microsoft.com/fwlink/?LinkId=260883 for
more information.
UPDATE 2, the solution
As described above, we can only have one configuration. This is a problem since Sql and SqlCe uses different providers. If we use "SetDefaultConnectionFactory" to fit one type of database, the other will fail.
Instead, supply the connection into the context as described in the post marked as answer below. Once you always initialize the context with a connection as opposed to a connectionstring you are good to go. You can remove the SetDefaultConnectionFactory call from the configuration. We're using only the code below for configuring the SqlCe Context and no configuration for the Sql Context.
public class CommonEfConfiguration : DbConfiguration
{
public CommonEfConfiguration()
{
// EF does not know if the ce provider by default,
// therefore it is required to be informed about it.
// The connection factories are not necessary since the connection
// is always created in the UnitOfWork classes
SetProviderServices(SqlCeProviderServices.ProviderInvariantName, SqlCeProviderServices.Instance);
}
}
EDIT: based On Error details:
Did you already try tell EF where the config class is found?
[DbConfigurationType("MyNamespace.MyDbConfiguration, MyAssemblyFullyQualifiedName")]
public class MyContextContext : DbContext
{
}
If that cant be made work, then see alternative
Use the Context with constructor DbConnection
public class MYDbContext : DbContext {
// MIgration parameterless constructor is managed in MyMigrationsContextFactory
public MyDbContext(string connectionName) : base(connectionName) { } // no this
public MYDbContext(DbConnection dbConnection, bool contextOwnsConnection) // THIS ONE
: base(dbConnection, contextOwnsConnection) { }
you then need a "DBConnection" connection for each provider.
For SQL server
public DbConnection GetSqlConn4DbName(string dataSource, string dbName) {
var sqlConnStringBuilder = new SqlConnectionStringBuilder();
sqlConnStringBuilder.DataSource = String.IsNullOrEmpty(dataSource) ? DefaultDataSource : dataSource;
sqlConnStringBuilder.IntegratedSecurity = true;
sqlConnStringBuilder.MultipleActiveResultSets = true;
var sqlConnFact = new SqlConnectionFactory(sqlConnStringBuilder.ConnectionString);
var sqlConn = sqlConnFact.CreateConnection(dbName);
return sqlConn;
}
repeat for SqlCe factory, it can also generate a DBConnection
SqlCe connection factor create connection
what i did:
public partial class MyDataBaseContext : DbContext
{
public MyDataBaseContext (string ConnectionString)
: base(ConnectionString)
{
}
}
I found the solution in a post on a Microsoft forum post.
Basically, I had two projects, each one with its own context. Entity Framework was loading just (the first) one of the DbConfiguration classes and trying to use this same configuration for both projects. That's the reason for the error message saying something like
"An instance of 'EfCeConfiguration' was set but this type was not discovered in the same assembly as the 'DataContext' context".
So, as someone suggested in that Microsoft forum post, I removed all [DbConfigurationType(typeof(DbConfigurationClass))] anotations from the classes which inherit from DbContext in both projects, and the error didn't happen anymore.

Ninject bound CustomMembershipProvider not calling Initialize method

I have created a custom membership provider that takes an instance of IUsersRepository in it's constructor.
private IUsersRepository usersRepository;
public CustomMembershipProvider(IUsersRepository usersRepository)
{
this.usersRepository = usersRepository;
}
This dependency is bound using Ninject
Bind<IUsersRepository>().To<SqlUsersRepository>().WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["AppDb"].ConnectionString);
Bind<MembershipProvider>().To<CustomMembershipProvider>();
and used in my AccountController like so
CustomMembershipProvider provider;
public AccountController(MembershipProvider membershipProvider)
{
this.provider = (CustomMembershipProvider)membershipProvider;
}
[HttpPost]
public ActionResult Register(User user)
{
MembershipCreateStatus status = new MembershipCreateStatus();
provider.CreateUser(user.FirstName, user.LastName, user.Email, user.Password, out status);
return View(user);
}
The problem with this is that when CustomMembershipProvider is instantiated the Initialize method is not called and thus my modified Web.Config is not read.
As a side to this, I've noticed that CustomMembershipProvider is being instantiated twice - the first time as I explained above, and then again when my [HttpPost] action method is called. The second time it's instantiated using a parameterless constructor and it calls the Initialize method. I don't know what happens to the second CustomMembershipProvider as provider.CreateUser() uses my un-Initialized CustomMembershipProvider.
I hope I've explained this well enough, any help would be appreciated.
I can't tell if you're using the Ninject.Mvc3 extension (which you probably should), but that will allow you to have a single instance of your MembershipProvider per web request. You'll have to do the binding like so:
Bind<MembershipProvider>().To<CustomMembershipProvider>().InRequestScope();
If you want to return the same instance every time you can use InSingletonScope.
Accessing web.config is not possible at the time bindings tend to be done in Mvc apps, but I usually get around that by having a custom configuration section and binding that to a method. By doing that the method will not get evaluated until the kernel is asked for a configuration section, and at that time web.config can be accessed. Something similar might work for your connection string.
Bind<MyConfigurationSection>().ToMethod(context => (MyConfigurationSection)ConfigurationManager.GetSection("mysection")).InSingletonScope();
Public Class SomeRolProvider
Inherits RoleProvider
Implements IProvider
'this service needs to get initialized
<Inject()>
Public Property _memberhip As IMemberschipService
Sub New()
'only this constructor is called
End Sub
Protected Overrides Function CreateKernel() As Ninject.IKernel
Dim modules = New NinjectModule() {New Anipmodule()}
Dim kernel = New StandardKernel(modules)
kernel.Inject(Roles.Provider)
kernel.Inject(Membership.Provider)
Return kernel
End Function
This will force the kernel to bind properties of the memberschip provider
Thanks for everybody's help on this question. I was unable to find a solution that would work well for this applications situation without the need for masses of code.
To get around the issue I looked at the default MVC 2 project and copied some of Microsoft's code. My project is probably not very testable but I needed a quick solution. I've set it up so that if I do have time to find a solution in the future, I'll be able to replace it with the current code.

Unity not using the default constructor of the class

I have this class :
public class Repo
{
public Repo() : this(ConfigurationManager.AppSettings["identity"], ConfigurationManager.AppSettings["password"])
{
}
public Repo(string identity,string password)
{
//Initialize properties.
}
}
I added a line to web.config so that this type will be automatically constructed by Unity container.
but during the execution of my application, I receive this error message :
"System.InvalidOperationException : the parameter identity could not be resolved when attempting to call constructor Repo(String identity, String password) -->Microsoft.Practices.ObjectBuilder2.BuildFailedException : The current Build operation ...."
1) Why isn't Unity using the default constructor ?
2) Suppose I want Unity to use the second constructor (the parametized one), How do I
pass that information to Unity via the configuration file ?
Unity by default picks the constructor with the most parameters. You have to tell Unity to use a different one explicitly.
One way to do this is with the [InjectionConstructor] attribute like this:
using Microsoft.Practices.Unity;
public class Repo
{
[InjectionConstructor]
public Repo() : this(ConfigurationManager.AppSettings["identity"], ConfigurationManager.AppSettings["password"])
{
}
public Repo(string identity,string password)
{
//Initialize properties.
}
}
A second way of doing this, if your opposed to cluttering up classes/methods with attributes, is to specify which constructor to use when configuring your container using an InjectionConstructor:
IUnityContainer container = new UnityContainer();
container.RegisterType<Repo>(new InjectionConstructor());
From the documentation:
How Unity Resolves Target Constructors and Parameters
When a target class contains more than one constructor, Unity will use
the one that has the InjectionConstructor attribute applied. If there
is more than one constructor, and none carries the
InjectionConstructor attribute, Unity will use the constructor with
the most parameters. If there is more than one such constructor (more
than one of the "longest" with the same number of parameters), Unity
will raise an exception.
Just try to register type this way:
<register type="IRepo" mapTo="Repo">
<constructor />
</register>
Because of no param element specified in constructor element it should call default constructor.
You can also do this registration in code:
container.RegisterType<IRepo, Repo>(new InjectionConstructor());
I had a more simple problem that resulted in this error.
The container that I was using was the wrong container. I had accidentally created two different containers and my container.RegisterType<Interface,ConcreteObject> was inside of another container from the one being used.

Categories

Resources