conditional DI with the help of config file - dependency-injection

How can we achieve conditional Dependency Injection with the help of Unity Application block config file ? Below is my piece of code.
namespace DependencyInjection
{
//UI
class Program
{
static void Main(string[] args)
{
IUnityContainer objContainer = new UnityContainer();
objContainer.LoadConfiguration(); //loads from app
Customer obj = objContainer.Resolve<Customer>();
obj.CustomerName = "test1";
obj.Add();
}
}
//ML
public class Customer
{
private IDAL Odal;
public string CustomerName { get; set; }
public Customer(IDAL iobj)
{
Odal = iobj;
}
public void Add()
{
Odal.Add();
}
}
//DAL
public interface IDAL
{
void Add();
}
public class SQLServerDAL:IDAL
{
public void Add()
{
Console.WriteLine("SQL Server inserted");
Console.ReadLine();
}
}
public class OracleDAL:IDAL
{
public void Add()
{
Console.WriteLine("Oracle inserted");
Console.ReadLine();
}
}
}
And my config file is like below:
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<container>
<register type="DependencyInjection.IDAL, DependencyInjection"
mapTo="DependencyInjection.SQLServerDAL,DependencyInjection"/>
</container>
</unity>
How can I achieve the following :
If(somecondition=true)
Customer object should resolve to SQLServerDal
Else
Customer object should resolve to OracleDal
Is it possible ? If yes, how ?

Related

When querying SQL with EF6 from a WebJob, query fails because it's trying to get a pluralized version of the table

My code looks like this:
public static void DoSomething(TextWriter log)
{
log.WriteLine("Hey man! I'm running!");
try
{
using (MyDBContext context = new MyDBContext())
{
MemberMaster mm = context.MemberMaster.SingleOrDefault(m => m.MemberMasterId == 1);
if (mm != null)
{
log.WriteLine(string.Format("MemberMasterId = {0}, Username = {1}", mm.MemberMasterId, mm.UserName));
}
else
{
log.WriteLine("Could not find Member with MembermasterId = 1");
}
}
}
catch (Exception ex)
{
log.WriteLine(ex.Message);
}
log.WriteLine("Done!");
}
MyDBContext.cs looks like this:
public class MyDBContext : DbContext
{
public MyDBContext() : this("MyDb")
{
}
public MyDBContext(string connectionName) : base(connectionName) { }
public DbSet<MemberMaster> MemberMaster { get; set; }
}
I've tried to add a modelBuilder to remove Pluralizing names but that simply results in an error about the DB Context having changed....use code first...etc..etc...
Is there a better way to do this? The WebJob is being deployed via AZure with a .ZIP file and resides in the same AppService as my Website.
I turn off plurallizing on Sets and Tables by overriding the OnModelCreating, to keep both named the same, and have had no problem:
public class MyDBContext : DbContext
{
static MyDBContext()
{
Database.SetInitializer<DbContext>(null);
}
public MyDBContext() : this("MyDb")
{
}
public MyDBContext(string connectionName) : base(connectionName) { }
public DbSet<MemberMaster> MemberMaster { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingEntitySetNameConvention>();
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
base.OnModelCreating(modelBuilder);
}
}

No parameterless constructor defined for this object with Dependency Resolver

I'm currently following "Dependancy Injection on asp net mvc 5 tutorial" in youtube. https://www.youtube.com/watch?v=27DQn6kZDFM
I follow as he said but I'm having this error.
No parameterless constructor defined for this object.
My Controller is UnityDemoController
public class UnityDemoController : Controller
{
private readonly ILocalWeaherServiceProvider _localWeaherServiceProvider;
public UnityDemoController(ILocalWeaherServiceProvider localWeaherServiceProvider)
{
_localWeaherServiceProvider = localWeaherServiceProvider;
}
//
// GET: /UnityDemo/
public ActionResult Index()
{
string currentWeatherInMyArea = _localWeaherServiceProvider.GetLocalWeatherByZipCode("0006");
return View();
}
}
IocConfiguration.cs This Configuration is under App_Start folder
public static class IocConfiguration
{
public static void ConfigureIocUnityContaioner()
{
IUnityContainer container = new UnityContainer();
RegisterServices(container);
DependencyResolver.SetResolver(new MyUnityDependancyResolver(container));
}
private static void RegisterServices(IUnityContainer container)
{
container.RegisterType<ILocalWeaherServiceProvider, LocalWeatherServiceProvider>(); // This means when somebody call/need ILocalWeaherServiceProvider then provide new Instance of the LocalWeatherServiceProvider
}
}
MyUnityDependancyResolver.cs
public class MyUnityDependancyResolver : IDependencyResolver
{
private IUnityContainer _unityContainer;
public MyUnityDependancyResolver(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
}
public object GetService(Type serviceType)
{
try
{
return _unityContainer.Resolve(serviceType);
}
catch (Exception)
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return _unityContainer.ResolveAll(serviceType);
}
catch (Exception)
{
return new List<object>();
}
}
}
Interface ILocalWeaherServiceProvider
public interface ILocalWeaherServiceProvider
{
string GetLocalWeatherByZipCode(string zipcode);
}
Service Class LocalWeatherServiceProvider
public class LocalWeatherServiceProvider : ILocalWeaherServiceProvider
{
public string GetLocalWeatherByZipCode(string zipcode)
{
return "Its is snowing right now in your Area : " + zipcode;
}
}
I have added Unity.
Can anyone tell me what went wrong here?
And avoid these kinds of error what are the things that I should look into these coding level?
I found out the solution by referring to below link.
https://cuttingedge.it/blogs/steven/pivot/entry.php?id=97
Change the UnityDemoController class as below.
public class UnityDemoController : Controller
{
private readonly ILocalWeaherServiceProvider _localWeaherServiceProvider;
public UnityDemoController() : this(new LocalWeatherServiceProvider())
{
}
public UnityDemoController(ILocalWeaherServiceProvider localWeaherServiceProvider)
{
_localWeaherServiceProvider = localWeaherServiceProvider;
}
//
// GET: /UnityDemo/
public ActionResult Index()
{
string currentWeatherInMyArea = _localWeaherServiceProvider.GetLocalWeatherByZipCode("0006");
return View();
}
}

AutoMapper+xUnit: Missing type map configuration or unsupported mapping

I cannot figure this one out. I have a N-Tier ASP.MVC application and I am writing my first Unit Test and it seems to fail on my AutoMapper configuration. I have used AutoMapper a million times and never had any problems using it.
I'm sure I am missing something simple, but I have been staring at this for 24 hours now.
Class Library: APP.DOMAIN
public class User : IEntity<int>
{
public int Id { get; set; }
[StringLength(20), Required]
public string UserName { get; set; }
}
Class Library: APP.SERVICE
References App.Domain
public class UserViewModel
{
public int Id { get; set; }
public string UserName { get; set; }
}
I have my AutoMapper bootstrapper in the service layer.
public static class AutoMapperBootstrapper
{
public static void RegisterMappings()
{
Mapper.CreateMap<User, UserViewModel>();
}
}
UserService.cs
public class UserService : IUserService
{
private readonly IUserRepository _userRepository;
public UserService(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public List<UserViewModel> GetUsers()
{
var users = _userRepository.GetAll();
if (users == null)
{
throw new Exception("No users found.");
}
return Mapper.Map<List<UserViewModel>>(users); // FAILS ON AUTOMAPPER
}
}
ASP.MVC Layer: APP.WEB
References App.Service
private void Application_Start(object sender, EventArgs e)
{
// Register AutoMapper
AutoMapperBootstrapper.RegisterMappings();
Mapper.AssertConfigurationIsValid();
// Code that runs on application startup
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
Unit Test Layer:
public class TestUserRepository :IUserRepository
{
public IEnumerable<User> GetAll()
{
var users = new List<User>()
{
new User { Id = 1, UserName = "Mary"},
new User { Id = 2, UserName = "Joe"}
};
return users;
}
}
public class UserServiceTest
{
private IUserService _userService;
private readonly IUserRepository _userRepository;
public UserServiceTest()
{
_userRepository = new TestUserRepository();
}
[Fact]
public void GetUsers_Should_Return_Correct_Number_Of_Users()
{
// Arrange
_userService = new UserService(_userRepository);
// Act
var result = _userService.GetUsers(); // FAILS ON AUTOMAPPER
// Assert
Assert.True(result.Any(u => u.UserName == "Mary"));
}
}
Failing Test Message:
*** Failures ***
Exception
AutoMapper.AutoMapperMappingException: AutoMapper.AutoMapperMappingException : Missing type map configuration or unsupported mapping.
Mapping types:
User -> UserViewModel
App.Data.Model.User -> App.Service.ViewModels.UserViewModel
Destination path:
List`1[0]
Source value:
App.Data.Model.User
at App.Service.Services.UserService.GetUsers() in D:\Repositories\App\App.Service\Services\UserService.cs:line 36
at App.Tests.Service.Tests.UserServiceTest.GetUsers_Should_Return_Correct_Number_Of_Users() in D:\Repositories\App\App.Tests\Service.Tests\UserServiceTest.cs:line 34
A little late to the party but have you tried setting the mapping before running the test?
public class UserServiceTest
{
public UserServiceTest()
{
// register the mappings before running the test
AutoMapperBootstrapper.RegisterMappings();
}
...
}
What we would need to do is Inject Custom Mapper Mock as given below. Add all those custom profiles that you have used for that particular class that you are unit testing and inject ConfigureMapper() in the Constructor of that class which is expecting IMapper Object
public IMapper ConfigureMapper()
{
var config = new MapperConfiguration(cfg =>
{
cfg.AddProfile<CustomProfile>();
cfg.AddProfile<UserCustomProfile>();
cfg.AddProfile<UserWorkProfile>();
});
return config.CreateMapper();
}
Hope this solves the issue.
I'm not sure what the problem is, it's been a while since I've last used AutoMapper, but I'm quite sure that the following will work:
return users.Select(Mapper.Map<UserViewModel>);
I have a problem with this line:
var authorDTO = mapper.Map<AuthorCreationDTO>(AuthorinsideDB);
So I change the version of Autormapper
from:
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="7.0.0" />
to
Version="6.0.0"
and it worked.

Register singleton that implements two interfaces

What is the correct way to configure an object in structuremap that implements two interface but is a singleton.
For example class Main implements both iMainFrmService and iActiveJobService.
Here is what I've tried, but I'm not sure if it's correct.
ObjectFactory.Initialize(pExpression=>
{
pExpression.ForSingletonOf<iMainFrmService>().Use<Main>();
pExpression.ForSingletonOf<iActiveJobService>().Use<Main>();
});
As mentioned in the answer linked to from the comment above, x.Forward< , >() does give the singleton for both the interfaces.
Please check out this dotnetfiddle for a working sample. Here is snippet that is posted there:
using System;
using StructureMap;
namespace StructureMapSingleton {
public class Program {
public static void Main(string [] args) {
Bootstrapper.Initialize();
var mainService = Bootstrapper.GetInstance<IMainService>();
mainService.MainMethod();
var secondaryService = Bootstrapper.GetInstance<ISecondaryService>();
secondaryService.SecondMethod();
Console.ReadLine();
}
}
public interface IMainService {
void MainMethod();
}
public interface ISecondaryService {
void SecondMethod();
}
public class MainService : IMainService, ISecondaryService {
private int _invokeCount;
public void MainMethod() {
this._invokeCount++;
Console.WriteLine("In MainService: MainMethod ({0})", this._invokeCount);
}
public void SecondMethod() {
this._invokeCount++;
Console.WriteLine("In MainService: SecondMethod ({0})", this._invokeCount);
}
}
public class Bootstrapper {
private static Container _container;
public static void Initialize() {
_container = new Container(x => {
x.For<IMainService>().Singleton().Use<MainService>();
//x.For<ISecondaryService>().Singleton().Use<MainService>();
x.Forward<IMainService, ISecondaryService>();
});
}
public static T GetInstance<T>() {
return _container.GetInstance<T>();
}
}
}

Structuremap No parameterless constructor defined for this object

I'm a newbie to StructureMap, and I've been trying to fix that error for some time now.
Just can't figure out how to fix it and where am I doing wrong.
I even set up a template MVC4 site, with nothing in it and still getting that error.
Can someone please help me out ?
public static class IoC {
public static IContainer Initialize() {
ObjectFactory.Initialize(x =>
{
x.Scan(scan =>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
});
x.For<IDbSession>().Use(() => MvcApplication.DbSession);
x.For<IDbService>().Use<DbService>();
});
return ObjectFactory.Container;
}
}
public class HomeController : Controller
{
protected readonly IDbService _dbService;
public HomeController(IDbService dbService)
{
_dbService = dbService;
}
...
}
public interface IDbSession : IDisposable
{
void Commit();
void Rollback();
}
public interface IDbService
{
StudentsService Students { get; }
CoursesService Courses { get; }
...
}
public class DbService : IDbService
{
private readonly IDbSession _dbSession;
public StudentsService Students { get; }
public CoursesService Courses { get; }
...
public DbService(IDbSession dbSession)
{
_dbSession = dbSession;
}
}
public class MvcApplication : System.Web.HttpApplication
{
private static readonly string _connectionString;
private static readonly IDbSessionFactory _dbSessionFactory;
public static IDbSession DbSession
{
get { return (IDbSession)HttpContext.Current.Items["Current.DbSession"]; }
private set { HttpContext.Current.Items["Current.DbSession"] = value; }
}
static MvcApplication()
{
_connectionString= ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
_dbSessionFactory = new DbSessionFactory(_connectionString);
}
protected MvcApplication()
{
BeginRequest += delegate
{
DbSession = _dbSessionFactory.Create();
};
EndRequest += delegate
{
if (DbSession != null)
DbSession.Dispose();
};
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterAuth();
}
}
You must configure the dependency resolver to handle parameters in a Controller's constructor. You can find out here how: http://ardalis.com/How-Do-I-Use-StructureMap-with-ASP.NET-MVC-3

Resources