Autofac to Common Service Locator (TypedParameter issue) - autofac

How do i modify the following from Autofac to use the Common Service Locator (where _context is of type IComponentContext):
var query = _context.Resolve<IContentQuery>(TypedParameter.From<IContentManager>(this));
The code above is taken from Orchard and and i'm trying to remove the dependency on Autofac. Usually i'd try something like:
var query = ServiceLocator.Current.GetInstance<IContentQuery>();
However this returns null and i can't see how to handle the TypedParameter stuff as i don't understand what it's doing.
I'd really appreciate it if someone could help. Thanks

A TypedParameter provides an additional value to the constructor of the component being resolved. In this case the underlying ContextQuery will accept a parameter of type IContentManager with the value this being passed.
Common Service Locator doesn't support parameterisation, so you will probably need to use the specific features of your underlying IoC container.
Hope this helps.
Nick

Related

How to resolve Autofac per-request service from custom attribute

I have configured my EF context configured like so
b.RegisterAssemblyTypes(webAssembly, coreAssembly)
.Where(t => t.IsAssignableTo<DbContext>())
.InstancePerLifetimeScope();
I would like to use it from a custom authorization attribute that hits the database using my EF context. This means no constructor-injection. I achieve this by using CommonSeviceLocator
var csl = new AutofacServiceLocator(container);
ServiceLocator.SetLocatorProvider(() => csl);
...
var user = await ServiceLocator.Current
.GetInstance<SiteContext>().FindAsync(id);
I am finding that this fails with a "multiple connections not supported" error if the browser issues two simultaneous requests to routes using this attribute. It seems like this might be due to what is mentioned in this answer. My guess is that ServiceLocator resolves from the root scope rather than the web request scope and the two request are conflicting (either request in isolation works fine).
This seems confirmed by that when I change to InstancePerRequest() I get this from any invocation of the attribute.
Autofac.Core.DependencyResolutionException No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is
being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.
So it seems like maybe ServiceLocator is simply not the way to go.
How do I resolve the request-scoped SiteContext from inside the attribute (using a service-locator pattern)?
Your issue derives from the fact that you are trying to put behavior inside of an Attribute. Attributes are for defining meta-data on code elements and assemblies, not for behavior.
Microsoft's marketing of Action Filter Attributes has led people implementing DI down the wrong path by putting both the Filter and the Attribute into the same class. As described in the post passive attributes, the solution is to break apart filter attributes into 2 classes:
An attribute that contains no behavior to mark code elements with meta-data.
A globally-registered filter that scans for the attribute and executes the desired behavior if present.
See the following for more examples:
Constructor Dependency Injection WebApi Attributes
Unity Inject dependencies into MVC filter class with parameters
Implementing passive attributes with dependencies that should be resolved by a DI container
Dependency Injection in Attributes: don’t do it!
Injecting dependencies into ASP.NET MVC 3 action filters. What's wrong with this approach?
How can I test for the presence of an Action Filter with constructor arguments?
Another option is to use IFilterProvider to resolve the filters as in IFilterProvider and separation of concerns.
Once you get your head around the fact that Attributes should not be doing anything themselves, using them with DI is rather straightforward.

Autofac configuration problems trying to integrate Quartz

I am working with the Owned type as found here: Strong reference of Autofac 2
I'm also using Quartz scheduler, MSMQ, and EF.
My config looks as follows. I've clearly got something wrong as the context that gets injected to the repositories is a different instance than the one given to the service.
builder.RegisterType<EmailAllocationJob>();
builder.RegisterGeneric(typeof(JobWrapper<>));
builder.RegisterType<DataContext>().InstancePerOwned<EmailAllocationJob>();
builder.RegisterType<DataContext>().As<IUnitOfWork>();
builder.RegisterType<EmailAccountRepository>().As<IEmailAccountRepository>();
builder.RegisterType<EmailMessageRepository>().As<IEmailMessageRepository>();
builder.RegisterType<EmailMessageQueue>().As<IEmailMessageQueue>();
builder.RegisterType<EmailAllocationService>().As<IEmailAllocationService>();
I can't for the life of me figure out how to get the configuration fixed. I'd reckon it's the line:
builder.RegisterType<DataContext>().As<IUnitOfWork>();
What I want to say is something like:
builder.RegisterType<DataContext>().As<IUnitOfWork>().InstancePerOwned<EmailAllocationJob>();
Thanks in advance if you can help.
Ok I got it. Needed the line:
builder.RegisterType<DataContext>().InstancePerOwned<EmailAllocationJob>()
.As<IUnitOfWork>().AsSelf();
So it seems important that the DataContext features as the generic argument to RegisterType ONCE, and that the method calls to As<>() and AsSelf() are to be daisy chained in a single statement. Seems obvious now, with a fresh head following yesterday evening.

Autofac aop wildcard: is it possible?

The canonical way of using AOP in Autofac is to declare interceptor on each component:
builder.RegisterType<Filter1>().As<IFilter>()
.EnableInterfaceInterceptors();
In my project I have a lot (tens of) IFilter implementations, so adding and maintaining them is inconvenient. I would prefer an ability to intercept all instances of service. Something like:
builder.EnableInterfaceInterceptors<IFilter>();
Is it possible?
I am not sure if EnableInterfaceInterceptors can handle multiple registrations, but if it can this should work:
builder.RegisterAssemblyTypes(assemblies).Where(t => t.IsAssignableTo<IFilter>())
.EnableInterfaceInterceptors();
If you need, this can be wrapped into an extension method (like almost all the ContainerBuilder registration methods) to give you the exact syntax you requested above.

How set a parameter type as inout when using rpc with gwt?

I've a sample gwt2 rpc service & i need to set some of it's parameters as out or inout (like out or ref parameter types in microsoft wcf), but i could not find anything about it in gwt documents or related forums :(
Can anybody help me please ?!
I understood that gwt rpc services can't contain any out or inout parameter(even if you use java arrays as method parameters, the data binding would be only one way).
In order to returning more than one value from your methods, you can simply return some complex serializable data structure from your service method(Hashmap or ListArray are good choices)

Castle Windsor - Null constructor argument

How can I pass a null constuctor argument using Castle Windsor? I thought the following would work
<parameters>
<repository>null</repository>
<message>null</message>
</parameters>`
If you want them to be null, it means that they are non-essential dependencies. By having them as ctor arguments you suggest otherwise. You should redesign your class to have another constructor that takes only essential dependencies, if you wish that they not change throughout the lifetime of an object (be readonly), or expose them as properties.
With Windsor you can't make it to pass nulls, for reasons mentioned in the other answer.
Wouldn't it better to simply have an additional public constructor that doesn't take these parameters, then you wouldn't need to register the parameters in the config?
This was discussed a while back on the mail list, and at the time I looked into the code. Null values are deliberately filtered out (mainly because the complicate type resolution).
I couldn't find a simple way to make a special case to add them.