我使用castle通过构造函数注入来解决依赖关系。 我的问题是服务的构造函数可能使用第三方插件代码。 如果此插件代码抛出异常,它将包含在已知异常中,例如“KnownException”。
我有一个特殊的异常策略来记录和处理“KnownException”。 问题是,如果Castle Windsorcontainer解决方案遇到异常,它将被包装在'Castle.MicroKernel.ComponentActivator.ComponentActivatorException'中。
有没有办法避免这种情况,只是让'KnownException'传播?
一个简单的场景:
public class KnownException : Exception
{
}
// registerd in castle
public class DetailViewModel
{
public DetailViewModel(Selector thirdPartySelector)
{
thirdPartySelector.GetElements(); // might throw known exception
}
}
// registered as TypedFactory in Castle
public interface IViewModelFactory
{
DetailViewModel Create(Selector thirdPartySelector);
}
public class MasterViewModel
{
private readonly IViewModelFactory viewModelFactory;
private readonly Selector selector;
public MasterViewModel(IViewModelFactory viewModelFactory)
{
this.viewModelFactory = viewModelFactory;
selector = Mock.Of<Selector>(); // for illustration purpose only. Creation is more elaborate, and not relly a problem here.
}
public void OnAddDetailed()
{
try
{
var vm = viewModelFactory.Create(selector);
// adding detailed view model.
}
catch (KnownException e)
{
// Log and continue
}
}
}
}
答案 0 :(得分:0)
显然,当Castle尝试解析组件时,ComponentActivatorException
会在抛出之前包装初始异常。没有办法绕过这种行为。
您最好的选择是抓住ComponentActivatorException
并抛出InnerException
以便再次找到已知的错误处理类型
答案 1 :(得分:0)
为避免城堡使用组件激活器,您可以使用UsingFactoryMethod
注册组件,即:
Component.For<IFoo>().UsingFactoryMethod(k => new Foo())
有一些缺点:
如果Foo
具有依赖关系,则需要自己从容器中解析这些依赖关系,并且拦截器将无法工作。如果需要,OnDestroy
可以帮助释放依赖项。
答案 2 :(得分:0)
我通过装饰工厂解决了这个问题,捕获了ComponentActivatorException并抛出了InnerException。 但我想知道,如果这应该由集装箱解决,就像我使用工厂一样,我不应该知道外面有一个集装箱。但是如果create方法抛出CastleWindsor异常,则情况并非如此。
我的解决方案:
[TestMethod]
public void CastleWindsor_FactoryThrows_MyException()
{
WindsorContainer Container = new WindsorContainer();
Container.AddFacility<TypedFactoryFacility>();
Container.Register(Component.For<IMyFactory>().ImplementedBy<MyFactoryDecorator>());
Container.Register(Component.For<IMyFactory>().AsFactory());
Container.Register(Component.For<MyClass>().LifestyleTransient());
var factory = Container.Resolve<IMyFactory>();
try
{
factory.Create();
}
catch (Exception e)
{
Assert.AreEqual(e.GetType(), typeof(MyException));
}
}
public class MyFactoryDecorator : IMyFactory
{
IMyFactory factory;
public MyFactoryDecorator(IMyFactory aFactory)
{
factory = aFactory;
}
MyClass IMyFactory.Create() => handleComponentActivatorException(() => factory.Create());
T handleComponentActivatorException<T>(Func<T> action)
{
try
{
return action();
}
catch (ComponentActivatorException e)
{
throw e.InnerException.InnerException;
}
}
}
public interface IMyFactory
{
MyClass Create();
}
public class MyException : Exception { }
public class MyClass
{
public MyClass()
{
throw new MyException();
}
}