16
votes

I am trying to implement basic UoW/Repository pattern with ASP.NET/Entity Framework Core and I have encountered very troubling behavior.

My solution consists of 4 projects in total.

.DAL project, where my entity classes are defined and where my DbContext is defined:

public class Product
{
    public int Id { get; set; }

    public string Name { get; set; }
}

public class ApplicationDbContext : DbContext
{
    public DbSet<Product> Products { get; set; }
}

.Facade project, where my IUnitOfWork and IProductRepository are defined:

public interface IUnitOfWork
{
    IProductRepository Products { get; }
}

public interface IProductRepository
{
    string GetName(int id);
}

.Facade.EF project, where my Facade is implemented with EF:

public class UnitOfWork : IUnitOfWork
{
    private ApplicationDbContext _context;
    public IProductRepository Products { get; private set; }

    internal ApplicationDbContext Context { get { return _context; } }

    public UnitOfWork()
    {
        _context = new ApplicationDbContext();
        Products = new ProductRepository(this);
    }
}

public class ProductRepository : IProductRepository
{
    private ApplicationDbContext _context;
    public ProductRepository(UnitOfWork uow)
    {
        _context = uow.Context;
    }
    public string GetName(int id)
    {
        return _context.Products
            .Where(x => x.Id == id)
            .Select(x => x.Name)
            .FirstOrDefault();
    }
}

.DemoApp project where my application code should be. This project should only know about UnitOfWork and UserRepository and not about ApplicationDbContext class.

  • .DAL references Entity Framework 6.1.3.

  • .Facade does not reference anything.

  • .Facade.EF references .DAL project, .Facade project and Entity Framework 6.1.3.

  • .DemoApp references Facade and Facade.EF but NOT Entity Framework 6.1.3. NOR .DAL project. Even though EF assemblies are added to my bin folder on build, EF is not directly referenced by this project.

With .NET Framework 4.6.x., if I try try to code against ApplicationDbContext in DemoApp, it tells me that class is not defined and is not providing me any usings to be added which is expected behavior.

.NET Framework 4.6.x Project

If I attempt to do the same with .NET Core 1.0 RC2 (by using Entity Framework Core), ApplicationDbContext is accessible from .DemoApp without adding direct reference to .DAL project which completely destroys my attempt to hide implementation details.

enter image description here

.DAL project is not directly referenced by .DemoApp project - why am I allowed to see classes from it there?

Is this expected behavior? Is there a way to make .NET Core projects to have the same behavior as .NET Framework 4.6.x projects?

2
Someone has added the correct answer (PrivateAssets=All) - Could you please accept it?Peter Morris
@PeterMorris I have accepted the answer. Thanks for pointing it out!Admir Tuzović

2 Answers

8
votes

I've been struggling with this for months and finally found a way to disable the transitive references of projects in Core.

In the .csproj file for .Facade.EF, you can add PrivateAssets="All" to the ProjectReference to .DAL:

<ItemGroup>
  <ProjectReference Include="..\.DAL\.DAL.csproj" PrivateAssets="All" />
</ItemGroup>

With this setting, projects that reference .Facade.EF no longer reference .DAL too.

In more abstract terms, if you want A to reference B and B to reference C, but don't want A to reference C, add this:

In B.csproj

<ItemGroup>
  <ProjectReference Include="..\C\C.csproj" PrivateAssets="All" />
</ItemGroup>

Source: https://github.com/dotnet/project-system/issues/2313

4
votes

That is intended behavior. It is called meta-packages and used for example for the NETStandard.Library package to include all libraries of the base class library. I do not think there is a way hiding them.