How do I resolve a WebAPI dependency in Autofac that requires a parameter from the route? - autofac

I am struggling with wiring dependencies through autofac in my WebApi 2 project. I have a following interface and class that i'd like to inject in my GET and POST controller actions,
public interface IRepository
{
IContext Context
{
get;
}
void SomeOperation();
}
public MyRepository : IRepository
{
IContext _context;
public MyRepository(IContext context)
{
_context = context;
}
public Context
{
get
{
return _context;
}
}
public void SomeOperation
{
// Perform some operation using _context;
}
}
I 'd like IRepository to be injected in controller like this,
public class MyController : ApiController
{
private readonly IRepository _repo;
public ApplicationsController(IRepository repo)
{
_repo = repo;
}
// GET: api/v1/Contexts({contextId})
public IHttpActionResult Get(string contextId)
{
_repo.SomeOperation();
}
}
IContext object to be injected in MyRepository has to be fetched from a factory, something like this
public class ContextFactory
{
Hashtable contextMap;
IContext Get(string contextId)
{
if contextMap.Contains(contextId)
return contextMap[contextId].Value;
else
{
IContextConfiguration configuration = ContextConfigurationFactory.Get(contextId);
IContext context = new ConcreteContext(configuration);
contextMap.Add[contextId, context];
return context;
}
}
}
I am not sure how to wire all the classes and convert logic in factory classes by injecting relationships through Autofac so that context id passed in url is passed to ContextConfigurationFactory.Get and instantiate ConcreteContext object when not found in hash and eventually Autofac injecting right context object in MyRepository before passing it on to Get action in the controller.

Let's simplify this a bit. What you're trying to do is:
Get the context ID from a route parameter.
Use that route parameter in the factory to create a context.
The rest seems pretty much peripheral - the repository, the controller, all that. The crux of the question is that you need to get a route parameter into your factory.
Given that, let's put together some simplified code:
public class ContextFactory
{
public IContext Get(string contextId)
{
return new Context(contextId);
}
}
public interface IContext
{
string Id { get; }
}
public class Context : IContext
{
public Context(string id)
{
this.Id = id;
}
public string Id { get; private set; }
}
That's basically what you have:
An IContext interface that things need.
A ContextFactory that is basically responsible for building these things.
A Context concrete implementation of IContext that is built by the factory.
I would probably do something like this:
var builder = new ContainerBuilder();
builder.RegisterType<ContextFactory>();
builder.Register(ctx =>
{
var routeData = HttpContext.Current.Request.RequestContext.RouteData;
var id = routeData.Values["contextId"] as string;
var factory = ctx.Resolve<ContextFactory>();
return factory.Get(id);
}).As<IContext>()
.InstancePerLifetimeScope();
Now when you resolve IContext it will use your factory, get the current context ID from route data, and pass it through the factory.
I will leave the following for you to look into:
What happens if the route parameter isn't there? (Autofac won't let you return null.)
What happens if the route parameter has invalid data?
The route parameter is pretty hackable, is this a security risk?
...and so on.

Related

Passing connection string to Entity framework at runt time for each call

My Entity framework context is as following
public partial class MyContext : DbContext, IMyContext
{
static MyContext()
{
System.Data.Entity.Database.SetInitializer<MyContext>(null);
}
public MyContext()
: base("Name=MyContext")
{
}
I am resolving it through autofac in the following way
builder.RegisterType(typeof(MainContext)).As(typeof(DbContext)).InstancePerLifetimeScope();
builder.RegisterType<MainContext>().As<IMainContext>().InstancePerRequest();
This db context gets called in repository layer
#region Fields
private readonly IMyContext _context;
#endregion
#region Constructors and Destructors
public EmployeeRepository(IMyContext context)
{
_context = context;
}
#endregion
public void Create(Employee emp)
{
this._context.Employee.Add(emp);
}
Now my issue is , I want to set the connection string dynamically per call. The connection string will be passed through a webapi which i want to pass on to this context. Can anyone help me how can i do that? I am confused about autofac here. Secondly how can i make sure each call sets connection string and does not cache it.
You can use a factory that will build the context and set the connectionstring for you.
public interface IContextFactory
{
IContext GetInstance();
}
public class MyContextFactory : IContextFactory
{
public IContext GetInstance()
{
String connectionString = this.GetConnectionString(HttpContext.Current);
return new MyContext(connectionString);
}
private String GetConnectionString(HttpContext context)
{
// do what you want
}
}
builder.RegisterType<MyContextFactory>()
.As<IContextFactory>()
.InstancePerRequest();
builder.Register(c => c.Resolve<IContextFactory>().GetInstance())
.As<IContext>()
.InstancePerRequest();
If you can't get connectionstring based on HttpContext, you can change contextFactory implementation to expect initialization by WebAPI before creating the instance. For example :
public interface IContextFactory
{
IContext GetInstance();
void Initialize(String connectionString);
}
public class MyContextFactory : IContextFactory
{
private String _connectionString;
public void Initialize(String connectionString)
{
this._connectionString = connectionString;
}
public IContext GetInstance()
{
if (this._connectionString == null)
{
throw new Exception("connectionString not initialized");
}
return new MyContext(this._connectionString);
}
}
At the beginning of your web API call (through attribute for example), you can call the Initialize method. Because the factory is InstancePerRequest you will have one instance for the duration of the request.
By the way, I'm not sure to understand this registration
builder.RegisterType(typeof(MainContext)).As(typeof(DbContext)).InstancePerLifetimeScope();
builder.RegisterType<MainContext>().As<IMainContext>().InstancePerRequest();
It looks buggy because you will have 2 different registration of the same type and not for the same scope, is it intended ? Furthermore, it doesn't sound a good idea to register a DbContext, do you need this registration ?
The following registration looks better :
builder.RegisterType<MainContext>()
.As<IMainContext>()
.As<DbContext>()
.InstancePerRequest();

Using Dependency Injection with Breezejs

I am building an EntityFramework/WebApi back end.
I want to decouple my WebApi from the Entity Framework, and utilize Dependency Injection so I can swap out the "data source" for the web API.
I have been looking at the Unit of Work and Repository patterns.
I also want to use breezejs.
The breezejs TempHire samples has been alot of help, so I will use this as an example for my question -
https://github.com/Breeze/breeze.js.samples/tree/master/net/TempHire
In this sample, on the data side we have the UnitOfWork class -
public class UnitOfWork
{
private readonly EFContextProvider<TempHireDbContext> _contextProvider;
public UnitOfWork()
{
_contextProvider = new EFContextProvider<TempHireDbContext>();
StaffingResources = new Repository<StaffingResource>(_contextProvider.Context);
Addresses = new Repository<Address>(_contextProvider.Context);
// .. etc.
}
public IRepository<StaffingResource> StaffingResources { get; private set; }
public IRepository<Address> Addresses { get; private set; }
// .. etc.
public SaveResult Commit(JObject changeSet)
{
return _contextProvider.SaveChanges(changeSet);
}
}
Then on the WebApi side, it uses it like this -
[BreezeController]
[Authorize]
public class ResourceMgtController : ApiController
{
private readonly UnitOfWork _unitOfWork = new UnitOfWork();
[HttpPost]
public SaveResult SaveChanges(JObject saveBundle)
{
return _unitOfWork.Commit(saveBundle);
}
// ... etc.
}
I would like to refactor to something like this, so that I could swap out the back end.
public class UnitOfWork : IUnitOfWork
public class ResourceMgtController : ApiController
{
private readonly IUnitOfWork _unitOfWork;
public ResourceMgtController(IUnitOfWork unitOfWork) {
this._unitOfWOrk = unitOfWork; // Dependency Injected...
}
// ... etc.
}
What I can't wrap my head around, is how I can make it generic. The breeze client needs a method like this -
[HttpPost]
public SaveResult SaveChanges(JObject saveBundle)
{
return _unitOfWork.Commit(saveBundle);
}
And I can't put this in IUnitOfWork -
SaveResult SaveChanges(JObject saveBundle)
And really keep it decoupled from breeze, be able to swap out the back end for another backend. Am I attempting the abstraction at the wrong point? I guess if I want breeze on the client I will need to couple it on the backend?
You clearly can define an interface with that method:
public interface IUnitOfWork {
...
SaveResult SaveChanges(JObject saveBundle); // no problem
}
I suspect that you are objecting to the fact that both SaveResult and JObject are classes defined by libraries (Breeze.ContextProvider and Newtonsoft.Json.Linq respectively) you'd rather not reference somewhere.
These references wouldn't bother me any more than I mind referencing System.Linq to get IQueryable. In fact, a test double of SaveResult (a public class of Breeze.ContextProvider) is trivially easy to construct. Here is its definition (and the definition of KeyMapping, its only non-native dependent type):
public class SaveResult
{
public List<object> Entities;
public List<KeyMapping> KeyMappings;
public List<object> Errors;
}
public class KeyMapping
{
public string EntityTypeName;
public object TempValue;
public object RealValue;
}
But if Breeze and Newtonsoft.Json references are that noxious to you and you're willing to surrender some type safety, you can always create the interface like this:
public interface IUnitOfWork {
...
object SaveChanges(object saveBundle); // no safety, no problem
}
Then in your concrete UnitOfWork you add a suitable overload:
public object IUnitOfWork.SaveChanges(object saveBundle)
{
return SaveChanges((JObject) saveBundle);
}
public SaveResult SaveChanges(JObject saveBundle)
{
return _contextProvider.SaveChanges(saveBundle);
}
... and Bob's your uncle.
Yes, I did try it (in DocCode); worked fine for me.

Windsor and DbContext per request - DbContext has been disposed

I have a method in HomeController, that I'm trying to access through URL, like this:
http://localhost/web/home/GetSmth
First time it works, but after refreshing page, I get this error:
The operation cannot be completed because the DbContext has been disposed.
As the title states, I'm trying to use Castle Windsor and DbContext per request.
public class Installer1 : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly()
.BasedOn<IController>()
.LifestyleTransient()
);
var connString = ConfigurationManager.ConnectionStrings["MainDbContext"].ConnectionString;
container.Register(Component.For<MainDbContext>().DependsOn(Property.ForKey("conn").Eq(connString)).LifeStyle.PerWebRequest);
container.Register(Component.For<ISomeService>().ImplementedBy<SomeService>());
}
}
HomeController looks like this:
public class HomeController : Controller
{
private ISomeService _someService;
public HomeController(ISomeService someService)
{
_someService = someService;
}
public ActionResult Index()
{
return View();
}
public JsonResult GetSmth()
{
var data = _someService.GetData().ToList();
return Json(data, JsonRequestBehavior.AllowGet);
}
}
You are registering ISomeService with the default lifecycle, which is singleton. Once it's created, it will keep using the same DbContext. Simplest solution is to change its lifecycle to per request or transient.
container.Register(Component.For<ISomeService>()
.ImplementedBy<SomeService>()
.LifeStyle.PerWebRequest);

Injecting DbContext into Repository class library

The projects in my solution are set up like this:
App.Data
App.Models
App.Web
In App.Data, I'm using Entity Framework to access my data with a bunch of Repositories to abstract interaction with it. For obvious reasons, I would like my App.Web to reference only the App.Data project and not Entity Framework.
I'm using Constructor Injection to give my Controllers a reference to a Repository container that looks like this:
public interface IDataRepository
{
IUserRepository User { get; set; }
IProductRepository Product { get; set; }
// ...
}
public class DataRepository : IDataRepository
{
private readonly AppContext _context;
public DataRepository(AppContext context)
{
_context = context;
}
// ...
}
DataRepository will have a AppContext object (which inherits from Entity Framework's DbContext) that all the child Repositories will use to access the database.
So finally we come to my problem: how do I use Constructor Injection on DataRepository considering it's a code library and has no entry-point? I can't bootstrap AppContext in App.Web because then I have to reference Entity Framework from that project.
Or am I just doing something stupid?
You can define a RepositoryConnection class in App.Data that acts as a wrapper to the Context and removes the need to reference EF in App.Web. If you are using an IoC Container you can control the lifetime of the RepositoryConnection class to ensure that all instances of Repository get the same Context. This is a simplified example ...
public class RepositoryConnection
{
private readonly AppContext _context;
public RepositoryConnection()
{
_context = new AppContext();
}
public AppContext AppContext { get { return _context; } }
}
public class DataRepository : IDataRepository
{
private readonly AppContext _context;
public DataRepository(RepositoryConnection connection)
{
_context = connection.AppContext;
}
// ...
}

How do I use Ninject with ActionResults while making the controller IoC-framework-agnostic?

Nearly all of the Ninject examples I've seen explain how to use it with ASP.NET MVC, which will automatically inject dependencies into controllers. How would I use Ninject manually though? Let's say I have a custom ActionResult:
public class JsonResult : ActionResult
{
[Inject] public ISerializer Serializer { get; set; }
public JsonResult(object objectToSerialize)
{
// do something here
}
// more code that uses Serializer
}
Then in my controller, I'm using JsonResult in a method like this:
public ActionResult Get(int id)
{
var someObject = repo.GetObject(id);
return new JsonResult(someObject);
}
As you can see, I'm instantiating the object myself, which sidesteps Ninject's injection, and Serializer will be null. However, doing it the following way doesn't seem quite right to me:
public ActionResult Get(int id)
{
var someObject = repo.GetObject(id);
return IoC.Kernel.Get<JsonResult>(someObject);
}
Because now there's not only a dependency on Ninject in the controller, but I also have to expose the Ninject kernel in a static class/singleton and ensure that objects that rely on injection are only created via kernel.
Is there a way to somehow configure Ninject to inject the dependency without relying on exposing the kernel? I'd like to be able to use the new keyword if at all possible.
Use a factory that gets the kernel injected: E.g.
public class ResultFactory : IResultFactory
{
public ResultFactory(IKernel kernel)
{
this.kernel = kernel;
}
public JsonResult CreateJsonResult(object obj)
{
var result = this.kernel.Get<JsonResult>();
result.ObjectToSerialize = obj;
return result;
}
}
Inject this factory into the controller and use it to create your action results.
I think you should turn your JsonResult inside out:
public class JsonResult : ActionResult
{
public ISerializer Serializer { get; private set; }
public object ObjectToSerialize { get; set; }
public JsonResult(ISerializer serializer)
{
this.Serializer = serializer;
}
// more code that uses Serializer
}
This way you can retrieve the JsonResult with the container like this:
public ActionResult Get(int id)
{
var result = IoC.Kernel.Get<JsonResult>();
result.ObjectToSerialize = repo.GetObject(id);
return result;
}
Changing the signature of the JsonResult also enables Ninject to create an instance automatically. Because of this you can let Ninject automatically inject it as dependency into your controller:
public MyController(JsonResult result)
{
this.result = result;
}
public ActionResult Get(int id)
{
this.result.ObjectToSerialize = repo.GetObject(id);
return this.result;
}