I would like to use IHttpClientFactory in a WPF application built using the Prism library. I have added two packages, Prism.Unity and Prism.Unity.Extensions and i attempt to register the IHttpClientFactory with the following code:
containerRegistry.RegisterServices(s => s.AddHttpClient("DefaultClient")
.AddPolicyHandler(GetRetryPolicy()));
However, I get the following error:
I have also added the following override:
protected override IContainerExtension CreateContainerExtension() => PrismContainerExtension.Current;
Prism 8 introduces registration methods for scoped services. The IContainerProvider interface declares an additional method CreateScope and a member CurrentScope that were not present in earlier versions.
public interface IContainerProvider {
// ...other members.
IScopedProvider CreateScope();
ScopedProvider CurrentScope { get; }
}
The PrismContainerExtension classes from Prism.Unity.Extensions in version 7.2.0.1054 and earlier do not implement this method. Consequently, you get an exception using it with Prism 8.
Since the types are incompatible, you either have to revert to Prism 7.2.0.1054 or you have to wait for a new version of Prism.Unity.Extensions that supports the new scoped services in Prism 8. There are already changes made in the repository, but a preview version is currently only available to sponsors.
Related
I am using Prism v7.2.0.1422 for a WPF app with .net Core 3.1.
I am using the Microsoft Dependency Injection for DI.
I don't want use Unity container.
regionAdapterMappings is empty.
View discovery and view injection don't work.
what do I need to be able to register regions in regionManager ?
MyPrismApplication.cs
public abstract class MyPrismApplication : PrismApplicationBase
{
protected override IContainerExtension CreateContainerExtension()
{
return PrismContainerExtension.Current;
}
protected override void RegisterRequiredTypes(IContainerRegistry containerRegistry)
{
base.RegisterRequiredTypes(containerRegistry);
containerRegistry.RegisterSingleton<IRegionNavigationContentLoader, RegionNavigationContentLoader>();
containerRegistry.RegisterSingleton<IServiceLocator, MicrosoftServiceLocatorAdapter>();
}
protected override void ConfigureRegionAdapterMappings(RegionAdapterMappings regionAdapterMappings)
{
base.ConfigureRegionAdapterMappings(regionAdapterMappings);
//Fix bug when RegionAdapterMappings are not registered into dependency container
PrismContainerExtension.Current.RegisterInstance(regionAdapterMappings);
}
}
the boolean requiresRebuild destroy all instances inside the container.
Prism v7.2.0.1422.
.net Core 3.1
Prism.Container.Extensions v7.2.0.54.
This isn't something that is currently supported out of the box. If you look back at the Prism 7.2 source code for either DryIoc or Unity, you'll see that there is some additional container work which cannot be abstracted out in the PrismContainerExtensions. Specifically you'll need to create ServiceLocatorAdapter.
This requirement goes away for Prism 8, however I have not had the time to update the Prism Container Extensions for Prism 8 and won't until after the next Prism 8 preview. In the mean time I suggest opening an issue on GitHub to track WPF support for the Microsoft.Extensions.DependencyInjection container.
I am converting a Prim 6 using MEF for IOC to Prism 7 Unity since MEF is not longer supported. The biggest difference I have to contend with is the presumption in MEF that everything is singleton by default while Unity tends to assume the opposite.
I have most of it converted but one thing I ran into was having a constructor reference a singleton via collections. For example, I have these interfaces and classes:
public interface IAppService { }
public interface IDebugService : IAppService { }
public class DebugService : IDebugService { }
public interface IOtherService : IAppService { }
public class OtherService : IOtherService { }
with DebugService and OtherService registers as singletons and mapped to both of their respective interfaces:
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterSingleton<IModuleMessageBus, ModuleMessageBus>();
containerRegistry.RegisterSingleton<DebugService>();
containerRegistry.RegisterSingleton<IDebugService, DebugService>();
containerRegistry.Register<IAppService, DebugService>(typeof(DebugService).FullName);
containerRegistry.RegisterSingleton<OtherService>();
containerRegistry.RegisterSingleton<IOtherService, OtherService>();
containerRegistry.Register<IAppService, OtherService>(typeof(OtherService).FullName);
}
The intent is DebugService/IDebugService and OtherService/IOtherService are registered/mapped as singletons which would return the same instance but IAppService as named instances of each so there can be more one IAppService registered. Any call to get a collection would include the singleton of DebugService and OtherService.
The second part is what is giving me a problem. Getting a collection of IAppService in a constructor always generates new instances. So, if I have this:
public SomeViewModel(
IModuleMessageBus messageBus
, IDebugService debugService
, IEnumerable<IAppService> services
) { }
public AnotherViewModel(
IModuleMessageBus messageBus
, IDebugService debugService
) { }
What will happen is the constructor for DebugService will be hit twice. Once for the IDebugService injection for BOTH constructors and again specifically for the IEnumerable. If I comment out , IEnumerable<IAppService> services then it is only hit once. How can I have one and only one instance of the services but still register them with other interfaces to obtain as collections.
UPDATE
Thanks to Haukinger's response, I took a look at Prism's github since that overload is not exposed by the module. Turns out they are adding it in 7.2. THe latest preview (5 days old as of the time of this writing) has it merged in:
https://github.com/PrismLibrary/Prism/pull/1668
UPDATE 2
Unfortunately, it still seems to be a problem. I changed the registration to this and it still is hit twice:
containerRegistry.RegisterSingleton<DebugService>();
containerRegistry.RegisterSingleton<IDebugService, DebugService>();
containerRegistry.GetContainer().RegisterSingleton(
typeof(IAppService)
, typeof(DebugService)
, typeof(DebugService).FullName
);
containerRegistry.RegisterSingleton<OtherService>();
containerRegistry.RegisterSingleton<IOtherService, OtherService>();
containerRegistry.GetContainer().RegisterSingleton(
typeof(IAppService)
, typeof(OtherService)
, typeof(OtherService).FullName
);
Upgrading PRISM to the preview will not make a difference since it still references the same unity versions. But updating the unity packages will break Prism since they contain braking changes (looks like in Unity.Abstraction).
ANSWER THANKS TO HAUKINGER
Haukinger put me on the right track so give him a bump if this helps!!
Since prism 7 (currently) is using Unit Container 5.8 / Unity Abstraction 3, we have to use the InjectionFactory which is marked as obsolete and will soon be removed. To get the above to work, I had to do this (soooo gross):
containerRegistry.RegisterSingleton<DebugService>();
containerRegistry.RegisterSingleton<IDebugService, DebugService>();
//Manually map the registration resolve
containerRegistry.GetContainer().RegisterType<IAppService>(
typeof(DebugService).FullName
, new InjectionFactory(c => c.Resolve<DebugService>())
);
containerRegistry.RegisterSingleton<OtherService>();
containerRegistry.RegisterSingleton<IOtherService, OtherService>();
//Manually map the registration resolve
containerRegistry.GetContainer().RegisterType<IAppService>(
typeof(OtherService).FullName
, new InjectionFactory(c => c.Resolve<OtherService>())
);
If you register transiently like this
containerRegistry.Register<IAppService, DebugService>(typeof(DebugService).FullName);
then resolving a new DebugService every time is expected behavior.
If you want only one DebugService instance to exist, register it as singleton:
containerRegistry.RegisterSingleton<IAppService, DebugService>(typeof(DebugService).FullName);
For a detailed description of what Unity 5 does here and why it does so (unlike older versions), have a look at this wiki page on github.
EDIT: it's a bit more complicated, and the solution looks quite a bit workaround-ish...
container.RegisterSingleton<Service>();
container.RegisterFactory<ISingleInterface>( x => x.Resolve<Service>() );
container.RegisterFactory<IEnumeratedInterface>( "service", x => x.Resolve<Service>() );
This is all for IUnityContainer, you have to get it from the IContainerRegistryby use of the GetContainer() extension.
Further reading at unity's github. Depending on your unity version, you can/have to use InjectionFactory instead of RegisterFactory.
I have a WPF application for which my users can create their own plugins by using MEF. Each plugin implements an interface that allows the main application to perform CRUD operations on some data source, e.g. a database.
I have created 2 plugins:
LocalDatabase - provides data from an SQLite database
RemoteDatabase - provides data from a MySQL database
Both are using Entity Framework to do their job. Each of those plugins needs to have its own implementation of the DbConfiguration class.
Now, the problem is that the WPF application loads those 2 plugins, but fails to assign each of them their own implementation of the DbConfiguration class, because it seems that you can have only one DbConfiguration per AppDomain.
So I always have only one of those plugins working.
I was thinking about having just one implementation of the DbConfiguration class and give each plugin an option to add its required configs to that, but the problem is that it creates some coupling between the WPF application and Entity Framework. I'd like to keep the Entity Framework stuff only inside the plugins without the need of modifying the WPF application. It shouldn't care about what plugins use to access their data source.
Is there any way of making it work this way? Could I maybe somehow create a separate AppDomain per each plugin, so maybe then each could use its own DbConfiguration class?
I've found a solution which is a bit hacky, but it does seem to work, so I thought I'd post it, in an unlikely case that someone would face the same issue somewhere in the future.
After some additional research, I've learnt that you can use the DbConfiguration.Loaded event to register some additional Dependency Resolvers for EF. So, in each plugin's constructor, I subscribe the event and add a new Dependency Resolver: SQLite for the LocalDatabase and MySql for the RemoteDatabase. I got rid of the custom DbConfiguration classes from each plugin.
This looked promising, but actually a new problem appeared - there were cases where LocalDatabase plugin called the MySql resolver and it actually returned the MySql implementation of the requested service type. Obviously the LocalDatabase plugin couldn't work with that, because it expected the SQLite implementation. And vice-versa.
So, each of the Resolvers, would actually need to check who called the GetService method - if it's some method from the same assembly that the custom resolver is in, it tries to resolve. Otherwise it's assumed that a resolver from different plugin should take care of that request and it returns null to actually let it do that.
The problem is that the GetService method doesn't supply any information about the requester. So that's where I came up with the hacky solution, which uses StackTrace to check whether any of the called methods belongs to the same Assembly that the current Resolver resides in.
public class CustomMySqlDbDependencyResolver : IDbDependencyResolver
{
private readonly Assembly _executingAssembly = Assembly.GetExecutingAssembly();
private readonly MySqlDependencyResolver _mySqlResolver = new MySqlDependencyResolver();
public object GetService(Type type, object key)
{
var stackTrace = new StackTrace();
StackFrame[] stackFrames = stackTrace.GetFrames().Skip(1).ToArray();
bool shouldResolve = stackFrames.Any(f => f.GetMethod().DeclaringType.Assembly.Equals(_executingAssembly));
if (!shouldResolve)
{
return null;
}
var resolvedService = _mySqlResolver.GetService(type, key);
return resolvedService;
}
public IEnumerable<object> GetServices(Type type, object key)
{
var service = GetService(type, key);
if (service != null)
{
yield return service;
}
}
}
I have registered following types with IOC (func) in App host.Classes & interfaces given below are in a separate class library .This class library contains a WCF service reference .
private void RegisteTyeps(Container container)
{
//Register Mapper
container.Register<IMapper>(c => _mapperConfiguration.CreateMapper());
container.RegisterAutoWiredAs<AppointmentHandler, IAppointmentHandler>().ReusedWithin(ReuseScope.Container);
container.RegisterAutoWiredAs<CalendarHandler, ICalendarHandler>().ReusedWithin(ReuseScope.Container);
container.RegisterAutoWiredAs<SettingHandler, ISettingHandler>().ReusedWithin(ReuseScope.Container);
}
I wanted to add some more service references (Which are slightly different than each other ) and generate proxies.Thus i added some more class libraries with respective service references .Each class libraries contains "same" interface and classe as mentioned above .
I wanted to dynamically load /Switch class library based on request header or something so that i can only use particular library which has the appropriate service reference & proxies.
How can i achieve this with service stack .Any one have any idea?
You can only register a dependency against a single Type or Interface in Funq. If you want to perform multiple registrations you would either need to register a Factory type, e.g:
container.Register(c => new AppointmentHandlers(
new AppointmentHandler1(),
new AppointmentHandler2());
Then resolve it with:
public AppointmentHandlers AppointmentHandlers { get; set; }
public object Any(MyRequest request)
{
var dep = AppointmentHandlers.AppointmentHandler1();
}
Otherwise you need to register them with different interfaces or use a named registration.
I'd like to use NServiceBus profiles to override the concrete classes used in the Spring.net dependency injection for use in Integration Testing.
In my EndpointConfig class, I have a component being configured:
NServiceBus.Configure.Instance.Configurer.ConfigureComponent<RealCommunicator>(ComponentCallModelEnum.None);
(This bit is OK!)
I created a new profile:
public class StubThirdPartyProfile : NServiceBus.IProfile
{
}
And a behaviour class to implement it:
public class StubThirdPartyBehaviour : IHandleProfile<StubThirdPartyProfile>
{
public void ProfileActivated()
{
Configure.Instance.Configurer.ConfigureComponent<StubCommunicator>(ComponentCallModelEnum.None);
}
}
Both StubCommunicator and RealCommunicator implement the same interface and I was hoping that the profile would remove the old dependency and use the StubCommunicator instead but this is not the case. Is there a way to do this?
When the solution is run, I get the following error:
Spring.Objects.Factory.UnsatisfiedDependencyException:
Error creating object with name 'Namespace.CommandHandler' :
Unsatisfied dependency expressed through object property 'Communicator':
There are 2 objects of Type [Namespace.ICommunicator] for autowire by type,
when there should have been just 1 to be able to autowire property 'Communicator' of object
We're using the Spring.net framework in NServicebus configured as so:
Configure.With().SpringFrameworkBuilder()
.XmlSerializer().Log4Net()
.MsmqTransport()
.IsTransactional(true);
Instead of configuring the real component in the endpoint config class, consider registering it in a class which handles the other NServiceBus profiles - Lite, Integration, Production.