im making a project with a persistence layer, domain layer, and business layer, i implementing the generic repository pattern and unit of work with entity framework core.
I want to use this project in a web api rest and in a UWP project.
The correct ways its override the method?, add the context in the startup configureservices? When dispose a dbcontext?
Read documentation on configuring DbContext: https://learn.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext
Basically, you add it to your services:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<BloggingContext>(options => options.UseSqlite("Data Source=blog.db"));
}
Then you inject it into whatever class you want. An easy example would be inejecting it into a Controller (but you could inject into any class that is added to your services):
public class MyController
{
private readonly BloggingContext _context;
public MyController(BloggingContext context)
{
_context = context;
}
...
}
The Dependency Injection library will then handle disposal - you do not call Dispose directly. This is described in documentation here.
The framework takes on the responsibility of creating an instance of
the dependency and disposing of it when it's no longer needed.
Related
This question is similar to my previous question about Razor Components, but instead, this question is about Razor Pages, which requires a different interception point.
I am making an ASP.NET Core application using the Pure DI approach explained in the book Dependency Injection Principles, Practices, and Patterns (DIPP&P). Part of my application has a web API controller. To implement Pure DI with my controller, I was easily able to follow section 7.3.1 "Creating a custom controller activator" from DIPP&P to create a controller activator class, similar to the example found in DIPP&P. This was done by implementing IControllerActivator and composing my composition root within the create method.
My application will also feature Razor Pages. I would like to continue using the Pure DI approach but I cannot find any examples on how to do this. My assumption is I need to create a RazorPageActivator class, which implements IRazorPageActivator and add my composition root to the Activate method. However, after reviewing the RazorPageActivator class found in the ASP.NET Core GitHub, it looks very complex and I fear if I intercept it (or override it?) by making my own class that implements IRazorPageActivator things will break and I'll be in a mess.
My question is how does one go about implementing Pure DI with Razor Pages, if possible?
With Razor Pages, the IPageModelActivatorProvider functions as your Composition Root's Composer. Here's an example based on the default Visual Studio (2019) Razor Pages project template.
Let's start with the custom IPageModelActivatorProvider, which acts as your Composer, which is part of your Composition Root:
public class CommercePageModelActivatorProvider
: IPageModelActivatorProvider, IDisposable
{
// Singletons
private readonly ILoggerFactory loggerFactory;
public CommercePageModelActivatorProvider(ILoggerFactory loggerFactory) =>
this.loggerFactory = loggerFactory;
public Func<PageContext, object> CreateActivator(
CompiledPageActionDescriptor desc) =>
c => this.CreatePageModelType(c, desc.ModelTypeInfo.AsType());
public Action<PageContext, object> CreateReleaser(
CompiledPageActionDescriptor desc) =>
(c, pm) => (pm as IDisposable)?.Dispose();
private object CreatePageModelType(PageContext c, Type pageModelType)
{
// Create Scoped components
var context = new CommerceContext().TrackDisposable(c);
// Create Transient components
switch (pageModelType.Name)
{
case nameof(IndexModel):
return new IndexModel(this.Logger<IndexModel>(), context);
case nameof(PrivacyModel):
return new PrivacyModel(this.Logger<PrivacyModel>());
default: throw new NotImplementedException(pageModelType.FullName);
}
}
public void Dispose() { /* Release Singletons here, if needed */ }
private ILogger<T> Logger<T>() => this.loggerFactory.CreateLogger<T>();
}
Notice a few things with this implementation:
The structure of this class is very similar to the one's given in the book's code samples.
It implements IDisposable to allow disposing of its own created singletons. In this case, no singletons are created in its constructor, so nothing needs to be disposed. The ILoggerFactory is "externally owned"; it is created by the framework, and will be disposed (if needed) by the framework.
The class uses a custom TrackDisposable extension method (shown later on) that allows tracking scoped and transient dependencies. The TrackDisposable method will add those instances to the request and allows the framework to dispose them when the request ends.
This is why the CreateReleaser method only disposes the Page itself. The disposing of all other created components is done by the framework when you track them for disposal. You can also choose to track the Page itself; in that case you can leave the CreateReleaser delegate empty.
There is a handy Logger<T>() method that simplifies the creation of ILogger<T> implementations. Those come from the framework and are created by the ILoggerFactory.
Here's the TrackDisposable extension method:
public static class DisposableExtensions
{
public static T TrackDisposable<T>(this T instance, PageContext c)
where T : IDisposable
{
c.HttpContext.Response.RegisterForDispose(instance);
return instance;
}
}
The last missing piece of infrastructure required is the registration of your CommercePageModelActivatorProvider into the framework's DI Container. This is done inside the Startup class:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
// Register your custom component activator here
services.AddSingleton<
IPageModelActivatorProvider, CommercePageModelActivatorProvider>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
}
}
I am building a Blazor Server front end to an existing domain layer. This layer offers various injectable services to do modifications on the EF Core repository. For this, the services itself requests a DbContext from the (standard Microsoft) DI container. This works fine with regular MVC.NET/Razor pages with a scoped DbContext instance, but as documented, this is problematic with Blazor. In a Blazor Server app we’d want to use DbContextFactory to generate short-lived DbContext instances for operations instead.
It’s no problem to have both a DbContext and DbContextFactory in the same application, but I’m struggling to understand how to adapt my services. Or if I even need to? To illustrate, this is the current code:
My Page:
#page “/items”
#inject ItemService ItemService
// somewhere in the code
ItemService.DoOperation(…)
My service
class ItemService
{
public ItemService(MyDbContext myDbContext)
{
…
}
public bool DoOperation(…)
{
…
_myDbContext.SaveChanges();
}
}
Startup.cs:
services.AddDbContext<MyDbContext>(options => …),
contextLifetime: ServiceLifetime.Transient,
optionsLifetime: ServiceLifetime.Singleton
);
services.AddDbContextFactory<MyDbContext>(options => …);
I’ve changed the lifetimes for DbContext according to the example given in this answer and so far I haven’t been able to create any issues, but I don’t fully understand the lifetime issues at play here. How can I engineer my service to play well in both a Blazor and a MVC/Razor Pages application in an obvious way?
In your typical MVC application, one request represents a single unit of work. The DbContext is generated as a scoped service and injected through the constructor. This is fine.
On the other hand, in Blazor Server one request no longer represents a single unit of work. The first request creates a circuit which means that any scoped service injected is going to have a lifetime as described here.
In Blazor Server apps, a unit of work is a SignalR message. (a button click for example that adds a new row to the database). Because of this, injecting your context directly is not the way to go.
That's why Blazor Server has IDbContextFactory<T>. Initialize it like this:
services.AddDbContextFactory<DbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("WebDB")));
In your Razor Components (tied to the Blazor app) you use it like so:
private readonly IDbContextFactory<DbContext> factory;
public Component(IDbContextFactory<DbContext> f)
{
factory = f;
}
public void Click()
{
using(DbContext cnt = factory.CreateDbContext())
{
// Your code here
}
}
This is further explained here.
Documentation: ASP.NET Core Blazor Server with Entity Framework Core (EFCore).
The problem is transitive: Your services rely on a should-be-scoped resource and that only works when you register those services as scoped as well. Which you can't.
The proper way is to rewrite your services to the DbContext per Operation model, and inject the DbContextFactory.
It looks like you already have a mixed model (with a SaveChanges per operation they are actually a UoW).
When you don't want to make those changes you could weasel your way out by registering the DbContext as Transient. That feels bad but it's designed to quickly release the underlying connection. So it's not the resource leak that it looks like.
my practice:
set dbcontext use database type
services.AddScoped<AuditableEntitySaveChangesInterceptor>();
if (configuration.GetValue<bool>("UseInMemoryDatabase"))
{
services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseInMemoryDatabase("BlazorDashboardDb");
options.EnableSensitiveDataLogging();
});
}
else
{
services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseSqlServer(
configuration.GetConnectionString("DefaultConnection"),
builder =>
{
builder.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName);
builder.EnableRetryOnFailure(maxRetryCount: 5,
maxRetryDelay: TimeSpan.FromSeconds(10),
errorNumbersToAdd: null);
builder.CommandTimeout(15);
});
options.EnableDetailedErrors(detailedErrorsEnabled: true);
options.EnableSensitiveDataLogging();
});
services.AddDatabaseDeveloperPageExceptionFilter();
}
as we know DbContext should be transient lifetime in blazor server.
services.AddTransient<IDbContextFactory<ApplicationDbContext>, BlazorContextFactory<ApplicationDbContext>>();
services.AddTransient<IApplicationDbContext>(provider => provider.GetRequiredService<IDbContextFactory<ApplicationDbContext>>().CreateDbContext());
as sample, not change use DbContext:
public class AddEditCustomerCommandHandler : IRequestHandler<AddEditCustomerCommand, Result<int>>
{
private readonly IApplicationDbContext _context;
private readonly IMapper _mapper;
private readonly IStringLocalizer<AddEditCustomerCommandHandler> _localizer;
public AddEditCustomerCommandHandler(
IApplicationDbContext context,
IStringLocalizer<AddEditCustomerCommandHandler> localizer,
IMapper mapper
)
{
_context = context;
_localizer = localizer;
_mapper = mapper;
}
}
I have a multi tier web application working on ASP.NET MVC 5.
I have completely separated Infrastructure (DAL) from UI using a business layer.
any time UI function needs a DAL access, it calls my business service and the business service does it's job and if needed returns a result.
For IoC, Business services are injected into UI project and Infrastructure injected into Business service using Ninject
I need my UI project to have exactly 0 reference to my infrastructure project, but when it comes to using ASP.NET Identity 2 framework, It needs reference to infrastructure for ApplicationDbContext.
There are two reference to my Infrastructure project one from IdentityConfig.cs in
var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
and another from Startup.Auth.cs in
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
what is the solution for this?
This is the schema of the Architecture I used:
Interfaces and factory methods will solve your problem. Whenever you want to create object - use simple factory that returns an interface of your object. And whenever you want to abstract from concrete implementation - use interfaces.
public class ApplicationDbContextFactory
{
public static IApplicationDbContext Create(IOwinContext owinContext)
{
return ApplicationDbContext.Create(owinContext);
}
}
With big thanks to #Andrei M for his great help and guidance,
I Solved this as below:
First Step: I Created An IDbContext Interface in my Domain Layer. (because from presentation we don't have access to my Infrastructure Layer)
public interface IDbContext : IDisposable
{
}
Second Step: Implement IDbContext Interface in my ApplicationDbContext in Infrastructure Layer.
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>, IDbContext
Third Step: As In my Project, the only layer that has reference to my Infrastructure Layer, is Business layer. so for use my ApplicationDbContext in my owin startup class in presentation layer, I need a Factory class in my business layer to return me a Db Context.
public static class DbContextFactory
{
public static IDbContext Create()
{
return new ApplicationDbContext();
}
}
Forth Step: Changing the Owin Startup class to use My DbContextFactory Class whenever it needs a DbContext.
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(DbContextFactory.Create);
Final Step: the only thing that remains is to change IdentityConfig.cs to don't reference directly to ApplicationDbContext in it's create method.
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var myUserStore = new UserStore<ApplicationUser>((IdentityDbContext<ApplicationUser>) context.Get<IDbContext>());
var manager = new ApplicationUserManager(myUserStore);
Actually for this step I have two solution, first is what you see above (Cast to IdentityDbContext<ApplicationUser>)
second is Cast to DbContext. I Don't know if I'll have any problem with casting to DbContext (in System.Data.Entity namespace) later, and for now I use the first solution for this.
I have a layered application with the following projects:
DAL (using EntityFramework with repositories)
DAL.Model (contains the entities, and is referenced by all the others)
Services
UI (in wpf)
The base repository looks like this:
public abstract class RepositoryBase<T> where T : class
{
private readonly MyContext context;
private readonly IDbSet<T> dbSet;
protected RepositoryBase(MyContext dataContext)
{
context = dataContext;
dbSet = context.Set<T>();
}
protected MyContext Context
{
get { return context; }
}
**And a series of virtual methods for Add, Delete, etc.
}
All repositories extend this one, such as:
public class MarketRepository : RepositoryBase<Market>
{
public MarketRepository(MyContext dataContext) : base(dataContext)
{
}
public IEnumerable<Market> GetAllMarkets()
{
return this.Context.Markets.ToList<Market>();
}
}
The services look like this:
public class MarketService
{
IMarketRepository _marketRepository;
public MarketService(IMarketRepository marketRepository)
{
_marketRepository = marketRepository;
}
public IEnumerable<Market> GetAllMarkets()
{
return _marketRepository.GetAllMarkets();
}
}
What I would like to achieve is that the UI layer would only have a reference to the Services layer, the Services layer only with the DAL layer (and all of them to Model, where the entities live) using DI (right now I'm using Unity).
The problem is, in my container in the UI I only want to do this
unity.RegisterType<IMarketService, MarketService>();
and not have to do it as well for the repositories, because then the UI layer would have a dependency on the DAL layer.
I thought about adding a parameterless constructor to the Service classes, like:
public MarketService() : this(new MarketRepository(*What would I put here?)) { }
but then I'm loosing the abstraction that the interface gives, and also I don't know what to do with the MyContext that the repository needs as a parameter; if I pass a new one, then I need to reference the DAL.
Should I change my repositories to create a new MyContext in the constructor, rather than getting it as a parameter?
How can I refactor my architecture to make it work properly and with minimal dependencies?
Well, I belive it is up to the bootstrapper to configure dependencies, in the higher level of the application. As it is usually the UI project, if it needs to reference other assemblies, so be it. If you do not like your UI project managing that, than create a bootstrapper project responsable for getting your app running and separete your UI classes in another one.
Your IoC container should support Dependency Injection using a string from an external configuration file. This way you are not hardcoding the mapping. Structuremap does this quite well, so I am sure other IoCs will.
Adding external dependenices as a parameter when creating an instance is the way to go.
I think you should make yourself more familiar with the different ways to configure Unity, so that the dependencies are resolved.
Could you elaborate why you are creating a repository when using a dependency injection framework?
When configuring DI, you should follow the same pattern - UI bootstrapper initializes Services, Services initialize DAL. (With autofac or ninject you could achiece this using modules. With unity you should emulate modules).
In pseudocode something like
//ui
void UILayer.ConfigureUnity(unity)
{
ServiceLayer.ConfigureUnity(unity)
}
//services
void ServiceLayer.ConfigureUnity(unity)
{
DAL.ConfigureUnity(unity)
unity.RegisterType<IMarketService, MarketService>();
}
//dal
void DAL.ConfigureUnity(unity)
{
unity.RegisterType<IMarketRepository, MarketRespository>();
unity.RegisterType<MyContext, MyContext>(); //not sure exact syntax - just register type for 'new Type()' activator.
}
I'd like to use EF directly in a business / service layer without using repositories but wondered where the best place to create / dispose the context if I want to make the class testable using a test DB?
Should it be using DI in the service constructor and mark the class as IDisposable and get rid of it there or just wrap each call in a using block?
I'm not sure on your reluctance on a repository class, but this is where I've been creating a destroying the EF context for my service layer.
So for my MVC web app, I register the repository using Autofac with lifetimescope
builder
.RegisterType<AccountRepository>()
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
My account service will get a reference to a repository instance from the container and will have access to a single context throughout the life time of the web request. Once the request is finished, Autofac will call dispose on the repository and clean up the context.
public sealed class AccountRepository : IAccountRepository, IDisposable
{
private AccountContext _context = new AccountContext();
public IList<AccountEntity> GetAccounts()
{
return _context.Accounts
.OrderBy(x => x.Name)
.ToList();
}
public void Dispose()
{
_context.Dispose();
_context = null;
}
}