I have previously used DryIOC as my IOC before, but I would like to try Splat for my IOC, would it be possible to combine these two?
I have tried making a LoginModule whom inherits the IModule so I have this on my LoginModule class:
public void OnInitialized(IContainerProvider containerProvider)
{
Locator.CurrentMutable.RegisterLazySingleton(() => new ServiceEntityMapper(), typeof(IServiceEntityMapper));
Locator.CurrentMutable.RegisterLazySingleton(() => new LoginAPIService(), typeof(ILoginAPIService));
Locator.CurrentMutable.RegisterLazySingleton(() => new LoginManager(
Locator.Current.GetService<IServiceEntityMapper>(),
Locator.Current.GetService<ILoginAPIService>()), typeof(ILoginManager));
}
and I have this for my view model constructor:
public LoginViewModel(INavigationService navigationService, ILoginManager loginManager = null) : base(navigationService)
{
LoginManager = loginManager ?? Locator.Current.GetService<ILoginManager>();
}
In result, I get this exception whenever I navigate to the page
{System.TypeLoadException: Could not resolve the signature of a virtual method
at System.Lazy`1[T].CreateValue () [0x00081] in <fe08c003e91342eb83df1ca48302ddbb>:0
at System.Lazy`1[T].LazyInitValue () [0x00080] in <fe08c003e91342eb83df1ca48302ddbb>:0
at System.Lazy`1[T].get_Value () [0x0003a] in <fe08c003e91342eb83df1ca48302ddbb>:0
at Splat.DependencyResolverMixins+<>c__DisplayClass7_0.<RegisterLazySingleton>b__0 () [0x00000] in <89c762f12a12451a8970372dc9921547>:0
at Splat.ModernDependencyResolver.GetService (System.Type serviceType, System.String contract) [0x00032] in <89c762f12a12451a8970372dc9921547>:0
at Splat.DependencyResolverMixins.GetService[T] (Splat.IDependencyResolver resolver, System.String contract)
From what I've seen Splat is a Service Locator not an actual DI Container. That said you certainly are not limited to the base Prism implementations, as those are provided to make it simple to adopt and get started. What I might suggest in your case is to create your own implementation of IContainerExtension and inherit from PrismApplicationBase.
You can see it's really not that much extra work in your App class by looking either at the implementations for Unity or DryIoc... there is a similar example using the Grace DI Container. Keep in mind that a couple of new API's have been added since the last preview, with a proposed breaking change to make IContainerRegistry have a fluent API.
Related
I would like to integrate Bot composer with Custom actions. The custom actions in turn calls different API to perform some business logic. I would like to inject interfaces and service provider to custom action. I am having trouble in doing this as it is failing and getting in to null pointer exceptions, eventhough I have added everything properly in the startup.cs. Could you please explain how can i achieve this?.
[JsonConstructor]
public MultiplyDialog(IServiceProvider serviceProvider, [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
: base()
{
serviceProvider.GetService<ApiService>() // serviceprovider always null
this.RegisterSourceLocation(sourceFilePath, sourceLineNumber);
}
You have to keep in mind that when using Adaptive Dialogs (that is, the core of Composer) Dialogs are singletons and, when using Composer, they're not instantiated from dependency injection (DI).
Also, since dialogs are singletons, you can't (well, you could but you shouldn't) use services like constructor injected DbContexts and similar (when working with the SDK, that is, coding).
The easiest way to solve this is by using HTTP requests using the HttpRequest action. This is the way that's built into the whole adaptive dialogs ecosystem to achieve this kind of functionality.
If you really insist on doing it with DI into the dialogs, you'd have to solve DI from the TurnContext and you'd have to set it up in the adapter. However, that's a bit convoluted an requires you to use a custom runtime.
UPDATE Added the way to implement DI with adaptive dialogs.
1 - Register the service class in the turn state in the adapter
public class AdapterWithErrorHandler : BotFrameworkHttpAdapter
{
public AdapterWithErrorHandler(
IConfiguration configuration,
ILogger<BotFrameworkHttpAdapter> logger,
//...
QnAClient qnaClient)
: base(configuration, logger)
{
// Add QnAClient to TurnState so we can use it while in the turn
Use(new RegisterClassMiddleware<QnAClient>(qnaClient));
//...
}
}
In the code above QnAClient is an typed HttpClient created with IHttpClientFactory so it's a safe to use singleton.
2 - Get the service from the TurnState wherever you need it
public async Task SetPropertiesAsync(DialogContext context, ...)
{
var qnaClient = context.Context.TurnState.Get<QnAClient>();
//...
}
BTW, this is a nice way to get an HttpClient properly managed by IHttpClientFactory when you register it like this in ConfigureServices:
services.AddHttpClient<QnAClient>()
.AddTransientHttpErrorPolicy(p => p.WaitAndRetryAsync(new[] { 1, 2, 3, 5, 8, 13 }.Select(t => TimeSpan.FromSeconds(t))))
.AddTransientHttpErrorPolicy(p => p.CircuitBreakerAsync(6, TimeSpan.FromSeconds(30)));
In this case with retry policies from Polly.
The other answer isn't super clear - so I will add some clear snippets. Say you want to inject your service MyService
First, some extra configuration:
services.AddSingleton<IMiddleware, RegisterClassMiddleware<MyService>>(sp => new RegisterClassMiddleware<MyService>(sp.GetRequiredService<MyService>()));
Then in your Dialog:
public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{
var myService = dc.Services.Get<MyService>();
}
Done!
I have a code in Web Api Delegating Handler that extract data from request header.
However, I can't register instance in Autofac container because Autofac container require SingleInstance only.
public class ExtractUserNameMessageHandler : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
var userNameFromFrontEnd = request.GetDependencyScope().GetService(typeof (IUserNameFromFrontEnd));
if (userNameFromFrontEnd == null)
{
var updatedContainerBuilder = new ContainerBuilder();
userNameFromFrontEnd = ExtractUserName(request);
if (userNameFromFrontEnd == null)
{
throw new Exception("We've got a request without UserName header");
}
updatedContainerBuilder.RegisterInstance(userNameFromFrontEnd)
.As<IUserNameFromFrontEnd>()
.InstancePerRequest();
var autofacDependencyResolver = GlobalConfiguration.Configuration.DependencyResolver as AutofacWebApiDependencyResolver;
if (autofacDependencyResolver == null)
{
throw new Exception("We can work with Autofac DI container");
}
updatedContainerBuilder.Update(autofacDependencyResolver.Container as IContainer);
}
When I try to update container I get an exception with message - registration can support singleinstance() sharing only.
What does it mean? I can't understand why we have this limitation. But in any cases my first goal - update container with new dependency.
Does anybody have ideas?
(Note: This question was cross-posted to the Autofac forums as well.)
When you register a specific instance, it's effectively a singleton - it's one instance, the instance you provided.
When you try to assign it InstancePerRequest or, really, any other lifetime scope besides SingleInstance, it doesn't make logical sense because you're not going to get a different instance per request (or whatever). You're going to get the exact same instance you registered, which is a singleton.
The exception message is trying to tell you how to avoid incorrect expectations: that it can't provide you a different instance per request even though you told it to because you didn't tell it how to create a new instance, you instead provided a specific instance.
If you need a different instance of an object per lifetime scope/request/whatever, you need to register a type, a delegate, or something else that tells Autofac how to create that new instance.
What that means is that if you want a different IUserNameFromFrontEnd per request, you need to move that logic out of a DelegatingHandler and into an Autofac registration delegate.
// Make sure to register the HttpRequestMessage in the container
// so you can resolve it...
builder.RegisterHttpRequestMessage(httpConfiguration);
// Then, whilst building your root container...
builder
.Register(ctx =>
{
var request = ctx.Resolve<HttpRequestMessage>();
return ExtractUserName(request);
})
.As<IUserNameFromFrontEnd>()
.InstancePerRequest();
Now it will probably do what you're looking to do - because you told Autofac how to create the instance that belongs in each request. It also means you don't need that DelegatingHandler anymore because Autofac will just do the right thing.
More advanced (and probably not useful here, but for completeness):
If, for whatever reason, you still feel like you need to modify the registration directly in the lifetime scope, instead of updating the container you should add the registration when the request lifetime scope is created.
Again, do not update the root container for per-lifetime-scope or per-request dependencies. It's not going to work how you think.
When a new lifetime scope is created, you can add registrations on the fly.
using(var scope = container.BeginLifetimeScope(
builder => builder.RegisterInstance(myfoo).As<IFoo>()))
{
// This will use the registrations in the container
// and the scope. f == myfoo
var f = scope.Resolve<IFoo>();
}
The AutofacDependencyResolver is the thing that creates the request lifetime scope and hands it off to Web API. You can see the full source here. The key method is BeginScope:
public IDependencyScope BeginScope()
{
var lifetimeScope = _container.BeginLifetimeScope(MatchingScopeLifetimeTags.RequestLifetimeScopeTag);
return new AutofacWebApiDependencyScope(lifetimeScope);
}
If you create your own AutofacDependencyResolver you can modify how the scope is created:
public IDependencyScope BeginScope()
{
var lifetimeScope = _container.BeginLifetimeScope(
MatchingScopeLifetimeTags.RequestLifetimeScopeTag,
builder => builder.RegisterInstance(myfoo).As<IFoo>());
return new AutofacWebApiDependencyScope(lifetimeScope);
}
This isn't an explicitly supported extension point in the Autofac Web API integration right now - that's why you'd have to create your own resolver.
However, this seems like overkill to solve the thing it appears you're trying to solve. I strongly recommend just registering the delegate with Autofac rather than trying to update existing containers or scopes. You will have far more luck using the path of least resistance.
I have an interface in the core project of my solution: IPersonManager, which has two concrete implementations, which belong to their own respective projects.
In my web project there is an MVC area representing both of these projects and there is a framework installer class in each area which registers the person manager class to the interface in each area as follows:
container.Register(AllTypes
.FromAssemblyNamed("MySolution.MyProject")
.Where(t => t.Name.EndsWith("Manager"))
.WithService.DefaultInterface()
.Configure(x => x.LifeStyle.PerWebRequest)
);
Following registration, when I GetHandlers on the Kernel for the IPersonManager interface I get the following:
{Castle.MicroKernel.IHandler[2]}
[0]: Model: {MySolution.Core.Interfaces.Services.IPersonManager}
/ {MySolution.Area1.PersonManager}
[1]: Model: {MySolution.Core.Interfaces.Services.IPersonManager}
/ {MySolution.Area2.PersonManager}
So I can see that both implementations have been registered.
The problem is that when I am in Area2 on the web site, windsor is resolving Area1's implementation of the interface rather than Area2.
It seems as though windsor is just giving me back the one that was registered first. Is there a way to get back the correct implementation based on MVC area?
I would consider an IHandlerSelector for this. You can examine the current HTTP request context and "help" windsor decide which implementation to use.
Went with Patrick's suggestion, here's the code:
public class PersonManagerHandlerSelector : IHandlerSelector
{
public bool HasOpinionAbout(string key, System.Type service)
{
return service == typeof (IPersonManager);
}
public IHandler SelectHandler(string key, System.Type service,
IHandler[] handlers)
{
var dataTokens = System.Web.HttpContext.Current.Request.
RequestContext.RouteData.DataTokens;
if (dataTokens.Any())
{
var area = System.Web.HttpContext.Current.Request.RequestContext.
RouteData.DataTokens["area"];
return !string.IsNullOrEmpty(area.ToString())
? handlers.First(x =>
x.ComponentModel.Name.Contains("." + area))
: handlers.First();
}
return handlers.First();
}
}
I'm trying to get dependency injection working in an ASP.NET MVC 3 application using Microsoft Unity. First i have implemented my own IDependencyResolver and activated it in my Global.asax file like so:
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
I found that i don't need to do anything else to get controller injection (via both the constructor and [Dependency] attribute) to work. With the default view engine i also found i could get the [Dependency] attribute to work in the standard views but not the Layout views. Is it possible to get this to work for the Layout Views aswell?
However i have implemented my own view engine which inherits from VirtualPathProviderViewEngine that overrides the CreateView/CreatePartialView methods and returns my own custom view (implements IView). See the Render method of the custom view below:
public void Render(ViewContext viewContext, TextWriter writer) {
var webViewPage = DependencyResolver.Current.GetService(_type) as WebViewPage;
//var webViewPage = Activator.CreateInstance(_type) as WebViewPage;
if (webViewPage == null)
throw new InvalidOperationException("Invalid view type");
webViewPage.VirtualPath = _virtualPath;
webViewPage.ViewContext = viewContext;
webViewPage.ViewData = viewContext.ViewData;
webViewPage.InitHelpers();
WebPageRenderingBase startPage = null;
if (_runViewStartPages)
startPage = StartPage.GetStartPage(webViewPage, "_ViewStart", _viewStartFileExtensions);
var pageContext = new WebPageContext(viewContext.HttpContext, webViewPage, null);
webViewPage.ExecutePageHierarchy(pageContext, writer, startPage);
}
With the commented out line i completely lost dependency injection within my views so i changed it to the line above which again works fine for the standard views but not for the Layout views. I'd appreciate it if you could show me how the above could be modified to work for the Layout views aswell?
Finally i'm trying to get action filter injection working aswell. I have found two different cases:
Apply the filter to the action via an attribute.
Defining it as a global filter, e.g.:
GlobalFilters.Filters.Add(new TestAttribute());
Neither seem to use the dependency resolver. Therefore i need to do some extra work. Please correct me if there's a better way. To enable the first scenario i did the following:
public class UnityFilterAttributeFilterProvider : FilterAttributeFilterProvider {
private IUnityContainer _container;
protected override IEnumerable<FilterAttribute> GetControllerAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor) {
var attributes = base.GetControllerAttributes(controllerContext, actionDescriptor);
foreach (var attribute in attributes) {
_container.BuildUp(attribute.GetType(), attribute);
}
return attributes;
}
protected override IEnumerable<FilterAttribute> GetActionAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor) {
var attributes = base.GetActionAttributes(controllerContext, actionDescriptor);
foreach (var attribute in attributes) {
_container.BuildUp(attribute.GetType(), attribute);
}
return attributes;
}
}
And then defined this within my Global.asax file like so:
FilterProviders.Providers.Remove(FilterProviders.Providers.Single(f => f is FilterAttributeFilterProvider));
FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(container));
This works fine but i was wondering if this is the correct way to do it? To resolve the second case i simply changed where i defined my global filter to the following:
GlobalFilters.Filters.Add(DependencyResolver.Current.GetService<TestAttribute>());
This again now works but is this the correct way to do it?
I'd appreciate the help. Thanks
It's been a while since I originally asked this but I thought I would share what I ended up doing.
In cases where I could not use constructor or attribute injection I solved it by using the DependencyResolver (service locator pattern). For example if I require the service IService I would simply inject it like so:
public IService Service => DependencyResolver.Current.GetService<IService>();
While some may consider this an anti-pattern I have found this performs well, leads to less problems and with new advances in C# I don't think it looks too bad.
However if you are using ASP.NET Core you should never have to use the service locator pattern as it has been rebuilt with dependency injection at the heart of it.
I'm using Ninject 1.0 and would like to be able to inject lazy initialisation delegates into constructors. So, given the generic delegate definition:
public delegate T LazyGet<T>();
I'd simply like to bind this to IKernel.Get() so that I can pass a lazy getter into constructors, e.g.
public class Foo
{
readonly LazyGet<Bar> getBar;
public Foo( LazyGet<Bar> getBar )
{
this.getBar = getBar;
}
}
However, I can't simply call Bind<LazyGet<T>>() because it's an open generic type. I need this to be an open generic so that I don't have to Bind all the different lazy gets to explicit types. In the above example, it should be possible to create a generic delegate dynamically that invokes IKernel.Get<T>().
How can this be achieved with Ninject 1.0?
Don't exactly understand the question, but could you use reflection? Something like:
// the type of T you want to use
Type bindType;
// the kernel you want to use
IKernel k;
// note - not compile tested
MethodInfo openGet = typeof(IKernel).GetMethod("Get`1");
MethodInfo constGet = openGet.MakeGenericMethod(bindType);
Type delegateType = typeof(LazyGet<>).MakeGenericType(bindType);
Delegate lazyGet = Delegate.CreateDelegate(delegateType, k, constGet);
Would using lazyGet allow you to do what you want? Note that you may have to call the Foo class by reflection as well, if bindType isn't known in the compile context.
I am fairly certain that the only way to do this (without some dirty reflection code) is to bind your delegate with type params. This will mean it needs to be done for each individual type you use. You could possibly use a BindingGenerator to do this in bulk, but it could get a bit ugly.
If there is a better solution (a clean one) I would love to hear it as I run into this problem from time to time.
From another similar question I answered:
public class Module : NinjectModule
{
public override void Load()
{
Bind(typeof(Lazy<>)).ToMethod(ctx =>
GetType()
.GetMethod("GetLazyProvider", BindingFlags.Instance | BindingFlags.NonPublic)
.MakeGenericMethod(ctx.GenericArguments[0])
.Invoke(this, new object[] { ctx.Kernel }));
}
protected Lazy<T> GetLazyProvider<T>(IKernel kernel)
{
return new Lazy<T>(() => kernel.Get<T>());
}
}