How to load to container MassTransit EndPoint in AbstractFacility - castle-windsor

I have a PersistenceFacility class .
This class inhereted "AbstractFacility" as "Castle.MicroKernel.Facilities".
I wonder load and install into container: IWindsorContainer.
public class PersistenceFacility: AbstractFacility
{
protected override void Init()
{
ServiceIoC.Container.Register(Component.For<IBusControl>().LifeStyle.Singleton.UsingFactoryMethod(k =>
{
var busControl = Bus.Factory.CreateUsingRabbitMq(config =>
{
config.Host(new Uri("blabla"), host =>
{
host.Username("guest");
host.Password("guest");
});
config.ReceiveEndpoint("", endpoint =>
{
endpoint.EnableMessageScope();
// Above method works but it is deprecated, instead below method should be used to get Consumer from container.
//endPoint.Consumer<YourConsumer>(container.Kernel);
});
});
return busControl;
}).LifeStyle.Singleton.Named("XXXMassTransitRMQ"));
}
// installer class
public class PersistenceInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container?.AddFacility<PersistenceFacility>();
}
}
//UOW Class
public class UnitOfWork
{
internal static IBusControl MassTransitRmqControl => ServiceIoC.Container?.Resolve<IBusControl>("XXXMassTransitRMQ");
}

First, I would consider moving to use the new container support for Windsor, as outlined in the documentation.
You can see how MassTransit registers components with Windsor by looking at the configuration.
I'm not sure an abstract facility is the way to go, given the approach taken by the links referenced above.

Related

AspNetCore RazorEngine will not use FileProviders configured in derived IOptions<RazorViewEngineOptions>

Use Case
A separated template engine that doesn't interfere in any way with normal Razor operation in an AspNetCore (2.X) web app.
Problem
Whilst trying to implement the above, I've created a whole bunch of derived wrapper classes based on RazorViewEngine, RazorViewCompilerProvider, DefaultRazorPageFactoryProvider, DefaultRazorViewEngineFileProviderAccessor and RazorViewEngineOptions in an effort that these can be registered with DI and injected whilst not having side affects in the normal Razor code path. I've succeeded except for one annoying issue, whereby I still need to configure my custom FileProvider (TemplateRepository) within the normal RazorViewEngineOptions rather than my wrapper class.
e.g. In the below code from Startup.cs, even though the file provider is specified in my custom Options object, and that is what is injected into the wrapper classes, the TemplateRepository is not called for a View request unless the second service.Configure is also included (using RazorViewEngineOptions).
services.Configure<TemplateOptions>(options =>
{
options.ViewLocationExpanders.Add(new TemplateNameExpander());
options.ViewLocationFormats.Add("{0}");
options.AreaViewLocationFormats.Add("{0}");
options.FileProviders.Clear();
options.FileProviders.Add(new TemplateRepository(new SqlConnectionFactory(configuration)));
});
services.Configure<RazorViewEngineOptions>(
options =>
{
options.FileProviders.Add(new TemplateRepository(new SqlConnectionFactory(configuration)));
});
This would suggest to me that somewhere in the RazorViewEngine dependency tree the RazorViewEngineOptions is being injected somewhere, but I cannot find it.
Full Source # GitHub
It seems that you have defined your custom RazorViewEngine but you do not tell MVC to use it.
Try to add below codes to add TemplateRazorEngine to MVC view engine.
services.Configure<TemplateOptions>(options =>
{
options.ViewLocationExpanders.Add(new TemplateNameExpander());
options.ViewLocationFormats.Add("{0}");
options.AreaViewLocationFormats.Add("{0}");
options.FileProviders.Clear();
options.FileProviders.Add(new TemplateRepository(new SqlConnectionFactory(configuration)));
});
services.Configure<MvcViewOptions>(options => {
var engine = services.BuildServiceProvider().GetRequiredService<TemplateRazorEngine>();
options.ViewEngines.Add(engine);
});
Late to the party but maybe you will use this in the future. I've also tried a lot of options and in the end I came to the conclusion that child containers would solve my particular issue. Unfortunately the AspNetCore container doesn't support them so I had to implement something quick that might not work in your case. Another option would be to use StructureMap or any other container that supports this functionality.
public class ChildServiceProvider : IServiceProvider, IDisposable
{
private readonly IServiceProvider _child;
private readonly IServiceProvider _parent;
public ChildServiceProvider(IServiceProvider parent, IServiceProvider child)
{
_parent = parent;
_child = child;
}
public ChildServiceProvider(IServiceProvider parent, IServiceCollection services)
{
_parent = parent;
_child = services.BuildServiceProvider();
}
public void Dispose()
{
(_child as IDisposable)?.Dispose();
}
public object GetService(Type serviceType)
{
return _child.GetService(serviceType) ?? _parent.GetService(serviceType);
}
}
And this is how I used it
public class Startup : IStartup
{
public IServiceProvider ChildServiceProvider { get; set; }
IServiceProvider IStartup.ConfigureServices(IServiceCollection services)
{
// Define a wrapper for the RazorViewEngine and it as a singleton
services.AddSingleton<CustomRazorEngine>(serviceProvider =>
{
// get the RazorViewEngine from the childContainer
var razorViewEngine = ChildServiceProvider.GetRequiredService<IRazorViewEngine>();
return new CustomRazorEngine(razorViewEngine);
});
return services.BuildServiceProvider();
}
public void Configure(IApplicationBuilder app)
{
ChildServiceProvider = CreateChildServiceProvider(app);
app.UseMvc();
}
IServiceProvider CreateChildServiceProvider(IApplicationBuilder parentApp)
{
// create the child container from the parentApp and register
// the custom RazorViewEngineOptions that you need for the isolated templating engine
// and whatever custom services that you need
var server = parentApp.ApplicationServices.GetRequiredService<IServer>();
var webHost = WebHost.CreateDefaultBuilder()
.ConfigureServices(services =>
{
services.AddOptions();
services.Configure<RazorViewEngineOptions>(opts =>
{
opts.FileProviders.Clear();
opts.FileProviders.Add(new CustomFileProvider());
});
services.AddMvc();
})
.Build();
return new ChildServiceProvider(parentApp.ApplicationServices, webHost.Services);
}
}
And the custom classes that you would need to implement
public class CustomFileProvider : IFileProvider
{
}
public class CustomRazorEngine
{
private readonly IRazorViewEngine _razorViewEngine;
public CustomRazorEngine(IRazorViewEngine razorViewEngine)
{
_razorViewEngine = razorViewEngine;
}
}
This was tested with dotnet 2.2 but haven't thoroughly tested it to be 100% that there are no performance issues or other hidden ones.
Also would be curious to know if you found another solution :)

Castle Windsor: get informed by the container after any object was resolved

I'm using Castle Windsor as DI Container and have following question:
Is it possible to get informed by the container each time, any object was created by the container and get a reference to this object?
I want to check after each resolve, if the resolved object implements a special interface (e.g. IEmergencyStop). I want to register this object at a special service (EmergencyStopHelper).
Following an example:
interface IEmergencyStop
{
void Stop();
}
interface IMotor : IEmergencyStop
{
void Run();
}
class Motor : IMotor
{
}
class EmergencyStopHelper
{
List<IEmergencyStop> emergencyStopList = new List<IEmergencyStop>();
public void Register(IEmergencyStop aClass)
{
emergencyStopList.Add(aClass);
}
public void StopAll() => emergencyStopList.ForEach( x => x.Stop());
}
container.Register(Component.For<IMotor>().ImplementedBy<Motor>().LifestlyleTransient());
container.Register(Component.For<EmergencyStopHelper>());
// TODO: any magic code which calls EmergencyStopHelper.Register(...)
// after following resolve
IMotor aMotor = container.Resolve<IMotor>();
var emergencyStop = container.Resolve<EmergencyStopHelper>();
emergencyStop.StopAll();

Using MvvmCross from content providers and activities

I am trying to use MvvmCross v3 in one of my applications which consists of activities, content providers and broadcast receivers. However, I am not quite succeeding.
The application consists of a Core PCL which contains logic, models and viewmodels and a Droid application which contains all MonoDroid-specific stuff.
In Core I have an App:MvxApplication class and in Droid I have a Setup:MvxSetup class which creates an App-instance and initialises stuff.
I can use the IOC parts with content providers, broadcast receivers and non-Mvx-activities without problems. When I now want to add an MvxActivity it falls apart.
When the Mvx Activity launches I get an exception "Cirrious.CrossCore.Exceptions.MvxException: MvxTrace already initialized".
Obviously I am initialising things in the wrong order / wrong place. But, I need a pointer in the right direction.
My App Class
public class App
: MvxApplication
{
public override void Initialize()
{
base.Initialize();
InitialisePlugins();
InitaliseServices();
InitialiseStartNavigation();
}
private void InitaliseServices()
{
CreatableTypes().EndingWith("Service").AsInterfaces().RegisterAsLazySingleton();
}
private void InitialiseStartNavigation()
{
}
private void InitialisePlugins()
{
// initialise any plugins where are required at app startup
// e.g. Cirrious.MvvmCross.Plugins.Visibility.PluginLoader.Instance.EnsureLoaded();
}
}
And my setup class
public class Setup
: MvxAndroidSetup
{
public Setup(Context applicationContext)
: base(applicationContext)
{
}
protected override IMvxApplication CreateApp()
{
return new App();
}
protected override IMvxNavigationSerializer CreateNavigationSerializer()
{
return new MvxJsonNavigationSerializer();
}
public override void LoadPlugins(Cirrious.CrossCore.Plugins.IMvxPluginManager pluginManager)
{
pluginManager.EnsurePluginLoaded<Cirrious.MvvmCross.Plugins.Json.PluginLoader>();
base.LoadPlugins(pluginManager);
}
public void RegisterServices()
{
// I register a bunch of singletons here
}
// The following is called from my content provider's OnCreate()
// Which is the first code that is run
public static void DoSetup(Context applicationContext)
{
var setup = new Setup(applicationContext);
setup.Initialize();
setup.RegisterServices();
}
My Content provider's OnCreate():
public override bool OnCreate()
{
Log.Debug(Tag, "OnCreate");
_context = Context;
Setup.DoSetup(_context);
return true;
}
My MvxActivity:
[Activity(Label = "#string/ApplicationName", MainLauncher = true)]
[IntentFilter(new[] { "Settings" })]
public class SettingsView
: MvxActivity
{
public new SettingsViewModel ViewModel
{
get { return (SettingsViewModel) base.ViewModel; }
set { base.ViewModel = value; }
}
protected override void OnViewModelSet()
{
SetContentView(Resource.Layout.Page_SettingsView);
}
}
Short answer (I'm in an airport on mobile)
all the mvx android views will check the setup singleton has been created - https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross.Droid/Platform/MvxAndroidSetupSingleton.cs (vnext tree - but similar on v3)
so if you are creating a setup, but not setting this singleton, then you will get a second setup created when you first show a view
i suspect you can just get your setup created via the singleton class, but if this isn't flexible enough for your needs, then please log an issue on github
would also love to see some blogging about this - I've not used custom content providers much (at all!)

Castle Windsor does not resolve AutoMapper profiles after update

Everything was working fine until I updated with NuGet the references for CastleWinsor and AutoMapper to their latest versions: Castle.Windsor.3.0.0.4001 and AutoMapper.2.0.0.
I have a list of AutoMapper profiles in the same assembly as the AutoMapperInstaller : IWindsorInstaller. They are in diferent namespaces, but this should not matter, right?
Here is a profile example:
namespace FieldService.Web.Mappings
{
public class RoleMappings : Profile
{
protected override void Configure()
{
AutoMapper.Mapper.CreateMap<RoleModel, Role>()
.ConstructUsing((role) => new Role() { Permissions = new List<Permission>() })
.ForMember(m => m.Permissions, o => o.MapFrom(src => src.Permissions.Where(p => p.Selected == true)));
}
}
}
Here is the AutoMapperInstaller
namespace FieldService.Web.Infrastructure.IOC
{
public class AutoMapperInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
Mapper.Initialize(x => x.ConstructServicesUsing(container.Resolve));
RegisterProfilesAndResolvers(container);
RegisterMapperEngine(container);
}
private void RegisterMapperEngine(IWindsorContainer container)
{
container.Register(
Component.For<IMappingEngine>().Instance(Mapper.Engine)
);
}
private void RegisterProfilesAndResolvers(IWindsorContainer container)
{
// register value resolvers
container.Register(AllTypes.FromAssembly(Assembly.GetExecutingAssembly()).BasedOn<IValueResolver>());
// register profiles
container.Register(AllTypes.FromThisAssembly().BasedOn<Profile>());
var profiles = container.ResolveAll<Profile>();
foreach (var profile in profiles)
Mapper.AddProfile(profile);
}
}
}
In Global.asax I have the method BootstrapContainer which I call from Application_Start method:
private static readonly IWindsorContainer container = new WindsorContainer();
public IWindsorContainer Container
{
get { return container; }
}
private static void BootstrapContainer()
{
container.Install(FromAssembly.This());
}
The exception I get is: Trying to map xxx to yyyModel. Missing type map configuration or unsupported mapping. Exception of type 'AutoMapper.AutoMapperMappingException' was thrown.
I debugged the installer and I think this line Container.Register(AllTypes.FromThisAssembly().BasedOn<Profile>()); is not working anymore.
If I try to resolve the profiles (next line) it returns 0 profiles.
I am not an expert with these two tools, and I am not sure this is the best method to initialize AutoMapper with Windsor but it worked until now.
Any idea why this is not working anymore?
This is a known and documented breaking change in Windsor (see breakingchanges.txt for details).
In short, if you're resolving your profiles as Profile you need to register them as Profile.
Container.Register(AllTypes.FromThisAssembly().BasedOn<Profile>().WithServiceBase());
For me this code worked :
public class AutoMapperInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
// Register all mapper profiles
container.Register(
Classes.FromAssemblyInThisApplication(GetType().Assembly)
.BasedOn<Profile>().WithServiceBase());
// Register IConfigurationProvider with all registered profiles
container.Register(Component.For<IConfigurationProvider>().UsingFactoryMethod(kernel =>
{
return new MapperConfiguration(configuration =>
{
kernel.ResolveAll<Profile>().ToList().ForEach(configuration.AddProfile);
});
}).LifestyleSingleton());
// Register IMapper with registered IConfigurationProvider
container.Register(
Component.For<IMapper>().UsingFactoryMethod(kernel =>
new Mapper(kernel.Resolve<IConfigurationProvider>(), kernel.Resolve)));
}
}

Have Castle Windsor select component based on requestor type namespace

I have an interface ISession whose instance is produced by a different Session Factory depending on which namespace the class belongs to.
Example of my component registration:
IWindsorContainer container = new WindsorContainer();
container.Register(Component.For<NHibernate.ISession>()
.UsingFactoryMethod((kernel, creationContext) =>
{
NHibernate.ISession session =
new SessionFactoryForNamespace1()
.Instance.GetSession();
return session;
})
.LifestylePerWebRequest());
container.Register(Component.For<NHibernate.ISession>()
.UsingFactoryMethod((kernel, creationContext) =>
{
NHibernate.ISession session =
new SessionFactoryForNamespace2()
.Instance.GetSession();
return session;
})
.LifestylePerWebRequest());
container.Register(Component.For<Namespace1.IRepository1()
.ImplementedBy<Namespace1.Repository1>());
container.Register(Component.For<Namespace2.IRepository2>()
.ImplementedBy<Namespace2.Repository2>());
Example of the resolution graph:
public class MyController
{
public MyController(Namespace1.IRepository1 repo1,
Namespace2.IRepository2 repo2) { }
}
namespace Namespace1
{
public interface IRepository1 { }
public class Repository1 : IRepository1
{
public Repository1(NHibernate.ISession session) { }
}
}
namespace Namespace2
{
public interface IRepository2 { }
public class Repository2 : IRepository2
{
public Repository2(NHibernate.ISession session) { }
}
}
When Castle Windsor is asked to resolve MyController, it then tries to resolve IRepository1 and IRepository2, and subsequently the ISession for each. I want to have Castle Windsor select the component handlers based on the requestor type's namespace which in my example is either Namespace1 or Namespace2.
I am new to Castle Windsor and not sure where in the resolution pipeline I'm supposed to be plugging into.
What is the best approach to accomplish what I have outlined above?
I think a service override would work for this.
UPDATE:
I also did an article on some of Windsor's advanced features (including a section on Service Overrides) that should augment the documentation linked above.
Here is how I implemented service override solution:
Repository interfaces now inherit from a common repository interface:
public class MyController
{
public MyController(Namespace1.IRepository1 repo1,
Namespace2.IRepository2 repo2) { }
}
public interface IRepository { }
namespace Namespace1
{
public interface IRepository1 : IRepository { }
public class Repository1 : IRepository1
{
public Repository1(NHibernate.ISession session) { }
}
}
namespace Namespace2
{
public interface IRepository2 : IRepository { }
public class Repository2 : IRepository2
{
public Repository2(NHibernate.ISession session) { }
}
}
Repository component registeration based on its namespace:
IWindsorContainer container = new WindsorContainer();
...
Action<Type> RegisterRepository = t =>
{
container.Register(
AllTypes.FromAssemblyContaining(t)
.BasedOn(typeof(IRepository))
.WithServiceAllInterfaces()
.Configure(c =>
{
c.DependsOn(
ServiceOverride
.ForKey<NHibernate.ISession>()
.Eq(c.Implementation.Namespace));
c.LifeStyle.Is(LifestyleType.Transient);
})
);
};
RegisterRepository(typeof(Namespace1.IRepository1));
RegisterRepository(typeof(Namespace2.IRepository2));
Seems to work :)