ASP MVC Entity Framework binding using Ninject - entity-framework

I am using Ninject in my ASP MVC 3 project, I have modified the global.asax file (as normally done) and then created a class NinjectControllerFactory like this:
public class NinjectControllerFactory : DefaultControllerFactory
{
private IKernel ninjectKernel;
public NinjectControllerFactory()
{
ninjectKernel = new StandardKernel();
AddBindings();
}
protected override IController GetControllerInstance(RequestContext requestContext,
Type controllerType)
{
return controllerType == null
? null
: (IController)ninjectKernel.Get(controllerType);
}
private void AddBindings()
{
// put additional bindings here
ninjectKernel.Bind<IServiceName>().To<ConcreteClass>();
}
}
All this works fine.
Now I want to add my Entity framework context object to the binding, so that I do not have to create a new instance of it for each service.
Can anyone tell how to do it?
Should I create a new interface which just defines a Entity framework context?
Thanks

You could use self-binding
kernel.Bind<MyDbContext>().ToSelf();
P.S you should also check-out Ninject.MVC3 package on nuget

Related

How to Create a DbContextFactory in .NETCore 3.1 & Blazor

I'm following guidelines in how to setup EF Core to work safely in Blazor & .NET Core 3.1.
The MS documentation is here: https://learn.microsoft.com/en-us/aspnet/core/blazor/blazor-server-ef-core?view=aspnetcore-3.1
In the instructions, advice is to create a DbContextFactory which is used to create a dbcontext in each service. All makes sense in the Blazor world, but the code won't compile as
AddDbContextFactory does not exist. If there's another way to do it in .Net Core 3.1/ EF Core 3 - I can't see it.
services.AddDbContextFactory<ContactContext>(opt =>
opt.UseSqlite($"Data Source={nameof(ContactContext.ContactsDb)}.db")
.EnableSensitiveDataLogging());
I found this extension method that the Microsoft docs page is using in its sample github project:
public static IServiceCollection AddDbContextFactory<TContext>(
this IServiceCollection collection,
Action<DbContextOptionsBuilder> optionsAction = null,
ServiceLifetime contextAndOptionsLifetime = ServiceLifetime.Singleton)
where TContext : DbContext
{
// instantiate with the correctly scoped provider
collection.Add(new ServiceDescriptor(
typeof(IDbContextFactory<TContext>),
sp => new DbContextFactory<TContext>(sp),
contextAndOptionsLifetime));
// dynamically run the builder on each request
collection.Add(new ServiceDescriptor(
typeof(DbContextOptions<TContext>),
sp => GetOptions<TContext>(optionsAction, sp),
contextAndOptionsLifetime));
return collection;
}
And the factory class is here:
public class DbContextFactory<TContext>
: IDbContextFactory<TContext> where TContext : DbContext
{
private readonly IServiceProvider provider;
public DbContextFactory(IServiceProvider provider)
{
this.provider = provider;
}
public TContext CreateDbContext()
{
if (provider == null)
{
throw new InvalidOperationException(
$"You must configure an instance of IServiceProvider");
}
return ActivatorUtilities.CreateInstance<TContext>(provider);
}
}
GetOptions method:
private static DbContextOptions<TContext>
GetOptions<TContext>(Action<DbContextOptionsBuilder> action,
IServiceProvider sp = null) where TContext: DbContext
{
var optionsBuilder = new DbContextOptionsBuilder < TContext > ();
if (sp != null)
{
optionsBuilder.UseApplicationServiceProvider(sp);
}
action?.Invoke(optionsBuilder);
return optionsBuilder.Options;
}
AddDbContextFactory will be introduced in .NET Core 5. See here: https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-ef-core-5-0-preview-7/.
The page you linked to gives you the code (albeit in pieces) to roll your own.
You will have to add the AddDbContextFactory<TContext> class and the FactoryExtensions to your project. Download the sample app there to make it complete.
And when you upgrade to net5 just replace it with the library version.

How do I register DbContext EF Core in ServiceStack Core?

With EF Core, DbContext is registered as Scoped by EF service extension. This is desirable because DbContext is not thread-safe and therefore it should be created per request.
ServiceStack IOC treats any Scoped registration in Startup as singleton, which contradicts with the point above.
One possible solution is to not use EF Core's service extension, but that seems to bring a lot of boilerplate code and reduce maintainability. Is there any better way?
--
UPDATE
I'd like to provide sample code for clarity
I added a private Guid to the DbContext class so that I can tell whether we have the new instance.
public class BloggingContext : DbContext
{
private readonly Guid _instance;
public BloggingContext(DbContextOptions<BloggingContext> options)
: base(options)
{
_instance = Guid.NewGuid();
}
public DbSet<Blog> Blogs { get; set; }
}
With .NET Core MVC, the controller code looks like
public class BlogsController : Controller
{
private readonly BloggingContext _context;
public BlogsController(BloggingContext context)
{
_context = context;
}
// skip for readability
}
For each request hitting the controller, the _instance inside BloggingContext returns an unique value. However, when using within a ServiceStack service, _instance always returns the same value.
public class BlogService : ServiceStack.Service
{
private readonly BloggingContext _context;
public BlogService(BloggingContext context)
{
_context = context;
}
// skip for readability
}
This behaviour is consistent with ServiceStack documentation about .NET Core Container Adapter that scoped dependencies registered in .NET Core Startup is singleton within ServiceStack. However, it is not desirable because we want DbContext to be created per request.
My solution is that I move the DbContext registration into AppHost code as below
public override void Configure(Container container)
{
container.AddScoped(c =>
{
var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
optionsBuilder.UseSqlServer(connection);
return new BloggingContext(optionsBuilder.Options);
});
}
This code works as I expect. Every instance of BloggingContext injected into my BlogService is now unique. However, I find myself unable to use any service collection extension which is very handy in .Net Core Startup anymore. For example, I want to use Entity Framework Unit Of Work and I couldn't call
services
.AddUnitOfWork<BloggingContext>();
Instead, I have to wire up all dependencies of that library myself like
public override void Configure(Container container)
{
container.AddScoped(c =>
{
var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
optionsBuilder.UseSqlServer(connection);
return new BloggingContext(optionsBuilder.Options);
});
container.AddScoped<IRepositoryFactory, UnitOfWork<BloggingContext>>();
container.AddScoped<IUnitOfWork, UnitOfWork<BloggingContext>>();
container.AddScoped<IUnitOfWork<BloggingContext>, UnitOfWork<BloggingContext>>();
}
You should be able to register it in .NET Core's IOC like any .NET Core App:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<BloggingContext>(options =>
options.UseSqlite("Data Source=blog.db"));
}
Then reference like a normal dependency in your ServiceStack Services:
public class MyServices : Service
{
public BloggingContext BloggingContext { get; set; }
}
Which uses ServiceStack's .NET Core Container Adapter to resolve any dependencies not in ServiceStack's IOC, in .NET Core's IOC.

Entity Framework Core DbContext and Dependency Injection

I'm building a service application using Web API, .Net Core and EntityFramework Core.
For configuring options in my DbContext I'm using these lines in "ConfigureServices" method in Startup.cs
var connection = #"Server=ISSQLDEV;Database=EventManagement;Trusted_Connection=True;";
services.AddDbContext<EMContext>(options => options.UseSqlServer(connection));
I know that if I add the context as a constructor parameter in the controller .Net will inject the context in the constructor.
But this is not the behavior I want. I don't want my web api to know anything about the dbcontext. I have a DataAccess Project with a repository class that handles all CRUD operations.
This means that I just want to say Repository.AddEvent(evt) in my controller and then repository knows how to handle that.
On the other hand, repository uses a simple dependency resolver to get the right "IDataAdapter" implementation. One of those implementations is SQLDataAdapter. This is the point I need my context.
How can I pass my context all the way to this point?
You can solve this by adding your dbcontext via constructor injection to your classes from your data access layer.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(o => o.UseSqlServer(myConnStr));
services.AddScoped<Repository>(); // 'scoped' in ASP.NET means "per HTTP request"
}
}
public class MvcController
{
private Repository repo;
public MvcController(Repository repo)
{
this.repo = repo;
}
[HttpPost]
public void SomeEndpoint()
{
this.repo.AddFoo(new Foo());
}
}
public class Repository
{
private DbContext db;
public Repository(ApplicationDbContext db)
{
this.db = db;
}
public void AddFoo(Foo obj)
{
this.db.Set<Foo>().Add(obj);
this.db.SaveChanges();
}
}
If you want to further customize how your DbContext is injected into your DI container, I suggest you look at what .AddDbContext is actually doing. See https://github.com/aspnet/EntityFramework/blob/1.0.0/src/Microsoft.EntityFrameworkCore/EntityFrameworkServiceCollectionExtensions.cs#L142-L158

Autofac and ASP.NET Web API ApiController

I have been using autofac with MVC 3 for a while and love it. I recently upgraded a project to MVC 4 and everything seems to be working except for Web Api ApiControllers. I am getting the following exception.
An error occurred when trying to create a controller of type 'MyNamespace.Foo.CustomApiController'. Make sure that the controller has a parameterless public constructor.
This seems to me to be an issue with DI via autofac. Am I missing something or is there something in the works. I know, MVC4 just came out and is a beta so I don't expect much but figured I could be missing something.
I have released Autofac integration packages on NuGet for the Beta versions of MVC 4 and Web API. The integrations will create an Autofac lifetime scope per controller request (MVC controller or API controller depending on the integration). This means that the controller and its dependencies will be automatically disposed at the end of each call. Both packages can be installed side-by-side in the same project.
MVC 4
https://nuget.org/packages/Autofac.Mvc4
http://alexmg.com/post/2012/03/09/Autofac-ASPNET-MVC-4-(Beta)-Integration.aspx
Web API
https://nuget.org/packages/Autofac.WebApi/
http://alexmg.com/post/2012/03/09/Autofac-ASPNET-Web-API-(Beta)-Integration.aspx
Links are now fixed.
I just configured this on one of my apps. There are different ways of doing it but I like this approach:
Autofac and ASP.NET Web API System.Web.Http.Services.IDependencyResolver Integration
First I created a class which implements System.Web.Http.Services.IDependencyResolver interface.
internal class AutofacWebAPIDependencyResolver : System.Web.Http.Services.IDependencyResolver {
private readonly IContainer _container;
public AutofacWebAPIDependencyResolver(IContainer container) {
_container = container;
}
public object GetService(Type serviceType) {
return _container.IsRegistered(serviceType) ? _container.Resolve(serviceType) : null;
}
public IEnumerable<object> GetServices(Type serviceType) {
Type enumerableServiceType = typeof(IEnumerable<>).MakeGenericType(serviceType);
object instance = _container.Resolve(enumerableServiceType);
return ((IEnumerable)instance).Cast<object>();
}
}
And I have another class which holds my registrations:
internal class AutofacWebAPI {
public static void Initialize() {
var builder = new ContainerBuilder();
GlobalConfiguration.Configuration.ServiceResolver.SetResolver(
new AutofacWebAPIDependencyResolver(RegisterServices(builder))
);
}
private static IContainer RegisterServices(ContainerBuilder builder) {
builder.RegisterAssemblyTypes(typeof(MvcApplication).Assembly).PropertiesAutowired();
builder.RegisterType<WordRepository>().As<IWordRepository>();
builder.RegisterType<MeaningRepository>().As<IMeaningRepository>();
return
builder.Build();
}
}
Then, initialize it at Application_Start:
protected void Application_Start() {
//...
AutofacWebAPI.Initialize();
//...
}
I hope this helps.

OData implementation for ASP.NET MVC

We have a fairly straight forward line of business application implemented with ASP.NET MVC2 and we have a new requirement to be able to share our data with other parts of the business, which include SharePoint 2010, Ruby and Python.
I'd like to use OData as the transport mechanism (as opposed to SOAP) using our existing MVC application. I'm struggling to find anyone mentioning an implementation of an OData provider for MVC.
Can you suggest either how I might be able to start rolling my own OData ASP.NET MVC provider or point me to somewhere which might have already started something similar?
You could check this out
https://meta.stackexchange.com/questions/43991/implement-odata-api-for-stackoverflow
implemented here https://data.stackexchange.com
OData with MVC is extremely easy to getup and going with MVC Web API.
e.g. Your OData controller would look like this:
public class ProductController : EntitySetController<Product, int>
{
private readonly IUnitOfWork _unitOfWork;
public ProductController(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public override IQueryable<Product> Get()
{
return _unitOfWork.Repository<Product>().Query().Get();
}
protected override Product GetEntityByKey(int key)
{
return _unitOfWork.Repository<Product>().FindById(key);
}
protected override Product UpdateEntity(int key, Product update)
{
update.State = ObjectState.Modified;
_unitOfWork.Repository<Product>().Update(update);
_unitOfWork.Save();
return update;
}
public override void Delete([FromODataUri] int key)
{
_unitOfWork.Repository<Product>().Delete(key);
_unitOfWork.Save();
}
protected override void Dispose(bool disposing)
{
_unitOfWork.Dispose();
base.Dispose(disposing);
}
}
A detailed walk-through can be seen here: http://blog.longle.net/2013/06/18/mvc-4-web-api-odata-entity-framework-kendo-ui-grid-datasource-with-mvvm/