For starters I'm using this module:
public class AutoMapperModule : NinjectModule
{
public override void Load()
{
Bind<ITypeMapFactory>().To<TypeMapFactory>();
foreach (var mapper in MapperRegistry.AllMappers())
{
Bind<IObjectMapper>().ToConstant(mapper);
}
Bind<AutoMapper.ConfigurationStore>().ToSelf().InSingletonScope().WithConstructorArgument("mappers", ctx => ctx.Kernel.GetAll<IObjectMapper>());
Bind<IConfiguration>().ToMethod(ctx => ctx.Kernel.Get<AutoMapper.ConfigurationStore>());
Bind<IConfigurationProvider>().ToMethod(ctx => ctx.Kernel.Get<AutoMapper.ConfigurationStore>());
Bind<IMappingEngine>().To<MappingEngine>();
}
}
I have a bootstrapper class for all my maps
public static void Configure(IKernel kernel)
{
Mapper.Initialize(map => map.ConstructServicesUsing(t => kernel.Get(t)));
}
I have resolvers that access the database and need the repositories injected.
It's working as is, but I can't figure out how to get it to work with unit tests and IMappingEngine.
public HomeController(IMappingEngine mappingEngine)
{
_mappingEngine = mappingEngine;
}
_mappingEngine.Map throws an exception because no map exists. Mapper.Map works.
What am I missing? How do I get my bootstrapper to work with unit tests so that the repositories in my resolvers to use the fake/mock repositories?
Try changing the mapping's bind.
Bind<IMappingEngine>().ToMethod(ctx => Mapper.Engine);
Related
I have service base class and different subclasses inherit from it how I can inject all services implement this class
public abstract class AppService
{
public string ServiceName {get;set;}
}
and I have other classes
public class CountryService:AppService
{
public list<Countries> getCountryByName(string name){
return ......
}
}
public class TestService:AppService
{
public void Test(){
return ......
}
}
How I can auto inject any class inherit from AppService without need to add this class inside StartUp manually
Update*****************
I am using the following to register services in startUp
services.Configure<ServiceConfig>(config =>
{
config.Services = new List<ServiceDescriptor>(services);
config.Path = "/listservices";
});
ContainerSetup.InitializeWeb(Assembly.GetExecutingAssembly(), services);
and in Services project here is the container Setup :
public static IServiceProvider InitializeWeb(Assembly webAssembly, IServiceCollection services) =>
new AutofacServiceProvider(BaseAutofacInitialization(setupAction =>
{
setupAction.Populate(services);
setupAction.RegisterAssemblyTypes(webAssembly).AsSelf();
}));
public static IContainer BaseAutofacInitialization(Action<ContainerBuilder> setupAction = null)
{
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
.Where(t => t.BaseType == typeof(AppService))
.AsSelf();
setupAction?.Invoke(builder);
return builder.Build();
}
Still Getting the error
An unhandled exception occurred while processing the request.
InvalidOperationException: Unable to resolve service for type
You can use AutoFacs built in AssemblyScanning for this.
The following is an example that will register all classes that inherit from AppService as their concrete type.
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
.Where(t => t.BaseType == typeof(AppService))
.AsSelf();
This will allow you to resolve CountryService or TestService from container.
I have an ASP.Net Core 2.1 using Entity framework with an Angular 5 front-end and Web Api controller for the back-end.
It works fine as is but now I wan to change it so the database connection string is NOT hard coded.
I am following this:
https://learn.microsoft.com/en-us/ef/core/miscellaneous/connection-strings
But it does not work. I get:
An unhandled exception occurred while processing the request.
InvalidOperationException: No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions object in its constructor and passes it to the base constructor for DbContext.
'((Microsoft.EntityFrameworkCore.Internal.InternalDbSet)db.TblEmployee).Local' threw an exception of type 'System.InvalidOperationException'
The logic paths is:
The home page appears. I then click on the "Current Employees" menu item.
It goes into the Angular service and executes the getEmployees() method which executes the web api method.
It goes to the Web api controller and executes the - GetAllEmployee() method which executes the employee data access layers method.
It goes to the employee data access layer class (I instantiate the dbContext here). I have a break point on the return statement. If I hover over the return statement I see the error. And of course when I continue, the app fails.
My database context class is:
namespace Angular5NetcoreEF.Models
{
public partial class DBAngular5NetcoreEFContext : DbContext
{
public DBAngular5NetcoreEFContext()
{
}
public DBAngular5NetcoreEFContext(DbContextOptions<DBAngular5NetcoreEFContext> options)
: base(options)
{
}
public virtual DbSet<TblCities> TblCities { get; set; }
public virtual DbSet<TblEmployee> TblEmployee { get; set; }
//protected override void OnConfiguring(DbContextOptionsBuilder
optionsBuilder)
//{
// if (!optionsBuilder.IsConfigured)
// {
// optionsBuilder.UseSqlServer("Server=
// (localdb)\\mssqllocaldb;Database=DBAngular5NetcoreEF;
// Trusted_Connection=True; MultipleActiveResultSets=true");
// }
//}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<TblCities>(entity =>
{
entity.HasKey(e => e.CityId);
entity.ToTable("tblCities");
entity.Property(e => e.CityId).HasColumnName("CityID");
entity.Property(e => e.CityName)
.IsRequired()
.HasMaxLength(20)
.IsUnicode(false);
});
modelBuilder.Entity<TblEmployee>(entity =>
{
entity.HasKey(e => e.EmployeeId);
entity.ToTable("tblEmployee");
entity.Property(e => e.EmployeeId).HasColumnName("EmployeeID");
entity.Property(e => e.City)
.IsRequired()
.HasMaxLength(20)
.IsUnicode(false);
entity.Property(e => e.Department)
.IsRequired()
.HasMaxLength(20)
.IsUnicode(false);
entity.Property(e => e.Gender)
.IsRequired()
.HasMaxLength(6)
.IsUnicode(false);
entity.Property(e => e.Name)
.IsRequired()
.HasMaxLength(20)
.IsUnicode(false);
});
}
}
}
So per the instructions, I commented out the OnConfiguring method above where I was doing the hard coding.
I added to the appsettings.json file:
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"ConnectionStrings": {
"DBAngular5NetcoreEFDatabase": "Server=(localdb)\\mssqllocaldb;Database=DBAngular5NetcoreEF;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"AllowedHosts": "*"
}
I added to my Startup.cs - ConfigureServices method :
using Angular5NetcoreEF.Models;
using Microsoft.EntityFrameworkCore;
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
// In production, the Angular files will be served from this directory.
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
// I added this.
services.AddDbContext<DBAngular5NetcoreEFContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DBAngular5NetcoreEFDatabase")));
}
You should not instantiate a new instance of DBAngular5NetcoreEFContext inside EmplyeeDataAccessLayer. Instead, you should inject it.
You also need to register EmployeeDataAccessLayer in DI container and inject it to EmployeeController.
Basically, you let the DI container resolves the dependencies for you.
public class Startup
{
...
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<DBAngular5NetcoreEFContext>
(options => options.UseSqlServer(Configuration.GetConnectionString("DBAngular5NetcoreEFDatabase")));
services.AddScoped<EmployeeDataAccessLayer>();
...
}
...
}
public class EmployeeController : Controller
{
private readonly EmployeeDataAccessLayer objemployee;
public EmployeeController(EmployeeDataAccessLayer employeeDataAccessLayer)
{
objemployee = employeeDataAccessLayer;
}
}
public class EmployeeDataAccessLayer
{
private readonly DBAngular5NetcoreEFContext _db;
public EmployeeDataAccessLayer(DBAngular5NetcoreEFContext db)
{
_db = db;
}
...
}
Another thought is to use interface instead of concrete implementation. It'll make your life easier when you implement unit tests.
the problem you are facing is fact, that you're not using Dependency Injection pattern.
First of all you need to insert DbContext from services via dependency injection by constructor by
public class EmployeeDataAccessLayer
{
private DBAngular5NetcoreEFContext _db;
public EmployeeDataAccessLayer(DBAngular5NetcoreEFContext db)
{
_db = db;
}
}
Second, all references should also be injected, so in every layer of the application, for each class like your EmployeeDataAccessLayer you should
First: Register it with dependency injection by using in Startup.cs -> ConfigureServices(): i.e.services.AddScoped<EmployeeDataAccessLayer>();,
Then inject it into constructor of Controller like in case above.
You can learn about dependency injection and example scopes (Scoped,Transient,Singleton...) from i.e. Doc
For security, in your current scenario to check when you have unconfigured context, you can do something like:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
throw new Exception("Context not configured");
}
}
As well as "temporary disable" empty constructor
I'm trying to inject my dependencies into an automapper profile; the profile is like so;
public class UserProfile : Profile
{
private IIdentityService _identity;
public UserProfile(IIdentityService identity)
{
_identity = identity;
}
protected override void Configure()
{
Mapper.CreateMap<User, UserViewModel>();
Mapper.CreateMap<List<User>, UsersViewModel>()
.ForMember(d => d.Users, o => o.MapFrom(s => s))
.ForMember(d => d.Domains, o => GetDomains());
}
public List<string> GetDomains()
{
return _identity.AvailableDomains();
}
}
Several articles suggest using code like so;
kernel.Bind<IMappingEngine>().ToMethod(ctx => Mapper.Engine);
I've tried adding this in NinjectWebCommon (both in CreateKernel and RegisterServices), but i'm still getting runtime errors as AutoMapper can't resolve without a default (empty) constructor. I'm guessing the issue is with the Ninject side of things (my implementation of it that is).
Error activating IntPtr
I'm trying to configure FluentSecurity (v.1.4) with Ninject (v.3) in an ASP.NET MVC 4 application.
I can't set up the ResolveServicesUsing() configuration expression without throwing the above error.
SecurityConfigurator.Configure(
configuration =>
{
configuration.ResolveServicesUsing(
DependencyResolver.Current.GetServices,
DependencyResolver.Current.GetService);
...
I've also tried using another overload for ResolveServicesUsing()
configuration.ResolveServicesUsing(
type => DependencyResolver.Current.GetServices(type));
FluentSecurity needs to be configured with Ninject to inject the method for finding my users' roles and also for the PolicyViolationHandler implementations.
UPDATE
I've found I can leave out the offending lines and still have my GetRolesFrom() implementation called (hurrah):
configuration.GetRolesFrom(
() =>
((IPersonManager)DependencyResolver
.Current
.GetService(typeof(IPersonManager)))
.GetCurrentUserRoles());
I still can't get my PolicyViolationHandler to work, however:
public class RequireRolePolicyViolationHandler : IPolicyViolationHandler
{
public ActionResult Handle(PolicyViolationException exception)
{
return new RedirectToRouteResult(
new RouteValueDictionary(
new
{
action = "AccessDenied",
controller = "Home"
}));
}
}
I'm doing the binding in a NinjectModule like this:
public class SecurityModule : NinjectModule
{
public override void Load()
{
this.Kernel.Bind<IPolicyViolationHandler>()
.To<RequireRolePolicyViolationHandler>();
}
}
Error activating IntPtr
Unfortunately you havn't posted the complete StackTrace. But usually you will get this exception when injecting a Func to some class without having a binding or using the Factory extension.
I use Fluent Security with Ninject as IOC container.
In your Fluent Security configuration, you need to set the service locator to the NinjectServiceLocator.
public static void Configure(IKernel kernel)
{
var locator = new NinjectServiceLocator(kernel);
ServiceLocator.SetLocatorProvider(() => locator);
SecurityConfigurator.Configure(
configuration =>
{
configuration.GetAuthenticationStatusFrom(() => HttpContext.Current.User.Identity.IsAuthenticated);
....
}
You can get the locator here.
Hope this helps
Im writing a test for an automapper map. One of the destination members in the map requires a value resolver, and that value resolver has service dependencies which are injected. I want to use the real implementation for the resolver (since thats part of the map im testing) but Id like to use mocks for the dependencies the resolver has.
Ofcourse I want to try to avoid using an ioc container for in my tests, but how do I easily resolve my value resolver's dependencies without one?
This is my rather simplified example, in the real case there are several resolvers with sometimes many dependencies, and I really dont like to basically implement my own dependency resolver in my tests. Should I use a lightweight ioc container?
[TestFixture]
public class MapperTest
{
private IMyService myService;
[SetUp]
public void Setup()
{
Mapper.Initialize(config =>
{
config.ConstructServicesUsing(Resolve);
config.AddProfile<MyProfile>();
});
}
public T Resolve<T>()
{
return (T) Resolve(typeof (T));
}
public object Resolve(Type type)
{
if (type == typeof(MyValueResolver))
return new MyValueResolver(Resolve<IMyService>());
if (type == typeof(IMyService))
return myService;
Assert.Fail("Can not resolve type " + type.AssemblyQualifiedName);
return null;
}
[Test]
public void ShouldConfigureCorrectly()
{
Mapper.AssertConfigurationIsValid();
}
[Test]
public void ShouldMapStuff()
{
var source = new Source() {...};
var child = new Child();
myService = MockRepository.GenerateMock<IMyService>();
myService .Stub(x => x.DoServiceStuff(source)).Return(child);
var result = Mapper.Map<ISource, Destination>(source);
result.Should().Not.Be.Null();
result.Child.Should().Be.SameInstanceAs(child);
}
}
public class MyProfile : Profile
{
protected override void Configure()
{
base.Configure();
CreateMap<ISource, Destination>()
.ForMember(m => m.Child, c => c.ResolveUsing<MyResolver>());
}
}
public class MyResolver: ValueResolver<ISource, Destination>
{
private readonly IMyService _myService;
public MyResolver(IMyService myService)
{
_myService = myService;
}
protected override Child ResolveCore(ISource source)
{
return _myService.DoServiceStuff(source);
}
}
}
Here's one solution, but basically its what iv done already:
http://groups.google.com/group/automapper-users/browse_thread/thread/aea8bbe32b1f590a/f3185d30322d8109
The suggestion is to use a service locator which are set up differently depending on test or real implementation.