From what I understand, in abp, when a class implements, ITransient interface, it is automatically registered in the dependency injection system.
When I create a new project in ASPNetZero, and a class implements the ITransient, I cannot inject the said class in other projects e.g Application
Using the following snippet does not allow me to use constructor injection.
public interface ITrackAppService : ITransientDependency
public class TrackAppService : ITrackAppService
But when I register it (Even if the class does not implements ITransient), then I can use constructor injection.
IocManager.RegisterIfNot<ITrack, Track>();
Did I mistakenly understood how ITransient works?
How do I use Itransient so I can use constructor dependency injection?
Note: The class I'm trying to inject to the Application project is in a different project I created.
If you are injecting an interface to a new project, you cannot use it that way out of the box. Because your new project doesn't know your dependencies.
Each new project that uses DI must to be set as an AbpModule.
See a sample module declaration.
[DependsOn(typeof(MyBlogCoreModule))]
public class MyBlogApplicationModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
}
Look out the [DependsOn] attribute on the class. This helps to register the project to the DI.
So what you need to do is,
Create a new class in the new project like I showed you above.
Add the [DependsOn(typeof(YourApplicationServiceModule))] attribute to this new module.
Related
I'd like to run some node code from my c#. Microsoft.AspNetCore.NodeServices seems to be the way to do this job however the examples are all very similar and all involve putting
services.AddNodeServices();
in the configure services function and then DI adds the implementation of INodeServices to a controller. Like this
public class foo
{
private readonly INodeServices _nodeServices;
public foo(INodeServices nodeServices)
{
_nodeServices = nodeServices;
}
}
As I'm using this in a class library rather than a webapi how is DI going to work? Also how do I call the class from a unit test, what can I pass into the constructor? I'm sure I'm missing something obvious.
The concept of DI is that it can be used to resolve object graphs. That is, it doesn't just resolve dependencies of the Controller class, but dependencies of those dependencies, dependencies of those dependencies, etc.
To use INodeServices in your own library, you simply need to reference Microsoft.AspNetCore.NodeServices, then accept it as a constructor parameter.
public class MyServiceFromMyLibrary : IMyServiceFromMyLibrary
{
private readonly INodeServices nodeServices;
public MyServiceFromMyLibrary(INodeServices nodeServices)
{
this.nodeServices = nodeServices;
}
// ...
}
Then reference your library from the Web API project and inject your service into a controller.
public class FooController
{
private readonly IMyServiceFromMyLibrary myService;
public FooController(IMyServiceFromMyLibrary myService)
{
this.myService = myService;
}
}
DI takes care of putting the INodeServices instance into your class provided it is registered in your composition root, as follows.
services.AddNodeServices();
services.AddTransient<IMyServiceFromMyLibrary, MyServiceFromMyLibrary>();
If your end game is to create a reusable library rather than an application layer refer to DI Friendly Library for some techniques to make your library easier to use without the use of dependency injection.
Also how do I call the class from a unit test, what can I pass into the constructor?
For a unit test, you would just need to mock INodeServices. The simplest way is to use a mocking library, such as Moq.
var mock = new Mock<INodeServices>();
mock.Setup(ns => ns.InvokeAsync(It.IsAny<string>())).Returns(...);
var target = new MyServiceFromMyLibrary(mock.Object);
// .. Call a method on target and then assert the results
References:
Using Node Services in ASP.NET Core
Dependency injection in ASP.NET Core
I have a mapper that takes data from a repository project. I have a IMenueMapper interface that is passed into the homecontroller like this:
public HomeController(IMenueMapper menueMapper)
{
_menueMapper = menueMapper;
}
but the menuemapper class itself use the IMenueMapperRepository, and this come from another project and is passed in via dll
public MenueMapper(IMenueItemsRepository menueItems)
{
_menueItems = menueItems;
}
While I can easily resolve the IMenuemapper in the MVC project, using structuremap.mvc5, I can't resolve the repository. Is there a way of achieving the DI in this instance?
You need to register the abstraction (repository interface and implementation) in the composition root.
You indicated that the IMenueMapper is registered via;
scan.AssemblyContainingType<MenueMapper>();
Since
but the MenueMapper class itself use the IMenueMapperRepository, and
this come from another project and is passed in via dll
Then it should also be scanned as it belongs to another assembly
scan.AssemblyContainingType<MenueItemsRepository>();
Make sure that the project references the assembly in question
I have a windsor container and windsor doesnt inject my property. The curious thing is with ServiceA the dependency is resolved but not with the component.
Container.AddFacility<WcfFacility>();
Container.Register(Component.For<PublisherService>().AsWcfService());
Container.Register(Component.For<IExecutionProgram>().ImplementedBy<ExecutionProgram>());
Container.Register(Component.For<IValidationProgram>().Instance(Factory.CreateProgramA()));
Container.Register(Component.For<RunnerService>().AsWcfService());
This is my Factory (All the Dependencies implement the same interface and all SubDependencies implement an other shared Interface):
public static class Factory{
public static IValidationProgram CreateProgramA(){
var program = new ValidationProgram(
new DependencyA(
new SubDependencyA(),
new SubDependencyB(),
),
new DependencyB()
);
}
}
In my RunnerService the IExecutionProgram, Property will be resolved.
In my IValidationProgram, I created the IExecutionProgram will not be resolved.
Properties are public in both Implementations.
What did I do wrong?
EDIT:
I added the factory. These Dependencies are all Interfaces and I need specific implementations for a program. So in general I would like to switch easily between programA or programB. I looked into type Facilities like Marwijn supposed, but I cant get the hang of it. How do I use it in my case?
I really would like to use SharpRepository together with Ninject, but I do not understand how to configure Ninject to share the Entity Framework DbContext between the repositories.
I am using Entity Framework version 5 and Ninject version 3.
Currently I am using Ef5Repository in my source code, but I want to replace it with ConfigurationBasedRepository. But I cannot figure out how to pass (or inject) the EF DbContext to the repositories.
Example (current state):
using SharpRepository.Repository;
public interface IProductRepository : IRepository<Product>
{
}
using SharpRepository.Ef5Repository;
using System.Data.Entity;
// TODO Tightly coupled to Ef5Repository.
public class ProductRepository : Ef5Repository<Product>, IProductRepository
{
// TODO The DbContext has to be injected manually.
public ProductRepository(DbContext context) : base(context)
{
}
// [...]
}
Goal:
using SharpRepository.Repository;
public interface IProductRepository : IRepository<Product>
{
}
public class ProductRepository : ConfigurationBasedRepository<Product, int>, IProductRepository
{
// [...]
}
I've already read the two blog posts SharpRepository: Getting Started and SharpRepository: Configuration, but they both do not help me, since:
The used DIC is StructureMap, not Ninject.
The source code examples are incomplete (e.g. usage of not declared variables).
So my question: Can someone provide me with some source code example how-to to achieve the goal described above (sharing one Entity Framework DbContext instance between all repositories extending ConfigurationBasedRepository)?
First, you will need to install the SharpRepository.Ioc.Ninject NuGet package. There are extension methods in here for hooking up Ninject to handle the loading a generic repository and setting the dependency resolver that SharpRepository uses.
Where ever you are setting up your Ninject binding rules (all the calls to kernel.Bind<>), you will need to add:
kernel.BindSharpRepository();
Next, in your Global.asax, or App_Start code, or your Bootstrapper logic (where ever you are calling application startup code) you will need to add the following:
// kernel is the specific kernel that you are setting up all the binding for
RepositoryDependencyResolver.SetDependencyResolver(new NinjectDependencyResolver(kernel));
This will tell SharpRepository to use this Ninject Kernel when getting a new DbContext.
The last thing to do is to setup the rules for binding for the DbContext itself. If you are in a web application you will most likely want the scope of the DbContext to be per request. I personally don't use Ninject but I found this reference for using InRequestScope. I believe your code would look something like this:
kernel.Bind<DbContext>().To<MyCustomEfContext>().InRequestScope().WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["MyCustomEfContext"].ConnectionString);
Most people won't need this next piece but if you have custom logic in your CustomEfContext (I have an override for logging on calls to SaveChanges() for example), then you'll need to define your custom context type in the configuration file like so:
<repositories>
<repository name="ef5Repository" connectionString="CustomEfContext" cachingStrategy="standardCachingStrategy" dbContextType="My.Data.CustomEfContext, My.Data" factory="SharpRepository.Ef5Repository.Ef5ConfigRepositoryFactory, SharpRepository.Ef5Repository" />
</repositories>
Where dbContextType defines the type of the custom DbContext you are using using the full type, namespace syntax. If you do this then you'll need to set Ninject to Bind on the custom context by changing .Bind<DbContext>() to .Bind<CustomEfContext>(). But like I said normally you can use DbContext directly without an issue.
First of all, the solution provided in the answer by Jeff T works!
I will conclude the steps I took to make Ninject work in a ASP.NET MVC 4 + EF 5 project. It is important to mention that the Specific Repository pattern is implemented via SharpRepository in the following example.
Required software
Install Ninject and "Ninject.MVC3" (which also installs "Ninject.Web.Common") via NuGet.
Install SharpRepository, "SharpRepository for EF5" and "SharpRepository with Ninject IOC" via NuGet.
Define the Repository layer
Create a DbContext derived class, e.g. Domain.EfContext. It is the
"recommended way to work with context".
Declare all required DbSet<T> as public properties, e.g. public DbSet<Product> Products { get; set; }
Declare the following two constructors in the class Domain.EfContext:
public EfContext() : base() {}
public EfContext(string connectionName) : base(connectionName) {}
Define an interface for the Specific Repository, e.g.:
// TODO By extending IRepository, the interface implements default Create-Read-Update-Delete (CRUD) logic.
// We can use "traits" to make the repository more "specific", e.g. via extending "ICanInsert".
// https://github.com/SharpRepository/SharpRepository/blob/master/SharpRepository.Samples/HowToUseTraits.cs
public interface IProjectRepository : IRepository<Project>
{
// TODO Add domain specific logic here.
}
Define a class which is implementing the Specific Repository and inherits from SharpRepository.Repository.ConfigurationBasedRepository<T, TKey>, e.g.:
public class ProductRepository : ConfigurationBasedRepository<Product, int>, IProductRepository
{
// TODO Implement domain specific logic here.
}
Define the Consumer layer
Create a Controller, e.g. Controllers.ProductController.
public class ProductController : Controller
{
private IProductRepository Repository { get; private set; }
// TODO Will be used by the DiC.
public ProductController(IProductRepository repository)
{
this.Repository = repository;
}
}
Set up Dependency Injection (DI) via the Dependency Injection Container (DiC) Ninject
The file App_Start/NinjectWebCommon.cs is automatically created by Ninject.Web.Common and we can load our modules and register our services in the method RegisterServices(IKernel kernel) : void of the class NinjectWebCommon.
Here is the complete source code of that method for the example:
private static void RegisterServices(IKernel kernel)
{
kernel.BindSharpRepository();
RepositoryDependencyResolver.SetDependencyResolver(
new NinjectDependencyResolver(kernel)
);
string connectionString = ConfigurationManager.ConnectionStrings["EfContext"].ConnectionString;
kernel.Bind<DbContext>()
.To<EfContext>()
.InRequestScope()
.WithConstructorArgument("connectionString", connectionString);
kernel.Bind<IProductRepository>().To<ProductRepository>();
}
Define the following sharpRepository section in the Web.config:
<sharpRepository>
<repositories default="ef5Repository">
<repository name="ef5Repository"
connectionString="EfContext"
cachingStrategy="standardCachingStrategy"
dbContextType="Domain.EfContext, Domain"
factory="SharpRepository.Ef5Repository.Ef5ConfigRepositoryFactory, SharpRepository.Ef5Repository"
/>
</repositories>
</sharpRepository>
In addition, the connectionStrings section to make the example complete (I am using SQL Server LocalDB).
<connectionStrings>
<add name="EfContext" providerName="System.Data.SqlClient" connectionString="Data Source=(localdb)\v11.0;Initial Catalog=Domain;Integrated Security=True" />
</connectionStrings>
I hope that this conclusion helps other people to get ASP.NET MVC 4 together with Entity Framework 5 and SharpRepository up and running!
Please leave me a reply if I took one or more unnecessary steps or if you see possibilities to improve the architecture described in the example.
Btw, I had to add the dbContextType attribute to the repository section to make it work (in contrast to the answer of Jeff T).
EDIT (2013-08-28): Striked out unnecessary steps (not required with the latest version of SharpRepository).
I'd like to use NServiceBus profiles to override the concrete classes used in the Spring.net dependency injection for use in Integration Testing.
In my EndpointConfig class, I have a component being configured:
NServiceBus.Configure.Instance.Configurer.ConfigureComponent<RealCommunicator>(ComponentCallModelEnum.None);
(This bit is OK!)
I created a new profile:
public class StubThirdPartyProfile : NServiceBus.IProfile
{
}
And a behaviour class to implement it:
public class StubThirdPartyBehaviour : IHandleProfile<StubThirdPartyProfile>
{
public void ProfileActivated()
{
Configure.Instance.Configurer.ConfigureComponent<StubCommunicator>(ComponentCallModelEnum.None);
}
}
Both StubCommunicator and RealCommunicator implement the same interface and I was hoping that the profile would remove the old dependency and use the StubCommunicator instead but this is not the case. Is there a way to do this?
When the solution is run, I get the following error:
Spring.Objects.Factory.UnsatisfiedDependencyException:
Error creating object with name 'Namespace.CommandHandler' :
Unsatisfied dependency expressed through object property 'Communicator':
There are 2 objects of Type [Namespace.ICommunicator] for autowire by type,
when there should have been just 1 to be able to autowire property 'Communicator' of object
We're using the Spring.net framework in NServicebus configured as so:
Configure.With().SpringFrameworkBuilder()
.XmlSerializer().Log4Net()
.MsmqTransport()
.IsTransactional(true);
Instead of configuring the real component in the endpoint config class, consider registering it in a class which handles the other NServiceBus profiles - Lite, Integration, Production.