It seems like StdSchedulerFactory returns a singleton with the name defined in config:
<add key="quartz.scheduler.instanceName" value="MyQuartzScheduler" />
As quartz config section consists of key value pairs it looks like using factory for instantiating scheduler limits the number of available schedulers to one.
AFIAK, you can create as many schedulers as you like within any application, but you cannot use default quartz config approach for this, as it expect only one collection of scheduler properties (look into StdSchedulerFactory implementation and this blog if interesting):
By default, In Quartz.Net, the StdSchedulerFactory is responsible for configuring the scheduler. When the Quartz.Net scheduler is started, the factory will try to automatically configure a scheduler by looking for configuration information in different places:
the hosting application’s configuration file
a file specified in an environment variable
the quartz.config file
the embedded configuration file
SO what you can do is not to use automatic scheduler configuration, but
by himself create a separate collections of properties and pass them to scheduler creation constructors:
public StdSchedulerFactory(NameValueCollection props);
using code approach:
NameValueCollection scheduler1Properties = new NameValueCollection();
properties["quartz.scheduler.instanceName"] = "SingleThreadScheduler";
properties["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz";
properties["quartz.threadPool.threadCount"] = "1";
...
var factory = new StdSchedulerFactory(scheduler1Properties);
or you can create separate quartz configs and directly use quartz PropertiesParser class to read
/// <summary>
/// Reads the properties from file system.
/// </summary>
/// <param name="fileName">The file name to read resources from.</param>
/// <returns></returns>
public static PropertiesParser ReadFromFileResource(string fileName)
and get collection:
/// <summary>
/// Gets the underlying properties.
/// </summary>
/// <value>The underlying properties.</value>
public virtual NameValueCollection UnderlyingProperties
{
get { return props; }
}
// PropertiesParser class is directly used in default config reading implementation.
Related
I need to create and use global variable as optional parameter, but do not know how I can implement it.
I created the global variable in Ranorex studio:
Also this variable appeared in Data binding tag:
But I can't use this variable in the code. (ASECore package do not contains any parameters).
You can use the global Variables in Ranorex Record module or Ranorex Code module. Let me please first make an introduction of how to use them.
Create in Record module
In the Record module, click button Variables... in the top right corner and add the variables you want to use in the redord module.
Then use them in your recording:
Create in Code module
When you create a code module, it will look like this:
/// <summary>
/// Description of MyCode.
/// </summary>
[TestModule("32310FEC-5336-4F83-B448-ABC851EE5731", ModuleType.UserCode, 1)]
public class MyCode : ITestModule
{
/// <summary>
/// Constructs a new instance.
/// </summary>
public MyCode()
{
// Do not delete - a parameterless constructor is required!
}
/// <summary>
/// Performs the playback of actions in this module.
/// </summary>
/// <remarks>You should not call this method directly, instead pass the module
/// instance to the <see cref="TestModuleRunner.Run(ITestModule)"/> method
/// that will in turn invoke this method.</remarks>
void ITestModule.Run()
{
Mouse.DefaultMoveTime = 300;
Keyboard.DefaultKeyPressTime = 100;
Delay.SpeedFactor = 1.0;
}
}
Now, right click in the code and choose "Insert new module variable". Then you can set a name and default value. Press ok and it will add something like this:
string _MyVariable = "DefaultValue";
[TestVariable("de0fb4a9-32ba-4635-8f0f-4ff6db184c3f")]
public string MyVariable
{
get { return _MyVariable; }
set { _MyVariable = value; }
}
Now, you can use the variables in the run method like normal C# properties:
repo.Calculator.CalculatorResults.PressKeys(Input_1);
repo.Calculator.PlusButton.Click();
repo.Calculator.CalculatorResults.PressKeys(Input_2);
repo.Calculator.EqualButton.Click();
How to bind Variables in Suite
When you created the global parameters, it's true that you can not bind them on the suite level.
Therefore close the dialog and right click on the Record/Code module and choose "Data binding"
In the lower table you can bind your variables of the Record/Code module to the global variables. If they have the same name, you can also Auto-bind them.
When you now execute the test suite, the values of the global variables will be used in test. If you execute the Record/Code module standalone, then the default values will be used in test.
Once you have set that variable in your highest node, you can use it and assign variables to it in lower nodes. So when you make a smart folder in your test suite and go to the data binding, you will notice the global is present under the parameters. All you need to do is make a recording with a variable that will use the global variable and link it in that folder.
I am using serilog with the sinks File and RollingFile in a crosscutting dll that delivers a logging service. I am configuring with the Appsettings nuget, therefore I have no static dependency to the mentioned sinks. However I do need them at runtime and they are not copied to the bin folder of the application, only to the bin folder of the dll. That means I get a Runtime Exception because the sink-dlls are not there. Is there a way to fix that? My workaround is creating a Variable of type RollingFileSink that I never use. But it is kind of ugly. UPDATE: that solution does not work in Release btw.
I had this issue before with Serilog, and the way I resolved it was to create a static reference to a type inside the assemblies I needed, via an assembly-level attribute that I declare inside the AssemblyInfo.cs of my main project.
Something like this:
[assembly: ImplicitDependency(typeof(Serilog.Sinks.RollingFile.RollingFileSink))]
[assembly: ImplicitDependency(typeof(Serilog.Sinks.File.PeriodicFlushToDiskSink))]
// etc...
And this is the attribute I created inside my project...
/// <summary>
/// Indicates that the marked assembly depends on the type that is specified in the constructor.
/// Typically used to force a compile-time dependency to the assembly that contains the type.
/// </summary>
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public sealed class ImplicitDependencyAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="ImplicitDependencyAttribute"/> class.
/// </summary>
/// <param name="dependencyType">A type from the assembly that is used dynamically.</param>
public ImplicitDependencyAttribute(Type dependencyType)
{
DependencyType = dependencyType;
}
/// <summary>
/// Gets the dependent type reference.
/// </summary>
/// <value>The dependent type reference.</value>
public Type DependencyType { get; private set; }
}
I want to use PropertyPlaceholderConfiguration to load different property file depends on spring.profiles.active passed when web application launched. I have different stages divided by two groups. read application.properties when spring profile is 'prod', otherwise read application-dev.properties file.
When I launched non-prod stage, the developmentPropertyPlaceholderConfigurer() called, "Development properties read" print out, I guess application-dev should be loaded. But When I use #Value("${aws.key}") to read the value, it's application.properties' value.
I don't know what's wrong
Forgot mention I use spring-boot.
I did little test, let's say I have two same properties name in both file. aws.key=dev in dev file aws.key=prod in default file. Even if I active dev stage, the aws.key=prod in application.properties was always read in. But, If I remove 'aws.key' in application.properties, then aws.key=dev was read in. I think the appliaction-dev.properties file was read in, then spring boot read application.properties again override the same properties even if I do not want spring boot to read application.property in non prod stage. how to solve it?
#Configuration
public class PropertyPlaceholderConfiguration {
#Bean
#Profile({"test","qa","demo","dev","AWS","localhost"})
public static PropertySourcesPlaceholderConfigurer developmentPropertyPlaceholderConfigurer() {
System.out.println("Development properties read");
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
configurer.setIgnoreUnresolvablePlaceholders(Boolean.TRUE);
configurer.setLocation(new ClassPathResource("application-dev.properties"));
return configurer;
}
#Bean
#Profile("prod") // The default
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
System.out.println("Production properties read");
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
configurer.setIgnoreUnresolvablePlaceholders(Boolean.TRUE);
configurer.setLocation(new ClassPathResource("application.properties"));
return configurer;
} }
I have a console app and web API both referencing the same data layer which is a separate project.
In that data layer, I have a class that requires a repository that we are grabbing from the container when that class is instantiated.
In that class, it has a base class which we are doing the following in the constructor to setup the Repository:
IContainerAccessor containerAccessor = HttpContext.Current.ApplicationInstance as IContainerAccessor;
Repository = containerAccessor.Container.Resolve<IRepository>();
What would be the best way to set this up? This is obviously a problem for our console application as it has no HttpContext.
If I'm correct you want to setup your console app so it can inject classes from the shared data layer.
To do so, you need to create an installer for the console app and tell it to run the installers in the shared library, but to modify the life style from 'PerWebRequest' to 'Singleton' or 'Transient'.
For more information read this article:
http://blog.ploeh.dk/2010/04/26/ChangingWindsorlifestylesafterthefact/
Be aware that changing this may cause problems.
I.e.: If multiple components configured as "perWebRequest" require a 'Unit-Of-Work' to be injected, then this uow will be different for all components if you change the life style to transient.
Changing it to Singleton causes the same but opposite problem. Objects that are created now will have the same object for different requests ...
If you are okay with the problems this code should get you starting
public class ConsoleAppInstaller: IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
// 1) make sure we do not use PerWebRequest life style types
var convertWebToTransient = new WebToTransientConvertor();
container.Kernel.ComponentModelBuilder.AddContributor(convertWebToTransient);
// 2) call installers on all libraries we use ...
container.Install(FromAssembly.Containing<SharedDataLayerInstaller>());
// 3) link internal services ...
container.Register(Component.For<IXxxxFactory>().AsFactory());
container.Register(Component.For<IYyyyFactory>().AsFactory());
container.Register(Classes.FromThisAssembly().Where(c => typeof(Form).IsAssignableFrom(c)).LifestyleTransient());
}
public static IWindsorContainer Bootstrap()
{
return new WindsorContainer().Install(FromAssembly.This());
}
}
/// <summary>
/// This class allows to intercept installers using PerWebRequest lifestyles and replaces them with Transient life styles.
/// <code>container.Kernel.ComponentModelBuilder.AddContributor(new WebToTransientConvertor())</code>
/// </summary>
public class WebToTransientConvertor : IContributeComponentModelConstruction
{
//http://blog.ploeh.dk/2010/04/26/ChangingWindsorlifestylesafterthefact/
public void ProcessModel(IKernel kernel, ComponentModel model)
{
if (model.LifestyleType == LifestyleType.PerWebRequest)
//model.LifestyleType = LifestyleType.Transient;
model.LifestyleType = LifestyleType.Singleton;
}
}
Spring documentation on http://springframework.net/docs/1.3.1/reference/html/objects.html says:
"In addition to object definitions which contain information on how to
create a specific object, the IApplicationContext implementations also
permit the registration of existing objects that are created outside
the container, by users. This is done by accessing the
ApplicationContext's IObjectFactory via the property ObjectFactory
which returns the IObjectFactory implementation
DefaultListableObjectFactory. DefaultListableObjectFactory supports
registration through the methods RegisterSingleton(..) and
RegisterObjectDefinition(..)."
I'm trying to access the ObjectFactory object after doing the following:
var context = ContextRegistry.GetContext();
But there is no ObjectFactory property. I'm using Spring.Net v1.3.1.20711 and have Spring.Core referenced in my project.
What am I missing?
The ObjectFactory property is not exposed by the IApplicationContext interface, but is part of the IConfigurableListableObjectFactory interface.
Your context variable will be of inferred type IApplicationContext, because of the return type of ContextRegistry.GetContext(), so in VS it will appear that the ObjectFactory property is not available. However, if you take a closer look, you will see that it is an XmlApplicationContext that has the ObjectFactory property, because it implements IConfigurableListableObjectFactory. As Sebastian points out in his answer, most (if not all) application contexts implement this interface.
E.g.:
var ctx = new XmlApplicationContext("objects.xml");
ctx.ObjectFactory.RegisterSingleton("MyObject2", new MyClass() { Name = "MyObject2"});
var o2 = (MyClass)ctx.GetObject("MyObject2");
Assert.AreEqual("MyObject2", o2.Name);
Just to add to Marjin's answer; here is an extension method to get the Factory which I use.
/// <summary>
/// Gets the ObjectFactory from the Spring context.
/// </summary>
/// <param name="context">The context.</param>
/// <returns></returns>
public static IConfigurableListableObjectFactory Factory(this IApplicationContext context)
{
return ((IConfigurableApplicationContext)context).ObjectFactory;
}