Autofac.Extras.Quartz with ConcurrentExecutionDisallowed not working - service

In my Windows service I am using Quartz.net together with Autofac. To assist me here I am using the Nuget Autofac.Extras.Quartz.
So far so good, but when I try to apply the DisallowConcurrencyExecution attribute it is ignored and multiple jobs are spawned.
I am using as follows:
REGISTRATION
builder.RegisterModule(new QuartzAutofacFactoryModule());
builder.RegisterType<CompanyDatabaseProcessor>().As<IJob>().InstancePerLifetimeScope();
SETUP
var fact = container.Resolve<IJobFactory>();
_scheduler = StdSchedulerFactory.GetDefaultScheduler();
_scheduler.JobFactory = fact;
_scheduler.Start();
var job = JobBuilder.Create<IJob>()
.WithIdentity("QProcJob", "A3Group")
.Build();
var trigger = TriggerBuilder.Create()
.WithIdentity("QProcTrigger", "A3Group")
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInSeconds(executeEvery)
.RepeatForever())
.Build();
_scheduler.ScheduleJob(job, trigger);
and when in my IJob, I check the context.JobDetail.ConcurrentExecutionDisallowed it is always set to false.

I see this question is old, but I encountered the same problem and I going to post my solution, so it could be useful to someone.
The problem is that when you use JobFactory, the type of your job is unknown to quartz, so he assigns an internal type (NoOpJob) that is not decorated with DisallowConcurrentExecution attribute, causing that JobDetailImpl(the class that is used by quartz.net for IJobDetail) return false in ConcurrentExecutionDisallowed property.
What I did was a simple class that inherits from JobDetailImpl and add an extensions method Build to the JobBuilder class to maintain the same fluent code in the job creation. Here is the code:
public class SingleJobDetail : JobDetailImpl
{
public SingleJobDetail() : base()
{
}
public override bool ConcurrentExecutionDisallowed => true;
}
public static class JobHelper
{
public static IJobDetail Build(this JobBuilder builder, bool disallowConcurrent)
{
var job = builder.Build();
if (!disallowConcurrent)
return job;
var singleJob = new SingleJobDetail();
singleJob.JobType = job.JobType;
singleJob.Description = job.Description;
singleJob.Key = job.Key;
singleJob.Durable = job.Durable;
singleJob.RequestsRecovery = job.RequestsRecovery;
if (!singleJob.JobDataMap.IsEmpty)
singleJob.JobDataMap = job.JobDataMap;
return singleJob;
}
}
And in the job creation:
var job = JobBuilder.Create().WithIdentity(id).Build(true);

Related

Concrete type instance registration in Autofac fails to resolve in a nested scope when using AnyConcreteTypeNotAlreadyRegisteredSource source

I have an Autofac container that uses "AnyConcreteTypeNotAlreadyRegisteredSource" to allow resolution of any concrete type without explicit need to register it. If I register a singleton instance of a concrete type using the RegisterInstance method, there are no issues with the resolution. However, if I create a child lifetime scope and do the same concrete type singleton instance registration, the child lifetime scope is not able to resolve the type anymore. It throws the following exception:
Autofac.Core.Activators.Reflection.NoConstructorsFoundException: 'No accessible constructors were found for the type 'AutofacTests.IssueTests+Manager'.'
Why is it even trying to instantiate the object when I have a singleton instance of that type registered already? It seems like this problem only comes when I try to resolve a concrete type instead of an interface.
Here is the test code that demonstrates the problem (The test method name and comments show what works and what does not):
using Autofac;
using Autofac.Features.ResolveAnything;
namespace AutofacTests
{
[TestClass]
public class IssueTests
{
private interface IPerson
{
}
private class Employee : IPerson
{
public Employee()
{
}
}
private class Manager : Employee
{
internal Manager(IPerson worker)
{
string s = "";
}
}
[TestMethod]
public void Resolution_ThatWorks()
{
ContainerBuilder builder = new ContainerBuilder();
var mgr = new Manager(null);
builder.RegisterInstance<IPerson>(mgr);
builder.RegisterInstance<Manager>(mgr);
using (var container = builder.Build())
{
var person = container.Resolve<Manager>();
Assert.IsNotNull(person, "Employee could not be resolved!");
}
}
[TestMethod]
public void ResolutionWithAnyTypeSource_ThatWorks()
{
ContainerBuilder builder = new ContainerBuilder();
// NOTE: This source registration does not impact the concrete type resolution when no child lifetime scope is involved.
builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
var mgr = new Manager(null);
builder.RegisterInstance<IPerson>(mgr);
builder.RegisterInstance<Manager>(mgr);
using (var container = builder.Build())
{
var person = container.Resolve<Manager>();
Assert.IsNotNull(person, "Employee could not be resolved!");
}
}
[TestMethod]
public void NestedResolution_ThatWorks()
{
ContainerBuilder builder = new ContainerBuilder();
using (var container = builder.Build())
{
void RegisterNestedServices(ContainerBuilder builder)
{
var mgr = new Manager(null);
builder.RegisterInstance<IPerson>(mgr);
builder.RegisterInstance<Manager>(mgr);
}
using (var childContainer = container.BeginLifetimeScope(RegisterNestedServices))
{
var person = childContainer.Resolve<Manager>();
Assert.IsNotNull(person, "Employee could not be resolved!");
}
}
}
[TestMethod]
public void NestedResolutionWithAnyTypeSource_ThatFails()
{
ContainerBuilder builder = new ContainerBuilder();
// NOTE: This source registration causes the resolution of a concrete type to fail in a child lifetime scope.
builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
using (var container = builder.Build())
{
void RegisterNestedServices(ContainerBuilder builder)
{
var mgr = new Manager(null);
builder.RegisterInstance<IPerson>(mgr);
builder.RegisterInstance<Manager>(mgr);
}
using (var childContainer = container.BeginLifetimeScope(RegisterNestedServices))
{
// Works
var person = childContainer.Resolve<IPerson>();
Assert.IsNotNull(person, "Person could not be resolved!");
// *** Fails ***
var emp = childContainer.Resolve<Manager>();
Assert.IsNotNull(emp, "Employee could not be resolved!");
}
}
}
}
}
Anyone has any idea what am I doing wrong or how to make this work in the child lifetime scopes?
Thanks.
It appears you're hitting this known issue where AnyConcreteTypeNotAlreadyRegisteredSource (ACTNARS) doesn't properly look at new registrations in child scopes.
At the time of this writing there is not a fix for it, but we'd love a PR to get it fixed. It's been open for a while now.

Testing code in a custom NancyFx Bootstrapper

I have a custom Nancy Bootstrapper which uses StructureMapNancyBootstrapper but the issue is the same regardless of container.
public class CustomNancyBootstrapper : StructureMapNancyBootstrapper
{
protected override void RequestStartup(IContainer container, IPipelines pipelines, NancyContext context)
{
var auth = container.GetInstance<ICustomAuth>();
auth.Authenticate(context);
}
}
I want to write a test to assert that Authenticate is called with the context... something like this...
[Test]
public void RequestStartup_Calls_CustomAuth_Authenticate_WithContext()
{
// set up
var mockAuthentication = new Mock<ICustomAuth>();
var mockContainer = new Mock<IContainer>();
var mockPipelines = new Mock<IPipelines>();
var context = new NancyContext();
mockContainer.Setup(x => x.GetInstance<ICustomAuth>()).Returns(mockAuthentication.Object);
// exercise
_bootstrapper.RequestStartup(_mockContainer.Object, _mockPipelines.Object, context);
// verify
mockAuthentication.Verify(x => x.Authenticate(context), Times.Once);
}
The problem is that I can't call RequestStartup because it's protected as defined in NancyBootstrapperBase.
protected virtual void RequestStartup(TContainer container, IPipelines pipelines, NancyContext context);
Is there a "proper"/"offical" Nancy way to do this without creating another derived class and exposing the methods as that just seems like a hack?
Thanks
I guess you can "fake" the request by using Browser from Nancy.Testing:
var browser = new Browser(new CustomNancyBootstrapper());
var response = browser.Get("/whatever");
There is a good set of articles about testing NancyFx application:
http://www.marcusoft.net/2013/01/NancyTesting1.html
Turns out Nancy offers a IRequetStartup interface so you can take the code out of the custom bootstrapper and do something like this...
public class MyRequestStart : IRequestStartup
{
private readonly ICustomAuth _customAuthentication;
public MyRequestStart(ICustomAuth customAuthentication)
{
if (customAuthentication == null)
{
throw new ArgumentNullException(nameof(customAuthentication));
}
_customAuthentication = customAuthentication;
}
public void Initialize(IPipelines pipelines, NancyContext context)
{
_customAuthentication.Authenticate(context);
}
}
and the test is easy and concise
[Test]
public void When_Initialize_Calls_CustomAuth_Authenticate_WithContext()
{
// set up
var mockAuth = new Mock<ICustomAuth>();
var requestStartup = new MyRequestStart(mockAuth.Object);
var mockPipeline = new Mock<IPipelines>();
var context = new NancyContext();
// exercise
requestStartup.Initialize(mockPipeline.Object, context);
// verify
mockAuth.Verify(x => x.Authenticate(context), Times.Once);
}
https://github.com/NancyFx/Nancy/wiki/The-Application-Before%2C-After-and-OnError-pipelines#implementing-interfaces

Can Autofac compose existing objects with Mef dependencies?

I am integrating a mef-based ServiceLocator with Autofac. The current locator is able to compose an existing object by setting up a CompositionBatch and then injecting dependecies on the object. A simple repro:
public void MefCompositionContainer_CanComposeExistingObjects()
{
//1. Initialize Mef
var composablePartCatalogs = new List<ComposablePartCatalog>
{
new AssemblyCatalog(Assembly.GetExecutingAssembly())
//A lot more here..
};
var aggregateCatalog = new AggregateCatalog(composablePartCatalogs);
var container = new CompositionContainer(aggregateCatalog, true);
//2. Mef is able to compose existing object
var objectWithPropertyImport = new ClassWithPropertyImport();
Compose(container, objectWithPropertyImport);
objectWithPropertyImport.ImportOfMefExport.Should().NotBeNull();
}
static T Compose<T>(CompositionContainer container, T value)
{
var batch = new CompositionBatch();
batch.AddPart(value);
container.Compose(batch);
return value;
}
The following classes are required:
[Export]
public class MefExport { }
//Note that this class does not have the [Export] attribute
public class ClassWithPropertyImport
{
[Import]
public MefExport ImportOfMefExport { get; set; }
}
Is it possible to accomplish the same with Autofac? If so - what should be added / changed here to compose objectWithPropertyImport?
public void Autofac_CanComposeExistingObjects()
{
//1. Initialize Mef
var composablePartCatalogs = new List<ComposablePartCatalog>
{
new AssemblyCatalog(Assembly.GetExecutingAssembly())
//A lot more here..
};
var aggregateCatalog = new AggregateCatalog(composablePartCatalogs);
//2. Initialize Autofac and setup mef-integration
var builder = new ContainerBuilder();
builder.Register(c => new AutofacExport()).Exported(x => x.As<AutofacExport>());
builder.RegisterComposablePartCatalog(aggregateCatalog);
var ioc = builder.Build();
var objectWithPropertyImport = new ClassWithPropertyImport();
// Now what?
// Updated according to solution from Travis Illig.
// The following code works for me:
ioc.InjectProperties(objectWithPropertyImport);
objectWithPropertyImport.ImportOfMefExport.Should().NotBeNull();
}
If all you need to do is inject the properties of a new object using Autofac, then use the InjectProperties method on the lifetime scope / container.
using Autofac;
public class ClassWithPropertyImport
{
public MyExport ImportedProperty { get; set; }
}
public class MyExport { }
var builder = new ContainerBuilder();
builder.RegisterType<MyExport>();
var container = builder.Build();
using(var scope = container.BeginLifetimeScope())
{
var c = new ClassWithPropertyImport();
scope.InjectProperties(c);
c.ImportedProperty.Should().NotBeNull();
}
As long as the types you're injecting are registered with Autofac, it should work fine. You don't need the type of the thing you're injecting onto registered. (Note the ClassWithPropertyImport is not registered with Autofac but the MyExport class is.)
Keep in mind it does mean Autofac needs to resolve the MyExport type - so if it has dependencies, those do need to be registered with Autofac as well.

Satisfy Imports in custom ExportProvider

I'd like to know how I can have Imports in my custom ExportProvider. Here's an example of what I'm trying to do:
public class MyExportProvider : ExportProvider
{
private List<Export> _exports;
[Import()]
private IConfig _config;
public MyExportProvider()
base()
{
_exports = new List<Export>();
}
protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition,
AtomicComposition composition)
{
if (!_exports.Any())
Initialize();
return _exports.Where(x => definition.IsConstraintSatisfiedBy(s.Definition);
}
private void Initialize()
{
var contractName = typeof(MyObject).FullName;
var exportDefinition = new ExportDefinition(contractName, null);
var export = new Export(exportDefinition, () => new MyObject(_config));
_exports.Add(export);
}
}
I am adding the provider when I create the CompositionContainer.
Unfortunately, the import is never satisfied. I can see this by setting AllowDefaults = true so my provider is created, but _config is always null.
How can I configure the container and/or provider so the Import will be satisfied?
When you are adding your export provider you are still creating your composition container. Thus I don't see how you can use the not yet created composition container to import parts of your custom export provider.
What I would do is first create a temporary CompositionContainer that will be used to create MyExportProvider.
Afterwards use the MyExportProvider to create your second final CompositionContainer that will be used by the rest of the application.
EDIT:
// this is your real container, only shown here for reference
CompositionContainer container;
public void BootstrapContainerMethod()
{
// Replace this part with the catalogs required to create your export provider.
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new DirectoryCatalog("./bin", "*.dll"));
// Your temporary container, declared here in local scope
// will be disposed because of using
using (var bootstrapContainer = new CompositionContainer(catalog))
{
var myExportProvider = bootstrapContainer.GetExportedValue<IMyExportProvider>();
// create your real container and optionnally add catalogs (not shown here)
container = new CompositionContainer(myExportProvider);
}
}
You might also consider the problem from another angle. Do you really need to have imports in your custom ExportProvider? I do not know your requirements, but maybe you can make do without having imports.
As an alternative to the dual CompositionContainer solution, you could wire this up in a single export provider, and have it compose itself using the same container. As an example, I've defined the following contract and it's export:
public interface ILogger
{
void Log(string message);
}
[Export(typeof(ILogger))]
public class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
}
And with my example ExportProvider, I expect to be able to import an instance of it:
public class TestExportProvider : ExportProvider
{
private readonly object _lock = new object();
private bool _initialised;
[Import]
public ILogger Logger { get; set; }
public void SetCompositionService(ICompositionService service)
{
if (service == null) throw new ArgumentNullException("service");
lock (_lock)
{
if (!_initialised)
{
InitialiseProvider(service);
}
}
}
private void InitialiseProvider(ICompositionService service)
{
service.SatisfyImportsOnce(this);
_initialised = true;
}
protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition)
{
if (_initialised)
{
Logger.Log("Getting available exports for '" + definition.ContractName + "'");
// Do work here.);
return Enumerable.Empty<Export>();
}
return Enumerable.Empty<Export>();
}
}
I provide an instance of an ICompositionService, which CompositionContainer implements, and I perform a first-time initialisation when I call SetCompositionService. It checks to see if it has already been initialised, and if not, goes ahead and calls the SatisfyImportsOnce method on itself.
We would wire this up, something like this:
// Build our catalog.
var catalog = new AssemblyCatalog(typeof(Program).Assembly);
// Create our provider.
var provider = new TestExportProvider();
// Create our container.
var container = new CompositionContainer(catalog, provider);
// Register the composition service to satisfy it's own imports.
provider.SetCompositionService(container);
Obviously you wouldn't be able to use any imports and your ExportProvider will explicitly create for you, but for everything else, it should work.

MVCContrib TestHelper problem with session.clear, session.abandon and Rhino Mock

Hi I'm trying to unit test my logout action on my controller but I have hard times to test or stub my Session in the HttpContext. I'm using MVC Contrib TestHelper to make it easier but now I need a little help.
Here's my test :
[TestFixture]
public class SessionControllerTest
{
private ISession _session;
private IConfigHelper _configHelper;
private IAuthenticationService _authService;
//private IMailHelper _mailHelper;
private ICryptographer _crypto;
private SessionController _controller;
private TestControllerBuilder _builder;
private MockRepository _mock;
[SetUp]
public void Setup()
{
_mock = new MockRepository();
_session = _mock.DynamicMock<ISession>();
_configHelper = _mock.DynamicMock<IConfigHelper>();
_authService = _mock.DynamicMock<IAuthenticationService>();
//_mailHelper = _mock.DynamicMock<IMailHelper>();
_crypto = _mock.DynamicMock<ICryptographer>();
_controller = new SessionController(_authService, _session, _crypto, _configHelper);
_builder = new TestControllerBuilder();
_builder.InitializeController(_controller);
}
[Test]
public void Logout_ReturnRedirectToAction()
{
_builder.InitializeController(_controller);
_authService.SignOut();
LastCall.Repeat.Once();
_builder.Session["memberNumber"] = string.Empty;
LastCall.Repeat.Once();
_controller.Session.Clear();
LastCall.Repeat.Any();
_controller.Session.Abandon();
LastCall.Repeat.Any();
//_builder.Session.Stub(s => s.Clear());
//_builder.Session.Stub(s => s.Abandon());
//_builder.Session.Clear();
//LastCall.Repeat.Once();
//_builder.Session.Abandon();
//LastCall.Repeat.Once();
_mock.ReplayAll();
var result = _controller.Logout();
_mock.VerifyAll();
result.AssertActionRedirect().ToAction<SessionController>(c => c.Login());
}
You can see my differents attemps. I get an error telling me that Session.Abandon() is not implemented, witch is right when you take a look at MVCContrib's TestHelper. But how can I mock or Stub the Session that's already mocked by the TestHelper?
The Exception in NUnit :
System.NotImplementedException : The
method or operation is not
implemented. at
MvcContrib.TestHelper.MockSession.Abandon()
Thank you for the help!
EDIT : Here's the new working test
[Test]
public void Logout_ReturnRedirectToAction()
{
_builder.InitializeController(_controller);
var mockSession = _mock.Stub<HttpSessionStateBase>();
_controller.HttpContext.BackToRecord();
_controller.HttpContext.Stub(c => c.Session).Return(mockSession);
_controller.HttpContext.Replay();
_authService.SignOut();
LastCall.Repeat.Once();
_builder.Session["memberNumber"] = string.Empty;
_controller.Session.Clear();
LastCall.Repeat.Once();
_controller.Session.Abandon();
LastCall.Repeat.Once();
_mock.ReplayAll();
var result = _controller.Logout();
_mock.VerifyAll();
result.AssertActionRedirect().ToAction<SessionController>(c => c.Login());
}
It's been a while since I used MvcContrib, so I pulled down the latest code and made a quick test project. It's very odd. Looking at the MvcContrib code (specifically, TestControllerBuilder), it creates mocks for most of the objects (request, response, server, etc...), but not for Session. I'm not sure why this is -- probably have to ask the creators.
However, there is a way to mock it yourself. You can create your own mock session and tell the controller to use yours instead of the one from MvcContrib.TestHelpers. Here's what I did in my test:
var mockSession = MockRepository.GenerateStub<HttpSessionStateBase>();
controller.HttpContext.BackToRecord();
controller.HttpContext.Stub(c => c.Session).Return(mockSession);
controller.HttpContext.Replay();
Now I run my controller method and then use Rhino.Mocks' AAA syntax for making sure the Abandon method was called:
controller.Session.AssertWasCalled(s => s.Abandon());
If you want to use record/replay semantics, you could set your expectations before calling controller.HttpContext.Replay().