Unity to Structure Map - c#

I am trying out the code from this post on Event Driven Architecture (very interesting by the way). His IOC container is Unity though and I would like to do this using Structure map.
His code is:
public class EventSubscriptions : ISubscriptionService
{
public static void Add<T>()
{
var consumerType = typeof(T);
consumerType.GetInterfaces()
.Where(x => x.IsGenericType)
.Where(x => x.GetGenericTypeDefinition() == typeof(IConsumer<>))
.ToList()
.ForEach(x => IoC.Container.RegisterType(x,
consumerType,
consumerType.FullName));
}
public IEnumerable<IConsumer<T>> GetSubscriptions<T>()
{
var consumers = IoC.Container.ResolveAll(typeof(IConsumer<T>));
return consumers.Cast<IConsumer<T>>();
}
}
I have the following which does not seem to be working:
public class SubscriptionService : ISubscriptionService
{
public static void Add<T>()
{
var consumerType = typeof(T);
consumerType.GetInterfaces()
.Where(x => x.IsGenericType)
.Where(x => x.GetGenericTypeDefinition() == typeof (IConsumer<>))
.ToList().ForEach(x => ObjectFactory.Inject(consumerType, x));
}
public IEnumerable<IConsumer<T>> GetSubscriptions<T>()
{
var consumers = ObjectFactory.GetAllInstances(typeof(IConsumer<T>));
return consumers.Cast<IConsumer<T>>();
}
}
I am obviously not too familiar with Structure Map. Some links or explanation on what I am doing wrong would be really appreciated.
Update:
From Henning's answer, I ended up with -
public class SubscriptionService : ISubscriptionService
{
public IEnumerable<IConsumer<T>> GetSubscriptions<T>()
{
var consumers = ObjectFactory.GetAllInstances(typeof(IConsumer<T>));
return consumers.Cast<IConsumer<T>>();
}
}
And then in my bootstrapping class that is called on application startup I have:
public static void ConfigureStuctureMap()
{
ObjectFactory.Initialize(x =>
{
x.Scan(y =>
{
y.Assembly("Domain");
y.Assembly("Website");
y.AddAllTypesOf(typeof(IConsumer<>));
y.WithDefaultConventions();
});
});
}

Although I'm not a structuremap expert, I do believe you can do it in another way.
Structuremap has the ability to scan any given assembly for a given interface and automatically register all the implementations. We do that in my current project and it works really great.
I don't remember the exact code we use, but you can check out the documentation for assembly scanning
http://structuremap.sourceforge.net/ScanningAssemblies.htm

Build custom TypeScanner class that implement ITypeScanner interface.
public class EventSubConventionScanner : ITypeScanner
{
public void Process(Type type, PluginGraph graph)
{
Type interfaceType = type.FindInterfaceThatCloses(typeof(IConsumer<>));
if (interfaceType != null)
{
graph.AddType(interfaceType, type);
}
}
}
After, in registry or initialize routine write:
Scan(x =>
{
x.With<EventSubConventionScanner>();
});

Related

Autofac register all of type IFoo named IFoo.Name

Just learning Autofac and struggling to rgister a handful of named instances by convention.
public interface IFoo
{
string AutoFactName{ get; }
object DoSomething();
}
looking at this interface what i am trying to accomplish is something along these lines
builder.RegisterTypes()
.AssignableTo<IFoo>()
.As<IFoo>()
.Named<IFoo>(i => i.AutoFactName);
I have tried a few variations of something to this effect.
the end goal is to dynamically register and resolve instances.
You should not need instances to register your types in Autofac. If you need information from your type it is better to use meta information like Attribute. Something like that :
[FooMetadata("Foo1")]
public class Foo1 : IFoo
{ }
and then use this metadata while registering
builder.RegisterAssemblyTypes(assembly)
.AssignableTo<IFoo>()
.Named<IFoo>(t => t.GetCustomAttribute<FooMetadata>().Foo);
If you rely need to get the named type in your instance you can do it with a IRegistrationSource
public class NamedFooRegistrationSource : IRegistrationSource
{
public bool IsAdapterForIndividualComponents => false;
public IEnumerable<IComponentRegistration> RegistrationsFor(
Service service,
Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
{
KeyedService keyedService = service as KeyedService;
if (keyedService == null || keyedService.ServiceKey.GetType() != typeof(String))
{
yield break;
}
IComponentRegistration registration = RegistrationBuilder
.ForDelegate(keyedService.ServiceType, (c, p) =>
{
Type foosType = typeof(IEnumerable<>).MakeGenericType(keyedService.ServiceType);
IEnumerable<IFoo> foos = (IEnumerable<IFoo>)c.Resolve(foosType);
foos = foos.Where(f => f.AutoFactName == (String)keyedService.ServiceKey).ToArray();
if (foos.Count() == 0)
{
throw new Exception($"no Foo available for {keyedService.ServiceKey}");
}
else if (foos.Count() > 1)
{
throw new Exception($"more than 1 Foo available for {keyedService.ServiceKey}");
}
else
{
return foos.First();
}
})
.Named((String)keyedService.ServiceKey, keyedService.ServiceType)
.CreateRegistration();
yield return registration;
}
}
and then register your Foo this way :
builder.RegisterAssemblyTypes(assembly)
.AssignableTo<IFoo>()
.As<IFoo>();
builder.RegisterSource<NamedFooRegistrationSource>();

ReactiveUI, get a list from a viewmodel when navigated to - if the viewmodel implements interface

I'm using ReactiveUI and its Router.
Some of my IRoutableViewModels implements a interface IHaveCommands, which have a property IEnumerable<IReactiveCommand> Commands { get; }
So, what I want, is a list of commands for the current viewmodel in my IScreen implementation, the AppBootstrapper.
What would be 'the right' way of implementing this?
I have sort of got it to work with the following code, but my guts tells me that there are other, better ways of doing it....
public class AppBootstrapper : ReactiveObject, IScreen
{
public IRoutingState Router { get; private set; }
public AppBootstrapper(IMutableDependencyResolver dependencyResolver = null, IRoutingState testRouter = null)
{
Router = testRouter ?? new RoutingState();
Router.CurrentViewModel.Where(x => x != null)
.Select(x => typeof(IHaveCommands).IsAssignableFrom(x.GetType()) ? ((IHaveCommands)x).Commands : null)
.ToProperty(this, x => x.Commands, out _toolbarCommands);
...
}
readonly ObservableAsPropertyHelper<IEnumerable<CommandSpec>> _toolbarCommands;
public IEnumerable<CommandSpec> ToolbarCommands { get { return _toolbarCommands.Value; } }
}
Any tips?
This looks great to me! Other than some possible minor readability fixups, this is What You Should Do™. Here's a slightly cleaner version:
Router.CurrentViewModel
.Select(x => {
var haveCmds = x as IHaveCommands;
return haveCmds != null ? haveCmds.Commands : null;
})
.ToProperty(this, x => x.Commands, out _toolbarCommands);

How do I mock a Func<> using Machine.Fakes (Moq)?

I'm trying to test some code I've written have run in to issues trying to mock a func using Machine.Fakes (which uses Moq under the hood). See the code below for an example.
public class RoutingEngine : IRoutingEngine
{
private readonly IMessageRouters _messageRouters;
public RoutingEngine(IMessageRouters messageRouters)
{
_messageRouters = messageRouters;
}
public void Route<T>(T inbound)
{
var messageRouters = _messageRouters.Where(x => x.CanRoute(inbound));
foreach(var router in messageRouters)
router.Route(inbound);
}
}
public class MessageRouters : IMessageRouters
{
public IList<IMessageRouter> _routers = new List<IMessageRouter>();
public IEnumerable<IMessageRouter> Where(Func<IMessageRouter, bool> func)
{
return _routers.Where(func);
}
public void Add(IMessageRouter messageRouter)
{
_routers.Add(messageRouter);
}
}
And the test is here
public class when_routing_a_message_with_fakes : WithSubject<RoutingEngine>
{
Establish that = () =>
{
Message = new MyMessage{ SomeValue= 1, SomeOtherValue = 11010 };
Router = The<IMessageRouter>();
Router.WhenToldTo(x => x.CanRoute(Message)).Return(true);
The<IMessageRouters>().WhenToldTo(x => x.Where(router => router.CanRoute(Message))).Return(new List<IMessageRouter> { Router });
};
Because of = () => Subject.Route(Message);
It should_do_route_the_message = () => Subject.WasToldTo(x => x.Route(Param.IsAny<MyMessage>()));
static MyMessage Message;
static IMessageRouter Router;
}
I get an unsupported expression for the above so I changed the where method on the IMessageRouters to the following:
public IEnumerable<IMessageRouter> Where(Expression<Func<IMessageRouter, bool>> func)
{
return _routers.Where(func.Compile());
}
Now I get this error
Object instance was not created by Moq.
Parameter name: mocked
Any ideas?
EDIT
So I tried writing another test without machine.fakes, as per Mocking methods with Expression<Func<T,bool>> parameter using Moq. Turns out it's an obvious problem. The func used in the real RoutingEngine is not being mocked
The<IMessageRouters>()
.WhenToldTo(x => x.Where(router => router.CanRoute(Param.IsAny<ProcessSkuCostUpdated>())))
.Return(new List<IMessageRouter> {Router});
The above has no bearing on the Where being executed at runtime and can't be as the func is compiled down to a private method at compile time. Seems like to mock the func, I need to push it up to an interface. Smells though as I'm pushing up internal behavior purely for testing.
I see two issues with your test code:
The expression you use for setting up the Where() call on IMessageRouters is too explicit. It should not care about what exact function is passed.
You are verifying whether Route() has been called on the Subject. Instead you should verify whether the Message has been passed to the IMessageRouter.
As an additional improvement, you can omit the Router field and use The<IMessageRouter>() directly.
[Subject(typeof(RoutingEngine))]
public class when_routing_a_message_with_fakes : WithSubject<RoutingEngine>
{
Establish that = () =>
{
Message = new MyMessage { SomeValue = 1, SomeOtherValue = 11010 };
The<IMessageRouter>().WhenToldTo(x => x.CanRoute(Message)).Return(true);
The<IMessageRouters>().WhenToldTo(x => x.Where(Param<Func<IMessageRouter, bool>>.IsAnything))
.Return(new List<IMessageRouter> { The<IMessageRouter>() });
};
Because of = () => Subject.Route(Message);
It should_route_the_message = () =>
The<IMessageRouter>().WasToldTo(x => x.Route(Message));
static MyMessage Message;
}
I see a way to avoid mocking the Func<> at all. I hope it's interesting to you :) Why not forget about the generalized Where(Func<>) method and provide the specific query method. You own the inbound messages and the router(s).
public class MessageRouters : IMessageRouters
{
public IList<IMessageRouter> _routers = new List<IMessageRouter>();
public IEnumerable<IMessageRouter> For<T>(T inbound)
{
return _routers.Where(x => x.CanRoute(inbound));
}
public void Add(IMessageRouter messageRouter)
{
_routers.Add(messageRouter);
}
}
The class under test becomes simpler (in signature, no Func<>).
public class RoutingEngine : IRoutingEngine
{
private readonly IMessageRouters _messageRouters;
public RoutingEngine(IMessageRouters messageRouters)
{
_messageRouters = messageRouters;
}
public void Route<T>(T inbound)
{
var messageRouters = _messageRouters.For(inbound);
foreach(var router in messageRouters)
router.Route(inbound);
}
}
I'm guessing you don't need to inspect the actual instance of the inbound message either, maybe you can get away with just a Type check, like
public IEnumerable<IMessageRouter> For<T>() { ... }
and
var messageRouters = _messageRouters.For<T>();
You don't have to mock any Func<>s now and you can just do an assert-was-called (or however that looks in Moq).

Preventing Autofixture from filling child collections

I'm using the latest version of Autofixture, and I'd like to prevent it from filling automatically child collections.
For example, I have a class Person that has a List property. I want all properties filled, except the list.
I tried using this customization :
public class RemoveMultiples : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customizations
.OfType<FilteringSpecimenBuilder>()
.Where(x => x.Specification is DictionarySpecification)
.ToList().ForEach(c => fixture.Customizations.Remove(c));
fixture.Customizations
.OfType<FilteringSpecimenBuilder>()
.Where(x => x.Specification is CollectionSpecification)
.ToList().ForEach(c => fixture.Customizations.Remove(c));
fixture.Customizations
.OfType<FilteringSpecimenBuilder>()
.Where(x => x.Specification is HashSetSpecification)
.ToList().ForEach(c => fixture.Customizations.Remove(c));
fixture.Customizations
.OfType<FilteringSpecimenBuilder>()
.Where(x => x.Specification is ListSpecification)
.ToList().ForEach(c => fixture.Customizations.Remove(c));
}
}
But it also prevents me from using .CreateMany().
edit: I can use .CreateMany(3) and it works.
Is there a setting somewhere that could let me autofill collections only when I need to?
edit2: Class person should look like this:
[Serializable]
public class Person
{
private ICollection<OtherClass> _otherClasses;
private string _something;
public virtual ICollection<OtherClass> OtherClasses
{
get { return _otherClasses; }
set { _otherClasses = value; }
}
}
Note that it's not always a Collection, but sometimes IList
Note2: I just realized that someone also removed the Customization for IEnumerable hence why the CreateMany() doesn't create anything.
Here's one way to do it.
Start by implementing a SpecimenBuilder that tells AutoFixture to skip assigning a value for collection property:
public class CollectionPropertyOmitter : ISpecimenBuilder
{
public object Create(object request, ISpecimenContext context)
{
var pi = request as PropertyInfo;
if (pi != null
&& pi.PropertyType.IsGenericType
&& pi.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>))
return new OmitSpecimen();
return new NoSpecimen(request);
}
}
Then encapsulate that in a Customization:
public class DoNotFillCollectionProperties : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customizations.Add(new CollectionPropertyOmitter());
}
}
The following tests now pass:
[Fact]
public void CreatePersonWithoutFillingCollectionProperty()
{
var fixture = new Fixture().Customize(new DoNotFillCollectionProperties());
var actual = fixture.Create<Person>();
Assert.Null(actual.OtherClasses);
}
[Fact]
public void CreateManyStillWorks()
{
var fixture = new Fixture().Customize(new DoNotFillCollectionProperties());
var actual = fixture.CreateMany<Person>();
Assert.NotEmpty(actual);
}
[Fact]
public void CreatListStillWorks()
{
var fixture = new Fixture().Customize(new DoNotFillCollectionProperties());
var actual = fixture.Create<List<Person>>();
Assert.NotEmpty(actual);
}
[Fact]
public void CreateCollectionStillWorks()
{
var fixture = new Fixture().Customize(new DoNotFillCollectionProperties());
var actual = fixture.Create<ICollection<Person>>();
Assert.NotEmpty(actual);
}

Multiple interceptors in NHibernate

I am very new to NHibernate and have been following various tutorials online, especially this one to create my own program. I really liked the use of the interceptor to add INotifyPropertyChanged to entities created using the DataBindingFactory and tried to follow the same idea to add IDataErrorInfo to entities created by the DataBindingFactory with another method CreateWithValidation(Type type):
public static object CreateWithValidation(Type type)
{
return _proxyGenerator.CreateClassProxy(type, new[]
{
typeof (IDataErrorInfo),
typeof (INotifyPropertyChanged)
}, new IInterceptor[]
{
new NotifyPropertyChangedInterceptor(type.FullName),
new DataErrorInfoInterceptor()
});
}
The code for the NotifyPropertyChangedInterceptor is the same as in the linked article and below is my implementation of the DataErrorInfoInterceptor class which came from this article:
public class DataErrorInfoInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
if (invocation.Method.DeclaringType.Equals(typeof(IDataErrorInfo)))
{
var validator = new ValidatorEngine();
var errors = validator.Validate(invocation.Proxy);
if (invocation.Method.Name.Equals("get_Item"))
{
String propertyName = Convert.ToString(invocation.Arguments[0]);
var propertyErrors = errors
.Where(e => e.PropertyName.Equals(propertyName))
.Select(e => e.Message)
.ToArray();
if (propertyErrors.Count() > 0)
{
invocation.ReturnValue = string.Join(Environment.NewLine, propertyErrors);
}
else
{
invocation.ReturnValue = null;
}
}
else if (invocation.Method.Name.Equals("get_Error"))
{
var allErrors = errors
.Select(e => e.Message)
.ToArray();
if (allErrors.Count() > 0)
{
invocation.ReturnValue = string.Join(Environment.NewLine, allErrors);
}
else
{
invocation.ReturnValue = null;
}
}
else
{
invocation.Proceed();
}
}
}
The problem that I have is that if I create an object using the CreateWithValidation() method and use it on a model, any text I enter into a textbox on the view is cleared when I tab away from the field (this probably happens in other fields as well but I've only tried it on textboxes). I suspect that this is because both of the classes implementing IInterceptor have the line invocation.Proceed() if the method that has been intercepted is not one that the class is interested in.
My question is, is it possible to have two interceptors like this or do I have to have one massive class, eg: CustomInterceptor which has all of the methods for, eg: INotifyPropertyChanged and IDataErrorInfo and deal with them there? That seems quite unwieldy to me.
For what it's worth, this is how I set the interceptor on my SessionFactory:
public static void Initialise()
{
Configuration config = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c
.Server("")
.Database("")
.Username("")
.Password("")))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<Map>()
.Conventions.AddFromAssemblyOf<EnumConvention>())
.BuildConfiguration();
ConfigureNhibernateValidator(config);
DataBindingInterceptor interceptor = new DataBindingInterceptor();
SessionFactory = config
.SetInterceptor(interceptor)
.BuildSessionFactory();
}
The problem is not multiple interceptors. And the problem is not calling invocation.Proceed(). The problem is that you don't call invocation.Proceed() in your DataErrorInfoInterceptor when the method is not from IDataErrorInfo (it's correct in the linked article). Because of this, when you call some getter or setter, nothing happens.
Right now, you have something like this:
if (invocation.Method.DeclaringType.Equals(typeof(IDataErrorInfo)))
{
if (invocation.Method.Name.Equals("get_Item"))
{
// some code
}
else if (invocation.Method.Name.Equals("get_Error"))
{
// more code
}
else
{
invocation.Proceed();
}
}
What you should have is this:
if (invocation.Method.DeclaringType.Equals(typeof(IDataErrorInfo)))
{
if (invocation.Method.Name.Equals("get_Item"))
{
// some code
}
else if (invocation.Method.Name.Equals("get_Error"))
{
// more code
}
}
else
{
invocation.Proceed();
}
Next time, try stepping through the code in debugger to see what's really going on.

Categories

Resources