Linq: scoped DataContext, unit-of-work, repository - c#

I have been researching about the unit-of-work and the repository pattern in C#. AFAIK, DataContext implements the unit of work pattern, and can be used to implement a repository interface. One last piece that's lacking in DataContext is a way to share this resource globally within a predefined scope.
I briefly looked at NCommon as a solution to this missing piece. Would you share your experience in NCommon, or recommend other solutions? Please also correct me if I have misunderstood. Thanks.

I always worked with DataContext in the same way NHibernate does: Having a static way to get it and different storages for storing it. For instance, it could be stored in the HttpContext.Current.Items collection for a web based application, or in Call.Context for the unit tests. When do you create the instance and when do you close it will depend on the scenario. Again, for web it make sense to do it on the Request_begin and Request_end events of your application. For unit tests, maybe on the setup and teardown.
Hope it helps.
Edit: Here's some implementation
public abstract class DataContextProvider
{
public abstract DataContext GetCurrent();
public abstract void OpenNew();
public void CloseCurrent()
{
var current = GetCurrent();
current.Dispose();
}
}
In your data context you add this:
public static DataContextProvider Provider { private get; set; }
public static DataContext Current { get { return Provider.GetCurrent(); } }
For web:
In your web project you put this class:
public class WebDataContextProvider : DataContextProvider
{
private const string Key = "WebDataContextProvider.DataContext";
public override DataContext GetCurrent()
{
return (DataContext)HttpContext.Current.Items[Key];
}
public override void OpenNew()
{
HttpContext.Current.Items[Key] = new DataContext();
}
}
And in your global.asax:
You add a field of type WebDataContextProvider:
WebDataContextProvider dataContextProvider = new WebDataContextProvider();
You override the application start event for doing:
DataContext.Provider = dataContextProvider;
In your Request Begin event you put:
dataContextProvider.OpenNew();
And in your Request End event you put:
dataContextProvider.CloseCurrent();
For test
For your test projects you can follow the same logic, but creating a TestDataContextProvider, like:
public class WebDataContextProvider : DataContextProvider
{
[ThreadStatic]
private static DataContext Current;
public override DataContext GetCurrent()
{
return Current;
}
public override void OpenNew()
{
Current = new DataContext();
}
}
And in your open and close the data context in your SetUp and TearDown methods, and configuring the "current provider" in the constructor of the Test or the TestFixtureSetUp
Hope it helps.

Related

Dependency Injection Architectural Design - Service classes circular references

I have the following service classes:
public class JobService {
private UserService us;
public JobService (UserService us) {
this.us = us;
}
public void addJob(Job job) {
// needs to make a call to user service to update some user info
// similar dependency to the deleteUser method
}
}
public class UserService {
private JobService js;
public UserService(JobService js) {
this.js = js;
}
public void deleteUser(User u) {
using (TransactionScope scope = new TransactionScope()) {
List<IJob> jobs = jobService.findAllByUser(u.Id);
foreach (IJob job in jobs) {
js.deleteJob(job);
}
userDao.delete(user);
scope.Complete();
}
}
}
Each of these service classes is getting instantiated by IoC container, and there is not a functional problem, but this to me feels like there is a potential design flaw in this approach and I'm wondering if there's an alternative approach that makes more sense.
As someone already pointed out, the problem is not with limitations to the DI container but with your design.
I see the reason that you have a separate UserService and a JobService which contain a reference to each other. This is because both UserService and JobService contain some logic that needs the other service as a reference (adding a job requires adding a user, etc.). However, I think that you should NOT reference one service from the other. Rather, you should have another layer of abstraction behind the services which the services will use for the common logic. So, the services will contain the logic which can't(shouldn't) be reused and the helpers will contain the shared logic.
For example:
public class UserHelper{
//add all your common methods here
}
public class JobService {
private UserHelper us;
public JobService (UserHelper us) {
this.us = us;
}
public void addJob(Job job) {
// calls helper class
}
}
public class UserService {
public UserService(UserHelper js) {
this.js = js;
}
public void deleteUser(User u) {
// calls helper class
}
}
In this way, you won't have any issues with circular references and you will have one place which contains the logic which needs to be reused by different services.
Also, I prefer having services which are completely isolated from one another.
The problem you are having has in fact nothing to do with the limitations of your DI container, but it is a general problem. Even without any container, it will be impossible to create those types:
var job = new JobService([what goes here???]);
var user = new UserService(job);
The general answer is therefore to promote one of the dependencies to a property. This will break the dependency cycle:
var job = new JobService();
var user = new UserService(job);
// Use property injection
job.User = user;
Prevent however from using more properties than strictly needed. These dependency cycles should be pretty rare and makes it much harder to either wire your types together, or to validate the DI configuration for correctness. Constructor injection makes this much more easy.
You can decouple the services by using events. Instead of calling a dependent method of another service when an action has been performed, an event is raised. An integrator can then wire up the services through the events. A service does not even know the existence of the other service.
public class JobService
{
public event Action<User, Job> JobAdded;
public void AddJob(User user, Job job)
{
//TODO: Add job.
// Fire event
if (JobAdded != null) JobAdded(user, job);
}
internal void DeleteJobs(int userID)
{
//TODO: Delete jobs
}
}
public class UserService
{
public event Action<User> UserDeleted;
public void DeleteUser(User u)
{
//TODO: Delete User.
// Fire event
if (UserDeleted != null) UserDeleted(u);
}
public void UpdateUser(User user, Job job)
{
//TODO: Update user
}
}
The integrator wires up the services
public static class Services
{
public static JobService JobService { get; private set; }
public static UserService UserService { get; private set; }
static Services( )
{
JobService = new JobService();
UserService = new UserService();
JobService.JobAdded += JobService_JobAdded;
UserService.UserDeleted += UserService_UserDeleted;
}
private static void UserService_UserDeleted(User user)
{
JobService.DeleteJobs(user.ID);
}
private static void JobService_JobAdded(User user, Job job)
{
UserService.UpdateUser(user, job);
}
}
(Note: I simplified event raising a bit. It's not thread safe like this. But you can assume that the events are subscribed in advance and will not be changed later.)
This wont work in Autofac. See circular dependencies section of the documentation.
Constructor/Constructor Dependencies Two types with circular
constructor dependencies are not supported. You will get an exception
when you try to resolve types registered in this manner.
You could potentially use relationship types (Func<>, Lazy<>) to break the cycle.
Your code is a bit too generic to come up with a proper solution but you should consider changing the direction of dependencies regardless of what IoC container you use.
public class JobService {
private UserService us;
public JobService (UserService us) {
this.us = us;
}
public void addJob(Job job) {
// needs to make a call to user service to update some user info
}
}
public class UserService {
private JobService js;
public UserService(Func<JobService> jsFactory) {
this.js = jsFactory(this);
}
public void deleteUser(User u) {
// needs to call the job service to delete all the user's jobs
}
}
Alternatively, In the case of your example you could move deleteUser and create a method, delete all jobs on the job service and instead of refering to the user use an id. this breaks the dependency by using the id.
Another alternative is to pass the job service as a parameter to deleteUser.

Mock implementation for use in automatic UI testing

I am working on adding basic automatic UI tests to the block of unit tests we run with each nightly build. We used MSTest coded UI and created a script.
The code-behind is dependent upon IClientManager which both the real manager and mock implement.
My problem is that I don't know how to switch automatically between the real and mock implementations inside the button click handler, when running a test.
My two other constraints are that I can't have a dependency on the mock assembly in the code-behind and that I can't use a DI framework, since the client is "security conscious" and getting a framework approved might take months.
Is there any way of doing this manually, and hopefully, not a bigger problem than the problem I am looking to solve?
Thank you!
You could build your own simple object container if you can't use a third party one (which is silly but I understand, I've been there before)
here is something that I whipped up that could get you started... haven't tested it and it is really rough, but hopefully you get the idea
public static class ObjectFactory
{
static IDictionary<Type, object> _factory = new Dictionary<Type, object>();
public static void Register<T>(Func<T> builder)
{
if (_factory.ContainsKey(typeof(T)))
_factory[typeof(T)] = builder;
else
_factory.Add(typeof(T), builder);
}
public static T GetInstance<T>()
{
if (_factory.ContainsKey(typeof(T)))
throw new ArgumentException(string.Format("Type <{0}> not registered in ObjectFactory", typeof(T).Name));
return ((Func<T>)_factory[typeof(T)])();
}
}
public interface IClientManager { }
public class RealClientManager : IClientManager { }
public class MockClientManager : IClientManager { }
public class MyView
{
public MyView()
{
// probably better to do this registry in some sort of application initialization
ObjectFactory.Register<IClientManager>(() => new RealClientManager());
}
public void SomeMethodThatNeedsClientManager()
{
var clientManager = ObjectFactory.GetInstance<IClientManager>();
}
}
public class MyTester
{
[TestMethod()]
public void SomeTest()
{
var view = new MyView();
// swap the client manager in the test
ObjectFactory.Register<IClientManager>(() => new MockClientManager());
// Asserts
}
}
you can see that if you've used StructureMap or some other DI container before they do a lot of the same thing with a lot of added niceties such as traversing your object graph and registering objects automatically based on conventions, managing object lifecycles, scoping of containers, etc... a lot of this stuff you could implement yourself too... but you should just really used a tried and true solution such as StructureMap

Does CompositionContainer.SatisfyImportsOnce reuse components?

In a WCF service project, I have created a simple wrapper for MEF CompositionContainer to simplify its instantiation :
internal class CompositionProxy
{
private static Lazy<CompositionContainer> m_lazyCC;
static CompositionProxy()
{
m_lazyCC = new Lazy<CompositionContainer>(() =>
{
var batch = new CompositionBatch();
var dc1 = new DirectoryCatalog(
HttpContext.Current.Server.MapPath("~/bin")
);
return new CompositionContainer(dc1);
}
);
}
public static CompositionContainer DefaultContainer
{
get
{
return m_lazyCC.Value;
}
}
}
The idea is to have one CompositionContainer for the application lifetime, which search for export in the bin directory.
Then, I set up some webservices, that requires to have on imported property :
All of them are built like this :
public class MyService: IMyService
{
public MyService()
{
CompositionProxy.DefaultContainer.SatisfyImportsOnce(this);
}
[Import]
private IContext Context { get; set; }
public void DoTheJob()
{
// Logic goes here
}
}
Elsewhere, I have one class that match this export :
[Export(typeof(IContext))]
public class MyContext
{
public MyContext(){
Log("MyContext created");
}
}
In the constructor, I ask the composition container to populate the IContext Context property.
This seems to work, in my service, I can see the Context property is correctly populated.
However, I'm experiencing memory leaks, and my tracing show me the MyContext class is instantiated only once.
Can you clarify if I'm misusing the composition framework ?
I supposed it's a good idea to have one composition container for the application lifetime, was I wrong ?
the multiple calls to SatisfyImportsOnce seems to populate the target with the same unique instance. Is it true ? If true, how can I simply change my code to have a new instance each time the method is called ?
Any suggestion to improve my code ?
I supposed it's a good idea to have one composition container for the application lifetime
Yes, you are supposed to create one container for the application lifetime.
the multiple calls to SatisfyImportsOnce seems to populate the target with the same unique instance. Is it true ? If true, how can I simply change my code to have a new instance each time the method is called ?
You need [Import(RequiredCreationPolicy=CreationPolicy.NonShared)].
Any suggestion to improve my code ?
If possible, do not expose the container as a global and litter your code with calls to it. That's the Service Locator pattern, which has some disadvantages when compared to Dependency Injection. Instead of your service trying to compose itself, just declare what it needs:
[Export(typeof(IMyService))]
public class MyService: IMyService
{
private readonly IContext context;
public MyService(
[Import(typeof(IContext),
RequiredCreationPolicy=CreationPolicy.NonShared)]
IContext context)
{
if (context == null)
throw new ArgumentNullException("context");
this.context = context;
}
public void DoTheJob()
{
// Logic goes here
}
}
In a WCF service, I think you should only need to call the container in your ServiceHostFactory implementation. I'm not really familiar with WCF though.

Ninject + ASP.NET Web Forms Not Working

I've successfully implemented Ninject in an MVC3 application, but am running into some trouble doing the same thing with ASP.NET Web Forms. I'm getting null references every time I try to access an injected property in my business layer. After setting breakpoints within the CreateKernel method, as well as several places within the ServiceLocator class, it looks like none of them are ever getting hit, so it's not even loading.
I'm sure I'm just approaching this wrong, but there is very little documentation or info out there for wiring up Ninject in a Web Forms application.
Basically here's what I have so far:
code behind
public class ReviewManager
{
[Inject] private IReviewRepository _reviewRepository { get; set; }
public ReviewManager() { }
public ReviewManager(IReviewRepository reviewRepository)
{
_reviewRepository = reviewRepository;
}
public Review GetById(int id)
{
if (id <= 0) throw new ArgumentException("ID must be greater than zero");
**I get a null reference exception on the next line. _reviewRepository is null**
return _reviewRepository.GetById(id);
}
}
global.asax.cs
public class Global : NinjectHttpApplication
{
protected override IKernel CreateKernel()
{
return ServiceLocator.Kernel;
}
// deleted for brevity
}
ServiceLocator.cs (edited for brevity, the relevant parts are here)
public static class ServiceLocator
{
public static IKernel Kernel { get; set; }
public static ILogger Logger { get; set; }
static ServiceLocator()
{
Kernel = new StandardKernel(new INinjectModule[] {
new LoggerBindings(),
new DataBindings()
});
if (Logger == null)
Logger = Kernel.Get<ILogger>();
}
}
public class LoggerBindings : NinjectModule
{
public override void Load()
{
Bind<ILogger>().To<NLogLogger>();
}
}
public class DataBindings : NinjectModule
{
public override void Load()
{
Bind<IReviewRepository>().To<ReviewRepository>();
}
}
ASP.Net via WebForms does not allow you to manage the lifecycle of all object instances (like MVC does). For example, the framework instantiates page objects. This means you probably can't implement DI in quite the same way as you would in MVC/WPF/Silverlight (the same problem is present in WinForms IIRC). You will likely have to initiate the dependency graph directly in each of your code behinds.
Translation: you will want to call ServiceLocator.Kernel.Get<IReviewRepository> when your page loads (or as lazy-init on the property).
The cool thing about MVC ist that it can run side a side of ASP.NET WebForm pages in the same application. In my opinion the best way to extend ASP.NET WebForms websites is to create new pages using MVC3 and to refactor every page that needs major changes to MVC3.
If this is no option go and use the Ninject.Web extension. It contains a IHttpModule that property injects all web pages and controlls after they are initialized. That way you can property inject the services als have them created by Ninject.
A potential workaround, by changing your DataBindings class as follows:
public class DataBindings : NinjectModule
{
public override void Load()
{
Bind<IReviewRepository>().To<ReviewRepository>();
Bind<ReviewManager>().ToSelf();
}
}
And within your caller, instead of
var rm = new ReviewManager();
Try using
var rm = ServiceLocator.Kernel.Get<ReviewManager>();
I havent tested this code, but i think it'll solve your null reference problem.
I use property injection for pages, masterpages and usercontrols. All my pages, for example, inherit from a base class that overrides RequestActivation method with the following code:
''' <summary>
''' Asks the kernel to inject this instance.
''' </summary>
Protected Overridable Sub RequestActivation()
ServiceLocator.Kernel.Inject(Me)
End Sub
And in each page I declare injectable properties:
<Inject()>
Property repo As IMyRepository

Writing a testable "import data from database" class

I am tasked with pulling all the rows from a 3rd party vendor's SQLite data table, creating business objects from those records, and sending the new business objects off to another class.
Pseudo-code:
var databasePath = "%user profile%\application data\some3rdPartyVendor\vendor.sqlite"
var connection = OpenSqliteConnection(databasePath);
var allGizmoRecords = connection.Query(...);
var businessObjects = TransformIntoBizObjs(allGizmoRecords);
someOtherClass.HandleNewBizObjs(businessObjects);
I've got all that working.
My question is: How can I write this class so it's unit testable?
Should I:
use the repository pattern to mock out the data access
actually provide a dummy SQLite database in the unit test
Or any better ideas? I'm using C#, but this question seems rather language-agnostic.
You could inject a test-only Sqlite database quite easily, refactoring the code to look like below. But how are you asserting the results? The business objects are passed to someOtherClass. If you inject an ISomeOtherClass, that class's actions need to be visible too. It seems like a bit of pain.
public class KillerApp
{
private String databasePath;
private ISomeOtherClass someOtherClass;
public KillerApp(String databasePath, ISomeOtherClass someOtherClass)
{
this.databasePath = databasePath;
this.someOtherClass = someOtherClass;
}
public void DoThatThing()
{
var connection = OpenSqliteConnection(databasePath);
var allGizmoRecords = connection.Query(...);
var businessObjects = TransformIntoBizObjs(allGizmoRecords);
someOtherClass.HandleNewBizObjs(businessObjects);
}
}
[TestClass]
public class When_Doing_That_Thing
{
private const String DatabasePath = /* test path */;
private ISomeOtherClass someOtherClass = new SomeOtherClass();
private KillerApp app;
[TestInitialize]
public void TestInitialize()
{
app = new KillerApp(DatabasePath, someOtherClass);
}
[TestMethod]
public void Should_convert_all_gizmo_records_to_busn_objects()
{
app.DoThatThing();
Assert.AreEqual(someOtherClass.Results, /* however you're confirming */);
}
}
Using an IRepository would remove some of the code from this class, allowing you to mock the IRepository implementation, or fake one just for test.
public class KillerApp
{
private IRepository<BusinessObject> repository;
private ISomeOtherClass someOtherClass;
public KillerApp(IRepository<BusinessObject> repository, ISomeOtherClass someOtherClass)
{
this.repository = repository;
this.someOtherClass = someOtherClass;
}
public void DoThatThing()
{
BusinessObject[] entities = repository.FindAll();
someOtherClass.HandleNewBizObjs(entities);
}
}
[TestClass]
public class When_Doing_That_Thing
{
private const String DatabasePath = /* test path */;
private IRepository<BusinessObject> repository;
private ISomeOtherClass someOtherClass = new SomeOtherClass();
private KillerApp app;
[TestInitialize]
public void TestInitialize()
{
repository = new BusinessObjectRepository(DatabasePath);
app = new KillerApp(repository, someOtherClass);
}
[TestMethod]
public void Should_convert_all_gizmo_records_to_busn_objects()
{
app.DoThatThing();
Assert.AreEqual(someOtherClass.Results, /* however you're confirming */);
}
}
But this still feels quite cumbersome. There are two reasons, 1) the Repository pattern has been getting some bad press lately from Ayende, who knows a thing or two about Repository. And 2) what are you doing writing your own data access!? Use NHibernate and ActiveRecord!
[ActiveRecord] /* You define your database schema on the object using attributes */
public BusinessObject
{
[PrimaryKey]
public Int32 Id { get; set; }
[Property]
public String Data { get; set; }
/* more properties */
}
public class KillerApp
{
private ISomeOtherClass someOtherClass;
public KillerApp(ISomeOtherClass someOtherClass)
{
this.someOtherClass = someOtherClass;
}
public void DoThatThing()
{
BusinessObject[] entities = BusinessObject.FindAll() /* built-in ActiveRecord call! */
someOtherClass.HandleNewBizObjs(entities);
}
}
[TestClass]
public class When_Doing_That_Thing : ActiveRecordTest /* setup active record for testing */
{
private ISomeOtherClass someOtherClass = new SomeOtherClass();
private KillerApp app;
[TestInitialize]
public void TestInitialize()
{
app = new KillerApp(someOtherClass);
}
[TestMethod]
public void Should_convert_all_gizmo_records_to_busn_objects()
{
app.DoThatThing();
Assert.AreEqual(someOtherClass.Results, /* however you're confirming */);
}
}
The result is a much smaller class and a business object and data-layer that you can change more easily. And you don't even have to mock the database calls, you can configure and initialize ActiveRecord to use a test database (in-memory, even).
Well, the only thing that would really need to be tested here is TransformIntoBizObjs, I would think, since the connection code should have been written/tested elsewhere. Simply passing things that might show up to Transform and seeing if the right thing pops out would be what you need to do.
Remember to test all usecases of Transform, even potentially weird items that probably shouldn't end up in the function call, but might. Never know what people have been shoving in their databases.
Inversion of Control (IoC) and Dependency Injection (DI) will go a long way towards making your code more testable. There are a lot of frameworks out there that can assist you with this, but for your purposes you don't necessarily need to go to all that effort.
Start with extracting an interface that might look something like this:
Interface ISqlLiteConnection
{
public IList<GizmoRecord> Query(...);
}
Once you've done that, you should refactor the OpenSqlLiteConnection() method to return an instance of ISqlLiteConnection, rather than the concrete implementation. To test, just create a class that implements your interface, which mocks up the actual DB queries and connections with determinate results.
Databases are complicates, you need to test your query code and you need to test it against a real sqlite instance - otherwise you can't be sure you didn't hit some rare sqlite quirk or bug.
And since the only way to test your query is to run it on a real sqlite file, and it's really easy to include such a file with your test there's no point to adding another layer just to make it "more" testable or to have "pure" unit tests.
Just make sure to add all the strange edge cases you can think of to your sample file.

Categories