Castle Windsor ArrayResolver ServiceOverrides Not Respected - castle-windsor

When using the ArrayResolver, if I register multiple dependencies that implement the same interface and I have registered classes that depend on an array of these dependencies, one would expect ServiceOverrides to be respected and allow control over which dependencies are injected into the contructors. Instead, I have seen and written tests that show every dependency is injected into the registered classes contructors.
using System.Linq;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.Resolvers.SpecializedResolvers;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
using NUnit.Framework;
namespace ServiceFramework.UnitTests
{
public class ArrayResolver_ServiceOverridesNotRespected
{
private class TestInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<IDependency>().ImplementedBy<Foo>().Named("foo"),
Component.For<IDependency>().ImplementedBy<Bar>().Named("bar"),
Component.For<IDependency>().ImplementedBy<Baz>().Named("baz"),
Component.For<IDependOnArray>().ImplementedBy<DependsOnArray>().Named("InjectAll"),
Component.For<IDependOnArray>().ImplementedBy<DependsOnArray>().Named("InjectFooOnly").ServiceOverrides(
ServiceOverride.ForKey("steps").Eq(new[] {"foo"})),
Component.For<IDependOnArray>().ImplementedBy<DependsOnArray>().Named("InjectFooAndBarOnly").ServiceOverrides(
ServiceOverride.ForKey("steps").Eq(new[] {"foo", "bar"})));
}
}
public interface IDependency
{
}
public class Foo : IDependency
{
}
public class Bar : IDependency
{
}
public class Baz : IDependency
{
}
public interface IDependOnArray
{
IDependency[] GetDependencies();
}
public class DependsOnArray : IDependOnArray
{
private readonly IDependency[] _steps;
public DependsOnArray(IDependency[] steps)
{
_steps = steps;
}
public IDependency[] GetDependencies()
{
return _steps;
}
}
[Test]
public void InjectFooOnly_WithoutArrayResolver()
{
using (var container = new WindsorContainer())
{
container.Install(new TestInstaller());
var fooItemTest = container.Resolve<IDependOnArray>("InjectFooOnly");
var dependencies = fooItemTest.GetDependencies().Select(d => d.GetType()).ToList();
Assert.That(dependencies, Has.Count.EqualTo(1));
Assert.That(dependencies, Has.Member(typeof(Foo)));
}
}
[Test]
[ExpectedException(typeof(AssertionException))]
public void InjectFooOnly_WithArrayResolver()
{
using (var container = new WindsorContainer())
{
container.Kernel.Resolver.AddSubResolver(new ArrayResolver(container.Kernel, true));
container.Install(new TestInstaller());
var fooItemTest = container.Resolve<IDependOnArray>("InjectFooOnly");
var dependencies = fooItemTest.GetDependencies().Select(d => d.GetType()).ToList();
Assert.That(dependencies, Has.Count.EqualTo(1));
Assert.That(dependencies, Has.Member(typeof(Foo)));
}
}
[Test]
public void InjectFooAndBarOnly_WithoutArrayResolver()
{
using (var container = new WindsorContainer())
{
container.Install(new TestInstaller());
var fooItemTest = container.Resolve<IDependOnArray>("InjectFooAndBarOnly");
var dependencies = fooItemTest.GetDependencies().Select(d => d.GetType()).ToList();
Assert.That(dependencies, Has.Count.EqualTo(2));
Assert.That(dependencies, Has.Member(typeof(Foo)));
Assert.That(dependencies, Has.Member(typeof(Bar)));
}
}
[Test]
[ExpectedException(typeof(AssertionException))]
public void InjectFooAndBarOnly_WithArrayResolver()
{
using (var container = new WindsorContainer())
{
container.Kernel.Resolver.AddSubResolver(new ArrayResolver(container.Kernel, true));
container.Install(new TestInstaller());
var fooItemTest = container.Resolve<IDependOnArray>("InjectFooAndBarOnly");
var dependencies = fooItemTest.GetDependencies().Select(d => d.GetType()).ToList();
Assert.That(dependencies, Has.Count.EqualTo(2));
Assert.That(dependencies, Has.Member(typeof(Foo)));
Assert.That(dependencies, Has.Member(typeof(Bar)));
}
}
[Test]
public void InjectAll()
{
using (var container = new WindsorContainer())
{
container.Kernel.Resolver.AddSubResolver(new ArrayResolver(container.Kernel, true));
container.Install(new TestInstaller());
var fooItemTest = container.Resolve<IDependOnArray>("InjectAll");
var dependencies = fooItemTest.GetDependencies().Select(d => d.GetType()).ToList();
Assert.That(dependencies, Has.Count.EqualTo(3));
Assert.That(dependencies, Has.Member(typeof(Foo)));
Assert.That(dependencies, Has.Member(typeof(Bar)));
Assert.That(dependencies, Has.Member(typeof(Baz)));
}
}
}
}

The issue is now fixed and the fix will be part of the next major version of Windsor.

Related

Topshelf TimeoutException

I'm trying to use Topshelf Framework to create a windows service. But when i try to start the service, there is this exception :
" The service failed to start... System.Service.Process.TimeoutException : the waiting period has expired and the operation has not been completed"
This is my code :
public class MyService : ServiceControl
{
private System.Timers.Timer _timer;
public void MyService()
{
_timer = new System.Timers.Timer(10);
_timer.AutoReset = false;
_timer.Elapsed += new ElapsedEventHandler(TimerOnElapsed);
}
private void TimerOnElapsed(object source, ElapsedEventArgs e)
{
//all the operation to do at the startup
}
public bool Start(HostControl hostControl)
{
_timer.Start();
return true;
}
public bool Stop(HostControl hostControl)
{
_timer.Stop();
return true;
}
}
Thanks for any help :)
There are several issues I notice:
The current code would make the timer fire only once (you have AutoReset = false)
with TopShelf, the MyService class should look like this:
using System.Timers;
using Topshelf;
namespace TopShelfTestService
{
public class MyService
{
private System.Timers.Timer _timer;
public MyService()
{
_timer = new System.Timers.Timer(10);
_timer.AutoReset = true;
_timer.Elapsed += new ElapsedEventHandler(TimerOnElapsed);
}
private void TimerOnElapsed(object source, ElapsedEventArgs e)
{
//all the operation to do at the startup
}
public bool Start(HostControl hostControl)
{
_timer.Start();
return true;
}
public bool Stop(HostControl hostControl)
{
_timer.Stop();
return true;
}
}
}
and the console app/ Program.cs will look like so:
using Topshelf;
namespace TopShelfTestService
{
class Program
{
static void Main(string[] args)
{
HostFactory.Run(x =>
{
x.Service<MyService>(s =>
{
s.ConstructUsing(name => new MyService());
s.WhenStarted((tc, hostControl) => tc.Start(hostControl));
s.WhenStopped((tc, hostControl) => tc.Stop(hostControl));
});
x.RunAsLocalSystem();
x.SetDescription("Sample Topshelf Host"); //7
x.SetDisplayName("Test Service with TopShelf"); //8
x.SetServiceName("TopShelfTestService");
});
}
}
}

LocalSettings and background tasks WP 8.1

How to change values in Windows.Storage.ApplicationData.Current.LocalSettings with background task. I use such code like back ground task:
namespace MainTask
{
public sealed class Task :IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance)
{
BackgroundTaskDeferral _deferral = taskInstance.GetDeferral();
var storage = Windows.Storage.ApplicationData.Current.LocalSettings;
int i = (int)storage.Values["var"];
i++;
storage.Values["val"] = i;
_deferral.Complete();
}
}
}
Background task started and there is in livecycle events in debugger and it reads the storage. But Values["val"] does not change.
namespace MainTask
{
public sealed class Task :IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance)
{
BackgroundTaskDeferral _deferral = taskInstance.GetDeferral();
var storage = Windows.Storage.ApplicationData.Current.LocalSettings;
int i = (int)storage.Values["var"];
i++;
storage.Values.Remove("val");
storage.Values.Add("val", i);
_deferral.Complete();
}
}
}

Type 1083: Syntax error: package is unexpected

So, I got this .as file that is called, let say, class A.
class A inside has other 2 classes, class B and class C, and the only class that is inside a package is class A. And it throws that error.
I downloaded this as an example, and it should work, however Flash Builder 4.6 doesn't like it.
The structure of the as file is like this:
imports
variables
class B
class C
package
public class A
/package
Btw, I'm using Flash Builder not Flash CC.
Update, posting code:
import com.adobe.serialization.json.JSON;
import com.shephertz.appwarp.WarpClient;
import com.shephertz.appwarp.listener.ConnectionRequestListener;
import com.shephertz.appwarp.listener.NotificationListener;
import com.shephertz.appwarp.listener.RoomRequestListener;
import com.shephertz.appwarp.listener.ZoneRequestListener;
import com.shephertz.appwarp.messages.Chat;
import com.shephertz.appwarp.messages.LiveResult;
import com.shephertz.appwarp.messages.LiveRoom;
import com.shephertz.appwarp.messages.LiveUser;
import com.shephertz.appwarp.messages.Lobby;
import com.shephertz.appwarp.messages.MatchedRooms;
import com.shephertz.appwarp.messages.Move;
import com.shephertz.appwarp.messages.Room;
import com.shephertz.appwarp.types.ResultCode;
import flash.utils.ByteArray;
var APIKEY:String = "key";
var SECRETEKEY:String = "secretkey";
var Connected:Boolean = false;
var INITIALIZED:Boolean = false;
var client:WarpClient;
var roomID:String;
var State:int = 0;
var User:String;
class connectionListener implements ConnectionRequestListener
{
private var connectFunc:Function;
public function connectionListener(f:Function)
{
connectFunc = f;
}
public function onConnectDone(res:int):void
{
if(res == ResultCode.success)
{
Connected = true;
}
else
{
Connected = false;
}
connectFunc(res);
}
public function onDisConnectDone(res:int):void
{
Connected = false;
}
}
class roomListener implements RoomRequestListener
{
private var connectFunc:Function;
private var joinFunc:Function;
public function roomListener(f:Function,f1:Function)
{
connectFunc = f;
joinFunc = f1;
}
public function onSubscribeRoomDone(event:Room):void
{
if(State == 2)
joinFunc();
else
connectFunc();
}
public function onUnsubscribeRoomDone(event:Room):void
{
}
public function onJoinRoomDone(event:Room):void
{
if(event.result == ResultCode.resource_not_found)
{
if(State == 1)
{
State = 3;
}
client.createRoom("room","admin",2,null);
}
else if(event.result == ResultCode.success)
{
if(State == 1)
{
State = 2;
}
roomID = event.roomId;
client.subscribeRoom(roomID);
}
}
public function onLeaveRoomDone(event:Room):void
{
client.unsubscribeRoom(roomID);
}
public function onGetLiveRoomInfoDone(event:LiveRoom):void
{
}
public function onSetCustomRoomDataDone(event:LiveRoom):void
{
}
public function onUpdatePropertyDone(event:LiveRoom):void
{
}
public function onLockPropertiesDone(result:int):void
{
}
public function onUnlockPropertiesDone(result:int):void
{
}
public function onUpdatePropertiesDone(event:LiveRoom):void
{
}
}
class zoneListener implements ZoneRequestListener
{
public function onCreateRoomDone(event:Room):void
{
roomID = event.roomId;
client.joinRoom(roomID);
}
public function onDeleteRoomDone(event:Room):void
{
}
public function onGetLiveUserInfoDone(event:LiveUser):void
{
}
public function onGetAllRoomsDone(event:LiveResult):void
{
}
public function onGetOnlineUsersDone(event:LiveResult):void
{
}
public function onSetCustomUserInfoDone(event:LiveUser):void
{
}
public function onGetMatchedRoomsDone(event:MatchedRooms):void
{
}
}
class notifylistener implements NotificationListener
{
private var joinFunc:Function;
private var msgFunc:Function;
private var leaveFunc:Function;
public function notifylistener(f:Function)
{
joinFunc = f;
}
public function msgListener(f:Function,f1:Function):void
{
msgFunc = f;
leaveFunc = f1;
}
public function onRoomCreated(event:Room):void
{
}
public function onRoomDestroyed(event:Room):void
{
}
public function onUserLeftRoom(event:Room, user:String):void
{
if(user != User)
{
leaveFunc();
}
}
public function onUserJoinedRoom(event:Room, user:String):void
{
if(State == 3)
joinFunc();
}
public function onUserLeftLobby(event:Lobby, user:String):void
{
}
public function onUserJoinedLobby(event:Lobby, user:String):void
{
}
public function onChatReceived(event:Chat):void
{
if(event.sender != User)
{
var obj:Object = com.adobe.serialization.json.JSON.decode(event.chat);
msgFunc(obj);
}
}
public function onUpdatePeersReceived(update:ByteArray):void
{
}
public function onUserChangeRoomProperty(room:Room, user:String,properties:Object):void
{
}
public function onPrivateChatReceived(sender:String, chat:String):void
{
}
public function onUserChangeRoomProperties(room:Room, user:String,properties:Object, lockTable:Object):void
{
}
public function onMoveCompleted(move:Move):void
{
}
}
package
{
import com.adobe.serialization.json.JSON;
import com.shephertz.appwarp.WarpClient;
public class AppWarp
{
public static var _roomlistener:roomListener;
public static var _zonelistener:zoneListener;
public static var _notifylistener:notifylistener;
public static var _connectionlistener:connectionListener;
private static function generateRandomString(strlen:Number):String{
var chars:String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var num_chars:Number = chars.length - 1;
var randomChar:String = "";
for (var i:Number = 0; i < strlen; i++){
randomChar += chars.charAt(Math.floor(Math.random() * num_chars));
}
return randomChar;
}
public static function connect(f:Function):void
{
if(INITIALIZED == false)
{
WarpClient.initialize(APIKEY, SECRETEKEY);
client = WarpClient.getInstance();
INITIALIZED = true;
}
if(Connected == false)
{
_connectionlistener = new connectionListener(f);
client.setConnectionRequestListener(_connectionlistener);
User = generateRandomString(16);
client.connect(User);
}
else
f(0);
}
public static function join(f1:Function, f2:Function):void
{
_roomlistener = new roomListener(f1,f2);
_zonelistener = new zoneListener();
_notifylistener = new notifylistener(f2);
client.setRoomRequestListener(_roomlistener);
client.setZoneRequestListener(_zonelistener);
client.setNotificationListener(_notifylistener);
State = 1;
client.joinRoomInRange(1,1,true);
}
public static function leave():void
{
client.leaveRoom(roomID);
}
public static function begin(f:Function, f1:Function, dir:int, x:int, y:int):void
{
_notifylistener.msgListener(f, f1);
send(0,dir,x,y);
}
public static function move(dir:int,x:int,y:int):void
{
send(1,dir,x,y);
}
public static function eat(dir:int,x:int,y:int):void
{
send(2,dir,x,y);
}
public static function send(type:int,dir:int,x:int,y:int):void
{
if(Connected == true)
{
var obj:Object = new Object();
obj.type = type;
obj.dir = dir;
obj.x = x;
obj.y = y;
client.sendChat(com.adobe.serialization.json.JSON.encode(obj));
}
}
}
}
I needed to place the package keyword at the very beginning of the .as file, otherwise an error is thrown.
You can only define one class in a package in a file. You can define other classes outside the package, but I don't think that is a good idea as I have observed that in some versions of compiler you have to place it at the beginning and in some at the end. Sometimes, it won't work in anyway.
A better way is to define different classes for each listener in different files. You can use the same package name.
I would recommend creating a single class to listen to all listeners by implementing all base listener classes.
For e.g.
//listener.as
package
{
public class Listener implements ConnectionRequestListener, RoomRequestListener, NotificationListener
{
}
}

How to dispach a custom event inside httpservice result event

In my AIR application, I try to dispatch a custom event from a class to main window.
This class is use to call httpservice. My goal is to send a custom window when the httpservice result is send.
package fr.inter.DataProvider
{
import flash.events.Event;
import flash.events.EventDispatcher;
import fr.inter.config.urlManager;
import fr.kapit.introspection.components.DisplayListComponent;
import mx.collections.XMLListCollection;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.HTTPService;
[Event(name="evtPatSelect", type="flash.events.Event")]
public class sPatient
{
private var _phppaIndex:String;
private var _phppaNomU:String;
private var _phppaPrenom:String;
private var phpSearchPatNom:HTTPService;
public function sPatient()
{
}
public function sPhpSearchPat(p:Object):void
{
phpSearchPatNom = new HTTPService();
phpSearchPatNom.method="POST";
phpSearchPatNom.resultFormat = "e4x";
phpSearchPatNom.addEventListener(ResultEvent.RESULT,resultListePatient);
phpSearchPatNom.addEventListener(FaultEvent.FAULT,serviceFault);
var urlPhp:urlManager=new urlManager();
phpSearchPatNom.url = urlPhp.urlService() + "20SearchNom.php";
phpSearchPatNom.send(p);
}
private function resultListePatient( event:ResultEvent ):void
{
var xmlList:XMLList = XML(event.result).patientPHP;
var xmlListColl = new XMLListCollection(xmlList);
if(xmlListColl.length==1)
{
_phppaIndex = xmlListColl.getItemAt(0).paIndex;
_phppaNomU = xmlListColl.getItemAt(0).paNomU;
_phppaPrenom = xmlListColl.getItemAt(0).paPrenom;
var evtPat:Event = new Event("evtPatSelect");
var evdips:EventDispatcher = new EventDispatcher();
evdips.dispatchEvent(evtPat);
}
}
private function serviceFault( event:FaultEvent )
{
trace( event.fault.message );
}
public function get phppaIndex():String
{
return _phppaIndex;
}
public function set phppaIndex(value:String):void
{
_phppaIndex = value;
}
public function get phppaNomU():String
{
return _phppaNomU;
}
public function set phppaNomU(value:String):void
{
_phppaNomU = value;
}
public function get phppaPrenom():String
{
return _phppaPrenom;
}
public function set phppaPrenom(value:String):void
{
_phppaPrenom = value;
}
}
}
In main window I've added a eventlistener but this seems not works.
Can you help me to solve that?
Thanks
First, extend the sPatient class as an EventDispatcher
public class sPatient extends EventDispatcher {
Then, create a class for your custom Event
public class MyCustomEvent extends Event {
public static const CUSTOM_TITLE:String = "custom_title";
public var eventData:Object;
public function CustomEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false, data:Object = null) {
super(type, bubbles, cancelable);
if(data != null) eventData = data;
}
public override function clone():Event {
return new CustomEvent(type, bubbles, cancelable);
}
public override function toString():String {
return formatToString("CustomEvent", "type", "bubbles", "cancelable", "eventPhase");
}
}
Then in your sPatient class, go:
this.dispatchEvent(new MyCustomEvent(MyCustomEvent.CUSTOM_TITLE));
And listen for it like so
sPatientInstance.addEventListener(MyCustomEvent.CUSTOM_TITLE,functionHandler);

Castle and generics

Considering this code :
interface IRepository<T>
{
void Save();
}
class Repository<T>
{
public virtual void Save() // something
{ }
}
interface IOtherRepository : IRepository<OtherClass>
{
void Other();
}
class OtherRepository : Repository<OtherClass>, IOtherRepository
{
public override void Save() // something different
{ }
public override void Other(){ }
}
How is it possible to configure Castle Windsor to give me an instance of OtherRepository when I call container.Resolve<IRepository<OtherClass>> ?
If Castle Windsor can't do this, which ioc containers can ?
var container = new WindsorContainer();
container.Register(Component.For(typeof(IRepository<>))
.ImplementedBy(typeof(Repository<>));
container.Register(Component.For<IRepository<OtherClass>, IOtherRepository>()
.ImplementedBy<OtherRepository>());
var repo = container.Resolve<IRepository<Something>>();
Assert.IsInstanceOfType(typeof(Repository<Something>), repo);
var specificRepo = container.Resolve<IRepository<OtherClass>>();
Assert.IsInstanceOfType(typeof(OtherRepository), specificRepo);
var otherRepo = container.Resolve<IOtherRepository>();
Assert.AreSame(otherRepo, specificRepo);