How to pass a parameter to a named services in LightInject? - light-inject

In LightInject,registering a named service goes a s follows:
container.Register<IFoo, Foo>();
container.Register<IFoo, AnotherFoo>("AnotherFoo");
var instance = container.GetInstance<IFoo>("AnotherFoo");
A service with a parameter:
container.Register<int, IFoo>((factory, value) => new Foo(value));
var fooFactory = container.GetInstance<Func<int, IFoo>>();
var foo = (Foo)fooFactory(42);
How to combine these two together, to have a named service with a parameter passed to a constructor?

You mean like this?
class Program
{
static void Main(string[] args)
{
var container = new ServiceContainer();
container.Register<string,IFoo>((factory, s) => new Foo(s), "Foo");
container.Register<string, IFoo>((factory, s) => new AnotherFoo(s), "AnotherFoo");
var foo = container.GetInstance<string, IFoo>("SomeValue", "Foo");
Debug.Assert(foo.GetType().IsAssignableFrom(typeof(Foo)));
var anotherFoo = container.GetInstance<string, IFoo>("SomeValue", "AnotherFoo");
Debug.Assert(anotherFoo.GetType().IsAssignableFrom(typeof(AnotherFoo)));
}
}
public interface IFoo { }
public class Foo : IFoo
{
public Foo(string value){}
}
public class AnotherFoo : IFoo
{
public AnotherFoo(string value) { }
}

Related

Create unit test for View() with a List in ASP.net core MVC application

I am new in unit testing. I have a controller - StudentsController with dependency injection and there my Index() method:
public class StudentsController : Controller
{
public readonly UniversityContext _context;//Database
public StudentsController(UniversityContext context)
{
_context = context;
}//Constructor with database
// GET: Students
public async Task<IActionResult> Index()
{
return View(await _context.Students.ToListAsync());
}
}
Next i need to write a correct unit test code, that check, if:
1) a View() have a list with my students
2) The query with students is not null.
I read about Mock objects, but I don't know how to write the correct code. My code that I wrote so far:
public class StudentsControllerTests
{
[Fact]
public async Task Index_ReturnsAViewResult_WithAListOfStudents()
{
var mockRepo = new Mock<UniversityContext>();
mockRepo.Setup(repo => repo.Students.ToList()).Returns(GetTestStudents());//There i get following error:Expression references a method that does not belong to the mocked object
var controller = new StudentsController(mockRepo.Object);
// Act
var result = controller.Index();
//// Assert
var viewResult = Assert.IsType<ViewResult>(result);
var model = Assert.IsAssignableFrom<IEnumerable<Student>>(
viewResult.ViewData.Model);
Assert.NotNull(model);//Second Condition
}
public List<Student> GetTestStudents()
{
var sessions = new List<Student>();
sessions.Add(new Student()
{
bDate = new DateTime(1994, 7, 2),
Name = "Test One"
});
sessions.Add(new Student()
{
bDate = new DateTime(1995, 7, 1),
Name = "Test Two"
});
return sessions;
}
}
Can someone explain me, how to correct my code?
You only need to mock the members of the context, which in this case is the .Students property. ToList is an extension method being call on the property and cannot be mocked by moq.
Also .Students is a DbSet and would need to be mocked as well.
Using the test classes from this answer :
How to mock an async repository with Entity Framework Core
The following generic extension methods were derived
public static class MockDbSetExtensions {
public static Mock<DbSet<T>> AsDbSetMock<T>(this IEnumerable<T> list) where T : class {
IQueryable<T> queryableList = list.AsQueryable();
Mock<DbSet<T>> dbSetMock = new Mock<DbSet<T>>();
dbSetMock.As<IQueryable<T>>().Setup(x => x.Provider).Returns(queryableList.Provider);
dbSetMock.As<IQueryable<T>>().Setup(x => x.Expression).Returns(queryableList.Expression);
dbSetMock.As<IQueryable<T>>().Setup(x => x.ElementType).Returns(queryableList.ElementType);
dbSetMock.As<IQueryable<T>>().Setup(x => x.GetEnumerator()).Returns(() => queryableList.GetEnumerator());
return dbSetMock;
}
public static Mock<DbSet<T>> ToAsyncDbSetMock<T>(this IEnumerable<T> source)
where T : class {
var data = source.AsQueryable();
var mockSet = new Mock<DbSet<T>>();
mockSet.As<IAsyncEnumerable<T>>()
.Setup(m => m.GetEnumerator())
.Returns(new TestAsyncEnumerator<T>(data.GetEnumerator()));
mockSet.As<IQueryable<T>>()
.Setup(m => m.Provider)
.Returns(new TestAsyncQueryProvider<T>(data.Provider));
mockSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(() => data.GetEnumerator());
return mockSet;
}
}
With the above utilities, update
mockRepo.Setup(repo => repo.Students.ToList()).Returns(GetTestStudents());
To
var studentsMockedDbSet = GetTestStudents().ToAsyncDbSetMock();
mockRepo.Setup(repo => repo.Students).Returns(studentsMockedDbSet.Object);

How could I create a sub type of `I` that would wrap other sub types of `I`?

Given the following in Java:
public interface Reply<T> {
T data();
}
public class StatusReply implements Reply<String> {
private final String status;
public StatusReply(String status) {
this.status = status;
}
#Override
public String data() {
return status;
}
}
I want to be able to do this in Scala:
class PassthroughReply[R <: Reply[_]](val reply: R)
extends Reply[T] { // won't compile, `T` type not found
override
def data[T : Reply]: T = reply.data
}
val statusReply = new StatusReply("OK")
val passthroughReply = new PassthroughReply[SatusReply](statusReply)
passthroughReply.data // Should return "OK"
What I want is that the data in an instance of PassthroughReply, should have the same type as the data of its wrapped sub type of Reply.
How about this?
class PassthroughReply[T](val reply: Reply[T]) extends Reply[T] {
override def data = reply.data
}

Autofac PropertiesAutowired - Is it possible to ignore a one or more properties?

Despite the advice to pass dependencies through the constructor I've found that the development cost of having parameterless constructors and then autowiring all of the properties on everything is significantly less and makes the application much easier to develop out and maintain. However sometimes (on a view model for example) I have a property that is registered with the container, but that I don't want to populate at construction (for example the selected item bound to a container).
Is there any way to tell the container to ignore certain properties when it autowires the rest?
At the moment I'm just resetting the properties marked with an attribute in the on activated event a la:
public static IRegistrationBuilder<TLimit, ScanningActivatorData, TRegistrationStyle>
PropertiesAutowiredExtended<TLimit, TRegistrationStyle>(
this IRegistrationBuilder<TLimit, ScanningActivatorData, TRegistrationStyle> builder)
{
builder.ActivatorData.ConfigurationActions.Add(
(type, innerBuilder) =>
{
var parameter = Expression.Parameter(typeof(object));
var cast = Expression.Convert(parameter, type);
var assignments = type.GetProperties()
.Where(candidate => candidate.HasAttribute<NotAutowiredAttribute>())
.Select(property => new { Property = property, Expression = Expression.Property(cast, property) })
.Select(data => Expression.Assign(data.Expression, Expression.Default(data.Property.PropertyType)))
.Cast<Expression>()
.ToArray();
if (assignments.Any())
{
var #action = Expression
.Lambda<Action<object>>(Expression.Block(assignments), parameter)
.Compile();
innerBuilder.OnActivated(e =>
{
e.Context.InjectUnsetProperties(e.Instance);
#action(e.Instance);
});
}
else
{
innerBuilder.OnActivated(e => e.Context.InjectUnsetProperties(e.Instance));
}
});
return builder;
}
Is there a better way to do this?
Not sure that this is a better one, but you can go from another side, register only needed properties via WithProperty syntax. Pros is that Autofac doesn't resolve unnecessary services. Here's a working example:
public class MyClass
{
public MyDependency MyDependency { get; set; }
public MyDependency MyExcludeDependency { get; set; }
}
public class MyDependency {}
public class Program
{
public static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<MyDependency>();
builder.RegisterType<MyClass>().WithPropertiesAutowiredExcept("MyExcludeDependency");
using (var container = builder.Build())
{
var myClass = container.Resolve<MyClass>();
Console.WriteLine(myClass.MyDependency == null);
Console.WriteLine(myClass.MyExcludeDependency == null);
}
}
}
public static class PropertiesAutowiredExtensions
{
// Extension that registers only needed properties
// Filters by property name for simplicity
public static IRegistrationBuilder<TLimit, TReflectionActivatorData, TRegistrationStyle>
WithPropertiesAutowiredExcept<TLimit, TReflectionActivatorData, TRegistrationStyle>(
this IRegistrationBuilder<TLimit, TReflectionActivatorData, TRegistrationStyle> registrationBuilder,
params string[] propertiesNames)
where TReflectionActivatorData : ReflectionActivatorData
{
var type = ((IServiceWithType)registrationBuilder.RegistrationData.Services.Single()).ServiceType;
foreach (var property in type
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(pi => pi.CanWrite && !propertiesNames.Contains(pi.Name)))
{
// There's no additional checks like in PropertiesAutowired for simplicity
// You can add them from Autofac.Core.Activators.Reflection.AutowiringPropertyInjector.InjectProperties
var localProperty = property;
registrationBuilder.WithProperty(
new ResolvedParameter(
(pi, c) =>
{
PropertyInfo prop;
return pi.TryGetDeclaringProperty(out prop) &&
prop.Name == localProperty.Name;
},
(pi, c) => c.Resolve(localProperty.PropertyType)));
}
return registrationBuilder;
}
// From Autofac.Util.ReflectionExtensions
public static bool TryGetDeclaringProperty(this ParameterInfo pi, out PropertyInfo prop)
{
var mi = pi.Member as MethodInfo;
if (mi != null && mi.IsSpecialName && mi.Name.StartsWith("set_", StringComparison.Ordinal)
&& mi.DeclaringType != null)
{
prop = mi.DeclaringType.GetProperty(mi.Name.Substring(4));
return true;
}
prop = null;
return false;
}
}

Resolving IDbSet<T> from AutoFac

I would like to implement generic repository pattern with IDbSet<> interface of Entity Framework.
When i ask IDbSet<T> from Autofac, It should resolve IDbContext then call its Set<T> method to return the concrete type of IDbSet<T>
As an example, it should be doing something like this:
builder.Register<IDbSet<T>>(context => context.Resolve<IDbContext>().Set<T>());
How can i achive this with Autofac?
It seems based on this answer: https://stackoverflow.com/a/7997162/872395
that the only solution is to create a custom IRegistrationSource where you create the closed registrations:
public class DbSetRegistrationSource : IRegistrationSource
{
public bool IsAdapterForIndividualComponents
{
get { return true; }
}
public IEnumerable<IComponentRegistration> RegistrationsFor(
Service service,
Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
{
var swt = service as IServiceWithType;
if (swt == null || !swt.ServiceType.IsGenericType)
yield break;
var def = swt.ServiceType.GetGenericTypeDefinition();
if (def != typeof(IDbSet<>))
yield break;
// if you have one `IDBContext` registeration you don't need the
// foreach over the registrationAccessor(dbContextServices)
yield return RegistrationBuilder.ForDelegate((c, p) =>
{
var dBContext = c.Resolve<IDBContext>();
var m = dBContext.GetType().GetMethod("Set", new Type[] {});
var method =
m.MakeGenericMethod(swt.ServiceType.GetGenericArguments());
return method.Invoke(dBContext, null);
})
.As(service)
.CreateRegistration();
}
}
The usage is very simple:
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterSource(new DbSetRegistrationSource());
containerBuilder.RegisterType<DbContext>().As<IDBContext>();
var container = containerBuilder.Build();

Autofac wiring question - beginner

Beginners question:
Given two classes: Myclass5 and Myclass6 how can one wire up following factory method (returned as Func)
such that
myclass5 and myclass6 instances and IMyClass that they depend on are all retrieved via autofac (assuming that these three instances are registered).
public static MyClass4 FactoryMethod(int nu)
{
if (nu == 1)
return new MyClass5(....);
if (nu == 4)
return new MyClass6(....);
throw new NotImplementedException();
}
public abstract class MyClass4
{
}
public class MyClass5 : MyClass4
{
public MyClass5(int nu, IMyClass a)
{
}
}
public class MyClass6 : MyClass4
{
public MyClass6(int nu, IMyClass a)
{
}
}
For FactoryMethod to be able to create the instances, it requires access to a container. I would suggest create a delegate type for the factory method, which makes it easy to take dependency on it. Registration goes like this:
var cb = new ContainerBuilder();
cb.RegisterType<SomeClass>().As<IMyClass>();
cb.RegisterType<MyClass5>();
cb.RegisterType<MyClass6>();
cb.Register((c, p) =>
{
var context = c.Resolve<IComponentContext>();
return new FactoryMethod(nu =>
{
var nuParameter = TypedParameter.From(nu);
switch (nu)
{
case 1:
return context.Resolve<MyClass5>(nuParameter);
case 4:
return context.Resolve<MyClass6>(nuParameter);
default:
throw new NotImplementedException();
}
});
});
var container = cb.Build();
At resolve time, you can then take a dependency on the FactoryMethod delegate type and use it to resolve instances:
var factory = container.Resolve<FactoryMethod>();
var instance5 = factory(1);
var instance6 = factory(1);
Note: the delegate instance we're creating needs a context. We cannot use the c parameter directly since that context is only temporary. Thus we must resolve a IComponentContext to "bake" into the lambda.
Update: if you would like to extract the factory implementation into a method that is not dependent on the container I would suggest the following:
public class FactoryMethodImpl
{
readonly Func<int, MyClass5> _factory5;
readonly Func<int, MyClass6> _factory6;
public FactoryMethodImpl(Func<int, MyClass5> factory5, Func<int, MyClass6> factory6)
{
_factory5 = factory5;
_factory6 = factory6;
}
public MyClass4 Create(int nu)
{
switch (nu)
{
case 1:
return _factory5(nu);
case 4:
return _factory6(nu);
default:
throw new NotImplementedException();
}
}
}
Now, change the registration code to this:
var cb = new ContainerBuilder();
cb.RegisterType<SomeClass>().As<IMyClass>();
cb.RegisterType<MyClass5>();
cb.RegisterType<MyClass6>();
cb.RegisterType<FactoryMethodImpl>().SingleInstance();
cb.Register(c=> new FactoryMethod(c.Resolve<FactoryMethodImpl>().Create));