Autofac and DI for ValidationAttribute - dependency-injection

I have the following validation attribute class:
public class ZipCodeValidationAttribute : ValidationAttribute
{
private readonly IValidationRepository _repository;
public override bool IsValid(object value)
{
var repository = _repository;
return repository.IsPostalCodeValid((string) value);
}
}
To test I am trying to use Autofac as my IOC and use property injection. I've set up the test as follows:
[TestMethod]
public void When_PostalCodeAttribute_Given_ValidPostalCode_Then_SystemReturnsTrue()
{
// arrange
var value = "53051";
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterType<ValidationRepository>().As<IValidationRepository>().InstancePerDependency();
containerBuilder.RegisterType<ZipCodeValidationAttribute>().PropertiesAutowired();
var container = containerBuilder.Build();
var attrib = container.Resolve<ZipCodeValidationAttribute>();
// act
var result = attrib.IsValid(value);
// assert
Assert.IsTrue(result);
}
During the test my repository isn't being resolved. New to Autofac and hoping someone can point me in the right direction.

I solved the whole problem (triggering DI under the control of Validator.TryValidate etc / ASP.NET MVC etc) in this answer, enabling one to write:
class MyModel
{
...
[Required, StringLength(42)]
[ValidatorService(typeof(MyDiDependentValidator), ErrorMessage = "It's simply unacceptable")]
public string MyProperty { get; set; }
....
}
public class MyDiDependentValidator : Validator<MyModel>
{
readonly IUnitOfWork _iLoveWrappingStuff;
public MyDiDependentValidator(IUnitOfWork iLoveWrappingStuff)
{
_iLoveWrappingStuff = iLoveWrappingStuff;
}
protected override bool IsValid(MyModel instance, object value)
{
var attempted = (string)value;
return _iLoveWrappingStuff.SaysCanHazCheez(instance, attempted);
}
}
With some helper classes (look over there), you wire it up e.g. in ASP.NET MVC like so in the Global.asax :-
DataAnnotationsModelValidatorProvider.RegisterAdapterFactory(
typeof(ValidatorServiceAttribute),
(metadata, context, attribute) =>
new DataAnnotationsModelValidatorEx(metadata, context, attribute, true));

You need to declare the repository as a property to be auto wired by Autofac.
public class ZipCodeValidationAttribute : ValidationAttribute
{
public IValidationRepository Repository { get; set; }
public override bool IsValid(object value)
{
return Repository .IsPostalCodeValid((string) value);
}
}

Related

Entity Framework, Unity, and MVC

I have a multi tier application using Entity Framework, MVC and Unity.
The basic setup is like this:
EF Data Access Layer
public class MyDataProvider : DbContext, IMyDataProvider
{
public MyDataProvider(SqlConnection existingConnection, bool contextOwnsConnection)
: base(existingConnection,contextOwnsConnection)
{
((IObjectContextAdapter)this).ObjectContext.CommandTimeout = 60;
Configuration.LazyLoadingEnabled = true;
Configuration.ValidateOnSaveEnabled = true;
Configuration.ProxyCreationEnabled = true;
Configuration.AutoDetectChangesEnabled = true;
}
public new IDbSet<TModel> Set<TModel>() where TModel : class
{
return base.Set<TModel>();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new EmployeeMapping());
base.OnModelCreating(modelBuilder);
}
public abstract class ServiceBase<TModel> : IDisposable, IService<TModel> where TModel : class, IModel
{
[Dependency]
public IMyDataProvider MyDataProvider { get; set; }
...
}
All services inherit from this class
I then inject specific services into the Business Logic Layer like so:
public class GetEmployees
{
[Dependency("EmployeeService")]
public IEmployeeService EmployeeService { get; set;
public IQueryable<Employee> GetAllEmployees()
{
return EmployeeService.GetTable();
}
...
}
In MVC I use a controller factory
public class MyControllerFactory : DefaultControllerFactory
{
private IUnityContainer _container;
public MyControllerFactory(IUnityContainer container)
{
_container = container;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType != null)
{
return _container.Resolve(controllerType) as IController;
}
else
{
return base.GetControllerInstance(requestContext, controllerType);
}
}
Global.asax
private static IUnityContainer InitContainer()
{
IUnityContainer unityContainer = new UnityContainer();
Bootstrapper bootstrapper = new Bootstrapper(unityContainer);
return unityContainer;
}
I pass the instance of UnityContainer into the Bootstrapper class. The Bootstrapper class self registers all assemblies.
In the MVC Controllers, I inject the Business Logic like so:
public class EmployeeController
{
[Dependency("GetEmployees")]
public IBusinessLogic GetEmployees_Operations { get; set; }
public ActionResult EmployeeMain()
{
var employees = GetEmployees_Operations.GetAllEmployees();
...
}
}
This all works great up to a point. Every so often I will get an exception thrown from MyDataProvider class: "EntityConnection can only be constructed with a closed DbConnection". This seems to happen during high use of the MVC site. The exception is simple enough to understand, but how should I go about fixing it?
I found that changing how I instantiate the business logic class from a field on the controller to inside the ActionResult method, I don't recieve the exception.
For example:
public class EmployeeController
{
//[Dependency("GetEmployees")]
//public IBusinessLogic GetEmployees_Operations { get; set; }
public ActionResult EmployeeMain()
{
IBusinessLogic GetEmployees_Operations = _ioc_Bootstrapper.Resolve(typeof(IBusinessLogic), "GetEmployees") as IBusinessLogic;
var employees = GetEmployees_Operations.GetAllEmployees();
...
}
}
Have I completely missed the boat on this and implemented Unity incorrectly?
Bootstrapper code
private void RegisterDAL(String assembly)
{
var currentAssembly = Assembly.LoadFrom(assembly);
var assemblyTypes = currentAssembly.GetTypes();
foreach (var assemblyType in assemblyTypes)
{
...
if (assemblyType.FullName.EndsWith("Provider"))
{
foreach (var requiredInterface in assemblyType.GetInterfaces())
{
if (requiredInterface.FullName.EndsWith("DataProvider"))
{
var typeFrom = assemblyType.GetInterface(requiredInterface.Name);
var typeTo = assemblyType;
var injector = GetInjectorConstructor(assemblyType.Module.Name);
RegisterType(typeFrom, typeTo, false, injector);
}
}
continue;
}
...
}
private InjectionConstructor GetInjectorConstructor(String moduleName)
{
...
connString = String.Concat("Data Source=MySqlServer, ";Initial Catalog=", catalogName, ";Application Name=", applicationName, ";Integrated Security=True; );
var conn = new SqlConnection(connString);
return new InjectionConstructor(conn, true);
}

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.

Intranet Application - Data Access in separate project

I have an MVC intranet application which uses EF 6. I have setup the DataAccess project in a separate class library which has EF 6 referenced. I have an entity which implements an interface:
public interface IAuditable
{
DateTime CreatedDateTime { get; set; }
string CreatedBy { get; set; }
}
public class Collection : IAuditable
{
// Properties
}
However, in the SaveChanges method I obviously don't have access to HttpContext.Current.User.Identity.Name as it is in a separate class library, so I was wondering how one would set this in SaveChanges?
public override int SaveChanges()
{
var addedEntries = ChangeTracker.Entries().Where(x => x.State == EntityState.Added);
foreach (var dbEntityEntry in addedEntries)
{
var entity = dbEntityEntry.Entity as IAuditable;
if (entity != null)
{
entity.CreatedDateTime = DateTime.Now;
// how do I set entity.CreatedBy = HttpContext.Current.User.Identity.Name?
}
}
return base.SaveChanges();
}
Edit
Following on from #CodeCaster solution, I have the following:
[BreezeController]
public class BreezeController : ApiController
{
private readonly BTNIntranetRepository _repository;
public BreezeController(BTNIntranetRepository repository)
{
_repository = repository;
_repository.LoggedInUser = HttpContext.Current.User.Identity.Name;
}
// Methods
}
But HttpContext.Current.User is null
This can be solved in many ways.
You're not really showing relevant code, but you can for example give the library class you expose a public string LoggedInUser (or ActingUser or give it a name) property which you set when instantiating it:
public class SomeController : Controller
{
private IDataSource _dataSource;
public SomeController(IDataSource dataSource)
{
_dataSource = dataSource;
_dataSource.LoggedInUser = HttpContext.Current.User.Identity.Name
}
}
You can then simply use that property in your IDataSource.SaveChanges() method:
public override int SaveChanges()
{
// ...
entity.CreatedBy = this.LoggedInUser;
}

Where to place AutoMapper.CreateMaps?

I'm using AutoMapper in an ASP.NET MVC application. I was told that I should move the AutoMapper.CreateMap elsewhere as they have a lot of overhead. I'm not too sure how to design my application to put these calls in just 1 place.
I have a web layer, service layer and a data layer. Each a project of its own. I use Ninject to DI everything. I'll utilize AutoMapper in both web and service layers.
So what are your setup for AutoMapper's CreateMap? Where do you put it? How do you call it?
Doesn't matter, as long as it's a static class. It's all about convention.
Our convention is that each "layer" (web, services, data) has a single file called AutoMapperXConfiguration.cs, with a single method called Configure(), where X is the layer.
The Configure() method then calls private methods for each area.
Here's an example of our web tier config:
public static class AutoMapperWebConfiguration
{
public static void Configure()
{
ConfigureUserMapping();
ConfigurePostMapping();
}
private static void ConfigureUserMapping()
{
Mapper.CreateMap<User,UserViewModel>();
}
// ... etc
}
We create a method for each "aggregate" (User, Post), so things are separated nicely.
Then your Global.asax:
AutoMapperWebConfiguration.Configure();
AutoMapperServicesConfiguration.Configure();
AutoMapperDomainConfiguration.Configure();
// etc
It's kind of like an "interface of words" - can't enforce it, but you expect it, so you can code (and refactor) if necessary.
EDIT:
Just thought I'd mention that I now use AutoMapper profiles, so the above example becomes:
public static class AutoMapperWebConfiguration
{
public static void Configure()
{
Mapper.Initialize(cfg =>
{
cfg.AddProfile(new UserProfile());
cfg.AddProfile(new PostProfile());
});
}
}
public class UserProfile : Profile
{
protected override void Configure()
{
Mapper.CreateMap<User,UserViewModel>();
}
}
Much cleaner/more robust.
You can really put it anywhere as long as your web project references the assembly that it is in. In your situation I would put it in the service layer as that will be accessible by the web layer and the service layer and later if you decide to do a console app or you are doing a unit test project the mapping configuration will be available from those projects as well.
In your Global.asax you will then call the method that sets all of your maps. See below:
File AutoMapperBootStrapper.cs
public static class AutoMapperBootStrapper
{
public static void BootStrap()
{
AutoMapper.CreateMap<Object1, Object2>();
// So on...
}
}
Global.asax on application start
just call
AutoMapperBootStrapper.BootStrap();
Now some people will argue against this method violates some SOLID principles, which they have valid arguments. Here they are for the reading.
Configuring Automapper in Bootstrapper violates Open-Closed Principle?
Update: The approach posted here is no more valid as SelfProfiler has been removed as of AutoMapper v2.
I would take a similar approach as Thoai. But I would use the built-in SelfProfiler<> class to handle the maps, then use the Mapper.SelfConfigure function to initialize.
Using this object as the source:
public class User
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime BirthDate { get; set; }
public string GetFullName()
{
return string.Format("{0} {1}", FirstName, LastName);
}
}
And these as the destination:
public class UserViewModel
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class UserWithAgeViewModel
{
public int Id { get; set; }
public string FullName { get; set; }
public int Age { get; set; }
}
You can create these profiles:
public class UserViewModelProfile : SelfProfiler<User,UserViewModel>
{
protected override void DescribeConfiguration(IMappingExpression<User, UserViewModel> map)
{
//This maps by convention, so no configuration needed
}
}
public class UserWithAgeViewModelProfile : SelfProfiler<User, UserWithAgeViewModel>
{
protected override void DescribeConfiguration(IMappingExpression<User, UserWithAgeViewModel> map)
{
//This map needs a little configuration
map.ForMember(d => d.Age, o => o.MapFrom(s => DateTime.Now.Year - s.BirthDate.Year));
}
}
To initialize in your application, create this class
public class AutoMapperConfiguration
{
public static void Initialize()
{
Mapper.Initialize(x=>
{
x.SelfConfigure(typeof (UserViewModel).Assembly);
// add assemblies as necessary
});
}
}
Add this line to your global.asax.cs file: AutoMapperConfiguration.Initialize()
Now you can place your mapping classes where they make sense to you and not worry about one monolithic mapping class.
For those of you who adhere to the following:
using an ioc container
don't like to break open closed for this
don't like a monolithic config file
I did a combo between profiles and leveraging my ioc container:
IoC configuration:
public class Automapper : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly().BasedOn<Profile>().WithServiceBase());
container.Register(Component.For<IMappingEngine>().UsingFactoryMethod(k =>
{
Profile[] profiles = k.ResolveAll<Profile>();
Mapper.Initialize(cfg =>
{
foreach (var profile in profiles)
{
cfg.AddProfile(profile);
}
});
profiles.ForEach(k.ReleaseComponent);
return Mapper.Engine;
}));
}
}
Configuration example:
public class TagStatusViewModelMappings : Profile
{
protected override void Configure()
{
Mapper.CreateMap<Service.Contracts.TagStatusViewModel, TagStatusViewModel>();
}
}
Usage example:
public class TagStatusController : ApiController
{
private readonly IFooService _service;
private readonly IMappingEngine _mapper;
public TagStatusController(IFooService service, IMappingEngine mapper)
{
_service = service;
_mapper = mapper;
}
[Route("")]
public HttpResponseMessage Get()
{
var response = _service.GetTagStatus();
return Request.CreateResponse(HttpStatusCode.Accepted, _mapper.Map<List<ViewModels.TagStatusViewModel>>(response));
}
}
The trade-off is that you have to reference the Mapper by the IMappingEngine interface instead of the static Mapper, but that's a convention I can live with.
All of above solutions provide a static method to call (from app_start or any where) that it should call other methods to configure parts of mapping-configuration. But, if you have a modular application, that modules may plug in and out of application at any time, these solutions does not work. I suggest using WebActivator library that can register some methods to run on app_pre_start and app_post_start any where:
// in MyModule1.dll
public class InitMapInModule1 {
static void Init() {
Mapper.CreateMap<User, UserViewModel>();
// other stuffs
}
}
[assembly: PreApplicationStartMethod(typeof(InitMapInModule1), "Init")]
// in MyModule2.dll
public class InitMapInModule2 {
static void Init() {
Mapper.CreateMap<Blog, BlogViewModel>();
// other stuffs
}
}
[assembly: PreApplicationStartMethod(typeof(InitMapInModule2), "Init")]
// in MyModule3.dll
public class InitMapInModule3 {
static void Init() {
Mapper.CreateMap<Comment, CommentViewModel>();
// other stuffs
}
}
[assembly: PreApplicationStartMethod(typeof(InitMapInModule2), "Init")]
// and in other libraries...
You can install WebActivator via NuGet.
In addition to the best answer, a good way is using Autofac IoC liberary to add some automation. With this you just define your profiles regardless of initiations.
public static class MapperConfig
{
internal static void Configure()
{
var myAssembly = Assembly.GetExecutingAssembly();
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(myAssembly)
.Where(t => t.IsSubclassOf(typeof(Profile))).As<Profile>();
var container = builder.Build();
using (var scope = container.BeginLifetimeScope())
{
var profiles = container.Resolve<IEnumerable<Profile>>();
foreach (var profile in profiles)
{
Mapper.Initialize(cfg =>
{
cfg.AddProfile(profile);
});
}
}
}
}
and calling this line in Application_Start method:
MapperConfig.Configure();
The above code finds all Profile sub classes and initiate them automatically.
Putting all the mapping logic in 1 location is not a good practice for me. Because the mapping class will be extremely large and very hard to maintain.
I recommend put the mapping stuff together with the ViewModel class in the same cs file. You can easily navigate to the mapping definition you want following this convention. Moreover, while creating the mapping class, you can reference to the ViewModel properties faster since they are in the same file.
So your view model class will look like:
public class UserViewModel
{
public ObjectId Id { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
public class UserViewModelMapping : IBootStrapper // Whatever
{
public void Start()
{
Mapper.CreateMap<User, UserViewModel>();
}
}
From new version of AutoMapper using static method Mapper.Map() is deprecated. So you can add MapperConfiguration as static property to MvcApplication (Global.asax.cs) and use it to create instance of Mapper.
App_Start
public class MapperConfig
{
public static MapperConfiguration MapperConfiguration()
{
return new MapperConfiguration(_ =>
{
_.AddProfile(new FileProfile());
_.AddProfile(new ChartProfile());
});
}
}
Global.asax.cs
public class MvcApplication : System.Web.HttpApplication
{
internal static MapperConfiguration MapperConfiguration { get; private set; }
protected void Application_Start()
{
MapperConfiguration = MapperConfig.MapperConfiguration();
...
}
}
BaseController.cs
public class BaseController : Controller
{
//
// GET: /Base/
private IMapper _mapper = null;
protected IMapper Mapper
{
get
{
if (_mapper == null) _mapper = MvcApplication.MapperConfiguration.CreateMapper();
return _mapper;
}
}
}
https://github.com/AutoMapper/AutoMapper/wiki/Migrating-from-static-API
For those who are (lost) using:
WebAPI 2
SimpleInjector 3.1
AutoMapper 4.2.1 (With Profiles)
Here's how I managed integrating AutoMapper in the "new way". Also,
a Huge thanks to this answer(and question)
1 - Created a folder in the WebAPI project called "ProfileMappers". In this folder I place all my profiles classes which creates my mappings:
public class EntityToViewModelProfile : Profile
{
protected override void Configure()
{
CreateMap<User, UserViewModel>();
}
public override string ProfileName
{
get
{
return this.GetType().Name;
}
}
}
2 - In my App_Start, I have a SimpleInjectorApiInitializer which configures my SimpleInjector container:
public static Container Initialize(HttpConfiguration httpConfig)
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();
//Register Installers
Register(container);
container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
//Verify container
container.Verify();
//Set SimpleInjector as the Dependency Resolver for the API
GlobalConfiguration.Configuration.DependencyResolver =
new SimpleInjectorWebApiDependencyResolver(container);
httpConfig.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
return container;
}
private static void Register(Container container)
{
container.Register<ISingleton, Singleton>(Lifestyle.Singleton);
//Get all my Profiles from the assembly (in my case was the webapi)
var profiles = from t in typeof(SimpleInjectorApiInitializer).Assembly.GetTypes()
where typeof(Profile).IsAssignableFrom(t)
select (Profile)Activator.CreateInstance(t);
//add all profiles found to the MapperConfiguration
var config = new MapperConfiguration(cfg =>
{
foreach (var profile in profiles)
{
cfg.AddProfile(profile);
}
});
//Register IMapper instance in the container.
container.Register<IMapper>(() => config.CreateMapper(container.GetInstance));
//If you need the config for LinqProjections, inject also the config
//container.RegisterSingleton<MapperConfiguration>(config);
}
3 - Startup.cs
//Just call the Initialize method on the SimpleInjector class above
var container = SimpleInjectorApiInitializer.Initialize(configuration);
4 - Then, in your controller just inject as usually a IMapper interface:
private readonly IMapper mapper;
public AccountController( IMapper mapper)
{
this.mapper = mapper;
}
//Using..
var userEntity = mapper.Map<UserViewModel, User>(entity);
For vb.net programmers using the new Version (5.x) of AutoMapper.
Global.asax.vb:
Public Class MvcApplication
Inherits System.Web.HttpApplication
Protected Sub Application_Start()
AutoMapperConfiguration.Configure()
End Sub
End Class
AutoMapperConfiguration:
Imports AutoMapper
Module AutoMapperConfiguration
Public MapperConfiguration As IMapper
Public Sub Configure()
Dim config = New MapperConfiguration(
Sub(cfg)
cfg.AddProfile(New UserProfile())
cfg.AddProfile(New PostProfile())
End Sub)
MapperConfiguration = config.CreateMapper()
End Sub
End Module
Profiles:
Public Class UserProfile
Inherits AutoMapper.Profile
Protected Overrides Sub Configure()
Me.CreateMap(Of User, UserViewModel)()
End Sub
End Class
Mapping:
Dim ViewUser = MapperConfiguration.Map(Of UserViewModel)(User)

Ninject And Connection Strings

I am very new to Ninject and am trying Ninject 2 with MVC and Linq. I have a SqlProductRepository class and all I want to know is what's the best way of passing the connectionstring in the constructor if I am injecting the Repository object in the controller.
public class SqlProductRepository:IProductRepository
{
private Table<Product> productsTable;
public SqlProductRepository(string connectionString)
{
productsTable = (new DataContext(connectionString)).GetTable<Product>();
}
public IQueryable<Product> Products
{
get { return productsTable; }
}
}
This is my ProductController class where I am injecting the Repository:
public class ProductsController : Controller
{
private int pageSize = 4;
public int PageSize { get { return pageSize; } set { pageSize = value; } }
IProductRepository _productsRepository;
[Inject]
public ProductsController(IProductRepository productRepository)
{
_productsRepository = productRepository;
}
public ViewResult List(int page)
{
return View(_productsRepository.Products
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToList()
);
}
}
Can somebody please guide me regarding this?
You can set it up in your binding
_kernel.Bind<IProductRepository>()
.To<SqlProductRepository>()
.WithConstructorArgument("connectionString",yourConnectionString );
You're doing:
new DataContext(connectionString)
in your code - this is the very newing and binding to classes you're trying to push out of your code by using a DI container. At the very least, consider adding an IConnectionStringSelector interface or something like that. You dont want to have 20 Bind calls for 20 repositories - you want a higher level abstraction than that.
I'd suggest the best solution is that you should be demanding either an IDataContext or an IDataContextFactory in the constructor instead and letting that worry about it.
You could supply the connection string as a constructor argument when binding the SqlProductRepository to the IProductRepository interface.
public class LinqToSqlModule : NinjectModule
{
public override void Load()
{
Bind<IProductRepository>().To<SqlProductRepository>()
.WithConstructorArgument(connectionString, "connectionstring");
}
}
I would suggest a slightly different approach. First of all, you might want to create a binding for the DataContext class in the kernel. You could do so by using a provider class to create your DataContext passing the connection string as an argument to its constructor. Then you bind the DataContext to the DataContextProvider.
public class DataContextProvider : Provider<DataContext>
{
protected override DataContext CreateInstance(IContext context)
{
string connectionString = "connectionstring";
return new DataContext(connectionString);
}
}
public class LinqToSqlModule : NinjectModule
{
public override void Load()
{
Bind<DataContext>().ToProvider<DataContextProvider>();
Bind<IProductRepository>().To<SqlProductRepository>();
}
}
Next modify the constructor of SqlProductRepository class to accept a DataContext object instead.
public class SqlProductRepository : IProductRepository
{
private readonly DataContext context;
public ProductRepository(DataContext context)
{
this.context = context;
}
public IQueryable<Product> Products
{
get { return context.GetTable<Product>(); }
}
}
By the way you don't have to decorate your constructor with the Inject attribute. Ninject will select the constructor with the most parameters by default.
Please refer below code snap:
//Bind the default connection string
public void BindDataContext()
{
ConstructorArgument parameter = new ConstructorArgument("connectionString", "[Config Value]");
Bind<DataContext>().ToSelf().InRequestScope().WithParameter(parameter);
}
//Re-Bind the connection string (in case of multi-tenant architecture)
public void ReBindDataContext(string cn)
{
ConstructorArgument parameter = new ConstructorArgument("connectionString", cn);
Rebind<DataContext>().ToSelf().InRequestScope().WithParameter(parameter);
}
For more information, please visit below link
MVC3, Ninject and Ninject.MVC3 problem

Resources