Autofac.Extras.Quartz sample code crashes - autofac

I attempting to use Quartz with Autofac due Autofac.Extras.Quartz library. But my code crashes
It is simple but it crashes:
using Autofac;
using Autofac.Extras.Quartz;
using Quartz;
using System;
namespace Test1_netCore
{
class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterModule(new QuartzAutofacFactoryModule());
var container = builder.Build();
IScheduler scheduler = container.Resolve<IScheduler>(); //crashes here
//
}
}
}
with exception:
Autofac.Core.DependencyResolutionException: 'An error occurred during the activation of a particular registration.
See the inner exception for details. Registration: Activator = IScheduler (DelegateActivator),
Services = [Quartz.IScheduler],
Lifetime = Autofac.Core.Lifetime.RootScopeLifetime,
Sharing = Shared,
Ownership = OwnedByLifetimeScope'
Inner Exception
MissingMethodException: Method not found: "Quartz.IScheduler Quartz.ISchedulerFactory.GetScheduler()".
However this runs OK, when I resolve ISchedulerFactory and get container from it
using Autofac;
using Autofac.Extras.Quartz;
using Quartz;
using System;
namespace Test1_netCore
{
class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterModule(new QuartzAutofacFactoryModule());
var container = builder.Build();
//IScheduler scheduler = container.Resolve<IScheduler>();
ISchedulerFactory factory = container.Resolve<ISchedulerFactory>();
IScheduler scheduler = factory.GetScheduler().Result;
//
}
}
}
What happens? I think I strongly misunderstand something.

I figure it out: Autofac.Extras.Quartz and Quartz assemblies was incompatible.
Autofac.Extras.Quartz (3.3.0) calls ISchedulerFactory method getScheduler() like this
builder.Register(c => c.Resolve<ISchedulerFactory>().GetScheduler())
(https://github.com/alphacloud/Autofac.Extras.Quartz/blob/26f33fa3be91a077e9edfefbc53606ab2f2ffc95/src/Autofac.Extras.Quartz/QuartzAutofacFactoryModule.cs#L89)
But in Quarts 3.0.0-alpha3 signature of this method is
Task<IScheduler> GetScheduler(CancellationToken cancellationToken = default(CancellationToken));
(https://github.com/quartznet/quartznet/blob/bb682fe4c051b2120086170cf03ae5111832b29f/src/Quartz/ISchedulerFactory.cs#L47)
However I can use versions together with approach in second code sample in my question, just resolve ISchedulerFactorythen getSchduler() from it manually.
(I really need exactly this versions of packeges because other dependencies in my project)

Related

Register more than one mock or service using AutoMock.GetLoose() (Autofac.Extras.Moq)

I'm in the process of upgrading our Autofac.Extras.Moq library to the latest version (6.0.0) within our Unit Test project. After upgrading, I noticed tests using: var mock = AutoMock.GetLoose(), no longer supported the "Provide" method. So I started digging into the documentation for some sort of workaround.
After taking a look at the Getting Started docs (https://autofaccn.readthedocs.io/en/v5.2.0/integration/moq.html#getting-started) I've noticed there is a new way of registering mocks and dependent services using AutoMock.GetLoose(cfg => cfg.RegisterMock(mockA)). However, some of our tests require more than one Mock injected, and it's not clear to me how to do this.
Take for example:
[Test]
public void Test()
{
var mockA = new Mock();
mockA.Setup(x => x.RunA());
var mockB = new Mock();
mockB.Setup(x => x.RunB());
// mockA is automatically registered as providing IServiceA
using (var mock = AutoMock.GetLoose(cfg => cfg.RegisterMock(mockA)))
{
// mockA will be injected into TestComponent as IServiceA
var component = mock.Create();
// ...and the rest of the test
}
}
How would I register both mockA and mockB?
Thanks.
Have you tried putting both registrations in the GetLoose lambda?
[Test]
public void Test()
{
var mockA = new Mock();
mockA.Setup(x => x.RunA());
var mockB = new Mock();
mockB.Setup(x => x.RunB());
// Register both mocks here:
using (var mock = AutoMock.GetLoose(cfg => {
cfg.RegisterMock(mockA);
cfg.RegisterMock(mockB);
}))
{
// ...and the rest of the test
}
}
If you tried this and it didn't work, you should update your question to include both:
That you tried it AND
What the exception message or incorrect result was
Otherwise, if this works... 🎉

Castle.MicroKernel.ComponentNotFoundException - When Unit Testing

I am trying to unit test an Orchestrator.
//Arrange
var containter = new WindsorContainer();
var Orch = containter.Resolve<ApiOrchestrator>();// Exception Thrown here
The Constructor for the Orchestrator is:
public ApiOrchestrator(IApiWrap[] apiWraps)
{
_apiWraps = apiWraps;
}
The registration is
public class IocContainer : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component.For<FrmDataEntry>().LifestyleTransient());
container.Register(Component.For<ApiOrchestrator>().LifestyleTransient());
container.Register(Component.For<IApiWrap>().ImplementedBy<ClassA>().LifestyleTransient());
container.Register(Component.For<IApiWrap>().ImplementedBy<ClassB>().LifestyleTransient());
}
}
The IocContainer is in the project being tested but the namespace is referenced and I can new up an Orchestrator. I want it to just give me the array of all registered IApiWrap.
Being new to Castle I don't understand what's missing. Code fix would be nice, but I'd really like to know why the container doesn't seem to have the orchestrator registered.
OK so 3 things are missing
A reference to Castle.Windsor.Installer
A call from container to installer to 'go look for' all of the registered classes.
The installer also needed to add a sub resolver to make a collection of the classes since a specific collection was not registered and a Collection of IApiWrap is required by the orchestrator.
The Installer change
public class IocContainer : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
//New Line
container.Kernel.Resolver.AddSubResolver(
new CollectionResolver(container.Kernel, true));
container.Register(Component.For<FrmDataEntry>().LifestyleTransient());
container.Register(Component.For<ApiOrchestrator>().LifestyleTransient());
container.Register(Component.For<IApiWrap>().ImplementedBy<SettledCurveImportCommodityPriceWrap>().LifestyleTransient());
container.Register(Component.For<IApiWrap>().ImplementedBy<ForwardCurveImportBalmoPriceWrap>().LifestyleTransient());
}
}
The Test / Resolving Change
//Arrange
var container = new WindsorContainer();
//New Line
container.Install(FromAssembly.InDirectory(new AssemblyFilter("","EkaA*") ));
var Orch = container.Resolve<ApiOrchestrator>();
Now it works, though any further explanation or correction of what the code is doing is welcome.

MSTest fails when I do run all, but works otherwise

So I have a Testclass using MSTest and every test works great if I run them one and one, however if I select 2 tests, namely can_register and cannot_Register_existing_username then the second fails (cannot_register_existing_username).
I have let my testclass inherit from an abstract class that looks like this:
public abstract class RollbackCapabilities
{
private TransactionScope _transactionScope;
[TestInitialize]
public virtual void TestInitialize()
{
_transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew, new TransactionOptions { Timeout = new TimeSpan(0, 10, 0) });
}
[TestCleanup]
public virtual void TestCleanup()
{
Transaction.Current.Rollback();
_transactionScope.Dispose();
}
}
If I comment this file out then it works (but now the data remains in the test-db which I don't want).
With this file above active the second test fails, the tests look like this
[TestMethod]
public void Can_Register()
{
//Arrange
AccountController ac = ControllerFactory.CreateAccountController();
RegisterModel model = new RegisterModel();
model.UserName = "TestUser";
model.Password= "TestPassword";
model.ConfirmPassword = "TestPassword";
//Act
ActionResult result = ac.Register(model);
//Assert
Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult));
Assert.AreEqual("Home", ((RedirectToRouteResult)result).RouteValues["controller"]);
Assert.AreEqual("Index", ((RedirectToRouteResult)result).RouteValues["action"]);
}
[TestMethod]
public void Cannot_Register_Existing_Username()
{
//Arrange
AccountController ac = ControllerFactory.CreateAccountController();
RegisterModel model = new RegisterModel();
model.UserName = "TestUser";
model.Password = "TestPassword";
model.ConfirmPassword = "TestPassword";
ac.Register(model);
RegisterModel model2 = new RegisterModel();
model2.UserName = "TestUser";
model2.Password = "OtherTestPassword";
model2.ConfirmPassword = "OtherTestPassword";
//Act
ActionResult result = ac.Register(model2);
//Assert
Assert.IsInstanceOfType(result, typeof(ViewResult));
Assert.AreEqual("", ((ViewResult)result).ViewName);
Assert.AreEqual(model2, ((ViewResult)result).ViewData.Model);
}
and finally the error i get is as follows:
Test method
Viducate.UnitTests.UserHandling.RegisterTests.Cannot_Register_Existing_Username
threw exception: System.Data.EntityCommandExecutionException: An
error occurred while executing the command definition. See the inner
exception for details. ---> System.Data.SqlClient.SqlException:
Invalid object name 'dbo.Users'.
Thats my problem, not big but very annoying and as mentioned if I run the tests one and one it works, it also works but leaves data in the db if I comment out my RollbackCapabilities class
Okay so I found out that my error was that I had created the database (but not tables) by hand because create database is not supported in multi-transaction.
however creating an empty database means that EF assumes there is tables already and that is why it failed with dont know what dbo.users are.
So what I did was created the tables as well and now it works. However this means I can never run this on a new development machine without first creating the tables and database. so annoying.
I think I will set up another test class that does not inherit my abstract rollback class and hade that create the tables permanently... should solve the problem as long as that runs first.

MEF Composition .NET 4.0

Thanks in advance for your assistance. I have the following exported part:
[Export (typeof(INewComponent))] // orignally tried just [Export} here and importing NewComponent below
public class NewComponent : INewComponent
{
// does stuff including an import
}
The Console test program imports the above:
public class Program
{
[Import] // have tried variations on importing "NewComponent NewComponent" etc
public INewComponent NewComponent
{
get;
set;
}
public static void Main(string[] args)
{
var p = new Program();
var catalog = new AssemblyCatalog(typeof(Program).Assembly);
var container = new CompositionContainer(catalog);
container.ComposeParts(p);
}
The Composition fails with these CompositionExceptions (I removed the namespace to protect the guilty :)):
1) No valid exports were found that match the constraint
'((exportDefinition.ContractName == "INewComponent") AndAlso
(exportDefinition.Metadata.ContainsKey("ExportTypeIdentity") AndAlso
"INewComponent".Equals(exportDefinition.Metadata.get_Item("ExportTypeIdentity"))))',
invalid exports may have been rejected.
The Composition works successfully if I do the composition in the main program like this:
public class Program
{
public static void Main(string[] args)
{
INewComponent newComponent = new NewComponent();
var catalog = new AssemblyCatalog(typeof(Program).Assembly);
var container = new CompositionContainer(catalog);
container.ComposeParts(newComponent);
}
}
Thank You
Is your Exported part contained in the same Assembly as Program? If it is in a separate DLL, you need to include that Assembly in your catalog as well, like this:
var aggregateCatalog = new AggregateCatalog();
aggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
aggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(NewComponent).Assembly));
var container = new CompositionContainer(aggregateCatalog);
// etc...
If that's doesn't work, then there is a nice open source tool called Visual MEFx that can help you analyze your catalog. Here is a short article about setting it up:
Getting Started With Visual MEFx
In your NewComponent class you wrote this:
// does stuff including an import
If there is a problem with that unshown import, then MEF will complain about the Program.NewComponent import instead of the actual deeper cause. This is called "stable composition". Stable composition can be useful, but it also complicates the debugging of a failed composition.
You can follow the instructions in the MEF documentation about Diagnosing Composition Errors to home in on the actual cause.
In a small program, you can also try to call container.GetExportedValue<ISomeExport>() for a few exports until you find the one that is causing problems.

Autofac ServiceLocator issue in release v2.4.5.724

I have just upgraded to MVC 3 and likewise need to upgrade Autofac.
The following code was working, but now fails with this error -
This resolve operation has already
ended. When registering components
using lambdas, the IComponentContext
'c' parameter to the lambda cannot be
stored. Instead, either resolve
IComponentContext again from 'c', or
resolve a Func<> based factory to
create subsequent components from.
public static IServiceLocator Locator;
public class ServiceA : IServiceA
{
}
public interface IServiceA
{
}
[Test]
public void TestAutofacServiceLocator()
{
// This resolve operation has already ended. When registering components using lambdas, the IComponentContext 'c' parameter to the lambda cannot be stored.
// Instead, either resolve IComponentContext again from 'c', or resolve a Func<> based factory to create subsequent components from.
var builder = new ContainerBuilder();
builder.RegisterType<ServiceA>().As<IServiceA>();
builder.Register(c => Locator = new AutofacServiceLocator(c)).As<IServiceLocator>().SingleInstance();
var container = builder.Build();
container.Resolve<IServiceLocator>();
var x = Locator.GetInstance<IServiceA>();
Assert.NotNull(x);
}
How should I resgister IServiceLocator?
I looked at the answer to question autofac registration issue in release v2.4.5.724 but I'm still confused.
I really should have read Nick's error message, the answer was in the message.
Fixed !!
builder.Register(c => Locator = new AutofacServiceLocator(c.Resolve()))
.As().SingleInstance();