Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it bad design to reference Autofac in my projects just for Owned<T>?

I've recently become a heavy user of Autofac's OwnedInstances feature. For example, I use it to provide a factory for creating a Unit of Work for my database, which means my classes which depend on the UnitOfWork factory are asking for objects of type :

Func<Owned<IUnitOfWork>>

This is incredibly useful--great for keeping IDisposable out of my interfaces--but it comes with a price: since Owned<> is part of the Autofac assembly, I have to reference Autofac in each of my projects that knows about Owned<>, and put "using Autofac.Features.OwnedInstances" in every code file.

Func<> has the great benefit of being built into the .NET framework, so I have no doubts that it's fine to use Func as a universal factory wrapper. But Owned<> is in the Autofac assembly, and every time I use it I'm creating a hard reference to Autofac (even when my only reference to Autofac is an Owned<> type in an interface method argument).

My question is: is this a bad thing? Will this start to bite me back in some way that I'm not yet taking into account? Sometimes I'll have a project which is referenced by many other projects, and so naturally I need to keep its dependencies as close as possible to zero; am I doing evil by passing a Func<Owned<IUnitOfWork>> (which is effectively a database transaction provider) into methods in these interfaces (which would otherwise be autofac-agnostic)?

Perhaps if Owned<> was a built-in .NET type, this whole dilemma would go away? (Should I even hold my breath for that to happen?)

like image 844
Jay Sullivan Avatar asked Mar 25 '11 21:03

Jay Sullivan


People also ask

Is Autofac a good choice for my project?

So Autofac provides you with easy inversion of control, with the idea that this will keep your dependencies manageable and your code clean as it grows. Interesting, given its good percentile scores in my research.

Can Autofac be used as a service locator?

BTW Autofac encourage people to use tagged contexts to solve such problems: Yes you are right, I was trying to use it as a service locator and DI. I was confused at the time, mostly because of how I was using StructureMap. As Mark Lindell pointed out, you don't generally need to access the container directly in an Autofac application.

How to add Autofac to NuGet?

To do this, right click on References > Add Reference. It’s simple to add Autofac. We can do this by using NuGet Packages or Package Manager Console. In this example, I used NuGet Packages. Thus, right click on References > Manage NuGet Packages. First, we are installing Autofac. Subsequently, install Autofac.integration.WebAPI, as shown below.

Is Autofac’s code testable?

Autofac exists to make your code testable, clean, and decoupled. So seeing its initial stats at a quick glance made me wonder, “is Autofac’s code testable, clean, and decoupled?” Its scores for testability and readability seem to indicate that yes, it is.


4 Answers

I don't think referencing the Autofac assembly is the real problem - I consider things like Owned appearing in application code a 'code smell'. Application code shouldn't care about what DI framework is being used and having Owned in your code now creates a hard dependency on Autofac. All DI related code should be cleanly contained in a set of configuration classes (Modules in the Autofac world).

like image 70
Kai G Avatar answered Nov 16 '22 04:11

Kai G


I would say that it's fine to reference a well defined set of core 3rd party DLLs in every project of an "enterprise application" solution (or any application that needs flexibility). I see nothing wrong with having a dependency on at least the following in every project that needs it:

  • A logging framework (e.g. log4net)
  • Some IoC container (e.g. Autofac)

The fact that these aren't part of the core .NET framework shouldn't stop us from using them as liberally.

The only possible negatives I can see are relatively minor compared to the possible benefits:

  • This may make the application harder to understand for the average programmer
  • You could have version compatibility problems in the future which you wouldn't encounter if you were just using the .NET framework
  • There is an obvious but minor overhead with adding all of these references to every solution
like image 32
steinar Avatar answered Nov 16 '22 03:11

steinar


I agree with @steinar, I would consider Autofac as yet another 3rd party dll that supports your project. Your system depends on it, why should you restrict yourself from referencing it? I would be more conserned if ILifetimeScope or IComponentContext were sprinkled around your code.

That said, I feel your consern. After all, a DI container should work behind the scenes and not "spill" into the code. But we could easily create a wrapper and an interface to hide even the Owned<T>. Consider the following interface and implementation:

public interface IOwned<out T> : IDisposable
{
    T Value { get; }
}

public class OwnedWrapper<T> : Disposable, IOwned<T>
{
    private readonly Owned<T> _ownedValue;

    public OwnedWrapper(Owned<T> ownedValue)
    {
        _ownedValue = ownedValue;
    }

    public T Value { get { return _ownedValue.Value; } }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
            _ownedValue.Dispose();
    }
}

The registration could be done, either using a registration source or a builder, e.g. like this:

var cb = new ContainerBuilder();
cb.RegisterGeneric(typeof (OwnedWrapper<>)).As(typeof (IOwned<>)).ExternallyOwned();
cb.RegisterType<SomeService>();
var c = cb.Build();

You can now resolve as usual:

using (var myOwned = c.Resolve<IOwned<SomeService>>())
{
    var service = myOwned.Value;       
}

You could place this interface in a common namespace in your system for easy inclusion. Both the Owned<T> and OwnedWrapper<T> are now hidden from your code, only IOwned<T> is exposed. Should requirements change and you need to replace Autofac with another DI container there's a lot less friction with this approach.

like image 22
Peter Lillevold Avatar answered Nov 16 '22 03:11

Peter Lillevold


Perhaps if Owned<> was a built-in .NET type, this whole dilemma would go away? (Should I even hold my breath for that to happen?)

It will become a built-in .NET type: ExportLifeTimeContext<T>. Despite the name, this class isn't really bound to the .NET ExportFactory<T>. The constructor simply takes a value, and an Action to invoke when the lifetime of that value is disposed.

For now, it is only available in Silverlight though. For the regular .NET framework you'll have to wait until .NET 4.x (or whatever the next version after 4.0 will be).

like image 40
Wim Coenen Avatar answered Nov 16 '22 02:11

Wim Coenen