Getting an instance of BusHealth using unity container - c#

How to get an instance of bushealth using Unity container IoC in Prism or without using a IoC container? Mass Transit relies on Microsoft Dependency Injection, however I am using Bus Factory to create an instance of the bus and its always not feasbile to use DI for legacy code.
_busControl = Bus.Factory.CreateUsingRabbitMq(sbc =>
{
sbc.Host(host, h =>
{
h.Username(username);
h.Password(password);
h.RequestedConnectionTimeout(timeout);
});
sbc.ReceiveEndpoint(e =>
{
...
});

You can either create an instance of BusHealth passing the bus instance on the constructor or you can register IBusHealth as a service in your container, with the BusHealth implementation type (which will require IBus to also be registered, as it is a required constructor dependency).
Then you can use the IBusHealth interface in your application to check bus health.
var busHealth = new BusHealth("bus");
_busControl = Bus.Factory.CreateUsingRabbitMq(sbc =>
{
sbc.ConnectBusObserver(busHealth);
sbc.ConnectEndpointConfigurationObserver(busHealth);
sbc.Host(host, h =>
{
h.Username(username);
h.Password(password);
h.RequestedConnectionTimeout(timeout);
});
sbc.ReceiveEndpoint(e =>
{
// ...
});
});
Of course, this doesn't explain how the bus/health objects get into your container, but I think you get the idea.

Related

SimpleInjector Lazy in a Reflection

We are using SimpleInjector as a Dependency Injector, and we are registering all interface types using assembly iteration.
public static void RegisterInterfaceTypes(this Container container, Assembly assembly)
{
assembly.GetExportedTypes()
.Select(t => new {
Type = t,
Interface = t.GetInterfaces().FirstOrDefault()
})
.ToList()
.ForEach(t =>
{
container.Register(t.Interface, t.Type, Lifestyle.Transient);
});
}
We also have lazy classes to register. We can register these classes like below one by one. But we want to register all lazy types with similar iteration using reflection.
container.Register(() => new Lazy<ICommonBusiness>(container.GetInstance<CommonBusiness>));
You can make use of the ResolveUnregisteredType extension method to make last-minute registrations for resolve Lazy<T> dependencies:
Source:
public static void AllowResolvingLazyFactories(this Container container)
{
container.ResolveUnregisteredType += (sender, e) =>
{
if (e.UnregisteredServiceType.IsGenericType &&
e.UnregisteredServiceType.GetGenericTypeDefinition() == typeof(Lazy<>))
{
Type serviceType = e.UnregisteredServiceType.GetGenericArguments()[0];
InstanceProducer registration = container.GetRegistration(serviceType, true);
Type funcType = typeof(Func<>).MakeGenericType(serviceType);
Type lazyType = typeof(Lazy<>).MakeGenericType(serviceType);
var factoryDelegate = Expression.Lambda(funcType, registration.BuildExpression()).Compile();
var lazyConstructor = (
from ctor in lazyType.GetConstructors()
where ctor.GetParameters().Length == 1
where ctor.GetParameters()[0].ParameterType == funcType
select ctor)
.Single();
var expression = Expression.New(lazyConstructor, Expression.Constant(factoryDelegate));
var lazyRegistration = registration.Lifestyle.CreateRegistration(
serviceType: lazyType,
instanceCreator: Expression.Lambda<Func<object>>(expression).Compile(),
container: container);
e.Register(lazyRegistration);
}
};
}
Usage:
container.AllowResolvingLazyFactories();
But please note the warnings from the documentation:
Warning: Registering [Lazy<T>] by default is a design smell. The use of [Lazy<T>] makes your design harder to follow and your system harder to maintain and test. Your system should only have a few of those [...] at most. If you have many constructors in your system that depend on a [Lazy<T>], please take a good look at your dependency strategy. The following article goes into details about why [this is] a design smell.
Warning: [...] the constructors of your components should be simple, reliable and quick (as explained in this blog post by Mark Seemann). That would remove the need for lazy initialization. For more information about creating an application and container configuration that can be successfully verified, please read the How To Verify the container’s configuration.

Using two Simple Injector container instances with different lifestyles in c#

I have a web forms application in the Global.asax of which I am buiding the Simple Injector container like below. The reason I am doing two is because I am using Hangfire to schedule recurring jobs and it does not take the Scoped lifestyle which I currently have for the application since it runs as a background worked thread. I am getting the below error when I am creating two instances of the container for my EF entities.
The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects
Can someone please tell me how I can have two containers with different lifestyles registered in my web forms applictaion.
ContainerConfig.BuildContainer();
var container = ContainerConfig.BuildContainerJobs();
public static Container BuildContainer()
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new ExecutionContextScopeLifestyle();
container.Register<TraceTimer>(Lifestyle.Scoped);
container.Register<Entities>(() => new Entities(), Lifestyle.Scoped);
container.Register<ReferenceDataCache>(
() => ReferenceDataCacheFactory.Create(), Lifestyle.Scoped);
var adapter = new SimpleInjectorAdapter(container);
ServiceLocator.SetLocatorProvider(() => (IServiceLocator)adapter);
ExecutionContextScopeManager.Current = (IExecutionContextScopeManager)adapter;
return container;
}
public static Container BuildContainerJobs()
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new ExecutionContextScopeLifestyle();
container.Register<Entities>(() => new Entities(), Lifestyle.Transient);
container.Register<ReferenceDataCache>(
() => ReferenceDataCacheFactory.Create(), Lifestyle.Transient);
var adapter = new SimpleInjectorAdapter(container);
ServiceLocator.SetLocatorProvider(() => (IServiceLocator)adapter);
ExecutionContextScopeManager.Current = (IExecutionContextScopeManager)adapter;
return container;
}
Global.asax code for registering
ContainerConfig.BuildContainer();
var container = ContainerConfig.BuildContainerJobs();
var options = new SqlServerStorageOptions
{
QueuePollInterval = TimeSpan.FromMinutes(5) // Default value
};
GlobalConfiguration.Configuration
.UseSqlServerStorage("Jobs",options);
GlobalConfiguration.Configuration.UseDefaultActivator();
GlobalConfiguration.Configuration.UseActivator(new SimpleInjectorJobActivator(container));
GlobalJobFilters.Filters.Add(new SimpleInjectorAsyncScopeFilterAttribute(container));
JobsHelper.SetRecurringJob();
_backgroundJobServer = new BackgroundJobServer();
This exception is not thrown by Simple Injector but by Entity Framework. This exception is typically caused by using instances of entities that are created with one DbContext inside another DbContext.
Unfortunately I can't be more specific and pinpoint where you are going wrong and how to fix this, because your question does not contain the appropriate details.

Managing Lifetime Scopes with Autofac

Context: Owin (self-host) + WebApi + UseAutofacMiddleware + UseAutofacWebApi
What I'm trying to do is:
Register an ILog instance in the app startup container.
For each request, register a new ILog instance wrapping the "root" instance, so that each middleware and/or per-request services can use it.
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterInstance(log).As<ILog>();
containerBuilder.Register(ctx => {
var rootLog = ctx.Resolve<ILog>();
return new PrependStringLog(rootLog, "request: ");
}).InstancePerRequest();
However, Autofac complains about circular dependencies when instancing middleware having an ILog in their constructors.
If I name the "root log", and resolve with the given name, everything works as expected.
containerBuilder.RegisterInstance(log)
.Named("root", typeof(ILog));
containerBuilder.Register(ctx => {
var rootLog = ctx.ResolveNamed<ILog>("root");
return new PrependStringLog(rootLog, "request: ");
}).InstancePerRequest();
Am I forced to use a named instance to make it work?
Autofac uses the latest registered service when a component request for a service.
In your case, the latest ILog registered is a lambda expression :
containerBuilder.Register(ctx => {
var rootLog = ctx.Resolve<ILog>();
return new PrependStringLog(rootLog, "request: ");
}).InstancePerRequest();
This lambda expression request an ILog which is what Autofac is trying to build : that's why it detects a circular dependency.
The easiest way to avoid the circular dependency is to make your registration not rely on itself. This is what you do by resolving a named ILog and this is the solution I recommend.
In your case, you can also directly use the root log without resolving it :
containerBuilder.RegisterInstance(rootLog).As<ILog>();
containerBuilder.Register(ctx => {
return new PrependStringLog(rootLog, "request: ");
}).InstancePerRequest();

Access objects within a Consumer

I am working on a project that consumes messages using MassTransit and RabbitMQ in C#
I'm building a prototype and right now the consumer project is a console application. Within the Main program.cs class, I connect to the bus and subscribe to accept messages from the publisher like this:
var bus = BusInitializer.CreateBus("Subscriber", x =>
{
x.Subscribe(subs =>
{
subs.Consumer<UpdatedInformation>().Permanent();
});
});
For reference, here's the CreateBus() method:
public static IServiceBus CreateBus(string queueName, Action<ServiceBusConfigurator> moreInitialization)
{
var bus = ServiceBusFactory.New(x =>
{
x.UseRabbitMq();
x.ReceiveFrom("rabbitmq://localhost/test" + queueName);
moreInitialization(x);
});
return bus;
}
And here is an example of one of the consumer classes:
class UpdatedInformationConsumer : Consumes<UpdatedInformation>.Context
{
public void Consume(IConsumeContext<UpdatedInformation> message)
{
Console.Write("\nMessage: " + message.Message);
Console.Write("\nPROCESSED: " + DateTime.Now.ToString());
}
}
In the main class of the subscriber, I also initialize services and other configurations. What I need to do is be able to access those services/objects in my consumer classes as I don't want to initialize new ones every time a message is received in consumed.
This should be relatively easy, but I'm stumped since I'm not actually creating instances of my consumer classes.
Rather than put a bunch of singletons in your service, which leads to a bunch of static methods and so forth, you can specify a consumer factory with your subscription that passes those dependencies to your consumer. You can also use any of the supported containers (or even your own) to resolve those dependencies.
x.Subscribe<UpdatedInformationConsumer>(() =>
new UpdatedInformationConsumer(dependency1, dependency2, etc));
A new instance of the consumer will be created for each message receiving, so object lifecycles can also be managed in this way.

Microsoft Shims with a WCF Service

I am attempting to follow this example and leverage a shim to remove the external dependency on a WCF service call which is called from the method I am executing the unit test on. Unlike the example, I generate my WCF client on the fly using code similar to this:
ChannelFactory<IReportBroker> factory = new ChannelFactory<IReportBroker>("ReportBrokerBasicHttpStreamed", new EndpointAddress(this.CurrentSecurityZoneConfigurationManager.ConfigurationSettings[Constants.ConfigurationKeys.ReportBrokerServiceUrl]));
IReportBroker proxy = factory.CreateChannel();
proxy.Execute(requestMessage))
How do I adapt that example to shim the proxy returned back by the CreateChannel method? I am assuming that in the ShimWCFService class, I need to add something like....
ShimChannelFactory<TService>.AllInstances.CreateChannel = (var1) => { return [instance of a mock object]};
However, I am unsure of how to associate a mock object of <TService> with that shim as the return value.
You need to shim the factory for every type parameter. Assume you have the three Service contracts 'IService0' 'IService1' and 'IService2'.
Then you need to setup the shims like this:
ShimChannelFactory<IService0>.AllInstances.CreateChannel = (_) => { return new Service0Mock(); }
ShimChannelFactory<IService1>.AllInstances.CreateChannel = (_) => { return new Service1Mock(); }
ShimChannelFactory<IService2>.AllInstances.CreateChannel = (_) => { return new Service2Mock(); }

Categories

Resources