When I register the following in SM and then attempt to create an instance I get the exception - 'StructureMap Exception Code: 202 No Default Instance defined for PluginFamily...'
Scan(x =>
{
x.Assembly("MVCDemo");
x.Assembly("MVCDemo.Infrastructure");
x.Assembly("MVCDemo.Services");
x.AddAllTypesOf(typeof (IRepository<>));
});
ForRequestedType<IRepository<Employee>>().TheDefault.Is.ConstructedBy(() => new EmployeeRepository());
var tmp4 = ObjectFactory.GetInstance<IRepository<Employee>>();
The exception occurs when I try and get an instance of IRepository.
Does anyone know what I'm missing?
Cheers
Ollie
The answer is I shouldn't use ObjectFactory to create instance, I should use the container:
var container = new Container(new MvcDemoRegistry());
var cultureProvider = container.GetInstance<IProvideCultureInfo>();
Ta
Ollie
You aren't supposed to use containers to get instances when using an IoC and DI. You should be using constructor injection and have the IoC handle the injection for you.
Related
I have method like the DeleteSettingAbout() after in text, where I am still getting error: "System.InvalidOperationException: A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.".
Code of the method is:
public async Task DeleteSettingAbout(int Id)
{
SettingAbout setting = await _context.SettingsAbout.FirstOrDefaultAsync(o => o.Id == Id);
if (setting != null)
{
_context.SettingsAbout.Remove(setting);
await _context.SaveChangesAsync();
}
}
In sartup.cs I set DBContext and DBRepository as Transient:
services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("AppDBConnection")),
ServiceLifetime.Transient);
services.AddTransient<IAppDbRepository, SQLAppDbRepository>();
But I am still getting this error.
How to solve this behavior? Thanks for answers.
UPDATE 2021-01-06
I tried the approach with creating the "DbContextFactory" and it solved my problem. I got inspiration from sample app https://github.com/dotnet/AspNetCore.Docs/tree/master/aspnetcore/blazor/common/samples/3.x/BlazorServerEFCoreSample (mentioned here: https://learn.microsoft.com/en-us/aspnet/core/blazor/blazor-server-ef-core?view=aspnetcore-3.1#sample-app-3x).
Now I have in my startup.cs this:
// new way suitable for Blazor - register factory and configure the options (new instance for each method call)
services.AddDbContextFactory<AppDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("AppDBConnection")));
services.AddScoped<IAppDbRepository, SQLAppDbRepository>();
I tried the approach with creating the "DbContextFactory" (mentioned by Stephen Cleary) and it solved my problem. I got inspiration from sample app https://github.com/dotnet/AspNetCore.Docs/tree/master/aspnetcore/blazor/common/samples/3.x/BlazorServerEFCoreSample (mentioned here: https://learn.microsoft.com/en-us/aspnet/core/blazor/blazor-server-ef-core?view=aspnetcore-3.1#sample-app-3x).
Now I have in my startup.cs this:
// new way suitable for Blazor - register factory and configure the options (new instance for each method call)
services.AddDbContextFactory<AppDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("AppDBConnection")));
services.AddScoped<IAppDbRepository, SQLAppDbRepository>();
Note: I needed to solve the problem in EF/Blazor = v3.1 (because my web-hosting does not support v5 for now)
Thank you all for answers!
I am using Castle Windsor v3.4.0 to create a RavenDB document session instance but when I use a RavenDB client version later than 3.0.3660 I get this error when calling the Store method:
Castle.MicroKernel.ComponentNotFoundException: 'No component for supporting the service System.Net.Http.HttpMessageHandler was found'
Here is the smallest piece code I can come up with that reproduces the error:
using Castle.Facilities.TypedFactory;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
using Raven.Client;
using Raven.Client.Document;
public class Program
{
public static void Main()
{
var container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
container.Register(
Component
.For<IDocumentStore>()
.ImplementedBy<DocumentStore>()
.DependsOn(new { Url = "http://localhost:8081", DefaultDatabase = "Test" })
.OnCreate(x => x.Initialize())
.LifeStyle.Singleton,
Component
.For<IDocumentSession>()
.UsingFactoryMethod(x => x.Resolve<IDocumentStore>().OpenSession())
.LifeStyle.Transient);
using (var documentSession = container.Resolve<IDocumentSession>())
{
documentSession.Store(new object());
documentSession.SaveChanges();
}
}
}
Here's what I believe is happening. A change was made to the RavenDB client after v3.0.3660 that changed how the HttpMessageHandler is created in the HttpJsonRequest class:
https://github.com/ravendb/ravendb/commit/740ad10d42d50b1eff0fc89d1a6894fd57578984
I believe that this change in combination with my use of the TypedFactoryFacility in my Windsor container is causing RavenDB to request an instance of HttpJsonRequestFactory and it's dependencies from Windsor rather than using it's own internal one.
How I can change my code to avoid this problem so that I can use a more recent version of the RavenDB client?
Given your MVCE, Windsor is set up to inject object's properties. So, when creating the DocumentStore, Castle is trying to find a value for the HttpMessageHandlerFactory property and is failing since nothing is configured for that particular type.
I was able to get your example to work (at least, it got to inserting the data into my non-existing server) by just filtering out that property:
container.Register(
Component.For<IDocumentStore>()
.ImplementedBy<DocumentStore>()
.DependsOn(new { Url = "http://localhost:8081", DefaultDatabase = "Test" })
.OnCreate(x => x.Initialize())
.PropertiesIgnore(p => p.Name == nameof(DocumentStore.HttpMessageHandlerFactory))
.LifeStyle.Singleton);
Alternatively, if you have a value for it, you could add it to the object passed to DependsOn().
I post this question and I got some explanations but I couldn't solve the problem. Now since event I have a better understanding I'm going to post this again in a new angle.
I have following lines in my node.
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
/*
* Associate the schema factory with the resource resolver, which is
* responsible for resolving the imported XSD's
*/
factory.setResourceResolver(new ResourceResolver());
Source schemaFile = new StreamSource(getClass().getClassLoader().getResourceAsStream(schemaName));
Schema schema = factory.newSchema(schemaFile);
Validator validator = schema.newValidator();
validator.validate(new DOMSource(document));
I think I have two options. Either to mock
Source schemaFile = new StreamSource(getClass().getClassLoader().getResourceAsStream(schemaName));
or
Schema schema = factory.newSchema(schemaFile);
I have been pulling my hair for two day to do the first one. I tried as follows
expectNew(StreamSource.class, InputStream.class).andReturn(mockSource);
and
expectNew(StreamSource.class, anyObject(InputStream.class)).andReturn(mockSource);
But didn't work.
Now I'm trying to mock the second line
Schema schema = factory.newSchema(schemaFile);
This one also not quite clear to me. Do I need to mock a factory like
SchemaFactory mockFactory = EasyMock.createMock(SchemaFactory.class);
or since factory is created using newInstance static method call is it a different way?
Appreciate any help on this problem.
Adding later
I got some lead with the situation. I have expectNew as follows.
expectNew(StreamSource.class, InputStream.class).andReturn(mockStreamSource);
When I run powermocks throws a error saying.
java.lang.AssertionError:
Unexpected constructor call javax.xml.transform.stream.StreamSource(null):
javax.xml.transform.stream.StreamSource(class java.io.InputStream): expected: 1, actual: 0
The reason is as I think getClass().getClassLoader().getResourceStream("..") return null anyway. So powermock didn't find it euqal to the initialization I describe by expectNew. How to say expect a null inputstream as parameter. I tried using just null. didn't work.
expectNew(StreamSource.class, null).andReturn(mockStreamSource);
If you're using easymock:
Extract the creation of the factory to a protected method.
protected SchemaFactory createSchemaFactory(){
return SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
}
In your test, instead of test the SUT itself create a partially mocked version of your SUT, mocking only the new method where the static invocation is done, and test it. Partial mocks using easymock.
I have following testing code trying to get one instance for generic and other for special purpose.
[TestMethod]
public void Test_Name_And_Named_Instances()
{
//MyClass implemented IMyClass
MyClass genericInstance = new MyClass("generic");
MyClass specialInstance = new MyClass("special");
IWindsorContainer container = new WindsorContainer();
container.Register(Component.For(IMyClass).Instance(genericInstance));
container.Register(Component.For(IMyClass).Instance(specialInstance).Named("special"));
IMyClass genericOne = container.Resolve<IMyClass>();
IMyClass specialOne = container.Resolve<IMyClass>("special");
Assert.AreSame(genericOne, genericInstance); //true
Assert.AreNotSame(genericOne, specialOne); //false
}
I expect to get two different instances, but the result is both genericOne and specialOne points to same objec genericInstance.
Any idea?
This doesn't compile:
container.Register(Component.For(IMyClass).Instance(genericInstance));
Should be:
container.Register(Component.For<IMyClass>().Instance(genericInstance));
Other than that, the test passes for me (Windsor 2.5.2)
EDIT:
If you flip the registrations, the test fails. This is by design. When you resolve without an explicit name, you're saying "give me the default component for this service", which in Windsor is the first registered component for that service type, by default.
If you need different components under the same service type, assign explicit names to all of them when registering and resolving.
I have a service class which has overloaded constructors. One constructor has 5 parameters and the other has 4.
Before I call,
var service = IoC.Resolve<IService>();
I want to do a test and based on the result of this test, resolve service using a specific constructor. In other words,
bool testPassed = CheckCertainConditions();
if (testPassed)
{
//Resolve service using 5 paramater constructor
}
else
{
//Resolve service using 4 parameter constructor
//If I use 5 parameter constructor under these conditions I will have epic fail.
}
Is there a way I can specify which one I want to use?
In general, you should watch out for ambiguity in constructors when it comes to DI because you are essentially saying to any caller that 'I don't really care if you use one or the other'. This is unlikely to be what you intended.
However, one container-agnostic solution is to wrap the conditional implementation into another class that implements the same interface:
public class ConditionalService : IService
{
private readonly IService service;
public ConditionalService()
{
bool testPassed = CheckCertainConditions();
if (testPassed)
{
// assign this.service using 5 paramater constructor
}
else
{
// assign this.service using 4 parameter constructor
}
}
// assuming that IService has a Foo method:
public IBaz Foo(IBar bar)
{
return this.service.Foo(bar);
}
}
If you can't perform the CheckCertainConditions check in the constructor, you can use lazy evaluation instead.
It would be a good idea to let ConditionalService request all dependencies via Constructor Injection, but I left that out of the example code.
You can register ConditionalService with the DI Container instead of the real implementation.
My underlying problem was that I was trying to resolve my class which had the following signature:
public DatabaseSchemaSynchronisationService(IDatabaseService databaseService, IUserSessionManager userSessionManager)
This was basically useless to me because my usersessionmanager had no active NHibernate.ISession because a connection to my database had not yet been made. What I was trying to do was check if I did have a connection and only then resolve this class which served as a service to run database update scripts.
When changing my whole class to perform the scripts in a different way, all I needed in its constructor's signature was:
public DatabaseSchemaSynchronisationService(ISessionFactory sessionFactory)
This allowed me to open my own session. I did, however have to first check if the connection was ready before attempting to resolve the class, but having IDatabaseSchemaSynchronisationService as a parameter to another class's constructor; this class also gettting resolved somewhere where I could not check the db connection was a bad idea.
Instead in this second class, I took the IDatabaseSchemaSynchronisationService paramater out of the constructor signature and made it a local variable which only gets instantiated (resolved) :
if (connectionIsReady)
Thanks to everyone who answered.