Type not found in cache: System.Func for injecting a type as a Func using MVVMLight SimpleIoc - mvvm-light

I am registering a type in MVVMLight SimpleIoc,
SimpleIoc.Default.Register<MyInjectingClass>();
Then I do a constructor injection of this type as a Func,
public class MyConsumerClass
{
readonly Func<MyInjectingClass> _injectingClassFactory;
public MyConsumerClass(Func<MyInjectingClass> injectingClassFactory)
{
_injectingClassFactory = injectingClassFactory;
}
}
But at runtime, I get this error,
Type not found in cache:
System.Func`1[[<...>.MyInjectingClass,
<...>, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].
How can I constructor inject a type as a Func?
Note:
I'm doing this stuff in a Xamarin.IOs project.
The NuGet I use for MVVMLight SimpleIoc is this.

I figured out that, to inject a type as a Func, then you have to
Register the type first
Then register it as a Func (consuming the above registered type)
That is,
SimpleIoc.Default.Register<MyInjectingClass>(); // should happen first
SimpleIoc.Default.Register<Func<MyInjectingClass>>(
() => () => SimpleIoc.Default.GetInstance<MyInjectingClass>(
Guid.NewGuid().ToString()
));
The type is simply registered in a way telling it to return a Func object of the MyInjectingClass, that retrieves a new object each time.
Guid.NewGuid().ToString() makes sure a new MyInjectingClass object is returned for the SimpleIoc.Default.GetInstance<MyInjectingClass> method.

Related

Unity to DryIoC conversion ParameterOverride

We are transitioning from Xamarin.Forms to .Net MAUI but our project uses Prism.Unity.Forms. We have a lot of code that basically uses the IContainer.Resolve() passing in a collection of ParameterOverrides with some primitives but some are interfaces/objects. The T we are resolving is usually a registered View which may or may not be the correct way of doing this but it's what I'm working with and we are doing it in backend code (sometimes a service). What is the correct way of doing this Unity thing in DryIoC? Note these parameters are being set at runtime and may only be part of the parameters a constructor takes in (some may be from already registered dependencies).
Example of the scenario:
//Called from service into custom resolver method
var parameterOverrides = new[]
{
new ParameterOverride("productID", 8675309),
new ParameterOverride("objectWithData", IObjectWithData)
};
//Custom resolver method example
var resolverOverrides = new List<ResolverOverride>();
foreach(var parameterOverride in parameterOverrides)
{
resolverOverrides.Add(parameterOverride);
}
return _container.Resolve<T>(resolverOverrides.ToArray());
You've found out why you don't use the container outside of the resolution root. I recommend not trying to replicate this error with another container but rather fixing it - use handcoded factories:
internal class SomeFactory : IProductViewFactory
{
public SomeFactory( IService dependency )
{
_dependency = dependency ?? throw new ArgumentNullException( nameof(dependency) );
}
#region IProductViewFactory
public IProductView Create( int productID, IObjectWithData objectWithData ) => new SomeProduct( productID, objectWithData, _dependency );
#endregion
#region private
private readonly IService _dependency;
#endregion
}
See this, too:
For dependencies that are independent of the instance you're creating, inject them into the factory and store them until needed.
For dependencies that are independent of the context of creation but need to be recreated for each created instance, inject factories into the factory and store them.
For dependencies that are dependent on the context of creation, pass them into the Create method of the factory.
Also, be aware of potential subtle differences in container behaviours: Unity's ResolverOverride works for the whole call to resolve, i.e. they override parameters of dependencies, too, whatever happens to match by name. This could very well be handled very differently by DryIOC.
First, I would agree with the #haukinger answer to rethink how do you pass the runtime information into the services. The most transparent and simple way in my opinion is by passing it via parameters into the consuming methods.
Second, here is a complete example in DryIoc to solve it head-on + the live code to play with.
using System;
using DryIoc;
public class Program
{
record ParameterOverride(string Name, object Value);
record Product(int productID);
public static void Main()
{
// get container somehow,
// if you don't have an access to it directly then you may resolve it from your service provider
IContainer c = new Container();
c.Register<Product>();
var parameterOverrides = new[]
{
new ParameterOverride("productID", 8675309),
new ParameterOverride("objectWithData", "blah"),
};
var parameterRules = Parameters.Of;
foreach (var po in parameterOverrides)
{
parameterRules = parameterRules.Details((_, x) => x.Name.Equals(po.Name) ? ServiceDetails.Of(po.Value) : null);
}
c = c.With(rules => rules.With(parameters: parameterRules));
var s = c.Resolve<Product>();
Console.WriteLine(s.productID);
}
}

Is it possible to use ICacheManager<> with different type of configurations at the same time?

Imagine that I have interfaces like below which all inherits from ICacheManager<>
public interface ICacheManagerRuntime<T> : ICacheManager<T>
public interface ICacheManagerRedis<T> : ICacheManager<T>
public interface ICacheManagerRedisWithRuntime<T> : ICacheManager<T>
I want to inject ICacheManager{CacheType} interfaces to implemantation of Cache classes like:
CacheRuntime, CacheRedis, CacheRedisWithRuntime
With unity I want to inject them like below:
container.RegisterType<ICacheManagerRuntime<object>>(
new ContainerControlledLifetimeManager(),
new InjectionFactory((c, t, n) =>
{
return CacheFactory.Build... // Return CacheManager just with RuntimeCacheHandle
})));
container.RegisterType<ICacheManagerRedis<object>>(
new ContainerControlledLifetimeManager(),
new InjectionFactory((c, t, n) =>
{
return CacheFactory.Build... // Return CacheManager just with RedisCacheHandle
})));
container.RegisterType<ICacheManagerRedisWithRuntime<object>>(
new ContainerControlledLifetimeManager(),
{
return CacheFactory.Build... // Return CacheManager just with RuntimeCacheHandleWithRedisBackPlane
})));
What ever I have done, I am getting this exception:
An unhandled exception of type 'Microsoft.Practices.Unity.ResolutionFailedException' occurred in Microsoft.Practices.Unity.dll
Additional information: Resolution of the dependency failed, type = "Solid.Play.Business.Interfaces.IProductService", name = "(none)".
Exception occurred while: Resolving parameter "cache" of constructor Solid.Play.Cache.Caches.CacheRuntime(Solid.Play.Cache.Interfaces.ICacheManagerRuntime`1[[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] cache).
Exception is: InvalidCastException - Unable to cast object of type 'CacheManager.Core.BaseCacheManager`1[System.Object]' to type 'Solid.Play.Cache.Interfaces.ICacheManagerRuntime`1[System.Object]'.
-----------------------------------------------
At the time of the exception, the container was:
Resolving Solid.Play.Business.Services.ProductService,(none) (mapped from Solid.Play.Business.Interfaces.IProductService, (none))
Resolving Solid.Play.Cache.Interception.CachingInterceptorBehavior,(none)
Resolving parameter "cache" of constructor Solid.Play.Cache.Interception.CachingInterceptorBehavior(Solid.Play.Cache.Interfaces.ICacheSolid cache)
Resolving Solid.Play.Cache.Caches.CacheSolid,(none) (mapped from Solid.Play.Cache.Interfaces.ICacheSolid, (none))
Resolving parameter "cacheRuntime" of constructor Solid.Play.Cache.Caches.CacheSolid(Solid.Play.Cache.Interfaces.ICacheRuntime cacheRuntime, Solid.Play.Cache.Interfaces.ICacheRedis cacheRedis, Solid.Play.Cache.Interfaces.ICacheRedisWithRuntime cacheRedisWithRuntime)
Resolving Solid.Play.Cache.Caches.CacheRuntime,(none) (mapped from Solid.Play.Cache.Interfaces.ICacheRuntime, (none))
Resolving parameter "cache" of constructor Solid.Play.Cache.Caches.CacheRuntime(Solid.Play.Cache.Interfaces.ICacheManagerRuntime`1[[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] cache)
The cast does not work because you are trying to cast an instance to an interface it does not implement.
Simplified, what you are trying looks like this:
public interface IBase
{
}
public interface ISub : IBase { }
public class BaseClass : IBase
{
}
var sub = (ISub)new BaseClass();
If you want to inject different kind of instances of the same interfaces, the Unity DI framework provides a way to do that via named injection.
Example:
container.RegisterType<ICacheManager<object>>("runtimeCache",
new ContainerControlledLifetimeManager(),
new InjectionFactory((c, t, n) =>
{
return CacheFactory.Build<object>(s =>
{
s.WithSystemRuntimeCacheHandle("cache.runtime");
});
}));
container.RegisterType<ICacheManager<object>>("redisCache",
new ContainerControlledLifetimeManager(),
new InjectionFactory((c, t, n) =>
{
return CacheFactory.Build<object>(s =>
{
s.WithRedisConfiguration("cache.redis", config =>
{
config
.WithAllowAdmin()
.WithDatabase(0)
.WithEndpoint("localhost", 6379);
})
.WithRedisCacheHandle("cache.redis");
});
}));
To resolve the first one, you'd use
var runtimeCache = container.Resolve<ICacheManager<object>>("runtimeCache");
You can inject the ICacheManager interface to constructors with attributes for example.
public YourClass([Dependency("runtimeCache")] ICacheManager<object> cache)
{
}

How do I create a session variable in DotVVM viewmodel?

I am building a site in DotVVM and when I try the following line of code but I get error: NullReferenceException
HttpContext.Current.Session.Add ("Value", Item3);
DotVVM is an OWIN middleware, so you have to configure OWIN first to enable session. First, you need to declare this method, which turns on ASP.NET session:
public static void RequireAspNetSession(IAppBuilder app) {
app.Use((context, next) =>
{
var httpContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
httpContext.SetSessionStateBehavior(SessionStateBehavior.Required);
return next();
});
// To make sure the above `Use` is in the correct position:
app.UseStageMarker(PipelineStage.MapHandler);
}
Then in the Startup.cs file, call it:
app.RequireAspNetSession();
Then you can use HttpContext.Current.Session["key"] to access your session state.
You can save an object in the Session by doing:
Session["Value"] = Item3;
You can retrieve an object from the Session by doing:
object value = Session["Value"];
Usually, you need to cast the value to the type you used, so if Item3 is a string, then you would do:
string value = (string)Session["Value"];
You can access session variables from your views as well, so you shouldn't need to store it in your viewmodel.

Having issues mapping from a simple list to a corresponding property in a ViewDto

I have a collection of "Alerts" (List) that I need to map to a property in a more complex class.
My destination class hierarchy is as follows:
public class BaseReplyDto<T> where T : class, new()
{
public List<ErrorType> Errors { get; set; }
public T ReplyData { get; set; }
}
public class GetAllAlertsReplyViewDto : BaseReplyDto<List<Alert>>{}
My Mapper configuration is this:
Mapper.CreateMap<List<Alert>, GetAllAlertsReplyViewDto>()
.ForMember(dest => dest.Errors, opt => opt.Ignore())
;
When I run the app, I get a mapper validation error:
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: AutoMapper.AutoMapperConfigurationException:
Unmapped members were found. Review the types and members below.
Add a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type
List`1 -> GetAllAlertsReplyViewDto (Destination member list)
System.Collections.Generic.List`1[[bioSynq.Infrastructure.Entities.Concrete.Alert, bioSynq.Infrastructure.Entities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] -> bioSynq.Infrastructure.ViewDtos.DisplayAlertsArea.GetAllAlertsReplyViewDto (Destination member list)
ReplyData
Basically, it's telling me I need to provide some configuration to map my list of Alerts into the list of alerts that is my ReplyData property.
I've mucked around with about twenty different versions of syntax (.ForMember, .ForSourceMember, etc), but can't find the right syntax to get what seems to be a very simple mapping of one list into another.
Anyone know the correct syntax to do this?
In your mapping configuration I don't see configuration for property public List<Alert> ReplyData { get; set; } from GetAllAlertsReplyViewDto class. My guess is that you need something like this
Mapper.CreateMap<List<Alert>, GetAllAlertsReplyViewDto>()
.ForMember(dest => dest.Errors, opt => opt.Ignore())
.ForMember(dest => dest.ReplyData , opt => opt.MapFrom(list => list));
Hope it'll help.

Test ControllerFactory (pre-start initialization stage)

I want to write a unit test that verifies my route registration and ControllerFactory so that given a specific URL, a specific controller will be created. Something like this:
Assert.UrlMapsToController("~/Home/Index",typeof(HomeController));
I've modified code taken from the book "Pro ASP.NET MVC 3 Framework", and it seems it would be perfect except that the ControllerFactory.CreateController() call throws an InvalidOperationException and says This method cannot be called during the application's pre-start initialization stage.
So then I downloaded the MVC source code and debugged into it, looking for the source of the problem. It originates from the ControllerFactory looking for all referenced assemblies - so that it can locate potential controllers. Somewhere in the CreateController call-stack, the specific trouble-maker call is this:
internal sealed class BuildManagerWrapper : IBuildManager {
//...
ICollection IBuildManager.GetReferencedAssemblies() {
// This bails with InvalidOperationException with the message
// "This method cannot be called during the application's pre-start
// initialization stage."
return BuildManager.GetReferencedAssemblies();
}
//...
}
I found a SO commentary on this. I still wonder if there is something that can be manually initialized to make the above code happy. Anyone?
But in the absence of that...I can't help notice that the invocation comes from an implementation of IBuildManager. I explored the possibility of injecting my own IBuildManager, but I ran into the following problems:
IBuildManager is marked internal, so I need some other authorized derivation from it. It turns out that the assembly System.Web.Mvc.Test has a class called MockBuildManager, designed for test scenarios, which is perfect!!! This leads to the second problem.
The MVC distributable, near as I can tell, does not come with the System.Web.Mvc.Test assembly (DOH!).
Even if the MVC distributable did come with the System.Web.Mvc.Test assembly, having an instance of MockBuildManager is only half the solution. It is also necessary to feed that instance into the DefaultControllerFactory. Unfortunately the property setter to accomplish this is also marked internal (DOH!).
In short, unless I find another way to "initialize" the MVC framework, my options now are to either:
COMPLETELY duplicate the source code for DefaultControllerFactory and its dependencies, so that I can bypass the original GetReferencedAssemblies() issue. (ugh!)
COMPLETELY replace the MVC distributable with my own build of MVC, based on the MVC source code - with just a couple internal modifiers removed. (double ugh!)
Incidentally, I know that the MvcContrib "TestHelper" has the appearance of accomplishing my goal, but I think it is merely using reflection to find the controller - rather than using the actual IControllerFactory to retrieve a controller type / instance.
A big reason why I want this test capability is that I have made a custom controller factory, based on DefaultControllerFactory, whose behavior I want to verify.
I'm not quite sure what you're trying to accomplish here. If it's just testing your route setup; you're way better off just testing THAT instead of hacking your way into internals. 1st rule of TDD: only test the code you wrote (and in this case that's the routing setup, not the actual route resolving technique done by MVC).
There are tons of posts/blogs about testing a route setup (just google for 'mvc test route'). It all comes down to mocking a request in a httpcontext and calling GetRouteData.
If you really need some ninja skills to mock the buildmanager: there's a way around internal interfaces, which I use for (LinqPad) experimental tests. Most .net assemblies nowadays have the InternalsVisibleToAttribute set, most likely pointing to another signed test assembly. By scanning the target assembly for this attribute and creating an assembly on the fly that matches the name (and the public key token) you can easily access internals.
Mind you that I personally would not use this technique in production test code; but it's a nice way to isolate some complex ideas.
void Main()
{
var bm = BuildManagerMockBase.CreateMock<MyBuildManager>();
bm.FileExists("IsCool?").Dump();
}
public class MyBuildManager : BuildManagerMockBase
{
public override bool FileExists(string virtualPath) { return true; }
}
public abstract class BuildManagerMockBase
{
public static T CreateMock<T>()
where T : BuildManagerMockBase
{
// Locate the mvc assembly
Assembly mvcAssembly = Assembly.GetAssembly(typeof(Controller));
// Get the type of the buildmanager interface
var buildManagerInterface = mvcAssembly.GetType("System.Web.Mvc.IBuildManager",true);
// Locate the "internals visible to" attribute and create a public key token that matches the one specified.
var internalsVisisbleTo = mvcAssembly.GetCustomAttributes(typeof (InternalsVisibleToAttribute), true).FirstOrDefault() as InternalsVisibleToAttribute;
var publicKeyString = internalsVisisbleTo.AssemblyName.Split("=".ToCharArray())[1];
var publicKey = ToBytes(publicKeyString);
// Create a fake System.Web.Mvc.Test assembly with the public key token set
AssemblyName assemblyName = new AssemblyName();
assemblyName.Name = "System.Web.Mvc.Test";
assemblyName.SetPublicKey(publicKey);
// Get the domain of our current thread to host the new fake assembly
var domain = Thread.GetDomain();
var assemblyBuilder = domain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
moduleBuilder = assemblyBuilder.DefineDynamicModule("System.Web.Mvc.Test", "System.Web.Mvc.Test.dll");
AppDomain currentDom = domain;
currentDom.TypeResolve += ResolveEvent;
// Create a new type that inherits from the provided generic and implements the IBuildManager interface
var typeBuilder = moduleBuilder.DefineType("Cheat", TypeAttributes.NotPublic | TypeAttributes.Class, typeof(T), new Type[] { buildManagerInterface });
Type cheatType = typeBuilder.CreateType();
// Magic!
var ret = Activator.CreateInstance(cheatType) as T;
return ret;
}
private static byte[] ToBytes(string str)
{
List<Byte> bytes = new List<Byte>();
while(str.Length > 0)
{
var bstr = str.Substring(0, 2);
bytes.Add(Convert.ToByte(bstr, 16));
str = str.Substring(2);
}
return bytes.ToArray();
}
private static ModuleBuilder moduleBuilder;
private static Assembly ResolveEvent(Object sender, ResolveEventArgs args)
{
return moduleBuilder.Assembly;
}
public virtual bool FileExists(string virtualPath) { throw new NotImplementedException(); }
public virtual Type GetCompiledType(string virtualPath) { throw new NotImplementedException(); }
public virtual ICollection GetReferencedAssemblies() { throw new NotImplementedException(); }
public virtual Stream ReadCachedFile(string fileName) { throw new NotImplementedException(); }
public virtual Stream CreateCachedFile(string fileName) { throw new NotImplementedException(); }
}

Resources