Using Autofac for WebForms and n-tier architecture - inversion-of-control

I am introducing unit testing to an existing webforms application. I am using Moq and Autofac. I'm trying to keep code changes to a minimum, but need to implement the unit testing.
So I have a presentation assembly, a business layer, and a data access layer. My business layer looks something like this:
public class EmployeeBL
{
public Employee SelectById(int id)
{
return new EmployeeDA().SelectById(id);
}
}
My Data access looks something like this:
public class EmployeeDA
{
// unitOfWork defined in the constructor
public Employee SelectById(int id)
{
return unitOfWork.Employees.Where(e => e.id == id);
}
}
Autofac's webforms assembly allows you to declare a public property and specify web.config settings to automatically inject a dependency via HttpModule. To test the EmployeeBL, I made the changes to web.config and declared EmployeeDA as a property:
// Modified for testing
[InjectProperties]
public class EmployeeBL
{
// public property to allow Autofac property injection
public IEmployeeDA EmployeeDA { get; set; }
public Employee SelectById(int id)
{
return EmployeeDA.SelectById(id);
}
}
This works for running the webforms application, but the problem is I need to unit test the business layer independently of a webforms instance. I would like to keep the [InjectProperties] attribute on my EmployeeBL, but I can't tell by the documentation how I can get the EmployeeDA to have its properties injected.
public class EmployeeBLTest
{
private static IContainer { get; set; }
[TestInitialize]
public void Initialize()
{
var builder = new ContainerBuilder();
// Use my fake employeeDA for testing
builder.RegisterType<FakeEmployeeDA>().As<IEmployeeDA>();
// Something magical happens
}
[TestMethod]
public void SelectByIdTest(int id) { /* testing stuff */ }
}

What about:
builder.RegisterType<EmployeeDA>().AsSelf().PropertiesAutowired();
see here:
http://code.google.com/p/autofac/wiki/PropertyInjection

Related

WCF with Entity Framework Code First

I want to use EF behind my WCF service to fetch data and display it to the client. I need the following suggestions:
Do I need to have the same interface for all the views (e.g. students, teachers etc.) or do I need to have a different interface and service for every table (or view)
Do I need to generate the database calls within my service (.svc) or some other architecture is preferred?
public Student[] GetAllStudents()
{
//database generation code here
}
How can I use EF code-first approach to generate database. I know that for an MVC app, you need to set the initializer in Global.asax or in web.config but I am not sure how it's called in this case. My model looks like this:
[DataContract]
public class Student
{
[DataMember]
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[DataMember]
public string Type { get; set; }
[DataMember]
public string Subject { get; set; }
[DataMember]
public string Description { get; set; }
}
What you really should do is break up your system in to more separate layers. Instead of having a WCF call that directly queries the database, create a "buisness logic" layer that translates the information that the WCF call provides you to what the EF call needs to know. This is called a N-Tier application
public class SchoolAPI : ISchoolAPI
{
private DataAccessLayer _dal = new DataAccessLayer();
public Student[] GetAllStudents()
{
return _dal.GetStudents(null, null);
}
public Student[] GetAllScienceStudents()
{
return _dal.GetStudents(null, DataAccessLayer.ScienceStudentType);
}
}
private class DataAccessLayer
{
public static readonly ScienceStudentType = //...
public Student[] GetStudents(string subject, string type)
{
using(var ctx = new SchoolContext())
{
IQueryable<Student> studentQuery = ctx.Students;
if(subject != null)
studentQuery = studentQuery.Where(s=>s.Subject == subject);
if(type != null)
studentQuery = studentQuery.Where(s=>s.Type == type);
return studentQuery.ToArray();
}
}
}
The caller of the WCF call does not need to know what the string ScienceStudentType is, all it cares about is that it gets the science students. By seperating the business logic from the database call the caller of your service no longer needs to know.
For EF it will initialize on the first time the framework goes out to "touch" the database and detects that it is not there if it is set up to do so. This is done in the constructor of SchoolContext but is getting a little too broad for this answer. I recommend finding a tutorial on EF and get it working in a simple test enviorment without WCF (maybe a simple console app that just calls GetStudents() then move in in to a WCF environment.

Creating a generic database context in MVC 4

I wrote a MVC 4 app. I have some questions:
public class DatabaseContext<TEntity>: DbContext where TEntity: class
{
...
public DbSet<TEntity> entity = {get; set;}
...
}
I want to create a generic database context like this DatabaseContext and use it for all my Entities defined in database tables.
Please, write an example.
I don't now how to initialize generic context in global.asax once and use it every time, in whichever part of the project necessary.
Please, write some examples.
It seems to me to what you're implementing is the Repository Pattern:
public interface IRepository<TEntity> where TEntity : class
{
IEnumerable<TEntity> GetAll();
TEntity GetById(Guid id);
}
Prevent letting your repository inherit from DbContext, since DbContext is an implementation of the Unit of Work pattern and a unit of work is not a repository (but rather contains or manages multiple repositories).
What you can do is to let your repository use the DbContext internally:
public class Repository<TEntity> : IRepository<TEntity>
{
private readonly DbContext context;
public Repository(DbContext context)
{
this.context = context;
}
public IEnumerable<TEntity> GetAll()
{
return this.context.Set<TEntity>();
}
public TEntity GetById(Guid id)
{
var entity = this.context.Set<Entity>().Find(id);
if (entity == null) throw new KeyNotFoundException(
typeof(TEntity).Name + " with id " + id + " not found);
return entity;
}
}
UPDATE
Since I'm a Dependency Injection enthusiast, I think that Dependency Injection is the solution to your problem. And since I'm a developer for the Simple Injector project, I'll show you how to do this using Simple Injector:
Step 1: Install the Simple Injector MVC Integration Quick Start NuGet package into your MVC project (I assume you know how to install NuGet packages).
Step 2: Compile your project. You'll get a compiler error in the SimpleInjectorInitializer class that the package just added. This is the line where you will have to make your registrations. You can just remove this #error line.
Step 3: Add the SimpleInjector.Extensions namespace to the top of the SimpleInjectorInitializer file:
using SimpleInjector.Extensions;
Step 4: Make the following registrations in the InitializeContainer method:
container.RegisterOpenGeneric(typeof(IRepository<>), typeof(Repository<>));
container.RegisterPerWebRequest<DbContext>(
() => new DbContext("Your connection string here"));
Step 5: Add the IRepository<T> dependencies to your contollers:
public class CustomerController : Controller
{
private readonly IRepository<Customer> customerRepository;
public CustomerController(IRepository<Customer> customerRepository)
{
this.customerRepository = customerRepository;
}
// controller methods here.
}
Now your repositories will be automatically be injected into your controllers.
Is there a reason you want to make a DatabaseContext with a generic type parameter? You won't be to instantiate it in a single place because each different DatabaseContext is a separate .NET Type.
Unless you're sticking rigidly to a particular pattern, I personally don't see any practical advantage of this approach over a single DatabaseContext with many sets:
public class DatabaseContext: DbContext
{
public DbSet<SomeEntity> SomeEntities { get; set; }
public DbSet<OtherEntity> OtherEntities { get; set; }
}
...
myDatabaseContext.SomeEntities.GetAll();
myDatabaseContext.OtherEntities.GetAll();
// OR:
myDatabaseContext.Set<SomeEntity>().GetAll();
myDatabaseContext.Set<OtherEntity>().GetAll();

Why DbContext doesn't implement IDbContext interface?

Why there is no IDbContext interface in the Entity Framework? Wouldn't it be easier to test things if there was an existing interface with methods like SaveChanges() etc. from which you could derive your custom database context interface?
public interface ICustomDbContext : IDbContext
{
// add entity set properties to existing set of methods in IDbContext
IDbSet<SomeEntity> SomeEntities { get; }
}
I see this IDbContext:
See this link And then you make a new partial class for your Entities Context With That interface.
public partial class YourModelEntities : DbContext, IDbContext
EDITED:
I edited this post, This Works for me.
My Context
namespace dao
{
public interface ContextI : IDisposable
{
DbSet<TEntity> Set<TEntity>() where TEntity : class;
DbSet Set(Type entityType);
int SaveChanges();
IEnumerable<DbEntityValidationResult> GetValidationErrors();
DbEntityEntry<TEntity> Entry<TEntity>(TEntity entity) where TEntity:class;
DbEntityEntry Entry(object entity);
string ConnectionString { get; set; }
bool AutoDetectChangedEnabled { get; set; }
void ExecuteSqlCommand(string p, params object[] o);
void ExecuteSqlCommand(string p);
}
}
YourModelEntities is your auto-generated partial class, and your need to create a new partial class with the same name, then add your new context interface, for this example is ContextI
NOTE: The interface hasn't implement all methods, because the methods are implemented in your auto-generate code.
namespace dao
{
public partial class YourModelEntities :DbContext, ContextI
{
public string ConnectionString
{
get
{
return this.Database.Connection.ConnectionString;
}
set
{
this.Database.Connection.ConnectionString = value;
}
}
bool AutoDetectChangedEnabled
{
get
{
return true;
}
set
{
throw new NotImplementedException();
}
}
public void ExecuteSqlCommand(string p,params object[] os)
{
this.Database.ExecuteSqlCommand(p, os);
}
public void ExecuteSqlCommand(string p)
{
this.Database.ExecuteSqlCommand(p);
}
bool ContextI.AutoDetectChangedEnabled
{
get
{
return this.Configuration.AutoDetectChangesEnabled;
}
set
{
this.Configuration.AutoDetectChangesEnabled = value;
}
}
}
}
I was thinking also about that, I assume you are going to use it for mocking DbContext. I find no reason for that, except that you will need to implement your own DbSet manually in your anyway for your mocked class (so will need to rewrite your own interface anyway).
Just create a mock DbContext extending your production DbContext overriding the methods that complicate testing. That way, any changes to the production DbContext are automatically reflected in the tests, save for the overridden methods. For any other classes that deal with persistence and take the DbContext just extend them as well passing in the extended mock DbContext.
namespace Test.Mocks
{
public sealed class MockDatabaseContext : MainProject.Persistence.Database.DatabaseContext
{
public MockDatabaseContext(ConfigurationWrapper config) : base(config)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var dbPath = "test.db";
optionsBuilder.UseSqlite($"Filename={dbPath}");
}
}
}
namespace Test.Mocks
{
public class MockInventoryFacade : InventoryFacade
{
public MockInventoryFacade(MockDatabaseContext databaseContext) : base(databaseContext)
{
}
}
}
There is no IDbContext because it would be useless, the only implementation of it would be the DbContext.
EF team is also going this way with IDbSet if you look at this design meeting note
For me, the real problem with EF when it comes to unit testing is the DbConnection in the DbContext, fortunately there is Effort a nice project on codeplex that starts to fill this.
Effort is a powerful tool that enables a convenient way to create automated tests for Entity Framework based applications.
It is basically an ADO.NET provider that executes all the data operations on a lightweight in-process main memory database instead of a traditional external database. It provides some intuitive helper methods too that make really easy to use this provider with existing ObjectContext or DbContext classes. A simple addition to existing code might be enough to create data driven tests that can run without the presence of the external database.
With this, you can leave your DbContext and DbSet as is and do your unit tests easily.
The only drawback with this is the difference between Linq providers where some unit tests may pass with effort and not with the real backend.
UPDATE with EF7
I still maintain that IDbContext would be useless and the problem comes from the DbConnection.
EF7 will not have an IDbContext either, in order to do unit testing they are now giving an in memory provider.
You can see Rowan Miller doing a demo here: Modern Data Applications with Entity Framework 7

Asp.Net Mvc templated helpers with interface types

I would like to use the Asp.net MVC templated helpers functionality to generate a standard UI for my objects throughout my application, but I've run into a significant issue:
I do not directly pass class types from my controllers into their views. Instead, I pass interface types.. with the actual implementation of the Model wrapped up in a Mongo or NHibernate specific class in an indirectly referenced project.
For discussion, my objects look like:
public interface IProductRepository {
IProduct GetByName(string name);
}
public interface IProduct {
string Name { get; set; }
}
public class NHibernateProductRepository : IProductRepository {
public IProduct GetByName(string name) {
/* NHibernate Magic here */
return nhibernateFoundProduct;
}
}
public class NHibernateProduct : IProduct {
public virtual Name { get; set; }
}
public class ProductController : Controller {
public ProductController(IProductRepository productRepo) {
_ProductRepo = productRepo;
}
public ActionResult Index(string name) {
IProduct product = _ProductRepo.GetByName(name);
return View(product);
}
}
Is it possible to use interface types with the Editor.For() syntax? Are there any problems or sticking points that I need to be aware of?
I have an EditorTemplate\IProduct.ascx file available. At this time, I can't seem to get that template to be rendered without hardcoding the "IProduct" name into the Editor.For() call. I would prefer this type of 'Convention over Configuration'....
The templates helpers will use the runtime type of the object for the name. In this case you should name the file NHibernateProduct.ascx
If you don't know the name of the type at design time than you could write a helper method that would inspect the object instance and walk the list of interfaces that a particular type is implementing and return a name based on that. Then you would call the appropriate override to EditorFor that takes the string "templateName" parameter.
I have decided to use an approach with a ViewModel native to the Web project that implements the IProduct interface.

Why does the entity framework need an ICollection for lazy loading?

I want to write a rich domain class such as
public class Product
{
public IEnumerable<Photo> Photos {get; private set;}
public void AddPhoto(){...}
public void RemovePhoto(){...}
}
But the entity framework (V4 code first approach) requires an ICollection type for lazy loading! The above code no longer works as designed since clients can bypass the AddPhoto / RemovePhoto method and directly call the add method on ICollection. This is not good.
public class Product
{
public ICollection<Photo> Photos {get; private set;} //Bad
public void AddPhoto(){...}
public void RemovePhoto(){...}
}
It's getting really frustrating trying to implement DDD with the EF4. Why did they choose the ICollection for lazy loading?
How can i overcome this? Does NHibernate offer me a better DDD experience?
I think i found the solution...See here for more details: http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/47296641-0426-49c2-b048-bf890c6d6af2/
Essentially you want to make the ICollection type protected and use this as the backing collection for the public IEnumerable
public class Product
{
// This is a mapped property
protected virtual ICollection<Photo> _photos { get; set; }
// This is an un-mapped property that just wraps _photos
public IEnumerable<Photo> Photos
{
get { return _photos; }
}
public void AddPhoto(){...}
public void RemovePhoto(){...}
}
For lazy loading to work the type must implement ICollection and the access must be public or protected.
You can't insert into an IEnumerable. This applies to the EF just as much as it does to your clients. You don't have to use ICollection, though; you can use IList or other writeable types. My advice to get the best of both worlds is to expose DTOs rather than entities to your clients.
You can overcome this by using the ReadOnlyCollection(Of T)
public class Product
{
private IList<Photo> _photos;
public IList<Photo> Photos {
get
{
return _photos.AsReadOnly();
}
private set { _photos = value; }
}
public void AddPhoto(){...}
public void RemovePhoto(){...}
}
EDIT:
ICollection<T> => IList<T>
Hope that is what you were looking for.