Entity Framework ObjectContext with Dependency Injection - asp.net

Well, it seems like I'm stuck in my application structure. Here's what I want to do:
UI layer: An ASP.NET webforms website.
BLL: Business logic layer which calls the repositories on DAL.
DAL: .EDMX file (Entity Model) and ObjectContext with Repository classes which abstract the CRUD operations for each entity.
Entities: The POCO Entities. Persistence Ignorant. Generated by Microsoft's ADO.Net POCO Entity Generator.
I'd like to create an obejctcontext per HttpContext in my repositories to prevent performance/thread [un]safety issues. Ideally it would be something like:
public MyDBEntities ctx
{
get
{
string ocKey = "ctx_" + HttpContext.Current.GetHashCode().ToString("x");
if (!HttpContext.Current.Items.Contains(ocKey))
HttpContext.Current.Items.Add(ocKey, new MyDBEntities ());
return HttpContext.Current.Items[ocKey] as MyDBEntities ;
}
}
The problem is the I don't want to access HttpContext in my DAL (Where the repositories are located). But I have to somehow pass HttpContext to DAL. based on the answer to my question here, I have to use IoC pattern. Ideally I'd like to achieve something like this in amulti-layered architecture.
I've checked out Autofac and it seems very promising. But I'm not sure how could I achieve this (Passing Httpcontext to make sure one ObjectContext is instantiated per HttpContext) in a multi-layered architecture. Could anyone give me some working example on how to achieve this? How can I be aware of HttpContext in DAL without directly accessing the HttpContext in DAL? I feel like I'm a bit lost in designing a multi-layered solution.

I have never used IoC container with WebForms so get this as some high level solution which should probably be futher improved.
You can try creating some IoC provider as singleton:
public class IoCProvider
{
private static IoCProvider _instance = new IoCProvider();
private IWindsorContainer _container;
public IWindsorContainer
{
get
{
return _container;
}
}
public static IoCProvider GetInstance()
{
return _instance;
}
private IoCProvider()
{
_container = new WindsorContainer(new XmlInterpreter(new ConfigResource("castle")));
}
}
Your web.config will have to contain sections like (the configuration is based on your previous post):
<configuration>
<configSections>
<section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
</configSections>
<castle>
<components>
<component id="DalLayer"
service="MyDal.IDalLayer, MyDal"
type="MyDal.MyDalLayer, MyDal"
lifestyle="PerWebRequest">
<!--
Here we define that lifestyle of DalLayer is PerWebRequest so each
time the container resolves IDalLayer interface in the same Web request
processing, it returns same instance of DalLayer class
-->
<parameters>
<connectionString>...</connectionString>
</parameters>
</component>
<component id="BusinessLayer"
service="MyBll.IBusinessLayer, MyBll"
type="MyBll.BusinessLayer, MyBll" />
<!--
Just example where BusinessLayer receives IDalLayer as
constructor's parameter.
-->
</components>
</castle>
<system.Web>
...
</system.Web>
</configuration>
Implementation of these interfaces and classes can look like:
public IDalLayer
{
IRepository<T> GetRepository<T>(); // Simplified solution with generic repository
Commint(); // Unit of work
}
// DalLayer holds Object context. Bacause of PerWebRequest lifestyle you can
// resolve this class several time during request processing and you will still
// get same instance = single ObjectContext.
public class DalLayer : IDalLayer, IDisposable
{
private ObjectContext _context; // use context when creating repositories
public DalLayer(string connectionString) { ... }
...
}
public interface IBusinessLayer
{
// Each service implementation will receive necessary
// repositories from constructor.
// BusinessLayer will pass them when creating service
// instance
// Some business service exposing methods for UI layer
ISomeService SomeService { get; }
}
public class BusinessLayer : IBusinessLayer
{
private IDalLayer _dalLayer;
public BusinessLayer(IDalLayer dalLayer) { ... }
...
}
Than you can define base class for your pages and expose the business layer (you can do the same with any other class which can be resolved):
public abstract class MyBaseForm : Page
{
private IBusinessLayer _businessLayer = null;
protected IBusinessLayer BusinessLayer
{
get
{
if (_businessLayer == null)
{
_businessLayer = IoCProvider.GetInstance().Container.Resolve<IBusinessLayer>();
}
return _businessLayer;
}
...
}
Complex solution whould involve using custom PageHandlerFactory to resolve pages directly and inject dependencies. If you want to use such solution check Spring.NET framework (another API with IoC container).

Related

Dependency injection in my singleton class .NET Core

I'm having trouble injecting the dependency I pass into the constructor of my Asegurador class.
When I want to instantiate, _instance = new Asegurador(); I don't have the parameter required by the constructor (IGeneralRepository), how can I solve this problem?
Note that my Asegurador class is a singleton.
private Asegurador(IGeneralRepository generalRepository)
{
_token = GetTokenAsync().Result;
_repository = generalRepository;
}
public static Asegurador Instance
{
get
{
if (_instance == null)
{
_local = System.Environment.GetEnvironmentVariable("SEGUROS_LOCAL") ?? "local";
_instance = new Asegurador();
}
return _instance;
}
}
When using a DI container you can (and should) let it take care of handling the Lifetime of a dependency.
.Net core's dependency injection lets you define 3 different lifetimes for your services (Docs):
Transient: a transient service is recreated each time it is injected
Scoped: a scoped service is created once for each request
Singleton: a singleton is created once in the whole application lifetime.
The best approach to achieve what you are trying to do is the following:
Amend your Asegurador class so that it has a public constructor and get rid of the static Instance property
public class Asegurador {
public Asegurador(IGeneralRepository generalRepository)
{
_token = GetTokenAsync().Result; //I know too few about it but I would try to pass it as a dependency as well
_repository = generalRepository;
}
}
instead of calling Asegurador.Instance inject the dependency in the client class
public class IUseTheAsegurador {
private Asegurador _asegurador;
public IUseTheAsegurador(Asegurador asegurador)
{
_asegurador = asegurador;
}
}
Register all in the DI in your Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSingleton<Asegurador>();
services.AddScoped<IUseAsegurador>(); //This can be Singleton or Transient as well, depending on your needs
...
}
I (a lot of people actually :D) prefer this approach because it leaves the responsability of guaranteeing a single instance to the DI and also because lets you write unit tests for the client class (IUseTheAsegurador in the example) in an easier way.

Dependency injection for non controller classes and calling them

Trying to wrap my head around dependency injection, coming from the world of static classes and instantiated classes. Here is what I currently have:
[SomeFilter]
public class AController : Controller
{
private readonly IOptions<AppSettings> _appSettings;
public AController(IOptions<AppSettings> appSettings)
{
_appSettings = appSettings;
}
// GET: /characters/
public IActionResult Index()
{
//do something
}
SomeFilter gets called immediately, and does this:
public class SomeFilter: ActionFilterAttribute, IActionFilter
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
OtherClass.RunMe();
}
}
OtherClass looks like this:
public class OtherClass
{
private readonly IOptions<AppSettings> _appSettings;
public OtherClass(IOptions<AppSettings> appSettings)
{
_appSettings = appSettings;
}
public RunMe()
{
//do something
}
I also have OtherClass registered as a service.Singleton in the Startup.cs.
I get an error stating:
"An object reference is required for a non-static field"
for the OtherClass.RunMe(); call.
I was under the assumption that I can call this class from anywhere within my code instead of having to create a new instance of it? Essentially, how do I call methods from other classes using dependency injection?
You can't constructor injection on filters. It's all about run time order. When you try injection on constructor, your IoC container not reachable at the moment. You should be use property/setter injection.
I prefer using structuremap container for to do this. Because structuremap has very easy to apply any type injection. For example when you have a filter registry like this
public class ActionFilterRegistry : Registry
{
public ActionFilterRegistry(Func<IContainer> containerFactory)
{
For<IFilterProvider>().Use(
new StructureMapFilterProvider(containerFactory));
Policies.SetAllProperties(x =>
x.Matching(p =>
p.DeclaringType.CanBeCastTo(typeof(ActionFilterAttribute)) &&
p.DeclaringType.Namespace.StartsWith("YourNameSpace") &&
!p.PropertyType.IsPrimitive &&
p.PropertyType != typeof(string)));
}
}
And you register it on your global.asax(prefer) or one of your startup class.
Example app_Start method.
DependencyResolver.SetResolver(new StructureMapDependencyResolver(() => Container ?? ObjectFactory.Container));
ObjectFactory.Container.Configure(cfg =>
{
cfg.AddRegistry(new StandardRegistry());
cfg.AddRegistry(new ControllerRegistry());
cfg.AddRegistry(new ActionFilterRegistry(() => Container));
cfg.AddRegistry(new MvcRegistry());
});
Then you can use any filter with injection. But pay attention you shouldn't be use contructor injection like you do.
I found a way to inject into the filter by using
[ServiceFilter(typeof(MyFilter))]
instead of just
[MyFilter]
and within the filter's
(ActionExecutingContext context)
{
var controller = context.Controller as Controller.
controller.whateverIneed
}
This now provides me with what I need within the filter. What I also realized is that I can't remove the need for creating references to other classes using new, as I was under the impression Core's dependency was all about "no more new". This gets into fundamentals with Core which I'm still grasping with.
What I ended up doing was creating new classes that do some work, but they are setup as services and registered in the startup.cs. I'm still grappling on how to intermingle registered services (which I can inject) and new instances of worker classes (which usually hold static information), and passing information between them all.

Autofac lazy property injection

I'm trying to inject business logic implementations into web API base controller. Somehow property in base controller is always null.
Also how can I do lazy injection?
Startups.cs
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterType<ViewBusinessLogic>().As<IViewBusinessLogic>().
PropertiesAutowired();
containerBuilder.Populate(services);
var container = containerBuilder.Build();
return container.Resolve<IServiceProvider>();
}
Interface, implementation and base controller:
public interface IViewBusinessLogic
{
IEnumerable<dynamic> GetView(Guid viewId);
}
public class ViewBusinessLogic : BusinessLogic, IViewBusinessLogic
{
public IEnumerable<dynamic> GetView(Guid viewId)
{
return new List<dynamic>
{
new { Test = "Test1" },
new { Test = "Test2" }
};
}
}
public abstract class BaseController : Controller
{
public IViewBusinessLogic ViewBusinessLogic { get; }
}
Controllers aren't resolved by the DI framework by default. You need to add AddControllerAsServices to have them be resolved by the DI of your choice.
From this GitHub issue:
Hi,
Maybe I'm wrong but as I tested deeply (and checked Mvc source code), Controllers are not resolved from IServiceProvider, but only constructor arguments of them are resolved from IServiceProvider.
Is that by design? I'm very suprised. Because, I'm using a different DI framework which supports property injection. And I can not use property injection since Controller instances are not requested from IServiceProvider.
Have you added AddControllersAsServices in your Startup (https://github.com/aspnet/Mvc/blob/ab76f743f4ee537939b69bdb9f79bfca35398545/test/WebSites/ControllersFromServicesWebSite/Startup.cs#L37)
The example above quoted for future reference.
public void ConfigureServices(IServiceCollection services)
{
var builder = services
.AddMvc()
.ConfigureApplicationPartManager(manager => manager.ApplicationParts.Clear())
.AddApplicationPart(typeof(TimeScheduleController).GetTypeInfo().Assembly)
.ConfigureApplicationPartManager(manager =>
{
manager.ApplicationParts.Add(new TypesPart(
typeof(AnotherController),
typeof(ComponentFromServicesViewComponent),
typeof(InServicesTagHelper)));
manager.FeatureProviders.Add(new AssemblyMetadataReferenceFeatureProvider());
})
// This here is important
.AddControllersAsServices()
.AddViewComponentsAsServices()
.AddTagHelpersAsServices();
services.AddTransient<QueryValueService>();
services.AddTransient<ValueService>();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}
As for the second part of your question: I don't think it's possible to have lazy instantiation via IoC container at all. Best fit for you is to create a factory class and inject the factory rather than the concrete service.
But usually you don't need lazy instantiation anyways, the instantiation of services should be fast. If it's not, you probably doing some funky stuff in the constructor (connecting somewhere, or doing other long running operations), which is an anti-pattern.

ASP.NET Unity.MVC DI with EF context

I'm using Unity.MVC for DI in my ASP.NET MVC 4.6 app. I have a service interface passed into the controller and that's working great. Now I want to pass in an interface to the EF context to the service but I'm not sure how to do this. I've read EF has this IObjectContextAdapter that I could pass into my service ctor and that works, but I need to then query the actual tables on inside my service from this context but because it's an IObjectContextAdapter it doesn't know my tables. How do I do this?
public class ContactService : IContactService
{
//private ContactsEntities context;
private IObjectContextAdapter context;
// test ctor
public ContactService(IObjectContextAdapter ctx)
{
context = ctx;
}
// prod ctor
public ContactService()
{
context = new ContactsEntities();
}
List<Contact> GetAllContacts()
{
return (from c in context.ObjectContext.?? // I need to query the Contacts table that would be attached to the actual context I pass in but still keep the decoupling from using an Interface passed into the ctor
}
}
The IObjectContextAdapter is the type of ObjectContext property of DbContext.
You should subclass DbContext e.g. ContactsDatabaseContext
public class ContactsDatabaseContext : DbContext, IContactsDatabaseContext
{
// ...
}
And then just register your ContactsDatabaseContext with your IoC container. Something like this:
container.RegisterType<IContactsDatabaseContext, ContactsDatabaseContext>();
Your ContactsDatabaseContext class and IContactsDatabaseContext interface should have properties of type DbSet<T> that refer to your tables e.g.:
IDbSet<BrandDb> Users { get; set; }
UPDATE:
Since you are using a generated file, then do this:
public partial class ContactsDatabaseContext : IContactsDatabaseContext
{
// Expose the DbSets you want to use in your services
}

How can you inject an asp.net (mvc2) custom membership provider using Ninject?

OK, so I've been working on this for hours. I've found a couple of posts here, but nothing that actually resolves the problem. So, let me try it again...
I have an MVC2 app using Ninject and a custom membership provider.
If I try and inject the provider using the ctor, I get an error: 'No parameterless constructor defined for this object.'
public class MyMembershipProvider : MembershipProvider
{
IMyRepository _repository;
public MyMembershipProvider(IMyRepository repository)
{
_repository = repository;
}
I've also been playing around with factories and Initialize(), but everything is coming up blanks.
Any thoughts/examples?
The Membership provider model can only instantiate a configured provider when it has a default constructor. You might try this using the Service Locator pattern, instead of using Dependency Injection. Example:
public class MyMembershipProvider : MembershipProvider
{
IMyRepository _repository;
public MyMembershipProvider()
{
// This example uses the Common Service Locator as IoC facade, but
// you can change this to call NInject directly if you wish.
_repository = ServiceLocator.Current.GetInstance<IMyRepository>;
}
This is how I was able to do this:
1) I created a static helper class for Ninject
public static class NinjectHelper
{
public static readonly IKernel Kernel = new StandardKernel(new FooServices());
private class FooServices : NinjectModule
{
public override void Load()
{
Bind<IFooRepository>()
.To<EntityFooRepository>()
.WithConstructorArgument("connectionString",
ConfigurationManager.ConnectionStrings["FooDb"].ConnectionString);
}
}
}
2) Here is my Membership override:
public class FooMembershipProvider : MembershipProvider
{
private IFooRepository _FooRepository;
public FooMembershipProvider()
{
NinjectHelper.Kernel.Inject(this);
}
[Inject]
public IFooRepository Repository
{
set
{
_FooRepository = value;
}
}
...
With this approach it doesn't really matter when the Membership provider is instantiated.
I had the same problem at the exact same spot in the book. It wasn't until later on in the book that I noticed there were two separate web.config files. I initially placed my connectionString key in the wrong web.config file. It wasn't until I placed the connectionString in the correct web.config file that the 'no parameterless constructor' error went away.

Resources