Currently I am trying to set up Dependency Injection using StructureMap for my MVC 5 project.
Following the instructions to set up the design pattern, it continues to fail in the regard when I try and make a call to the controller using the Route Prefix the constructors are never hit, so the object is never initialized, so the program keeps stating the object needs initializing. Prior to this issue, the program would not compile without parameterless constructors but when I do add a parameterless constructor the Interface object I use in the controller is null.
I am following the naming convention that is required by the framework, so the objects should be picked up by the default methods provided by StructureMap, and that is initialized in the DefaultRegistry.cs which is prebuilt when you install StructerMap in the Nuget Packages.
The format for the classes that are using the Repository Design Pattern are below:
Controller Class:
[RoutePrefix("api/data")]
public class TrialController : Controller
{
private readonly ITeacherService _teacherService;
public TrialController(ITeacherService teacherService)
{
_teacherService = teacherService;
}
[Route("trial")]
[HttpGet]
public void Get()
{
_teacherService.GetTeacher();
}
}
Service Class
public interface ITeacherService
{
void GetTeacher();
}
public class TeacherService : ITeacherService
{
public ITeacherRepository _teacherRepository;
public TeacherService(ITeacherRepository teacherRepository)
{
_teacherRepository = teacherRepository;
}
public void GetTeacher()
{
_teacherRepository.GetTeacher();
}
}
Repository Class
public interface ITeacherRepository
{
bool GetTeacher();
}
public class TeacherRepository : ITeacherRepository
{
public readonly ITeacherRepository _teacherRepository;
public TeacherRepository(ITeacherRepository teacherRepository)
{
_teacherRepository = teacherRepository;
}
public bool GetTeacher()
{
return true;
}
}
Thank you for taking your time to read this, and if any advice on how to resolve issue much appreciated :)
Related
I'm trying to register by convention multiple implementation of single interface and later use all those interfaces as dependency in other classes. Unfortunatelly, I'm having some problems trying to do so.
I want to register multiple implementation, so I added WithName.TypeName druing registration but this seems to be causing problems. Without it, I can't register multiple implementations for single interface.
Below is simple example which is not working. Unity is throwing exception and I don't know why.
Unity.ResolutionFailedException: 'Resolution failed with error: No
public constructor is available for type KYPClient.IConf.
namespace KYPClient
{
public interface IConf
{
string conf();
}
public class Conf : IConf
{
public string conf()
{
return "conf";
}
}
public interface ILoader
{
string load();
}
public class Load_1 : ILoader
{
public string load()
{
return "load-1";
}
}
public class Load_2 : ILoader
{
public string load()
{
return "load-2";
}
}
public class MainCls
{
private IConf _conf;
private IEnumerable<ILoader> _loaders;
public MainCls(IConf conf, IEnumerable<ILoader> loaders)
{
_conf = conf;
_loaders = loaders;
}
public void Run()
{
System.Console.WriteLine(_conf.conf());
foreach (var l in _loaders)
{
Console.WriteLine(l.load());
}
}
}
internal static class Client
{
private static void Main()
{
using var container = new UnityContainer();
container.RegisterTypes(
AllClasses.FromAssemblies(typeof(MainCls).Assembly),
WithMappings.FromAllInterfaces,
WithName.TypeName,
WithLifetime.ContainerControlled);
var main = container.Resolve<MainCls>();
main.Run();
}
}
}
The issue is you're using the WithName.TypeName option. This means that each type from the assembly is done as a named registration in the container. This is a good thing in your case because you are registering multiple ILoader instances, so the container has to be able to differentiate them. However, it also means that when it's being resolved, you have to pass the name in order for the container to find it.
In other words, when the container sees the constructor public MainCls(IConf conf, IEnumerable<ILoader> loaders) it interprets that as "inject the IConf instance with the default name" which doesn't exist in your container. Your IConf is registered with the name "Conf" (or possibly "KYPClient.Conf", I'm not sure, as I've never used the RegisterTypes method).
Thus, you have to explicitly name it in your constructor. Also, per How to configure Unity to inject an array for IEnumerable you need an array to get all the registered ILoader types.
public MainCls([Dependency("Conf")] IConf conf, ILoader[] loaders)
Of course, there are some drawbacks to using named dependencies (such as, what happens if you refactor and rename your class). Take a look at the second answer to With Unity how do I inject a named dependency into a constructor? for a strategy around that using a factory pattern.
I've read that using inheritance is not possible when using Specflow, which makes sense most of the time. However, I've run across a situation that seems to require the proper the use of inheritance. Here are my classes:
Base Class:
public class StepBaseClass
{
protected readonly ScenarioContext scenarioContext;
public StepBaseClass(ScenarioContext scenarioContext)
{
this.scenarioContext = scenarioContext;
}
}
First Inherited Class:
[Binding]
public class StudioEnterpriseImportConnectorSteps:StepBaseClass
{
public StudioEnterpriseImportConnectorSteps(ScenarioContext scenarioContext) :base(scenarioContext)
{
}
[Given(#"I have a data record that I want to send to the import service")]
public void GivenIHaveADataRecordThatIWantToSendToTheImportService()
{
scenarioContext.Pending();
}
[When(#"I send the information to an invalid URL")]
public void WhenISendTheInformationToAnInvalidURL()
{
scenarioContext.Pending();
}
[Then(#"an error should be generated")]
public void ThenAnErrorShouldBeGenerated()
{
scenarioContext.Pending();
}
}
2nd inherited class:
[Binding]
public class SitemapSteps:StepBaseClass
{
public SitemapSteps(ScenarioContext scenarioContext):base(scenarioContext)
{
}
[When(#"I visit the URL (.*)")]
public void WhenIVisitTheSitemapURL(string URL)
{
scenarioContext.Add("result", TestUtilities.GetResponseCode(URL));
scenarioContext.Add("response", TestUtilities.GetResponseBody(URL));
}
[Then(#"the response code should be (.*)")]
public void ThenTheResponseCodeShouldBe(string responseCode)
{
HttpStatusCode result = scenarioContext.Get<HttpStatusCode>("result");
Assert.Equal(responseCode, result.ToString());
}
}
As you can see, the only thing that I'm inheriting the the scenarioContext, which is something that I need to do in order to write multi-threaded tests. So instead of repeating this piece of code for each of my classes, I would like to be able to inherit from a base class. What is the proper method of initializing that variable so that I can use it in each of my derived classes?
The proper way depends as always on your individual situaion.
I recommend always to not use base classes and use context injection everywhere. The small number of code that is repeated in the constructor is a small price for a good separation and splitting of your bindings and their implementation.
To get more info about this topic, Gaspar Nagy wrote a nice blog article about the pros and cons of step base classes in SpecFlow:
http://gasparnagy.com/2017/02/specflow-tips-baseclass-or-context-injection/
After initializing my Dependency Injection in the Specflow Test hooks, I would have a class called ApplicationContext with a static resolve method which would return me my ScenarioContext instance like so:
public class ApplicationContext
{
public static T Resolve<T>() where T: class
{
return container.GetInstance<T>();
}
}
Then in my steps class, I would resolve the ScenarioContext like this:
scenarioContext = (ScenarioContext)ApplicationContext.Resolve<IScenarioContext>();
Code at bottom is from a working WPF sample application that used Autofac for dependency injection.
I want to convert to latest version of MEF instead. I also have NuGet packages CommonServiceLocator (V. 1.3) and Prism.Core, Prism.Mef and Prism.Wpf (all 6.1) installed.
When I do
var provider = ServiceLocator.Current.GetInstance<FriendDataProvider>();
I get an ActivationException from the "Func..." declaration in the constructor of FriendDataProvider.
Can MEF do this at all? If yes, what attribute declarations are required?
[Export]
public class FriendDataProvider
{
private readonly Func<IDataService> _dataServiceCreator;
[ImportingConstructor]
public FriendDataProvider(Func<IDataService> dataServiceCreator) // <= DI ERROR
{
_dataServiceCreator = dataServiceCreator;
}
public void DoSomething()
{
using (var service = _dataServiceCreator()) // Factory
{ }
}
}
[Export(typeof(IDataService))]
public class DataService : IDataService
{
public ClassA GetSomething()
{
return new ClassA();
}
public void Dispose()
{ }
}
public interface IDataService : IDisposable
{
ClassA GetSomething();
}
public class ClassA
{ }
Most likely you are looking for MEF ExportFactory class:
https://msdn.microsoft.com/en-us/library/ff382807(v=vs.110).aspx
It'a a mixture of Owned<> and Func<> ideas from AutoFac. Mind that ExportFactory.CreateExport returns ExportLifetimeContext which is Disposable. Disposing the export lifetime context will also dispose the injected part + all its dependencies. ExportFactory behavior is slightly different depending on Instancing mode of the owner part. If the owner class is a singleton ExportFactory will always create you new instance (behaves like Func< Owned< T>> in Autofac), but if you use it in combination with CompositionScopes you'll get behavior similar to Func< T> in AutoFac. See example: http://blogs.microsoft.co.il/bnaya/2013/01/16/mef-20-mini-series-part-6-composition-scoping-and-lifetime-management/
Here is your example re-written using ExportFactories:
[Export]
public class FriendDataProvider
{
private readonly ExportFactory<IDataService> _dataServiceCreator;
[ImportingConstructor]
public FriendDataProvider(ExportFactory<IDataService> dataServiceCreator) // <= DI ERROR
{
_dataServiceCreator = dataServiceCreator;
}
public void DoSomething()
{
using (var service = _dataServiceCreator.CreateExport()) // Factory
{
}
}
}
[Export(typeof(IDataService))]
public class DataService : IDataService
{
public ClassA GetSomething()
{
return new ClassA();
}
public void Dispose()
{ }
}
public interface IDataService : IDisposable
{
ClassA GetSomething();
}
public class ClassA
{ }
I have the following installer but for some odd reason it is not resolving correctly. I have an interface where there are 2 implementations of it but want to inject the correct instance based on naming conventions.
I am expecting in this instance that the correct instance of ICommand will be injected based on how they are named. However, for some odd reason both controllers are picking the very first instance, i.e. FooCommand due to it being defined first in the installer.
Not sure what I have done wrong? Perhaps, is there an alternative way of doing this?
public interface ICommand { }
public class FooCommand : ICommand { }
public class BarCommand : ICommand { }
public class SomeController : ApiController
{
public SomeController(ICommand fooCommand) { }
}
public class HelloController : ApiController
{
public HelloController(ICommand barCommand) { }
}
container.Register(
Component.For<ICommand>()
.Named("fooCommand")
.ImplementedBy<FooCommand>()
.LifestyleSingleton(),
Component.For<ICommand>()
.Named("barCommand")
.ImplementedBy<BarCommand>()
.LifestyleSingleton());
Like #steven said, it's generally not a good idea and if not managed properly may lead to discoverability issues down the line, but assuming you know what you're doing you can build a IContributeComponentModelConstruction that will match constructor parameters of type ICommand on your controllers with Windsor components having the same name.
public class ControllerCommandMatcher : IContributeComponentModelConstruction
{
public void ProcessModel(IKernel kernel, ComponentModel model)
{
// or whatever other condition to bail out quickly
if (model.Implementation.Name.EndsWith("Controller") == false) return;
foreach (var constructor in model.Constructors)
{
foreach (var dependency in constructor.Dependencies)
{
if (dependency.TargetItemType != typeof (ICommand)) continue;
dependency.Parameter = new ParameterModel(dependency.DependencyKey,
ReferenceExpressionUtil.BuildReference(dependency.DependencyKey));
}
}
}
}
The tricky bit is this:
new ParameterModel(dependency.DependencyKey,
ReferenceExpressionUtil.BuildReference(dependency.DependencyKey))
It basically tells Windsor that the dependency (the constructor parameter), for example fooCommand should be satisfied with a component of the same name (fooCommand).
Then add your contributor to the container
container.Kernel.ComponentModelBuilder.AddContributor(new ControllerCommandMatcher());
Here's the documentation
Im faced with an impending upgrade to an ASP.NET site and I am thinking of introducing DI using Unity. I have researched the ASP.NET DI side of things and have 2 options (Global.asax or IHttpModule). Im happy to use either.
As always, there is a legacy object model in place that I would like to upgrade/change. I would like to go down the route of Constructor injection (passing in the DAO) however, each object has a mix of static and instance methods that both currently call into the DB using SqlCommand objects themselves. I want this removed to provide DB independence, therefore can anyone suggest the best way to do the DI in this case? Im open to drastic changes if they are needed.
public class ExampleClass
{
public ExampleClass(int test)
{
TestProperty = test;
}
public int TestProperty {get; set;}
public int Save()
{
// Call DB and Save
return 1;
}
public static ExampleClass Load(int id)
{
// Call DB and Get object from DB
return new ExampleClass(1);
}
}
Thanks for any suggestions
Matt
If you remove all static methods and introduce some abstractions you should be good to go:
public class ExampleClass
{
public int TestProperty { get; set; }
}
public interface IRepository
{
ExampleClass Load(int id);
int Save();
}
public class RepositorySql: IRepository
{
// implement the two methods using sql
}
and in your ASP page:
private IRepository _repo = FetchRepoFromContainer();
public void Page_Load()
{
var someObj = _repo.Load(1);
// ... etc
}