I'm currently trying out Autofac in a new ASP.NET MVC project after having used Ninject, Castle Windsor and other IoC containers in the last years. So while I know about IoC containers in general, I'm fairly new to Autofac and I'm still looking for some best practices.
Currently I'm trying to find out if there is a way to resolve the innermost nested scope.
I have the following situation: a component that is registered as SingleInstance() has a method that creates a nested lifetime scope, providing a configuration action to configure some components as InstancePerLifetimeScope, and within this nested scope resolves the registered components to do something useful, like so:
ILifetimeScope currentScope = ???;
using (var scope = currentScope.BeginLifetimeScope(cb => {
cb.RegisterType<X>().InstancePerLifetimeScope();
// ...
}))
{
var comp = scope.Resolve<X>();
// ...
}
The issue is that I would like currentScope to be the innermost lifetime scope, because I know that X depends on components inside the innermost scope. In the simplest case that would be e.g. the current request lifetime scope. I can of course get it with AutofacDependencyResolver.Current.RequestLifetimeScope but I don't want to use that as it isn't really well testable. Also, that lifetime scope isn't necessarily the innermost.
So, is there a way to find the innermost lifetime scope given e.g. the root container or a different ILifetimeScope?
In Autofac, the innermost scope is always the container. Using the AutofacDependencyResolver, it'd be
AutofacDependencyResolver.Current.ApplicationContainer
There is no way from a nested scope (if all you have is an ILifetimeScope) to "walk backward" to get to the container. I'm not necessarily sure you want to do that, anyway.
It sounds like your SingleInstance component is doing some sort of service location, basically, with manual registration/resolution of certain components. If the set of types being registered is fixed, I might recommend (if possible) some redesign of your system, so the SingleInstance component isn't registered as SingleInstance anymore and instead gets registered as InstancePerDependency, then have that take these other items in as constructor parameters.
Instead of...
// Consuming class like this...
public class BigComponent
{
public void DoSomethingCool()
{
using(var scope = ...)
{
var c = scope.Resolve<SubComponent>();
c.DoWork();
}
}
}
// ...and container registrations like this...
builder.RegisterType<BigComponent>().SingleInstance();
You might try inverting it a bit:
// Consuming class like this...
public class BigComponent
{
private SubComponent _c;
public BigComponent(SubComponent c)
{
_c = c;
}
public void DoSomethingCool()
{
_c.DoWork();
}
}
// ...and container registrations like this...
builder.RegisterType<BigComponent>().InstancePerDependency();
builder.RegisterType<SubComponent>().InstancePerLifetimeScope();
The idea is to not have to do the on-the-fly registration-and-immediate-resolution thing.
If you're stuck doing service location, you'll need to use AutofacDependencyResolver.Current.ApplicationContainer if you need the absolute innermost scope, but keep in mind any objects you register scoped to InstancePerHttpRequest will not be resolvable if you do that, so you could get into trouble. It really is recommended to use the AutofacDependencyResolver.Current.RequestLifetimeScope instead. That would make your method:
var requestScope = AutofacDependencyResolver.Current.RequestLifetimeScope;
using (var scope = requestScope.BeginLifetimeScope(cb => {
cb.RegisterType<X>().InstancePerLifetimeScope();
// ...
}))
{
var comp = scope.Resolve<X>();
// ...
}
In a testing environment, the AutofacDependencyResolver lets you swap in the provider that dictates how request lifetimes get generated. You can implement a simple/stub one like this:
public class TestLifetimeScopeProvider : ILifetimeScopeProvider
{
readonly ILifetimeScope _container;
private ILifetimeScope _lifetimeScope = null;
public TestLifetimeScopeProvider(ILifetimeScope container)
{
if (container == null) throw new ArgumentNullException("container");
_container = container;
}
public ILifetimeScope ApplicationContainer
{
get { return _container; }
}
public ILifetimeScope GetLifetimeScope()
{
if (_lifetimeScope == null)
{
_lifetimeScope = ApplicationContainer.BeginLifetimeScope("httpRequest")
}
return _lifetimeScope;
}
public void EndLifetimeScope()
{
if (_lifetimeScope != null)
_lifetimeScope.Dispose();
}
}
Again, just a stub for unit testing, not something you'd ever use in production.
Then when you wire up the DependencyResolver in your test, you provide your lifetime scope provider:
var lsProvider = new TestLifetimeScopeProvider(container);
var resolver = new AutofacDependencyResolver(container, lsProvider);
DependencyResolver.SetResolver(resolver);
This lets you use InstancePerHttpRequest and such inside unit tests without actually having a real request context. It also means you should be able to use the request lifetime scope in your registration/resolution method and not have to fall back on the application container.
For those who are searching for ASP.NET WebApi:
You can use GetRequestLifetimeScope() method of AutofacWebApiDependencyResolver.
Related
Here's what I'm doing so far (code simplified):
public class MyRegistrationSource : IRegistrationSource
{
public MyRegistrationSource(ContainerBuilder builder /*,...*/)
{
// ...
this.builder = builder;
}
public IEnumerable<IComponentRegistration> RegistrationsFor(
Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
{
// Some checks here
var interfaceType = serviceWithType.ServiceType;
var implementorType = FindTheRightImplementor(interfaceType);
if (myRegisterConditionSatisfied)
{
return Register(implementorType, interfaceType);
}
return Empty;
}
private IEnumerable<IComponentRegistration> Register(Type concrete, Type #interface)
{
var regBuilder = builder.RegisterType(concrete).As(#interface).IfNotRegistered(#interface);
return new[] { regBuilder.CreateRegistration() };
}
}
Then, at startup I'm doing something like
builder.RegisterSource(
new NonRegisteredServicesRegistrationSource(builder/*, ...*/));
The above is intended to register those matching services only when there's no previous registration. I tried doing the registration without using the ContainerBuilder but couldn't get it to work.
This is working but are there any issues in passing-in the ContainerBuilder instance to the RegistrationSource?
Thanks!
I'd probably argue against passing in a ContainerBuilder.
Every type you register in your source will add a callback to a list of callbacks inside the Container Builder which will never get cleared, potentially creating a memory leak.
I'd suggest calling the static method RegistrationBuilder.ForType instead, which will give you a fluent builder and should let you subsequently call CreateRegistration as you are now.
You can see some pretty good examples of how do this in our Moq integration:
var reg = RegistrationBuilder.ForType(concrete)
.As(#interface)
.CreateRegistration();
Also, I don't believe IfNotRegistered will have any effect when used outside the context of a ContainerBuilder. You should use the provided registrationAccessor parameter to the registration source to look up a TypedService to see if it has already been registered:
var isRegistered = registrationAccessor(new TypedService(#interface)).Any();
I have application MVC use Unity Ioc.
Declare and init service:
public static void Initialize()
{
IUnityContainer container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
private static IUnityContainer BuildUnityContainer()
{
IUnityContainer container = new UnityContainer();
container.RegisterType<ImyService, myService>(new HttpContextLifetimeManager<ImyService>());;
return container;
}
In class i use code bellow:
var service = DependencyResolver.Current.GetService<ImyService>();
This is file UnityControllerFactory.cs
public override object GetValue()
{
var assemblyQualifiedName = typeof(T).AssemblyQualifiedName;
if (assemblyQualifiedName != null)
return HttpContext.Current.Items[assemblyQualifiedName];
return null;
}
When i running application, it return error at: HttpContext.Current.Items[assemblyQualifiedName];
Error:
Additional information: Object reference not set to an instance of an
object.
How to i can using service in my class. Thanks!
the issue here is that the HTTPContext is null when used from a class ( or class library ) like you are trying to do. That's because there is no request to work with. When you use it from a controller everything works because the controller is hit as part of a request so you're golden there.
You could update your UnityController Factory class and pass the needed HTTPContext data as a parameter instead, then you can use it when you need to. It complicates things a little bit though.
Note, you more than likely don't need to pass the whole HTTPContext object, just pass the minimum you can get away with.
I have setup RavenDB embedded in my MVC application. I follower all the tutorials to make the RavenController and I can query the Session in the controller.
Now I would really like to break away from mixing data in the controller and create a Data layer so that I can do some Business logic which will help me create complex View Models.
How do I query the Session in a plain class file? I can't seem to find any info on how to do this.
Dependency Injection is great for this. You move aside the creation of the necessary services and let the container manage the lifecycle of the components, including scoping IDocumentSession to one instance per HTTP request.
As an example, using Autofac (you'd need both the Autofac and Autofac.Mvc5 packages) you could have a class in your App_Start folder like this, and then call AutofacConfig.Configure() from your Global.asax:
public static class AutofacConfig
{
public static IContainer Container { get; private set; }
public static void Configure()
{
var builder = new ContainerBuilder();
var thisAssembly = Assembly.GetExecutingAssembly();
// Register our controllers with the container
builder.RegisterControllers(thisAssembly).PropertiesAutowired(PropertyWiringOptions.PreserveSetValues);
// Provide injections of the HTTP abstractions (HttpContextBase, etc.)
builder.RegisterModule(new AutofacWebTypesModule());
// Create and register the Raven IDocumentStore
builder.Register(c =>
{
var store = new DocumentStore {ConnectionStringName = "RavenDB"};
store.Initialize();
Raven.Client.Indexes.IndexCreation.CreateIndexes(typeof (MvcApplication).Assembly, store);
return store;
})
.As<IDocumentStore>()
.SingleInstance();
// Provide injection of Raven IDocumentSession
builder.Register(c => c.Resolve<IDocumentStore>().OpenSession())
.InstancePerRequest();
Container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(Container));
}
}
Then, when you need an IDocumentSession some place outside of a controller:
// Business logic, or other class that injection is not provided for.
var session = AutofacConfig.Container.Resolve<IDocumentSession>();
Also include autofac otherwise you will get an error saying "does not contain definition Resolve ..."
using Autofac;
You can do similar things with most other DI container libraries; the API is just slightly different.
HttpContext.Current.Session holds current session, but you should definitely not use it in business logic layer. Business logic layer should not be aware of HttpContext.
Basic solution to this problem would be to create interface:
public interface ISession
{
int SomeValue { get; set; }
}
and implementation
public class HttpContextBasedSession : ISession
{
public int SomeValue
{
get
{
return Convert.ToInt32(HttpContext.Current.Session["SomeValue"]);
}
set
{
HttpContext.Current.Session["SomeValue"] = value;
}
}
}
Bind it with dependency injection framework.
I have a Data Access Layer, a Service Layer, and a Presentation Layer. The Presentation Layer is ASP.NET MVC2 RTM (web), and the Service Layer is WCF (services). It's all .NET 3.5 SP1.
The problem is that in the services, the objects being returned are marked with the [DataContract] attribute. The web is using the AppFabric Cache (a.k.a Velocity) SessionStateProvider to store session state. Due to this, anything I store in the session must be serializable.
Here comes the problem: the DataContracts aren't marked with [Serializable] and as far as I can remember, by introducing it onto a class already marked with [DataContract] some issues arise, and so I don't believe this is a solution.
I was initially planning on using the DataContracts right in the web layer, using them as models to views related to rendering the DataContracts (probably nested inside a higher level ViewModel class). But due to the session state provider requiring all objects stored inside it to be serializable, I'm starting to rethink this strategy. It would be nice to have though, since they contain validation logic using the IDataErrorInfo interface, and the same validation logic could be re-used in MVC as part of model binding.
What do you believe is the best way to allow me to reduce the work needed?
I've currently thought of the following different ways:
A. Create a 'ServiceIntegration' part in the web project.
This would be a middle man between my controllers and my WCF service layer. The ServiceIntegration part would speak to the service layer using DataContracts, and to the Web layer using ViewModels, but would have to transform between the DataContracts and ViewModels using a two-way Transformer.
Also, since the IDataErrorInfo Validation wouldn't be re-usable, it would be necessary to create a Validator per DataContract too, that uses the Transformer to convert from ViewModel to DataContract, perform validation using IDataErrorInfo and return its results. This would then be used inside action methods of Controllers (e.g. if (!MyValidator.IsValid(viewModel)) return View();)
Different classes required: xDataContract, xViewModel, xTransformer, xValidator
B. Create a 'SessionIntegration' part in the web project
This would be a middle-man between the controllers (or anything accessing the session) and the session itself. Anything requiring access to the session would go through this class. DataContracts would be used in the entire application, unless they are being stored into the session. The SessionIntegration part would take the responsibility of transforming the DataContract to some ISerializable form, and back. No additional Validator is needed because of the use of of IDataErrorInfo interface on the DataContract.
Different classes required: xDataContract, xTransformer, xSerializableForm
Note: there would still be ViewModels around in both scenarios, however with (B) I'd be able to compose ViewModels from DataContracts.
(B) has the benefit of not needing an extra validator.
Before I go off and implement (A)/(B) fully, I'd like some feedback. At the moment, I'm starting to lean towards (B), however, (A) might be more flexible. Either way, it seems like way too much work for what it's worth. Has anyone else come across this problem, do you agree/disagree with me, and/or do you have any other way of solving the problem?
Thanks,
James
Without going the full blown route of A or B, could you just make a generic ISerializable wrapper object and put those in your SessionState?
[Serializable]
public class Wrapper : ISerializable
{
public object Value { get; set; }
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
if (Value != null)
{
info.AddValue("IsNull", false);
if (Value.GetType().GetCustomAttributes(typeof(DataContractAttribute), false).Length == 1)
{
using (var ms = new MemoryStream())
{
var serializer = new DataContractSerializer(Value.GetType());
serializer.WriteObject(ms, Value);
info.AddValue("Bytes", ms.ToArray());
info.AddValue("IsDataContract", true);
}
}
else if (Value.GetType().IsSerializable)
{
info.AddValue("Value", Value);
info.AddValue("IsDataContract", false);
}
info.AddValue("Type", Value.GetType());
}
else
{
info.AddValue("IsNull", true);
}
}
public Wrapper(SerializationInfo info, StreamingContext context)
{
if (!info.GetBoolean("IsNull"))
{
var type = info.GetValue("Type", typeof(Type)) as Type;
if (info.GetBoolean("IsDataContract"))
{
using (var ms = new MemoryStream(info.GetValue("Bytes", typeof(byte[])) as byte[]))
{
var serializer = new DataContractSerializer(type);
Value = serializer.ReadObject(ms);
}
}
else
{
Value = info.GetValue("Value", type);
}
}
}
}
As an extension to the provided answer, I added these two methods to ease storing/retrieving the data.
public static void Set<T>(HttpSessionStateBase session, string key, T value)
{
session[key] = new Wrapper(value);
}
public static T Get<T>(HttpSessionStateBase session, string key)
{
object value = session[key];
if (value != null && typeof(T) == value.GetType())
{
return (T) value;
}
Wrapper wrapper = value as Wrapper;
return (T) ((wrapper == null) ? null : wrapper.Value);
}
This makes it a little easier to set/get values from the session:
MyDataContract c = ...;
Wrapper.Set(Session, "mykey", c);
c = Wrapper.Get<MyDataContract>(Session, "mykey");
To make it even easier, add extension methods:
public static class SessionWrapperEx
{
public static void SetWrapped<T>(this HttpSessionStateBase session, string key, T value)
{
Wrapper.Set<T>(session, key, value);
}
public static T GetWrapped<T>(this HttpSessionStateBase session, string key)
{
return Wrapper.Get<T>(session, key);
}
}
And use as below:
MyDataContract c = ...;
Session.SetWrapped("mykey", c);
c = Session.GetWrapped<MyDataContract>("mykey");
My case it is Ninject 2.
// normal explicit dispose
using (var dc = new EFContext)
{
}
But sometimes I need to keep the context longer or between function calls.
So I want to control this behavior through IoC scope.
// if i use this way. how do i make sure object is disposed.
var dc = ninject.Get<IContext>()
// i cannot use this since the scope can change to singleton. right ??
using (var dc = ninject.Get<IContext>())
{
}
Sample scopes
Container.Bind<IContext>().To<EFContext>().InSingletonScope();
// OR
Container.Bind<IContext>().To<EFContext>().InRequestScope();
From what I know (I did a research about a month ago) Ninject does not support lifecycle management at all. Castle Windsor and AutoFac (and to some extent StructureMap, but only when using nested containers) will take care of disposing disposable components they create at appropriate time.
If you have control over the interface of IContext, add IDisposable to the list of interfaces from which it inherits. If not, downcast the IContext you get to an IDisposable...
var context = ninject.Get<IContext>();
using ((IDisposable)context)
{
}
You also have the option of altering the interface of IContext to do this by composition, if you control IContext...
public interface IContext
{
// ...
IDisposable GetUsageHandle();
}
var context = ninject.Get<IContext>();
using (context.GetUsageHandle())
{
}
In addition to the standard scopes of Transient, OnePerThread, and Singleton, you can use an ActivationBlock in order to control the lifetime of a whole set of objects. When the block is disposed, all object retrieved by the block go out of scope - so singletons and others are disposed of when their instances are requested by the activation block.
var kernel = new StandardKernel();
kernel.Bind<NotifiesWhenDisposed>().ToSelf();
NotifiesWhenDisposed instance = null;
using(var block = new ActivationBlock(kernel))
{
instance = block.Get<NotifiesWhenDisposed>();
instance.IsDisposed.ShouldBeFalse();
}
instance.IsDisposed.ShouldBeTrue();