Intranet Application - Data Access in separate project - asp.net-mvc

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;
}

Related

Error with dependency injection and generic base class

I am learning repository and unit of work patterns using generics and dependency injection. I have a persistent error that I have been churning on and I am clearly missing something fundamental.
I am getting the following error which whilst I understand that it is looking for a database table column called 'Id'
Because my Entity class inherits from BaseEntity I suspect this is the problem but I don't understand why and what I am best to do to fix it.
public class BaseEntity<T>
{
public T Id { get; set; }
}
Error returned
An exception of type 'System.Data.Entity.Core.EntityCommandExecutionException' >occurred in EntityFramework.SqlServer.dll but was not handled in user code
Additional information: An error occurred while executing the command >definition. See the inner exception for details.
Inner exception
{"Invalid column name 'Id'."}
To add some context I am using EF6 MVC5 and AutoFac for the Dependancy injection.
Entity class
(A column 'id' doesn't exist in the database - the key in the database is 'EmrgencyAttendanceId') and the Entity class also sets the key as 'EmrgencyAttendanceId' like so.
[Table("reporting.EDISRecords")]
public class EDISRecord : BaseEntity<int>
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int EmergencyAttendanceId { get; set; }
[StringLength(50)]
public string Hospital { get; set; }
[StringLength(20)]
public string URNumber { get; set; }
Controller action
The controller calls the GetRecord method of the EDISRecordService passing a Lambda expression. I use DbFunctions.TruncateTime because the database stores as date time and I only want to search on the date.
public ActionResult Search(string Date, string CaseNumber)
{
if (!string.IsNullOrEmpty(Date) || !string.IsNullOrEmpty(CaseNumber))
{
DateTime dt = DateTime.Parse(Date);
var EmergencyAttendance = _edisRecordService.GetRecord(m => (DbFunctions.TruncateTime(m.ArrivalDateTime) == dt) && (m.RTAIdentifier == CaseNumber));
//for initialising view model
SeperationSummaryViewModel model = new SeperationSummaryViewModel();
//assign values for view model
if (EmergencyAttendance != null)
{
if (EmergencyAttendance.DepartureDestination != null)
{
if (EmergencyAttendance.DepartureDestination.Substring(0, 1) == ".")
{
model.DepartureDestination = EmergencyAttendance.DepartureDestination.Substring(1);
}
else
{
model.DepartureDestination = EmergencyAttendance.DepartureDestination;
}
}
else
{
model.DepartureDestination = "Not recorded by Emergency Department";
}
if (EmergencyAttendance.InpatientAdmissionDiagnosis != null)
{
model.InpatientAdmissionDiagnosis = EmergencyAttendance.InpatientAdmissionDiagnosis;
}
else
{
model.InpatientAdmissionDiagnosis = "Not recorded by Emergency Department";
}
}
//send view model into UI (View)
return PartialView("_SeperationInformationPartialView", model);
}
else
{
if (string.IsNullOrEmpty(Date) || string.IsNullOrEmpty(CaseNumber))
{
return PartialView("Blank");
}
}
return PartialView("Error");
}
Service Class
The service class instantiates a unit of work and calls the repository Get method passing through the Lambda expression.
public class EDISRecordService : IEDISRecordService
{
private readonly IUnitOfWork<DataWarehouseDataManager> _unitOfWork;
public EDISRecordService(IUnitOfWork<DataWarehouseDataManager> unitOfWork)
{
_unitOfWork = unitOfWork;
}
public EDISRecord GetRecord(Expression<Func<EDISRecord, bool>> #where)
{
return _unitOfWork.EDISRecordRepository.Get(#where);
}
}
RepositoryBase class
The repository class inherits from the repository base class which impliments the Get method passing the lambda to 'Expression> #where'
public class RepositoryBase<TEntity> : Disposable, IRepository<TEntity>
where TEntity : class
{
private readonly DbContext _dataContext;
private IDbSet<TEntity> Dbset
{
get { return _dataContext.Set<TEntity>(); }
}
public RepositoryBase(DbContext dbContext)
{
_dataContext = dbContext;
}
public TEntity Get(Expression<Func<TEntity, bool>> #where)
{
return Dbset.Where(where).FirstOrDefault();
}
protected override void DisposeCore()
{
if (_dataContext != null)
_dataContext.Dispose();
}
}
It fails in this method
public TEntity Get(Expression<Func<TEntity, bool>> #where)
{
return Dbset.Where(where).FirstOrDefault(); <<<<<< Fails Here <<<<<
}
I was on the right track and it was because I was inheriting from the Base Entity.
When I re read my problem it became clear.
The solution was to simply not to inherit from base entity class and all is good.

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.

Generic repository pattern and multiple selects

I am trying to learn the repository pattern and looking at a generic repository I cannot see how to handle customized select statements. For example, using this article the author uses a select by ID and a select all.
public interface IGenericRepository<T> where T:class
{
IEnumerable<T> SelectAll();
T SelectByID(object id);
void Insert(T obj);
void Update(T obj);
void Delete(object id);
void Save();
}
Later the article the IGenericRepository interface is implemented using Northwind. Then that is used to create a Customer controller.
public class CustomerController : Controller
{
private IGenericRepository<Customer> repository = null;
public CustomerController()
{
this.repository = new GenericRepository<Customer>();
}
...
This would handle selecting a list of all Customers or for one Customer by ID but where I get stuck is some more real world examples like "select all Customers for a client" or "select all Customers for a region". Plus, you could have another controller based on a different entity that would filter on different attributes. I assume I'm missing something basic. If the user interface needed to present the Customer entity (or any other entity) by various filters, how would this be done by sticking with one generic repository?
Here you go; to handle any select criteria apart from the Id, you can add Where method
like below
public interface IGenericRepository<T> where T:class
{
IEnumerable<T> SelectAll();
T SelectByID(object id);
IEnumerable<T> Where(Expression<Func<T,bool>> predicate)// this one
void Insert(T obj);
void Update(T obj);
void Delete(object id);
void Save();
}
Now in the Where method implementation do it like this
public IEnumerable<T> Where(Expression<Func<T,bool>> predicate)
{
return _objectSet.Where(predicate).AsEnumerable();
}
Here _objectSet in created in repository constructor like this :
public Repository(ObjectContext context)
{
_context = context;
_objectSet = _context.CreateObjectSet<T>();
}
public CustomerController()
{
_context = new NorthwindEntities();
_reporsitory = new Repository<Customer>(_context);
}
Use of Where method like
reporsitory.Where(c=>c.Country=="Canada").ToList();
For full reference see this project on codeplex (download /browse source code)
https://efgenericrepository.codeplex.com/SourceControl/latest
I think the implementation of the GenericRepository should somehow be able to return the IQueryable of current entity, like adding Get() method.
protected IQueryable<T> Get() // Notice that the access modifier is protected.
{
return table;
}
Then you could just create a derived class from GenericRepository and add a select method that accepts the Filter class.
public class CustomerRepository : GenericRepository<Customer>
{
public IEnumerable<T> SelectAll(CustomerFilter filter){ .. }
}
The filter class contains 2 filters.
public class CustomerFilter
{
public int? ClientId { get; set; }
public int? RegionId { get; set; }
}
Then the SelectAll implementation would be.
public IEnumerable<T> SelectAll(CustomerFilter filter)
{
var query = Get();
if (filter == null)
{
return query;
}
if (filter.ClientId.HasValue)
{
query = query.Where(q => q.ClientId == filter.ClientId.Value);
}
if (filter.RegionId.HasValue)
{
query = query.Where(q => q.RegionId == filter.RegionId.Value);
}
return query;
}
In the controller, calling it like.
public ActionResult Get(int? clientId, int? regionId)
{
var filter = new CustomerFilter { ClientId = clientId, RegionId = regionId };
var customers = _repository.SelectAll(filter);
return View();
}
You might need to see this post as your reference.
An approach I've seen in one asp.net mvc based mission critical app, is to use the generic interface as defined in the question. Then there is an abstract class that implements that interface. And there is one more repository class that inherits the abstract class, which has all methods specific to that class.
public interface IGenericRepository<T> where T:class
{
...
}
public abstract class GenericRepository<T> : IGenericRepository where T:class
{
...
}
And the CustomerRepository class
public class CustomerRepository : GenericRepository<Customer>
{
//add method specific to Customer like select Customers in specific country
}
And in the controller
public class CustomerController : Controller
{
private CustomerRepository repository = null;
public CustomerController()
{
this.repository = new CustomerRepository();
}
...

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)

How to avoid repositories that duplicate code

I have successfully setup a simple mvc application that lists teams. I'm using Ninject to inject the appropriate repository depending on the controller (thanks to stack overflow ;). All looks good, except that the repository code looks exactly the same. And I know that's wrong. So my TeamRepository has two classes (for now).
public class SwimTeamRepository : ITeamRepository<SwimTeam>
{
private readonly Table<SwimTeam> _teamTable;
public SwimTeamRepository(string connectionString)
{
_teamTable = (new DataContext(connectionString).GetTable<SwimTeam>());
}
public IQueryable<SwimTeam> Team
{
get { return _teamTable; }
}
}
public class SoccerTeamRepository : ITeamRepository<SoccerTeam>
{
private readonly Table<SoccerTeam> _teamTable;
public SoccerTeamRepository(string connectionString)
{
_teamTable = (new DataContext(connectionString).GetTable<SoccerTeam>());
}
public IQueryable<SoccerTeam> Team
{
get { return _teamTable; }
}
}
They look exactly the same except for the Class and Table name, so clearly I need to re-factor this. What would be the best approach here? Singleton? Factory Method?
Thanks in advance!
You could use generics:
public interface ITeamRepository<T>
{
}
public class TeamRepository<TTeam> : ITeamRepository<TTeam>
where TTeam : Team
{
private readonly Table<TTeam> _teamTable;
public TeamRepository(string connectionString)
{
_teamTable = (new DataContext(connectionString).GetTable<TTeam>());
}
public IQueryable<TTeam> Team
{
get { return _teamTable; }
}
}
public class Team
{
}
public class SwimTeam : Team
{
}
Then use it like so...
public void MyMethod()
{
var repository = new TeamRepository<SwimTeam>();
}
...and set up your IoC container w/ Ninject like so...
public class MyModule : NinjectModule
{
public override void Load()
{
Bind<ITeamRepository<SwimTeam>>
.To<TeamRepository<SwimTeam>>();
}
}
public void MyMethod()
{
var repository = kernel.Get<ITeamRepository<SwimTeam>>();
}
If you want to get REAL generic and have a single repository for ALL of your mapped classes, you can do something like this:
public interface IRepository
{
IQueryable<T> Get<T>() where T : class, new();
}
public class Repository : IRepository, IDisposable
{
private DataContext _dataContext;
public Repository(string connectionString)
{
_dataContext = new DataContext(connectionString);
}
public IQueryable<T> Get<T>()
where T : class, new()
{
return _dataContext.GetTable<T>().AsQueryable();
}
public void Dispose()
{
if (_dataContext != null)
{
_dataContext.Dispose();
_dataContext = null;
}
}
}
...which you could call like so (after setting up your Ninject container)...
using (var repository = kernel.Get<IRepository>())
{
var swimTeam = repository.Get<SwimTeam>();
}
Since Ninject takes care of the life-cycle management of your objects, you don't HAVE to wrap the repository in a using statement. In fact, you don't want to use a using statement there at all if you plan to use the repository more than once within the scope of its lifetime. Ninject will automatically dispose of it when it's life-cycle ends.
Here's a good article by Rob Conery on using this kind of technique to reduce the friction of using different ORMs.
EDIT by keeg:
I Think
public class TeamRepository<TTeam> : ITeamRepository<TTeam> where TTeam : Team {}
Should be
public class TeamRepository<TTeam> : ITeamRepository<TTeam> where TTeam : class {}
Please correct if I'm wrong.
Is this what you want?
public class TeamRepository : ITeamRepository<T>
{
private readonly Table<T> _teamTable;
public TeamRepository(string connectionString)
{
_teamTable = (new DataContext(connectionString).GetTable<T>());
}
public IQueryable<T> Team
{
get { return _teamTable; }
}
}

Resources