How to register IEnumerable<IService> In DryIoc Mvc Controller like Autofac Enumeration (IEnumerable<B>, IList<B>, ICollection<B>) - dryioc

Test Code With Autofac is Ok,but with DryIoc is error. How to make this work.
public class HomeController : Controller
{
private readonly ITestAppService _testAppService;
private readonly IEnumerable<ITestAppService> _testAppServiceList;
public HomeController(ITestAppService testAppService, IEnumerable<ITestAppService> testAppServiceList)
{
_testAppService = testAppService;
_testAppServiceList = testAppServiceList;
}
}
public class Test1AppService : ITestAppService{}
public class Test2AppService : ITestAppService{}
public interface ITestAppService: IAppService{}
The error 'Make sure that the controller has a parameterless public constructor ' is caused by field ITestAppService in controller not the field IEnumerable.Following is my register code.
var impls =
typeof(IAppService).Assembly
.GetTypes()
.Where(type =>
type.IsPublic &&
!type.IsAbstract &&
type.GetInterfaces().Length != 0 && typeof(IAppService).IsAssignableFrom(type));
foreach (var type in impls)
{
container.Register(type.GetInterfaces().First(), type, Reuse.Transient);
}
Resolved by dadhi's suggestion,My container is
DryIoc.IContainer container = new DryIoc.Container(
rules =>
{
return rules.WithFactorySelector(Rules.SelectLastRegisteredFactory())
.WithResolveIEnumerableAsLazyEnumerable();
}
);
The dryioc wiki about Resolving from multiple default services may need some update. Rules.SelectLastRegisteredFactory is a method.

The problem is that consdering two implementations of ITestAppService container doesn't know which to select for the first dependency. But you may explicitly define the convention:
var container = new Container(rules => rules
.WithFactorySelector(Rules.SelectLastRegisteredFactory));

Related

Dependency Injection with Moq and AutoMoq (AutoFixture) w/ xUnit

I'm writing this because I've tried for a bit to figure this out myself with no luck. Every example I can find for whatever reason seems to suggest that this just works out of the box but whenever I try to do the same, I always get errors. Basically, I have a controller with two properties that are injected via. DI, let's say
public class SomeController
{
private ISomeInterface _i;
private MyConfig _c;
public SomeController(ISomeInterface i, MyConfigContext cxt) // Where cxt is Type of DbContext
{
_i = i;
_c = cxt.Configs.FirstOrDefault();
}
public OkResult PostModel(SomeModel c)
{
// Do things
return Ok();
}
}
And in my tests using xUnit, Moq & AutoFixture I'm trying to avoid having to manually instantiate dependencies B and C:
public class SomeControllerTests
{
private MyDbContext _cxt;
private Fixture _fixture;
public SomeControllerTests()
{
_cxt = GetCxt() // GetCxt() just returns a context instance, nothing special
_fixture = new Fixture();
_fixture.Customize(new AutoMoqCustomization { ConfigureMembers = true });
_fixture.Customizations.Add(
new TypeRelay(
typeof(ISomeInterface),
typeof(SomeConcreteClass)
)
);
}
[Fact, AutoData]
public void PostStatus_ReturnsOk_GivenValidRequest()
{
SomeController c = _fixture.Create<SomeController>();
SomeModel m = _fixture.Create<SomeModel>();
var result = c.PostModel(m);
Asset.IsType<OkResult>(result);
}
}
With the above I am getting a NotImplementedException when I run the tests and it won't tell me what exactly is not being implemented so I have no way of knowing what the issue is. I must be missing something in the docs. I want to use AutoFixture to make my tests more durable but so far it has been a pain trying to use it. I really don't want to have to mock/stub my entire app manually just to run a test. I would ideally like to use the syntax shown in the AutoFixture docs where you put your test-relevant instances in the params of the test and they are created for you but I haven't had any luck with it, like...
[Theory, AutoData]
SomeTestMethod(SomeController c, SomeModel m)
{
var result = c.PostModel(m);
Assert.IsType<OkResult>(result);
}
Thanks for Reading (:
Try to add next attribute and use it instead of AutoData.
using AutoFixture.AutoMoq;
using AutoFixture.Xunit2;
namespace Cats
{
public class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute()
: base(() => new Fixture().Customize(new AutoMoqCustomization()))
{
}
}
}
[Theory, AutoMoqData]
SomeTestMethod(SomeController c, SomeModel m)
{
var result = c.PostModel(m);
Assert.IsType<OkResult>(result);
}

MVC Core 2.0 Unit Testing and Automapper

I am attempting to Unit Test a method that uses Automapper ProjectTo and I'm not sure how to register the mappings in MVC Core. I am using the built in unit testing.
The following is my unit test.
[TestClass]
public class BusinessGenderServiceTest
{
[ClassInitialize]
public static void Init(TestContext context)
{
}
[TestMethod]
public void GetTest()
{
var options = new DbContextOptionsBuilder<GotNextDbContext>()
.UseInMemoryDatabase(databaseName: "GetTest")
.Options;
using (var context = new GotNextDbContext(options))
{
context.GenderLanguage.Add(new GenderLanguage { Id = 1, Name = "Male", Language = 1 });
context.GenderLanguage.Add(new GenderLanguage { Id = 2, Name = "Female", Language = 1 });
context.GenderLanguage.Add(new GenderLanguage { Id = 3, Name = "Hombre", Language = 2 });
context.GenderLanguage.Add(new GenderLanguage { Id = 4, Name = "Hombre", Language = 2 });
context.SaveChanges();
}
using (var context = new GotNextDbContext(options))
{
var service = new GenderService(context);
var result = service.Get(1);
Assert.AreEqual(2, result.Count());
}
}
}
I am getting the following error when I run the test:
Message: Test method GotNext.Test.BusinessGenderServiceTest.GetTest threw exception:
System.InvalidOperationException: Mapper not initialized. Call Initialize with appropriate configuration. If you are trying to use mapper instances through a container or otherwise, make sure you do not have any calls to the static Mapper.Map methods, and if you're using ProjectTo or UseAsDataSource extension methods, make sure you pass in the appropriate IConfigurationProvider instance.
I was able to solve this problem by configuring and initializing automapper in the Init method of each test class.
For example
[ClassInitialize]
public static void Init(TestContext testContext)
{
var mappings = new MapperConfigurationExpression();
mappings.AddProfile<LocationProfile>();
mappings.AddProfile<CompanyProfile>();
Mapper.Initialize(mappings);
}
You can configure AutoMapper in class like this:
public static class AutoMapperConfig
{
public static IMapper Initialize()
{
return new MapperConfiguration((cfg =>
{
cfg.CreateMap<User, UserDto>();
})).CreateMapper();
}
}
And next use it in startup.cs ConfigureService method
services.AddSingleton(AutoMapperConfig.Initialize());
Create a class or classes that configure AutoMapper and instantiate (and call methods, if applicable) in the Startup class.
I got this same error ("System.InvalidOperationException: Mapper not initialized. Call Initialize with appropriate configuration. ...") when I inadvertently / mindlessly switched between AutoMapper's Instance API (which I did have configured) and AutoMapper's Static API (which I did NOT have configured).
Looking closely at the line of code flagged in the error message, I realized I used upper-case 'M' Mapper.Map() instead of my instance member lower-case 'm' mapper.Map().

Open Generics Registration

Suppose I have the following classes:
public class Setup { }
public class Configuration<T> where T : class
{
internal Configuration(Setup setup) { }
}
public class Process<T> where T : class
{
internal Process(Configuration<T> configuration) { }
}
I want to register these classes in DryIoc and need each Process<T> to be singleton (as would be Configuration<T>). So, Process<ClassA> would resolve the same instance, and Process<ClassB> will do the same. But Process<ClassA> and Process<ClassB> would be 2 different instances.The same applies to Configuration<T>.How would I register these 3 classes to achieve what I need?Note that constructors are internal.
This is what I've done without success:
var container = new Container();
container.Register<Setup>(Reuse.Singleton);
container.Register(typeof (Configuration<>),
made: Made.Of(typeof (Configuration<>).GetConstructorOrNull(true, typeof (Setup))));
container.Register(typeof(Process<>), Reuse.Singleton,
Made.Of(typeof(Process<>).GetConstructorOrNull(true, typeof(Configuration<>))));
I get: "An exception of type 'System.NullReferenceException' occurred in DryIoc.dll but was not handled in user code" when, as an example I dovar a = container.Resolve<Process<EventArgs>>();
The problem is with getting constructor from generic type. For now you may use DryIoc API to get ConstructorWithResolvableArgumentsIncludingNonPublic:
Working sample looks like that:
var container = new Container();
container.Register<Setup>(Reuse.Singleton);
container.Register(typeof(Configuration<>), Reuse.Singleton,
made: FactoryMethod.ConstructorWithResolvableArgumentsIncludingNonPublic);
container.Register(typeof(Process<>), Reuse.Singleton,
FactoryMethod.ConstructorWithResolvableArgumentsIncludingNonPublic);
var p = container.Resolve<Process<EventArgs>>();
In future versions it will be more simple like FactoryMethod.Constructor(includeNonPublic: true).
Update with workaround:
This is an actual issue in DryIoc 2.9.7 with creating singletons with internal constructor. The fix is on the way. For now you can use a workaround by disabling certain singleton optimizations with rule:
var container = new Container(rules => rules.WithoutEagerCachingSingletonForFasterAccess());
Updated live sample.
Update with fix:
The problem is fixed in DryIoc 2.10

Controller Cleaning. Doctrine in Model

I want to make my controller thin and to separate business-logic from other operations. For example I have an action:
public function indexAction()
{
$languages = $this ->getEntityManager()
->getRepository('\ApanelLanguage\Entity\LanguageCommon')
->getLanguagesList();
$viewModel = new ViewModel(['languages' => $languages]);
return $viewModel;
}
but I want to get action like this:
public function indexAction()
{
$model = $new LanguageModel();
$model->getLanguagesList();
return $viewModel;
}
Is it possible to do? What must I have in Language/Model/LanguageModel ?
Thank you
Removing the business logic from your controller is a great idea for code reuse and maintainability; however I would recommend against moving the logic to your models. A better solution would be to add a service layer to your application.
What is a service layer? Martin Fowler describes it as the following:
[A service layer] defines an application's boundary with a layer of services that establishes a set of available operations and coordinates the application's response in each operation.
This essentially means that we add a class in-between your controller and your model.
The great advantage of this approach is that should you need to update the business logic of your application there is no need to update the controller. The controller also becomes unaware of any specific code and therefore can be reusable in other unrelated projects.
This 'service' could have a simple API, for example:
interface ServiceInterface
{
public function setObjectManager($objectManager);
public function setRepository($respository);
public function find($id);
public function fetchRow($criteria);
public function fetchAll($criteria);
public function insert($object);
public function update($object);
public function delete($object);
}
Then you can implement this interface for your new 'LanguageService'.
class LanguageService implements ServiceInterface
{
// ... all methods from interface
public function getLanguageList()
{
return $this->repository->getLanguagesList();
}
}
Lastly update your controller to use the new service
class FooController extends AbstractActionController
{
protected $languageService;
public function __construct(ServiceInterface $languageService)
{
$this->languageService = $languageService;
}
public function indexAction()
{
$languages = $this->languageService->getLanguageList();
$viewModel = new ViewModel(['languages' => $languages]);
return $viewModel;
}
public function insertAction()
{
$request = $this->getRequest();
$service = $this->languageService;
$form = $service->getInsertForm();
if ($request->isPost()) {
$form->setData($request->getPost());
if ($form->isValid()) {
// if our form used the DoctrineObjectHydrator
// we will get a entity back populated with the
// form data
$language = $service->insert($form->getData());
if ($language instanceof Entity\Language) {
// success
} else {
// failure
}
}
}
//
}
}

Problems with mocking IUnityContainer when testing UnityControllerFactory in MVC project

I am having trouble testing a unity controller factory. I am mcoking out the unity container and asserting that a method was called on it. I am getting invalid cast expection though but cannot really see what is wrong with my code.
Here is the class under test:
public class UnityControllerFactory : IControllerFactory
{
private readonly IUnityContainer _container;
public UnityControllerFactory(IUnityContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
_container = container;
}
public IController CreateController(RequestContext requestContext, string controllerName)
{
return _container.Resolve<IController>(controllerName);
}
public void ReleaseController(IController controller)
{
_container.Teardown(controller);
}
}
and here is the test:
[Test]
public void CreateControllerCallsResolveOnContainerWithCorrectArgument()
{
const string controllerName = "WhateverController";
var containerMock = MockRepository.GenerateMock<IUnityContainer>();
var controllerFactory = new UnityControllerFactory(containerMock);
controllerFactory.CreateController(null, controllerName);
containerMock.AssertWasCalled(x => x.Resolve<IController>(controllerName));
}
and here is the error message:
System.InvalidCastException : Unable to cast object of type 'ObjectProxy42336d85f7bb400f9590892348d1d597' to type 'System.Web.Mvc.IController'
The generic Resolve<T>(string) method is an extension method and cannot be mocked. You have two choices here:
Use a non-generic Resolve(Type, string) method or
Wrap IUnityContainer with your own interface so that the generic methods you want to use are interface methods, not extension methods.
Why don't you just use a IUnityContainer's real implementation and register mock/stubs inside it?