WhatDoIHave and AssertConfigurationIsValid missing in StructureMap v3 - structuremap

I'm getting the dreaded "No default Instance is registered and cannot be automatically determined for type" even though I have set a registry for the default conventions.
To debug I am trying the WhatDoIHave and Asset... methods but these no longer exist on ObjectFactory. Am I missing something or have these been removed in the latest version?

Jeremy Miller explains new improved error reporting in SM3 3.0 here.
"WhatDoIHave" remains in SM 3:
(taken from the above blog entry)
[Test]
public void what_do_I_have()
{
var container = new Container(x => {
x.For<IDevice>().AddInstances(o => {
o.Type<ADevice>().Named("A");
o.Type<BDevice>().Named("B").LifecycleIs<ThreadLocalStorageLifecycle>();
o.Type<CDevice>().Named("C").Singleton();
});
x.For<IDevice>().UseIfNone<DefaultDevice>();
});
Debug.WriteLine(container.WhatDoIHave());
Debug.WriteLine(container.WhatDoIHave(pluginType:typeof(IDevice)));
}

Related

Dependency Injection with Unity MVC5 - InjectionFactory Deprecated

With the latest version of Unity (MVC5) the InjectionFactory has become deprecated. Below is the Obsolete warning you will receive when trying to use it.
[Obsolete("InjectionFactory has been deprecated and will be removed in next release. Please use IUnityContainer.RegisterFactory(...) method instead.", false)]
Unfortunately I lack the knowledge with this API to put in the appropriate fix.
As you can see from the code below I'm trying to register an IAuthenticationManager using the old solution which leverages InjectionFactory. Does anyone know how this would look with the new solution?
public static void RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType<IAuthenticationManager>(new InjectionFactory(c => HttpContext.Current.GetOwinContext().Authentication));
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
Below I've also included a controller which references this object.
public class AccountController : Controller
{
private AdAuthenticationService _signInService;
public AccountController() { }
public AccountController(IAuthenticationManager signInManager)
{
this._signInService = new AdAuthenticationService(signInManager);
}
etc...
Let me know if you all have any other questions and thanks for the help.
I feel a little stupid. I took the time to actually read the warning and the answer was right there.
One line replacement:
Old:
container.RegisterType<IAuthenticationManager>(new InjectionFactory(c => HttpContext.Current.GetOwinContext().Authentication));
New:
container.RegisterFactory<IAuthenticationManager>(c => HttpContext.Current.GetOwinContext().Authentication);

Trying to add AutoMapper to Asp.net Core 2?

I worked on a asp.net core 1.1 project a while ago and use in projetc AutoMapper.
in asp.net core 1.1, I add services.AddAutoMapper() in startup file :
StartUp file in asp.net core 1.1:
public void ConfigureServices(IServiceCollection services)
{
//Some Code
services.AddMvc();
services.AddAutoMapper();
}
And I use AutoMapper in Controller easily.
Controller :
public async Task<IActionResult> AddEditBook(AddEditBookViewModel model)
{
Book bookmodel = AutoMapper.Mapper.Map<AddEditBookViewModel, Book>(model);
context.books.Add(bookmodel);
context.SaveChanges();
}
And everything was fine.
But I'm currently working on a Asp.net Core 2 project and I get the error with services.AddAutoMapper() in sturtap file.
Error CS0121 The call is ambiguous between the following methods or properties: 'ServiceCollectionExtensions.AddAutoMapper(IServiceCollection, params Assembly[])' and 'ServiceCollectionExtensions.AddAutoMapper(IServiceCollection, params Type[])'
What is the reason for this error?
Also, services.AddAutoMapper in asp.net core 2 has some parameters. what should I send to this parameter?
If you are using AspNet Core 2.2 and AutoMapper.Extensions.Microsoft.DependencyInjection v6.1
You need to use in Startup file
services.AddAutoMapper(typeof(Startup));
You likely updated your ASP.NET Core dependencies, but still using outdated AutoMapper.Extensions.Microsoft.DependencyInjection package.
For ASP.NET Core you need at least Version 3.0.1 from https://www.nuget.org/packages/AutoMapper.Extensions.Microsoft.DependencyInjection/3.0.1
Which references AutoMapper 6.1.1 or higher.
AutoMapper (>= 6.1.1)
Microsoft.Extensions.DependencyInjection.Abstractions (>= 2.0.0)
Microsoft.Extensions.DependencyModel (>= 2.0.0)
The older packages depend on Microsoft.Extensions.DependencyInjection.Abstractions 1.1.0 and can't be used with ASP.NET Core since there have been breaking changes between Microsoft.Extensions.DependencyInjection.Abstractions 1.1.0 and 2.0
In new version (6.1) of AutoMapper.Extensions.Microsoft.DependencyInjection nuget package you should use it as follows:
services.AddAutoMapper(Type assemblyTypeToSearch);
// OR
services.AddAutoMapper(params Type[] assemblyTypesToSearch);
e.g:
services.AddAutoMapper(typeOf(yourClass));
Install package:
Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection -Version 7.0.0
Nuget:
https://www.nuget.org/packages/AutoMapper.Extensions.Microsoft.DependencyInjection/
In Startup Class:
services.AddAutoMapper(typeof(Startup));
None of these worked for me, I have a .NET Core 2.2 project and the complete code for configuring the mapper looks like this(part of ConfigureService() method):
// Auto Mapper Configurations
var mappingConfig = new MapperConfiguration(mc =>
{
mc.AddProfile(new SimpleMappings());
});
IMapper mapper = mappingConfig.CreateMapper();
services.AddSingleton(mapper);
Then I have my Mappings class which I've placed in the BL project:
public class SimpleMappings : Profile
{
public SimpleMappings()
{
CreateMap<DwUser, DwUserDto>();
CreateMap<DwOrganization, DwOrganizationDto>();
}
}
And finally the usage of the mapper looks like this:
public class DwUserService : IDwUserService
{
private readonly IDwUserRepository _dwUserRepository;
private readonly IMapper _mapper;
public DwUserService(IDwUserRepository dwUserRepository, IMapper mapper)
{
_dwUserRepository = dwUserRepository;
_mapper = mapper;
}
public async Task<DwUserDto> GetByUsernameAndOrgAsync(string username, string org)
{
var dwUser = await _dwUserRepository.GetByUsernameAndOrgAsync(username, org).ConfigureAwait(false);
var dwUserDto = _mapper.Map<DwUserDto>(dwUser);
return dwUserDto;
}
}
Here is a similar link on the same topic:
How to setup Automapper in ASP.NET Core
If you are using AspNet Core 2.2.Try changing your code
from:
services.AddAutoMapper();
to:
services.AddAutoMapper(typeof(Startup));
It worked for me.
In .Net 6, you can do it like
builder.Services.AddAutoMapper(typeof(Program).Assembly); // Since there is no Startup file
OR
builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
Basically, it requires the assembly name as shown in screenshot below
I solved this by creating a class that inherits AutoMapper.Profile
public class model_to_resource_profile : Profile
{
public model_to_resource_profile()
{
CreateMap<your_model_class, your_model_resource_class>();
}
}
And adding this line in the Startup.cs:
services.AddAutoMapper(typeof(model_to_resource_profile ));
try this, works with 2.1 and up, i have not used any previous version so can't tell.
services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
The official docs:
https://automapper.readthedocs.io/en/latest/Dependency-injection.html#asp-net-core
You define the configuration using profiles. And then you let
AutoMapper know in what assemblies are those profiles defined by
calling the IServiceCollection extension method AddAutoMapper at
startup:
services.AddAutoMapper(profileAssembly1, profileAssembly2 /*, ...*/);
or marker types:
services.AddAutoMapper(typeof(ProfileTypeFromAssembly1), typeof(ProfileTypeFromAssembly2) /*, ...*/);
If you are having issue with adding your auto mapper, It is better you check through the type and version you added.
If it is not "AutoMapper.Extensions.Microsoft.DependencyInjection", then you won't be able to use "services.AddAutoMapper()".
Sometimes, you might mistakenly add "AutoMapper
Dec 6th 2019 Based upon initial attempt in a pluralsight course Building an API with ASP.NET Core by Shawn Wildermuth. As I got the error "...ambiguous 'ServiceCollectionExtensions.AddAutoMapper(IServiceCollection, params Assembly[])..."
I started researching proper syntax to implement AddAutoMapper in Core 2.2. My NuGet reference is version 7.0.0 After the tutorial had me create the Profile class in my Data repository directory which additionally referenced my model nir weiner & dev-siberia's answers above led me to trying to reference the profile class in the Startup.ConfigureServices() by name:
services.AddAutoMapper(typeof(CampProfile));
the content of the profile class is just a (no pun intended) old school map of the data class and the model in its constructor
this.CreateMap<Camp, CampModel>();
This addressed the poor lack of documentation for this current version.
Respectfully,
ChristianProgrammer

No default instance or named instance 'Default' for requested plugin type

I'm trying to avoid referencing the concrete type library in my main project, but I'm getting this error:
No default instance or named instance 'Default' for requested plugin type StackExchangeChatInterfaces.IClient
1.) Container.GetInstance(StackExchangeChatInterfaces.IClient ,{username=; password=; defaultRoomUrl=; System.Action`2[System.Object,System.Object]=System.Action`2[System.Object,System.Object]})
I've setup my container to scan for assemblies, like so:
var container = new Container(x =>
{
x.Scan(scan =>
{
scan.AssembliesFromApplicationBaseDirectory();
scan.ExcludeNamespace("StructureMap");
scan.WithDefaultConventions();
scan.AddAllTypesOf<IMessageHandlers>();
});
//x.For<IClient>().Use<Client>(); //GetInstance will work if this line is not commented out.
});
When I try to get an instance, I get the error, my code for getting an instance is here:
chatInterface = container
.With("username").EqualTo(username)
.With("password").EqualTo(password)
.With("defaultRoomUrl").EqualTo(roomUrl)
.With<Action<object, object>>(delegate(object sender, object messageWrapper)
{
string message = ((dynamic)messageWrapper).Message;
Console.WriteLine("");
Console.WriteLine(message);
foreach (var item in messageHandlers)
{
item.MessageHandler.Invoke(message, chatInterface);
}
}).GetInstance<IClient>();
If I explicitly map the concrete class to the interface, everything works hunky dory, but that means I need to reference the project that Client is in, which I don't want to do.
This is really interesting. Looks like default conventions are not able to register types with such constructor (tried on both versions 2.6.3 and 3+). I was only registered when only parameterless constructor was specified. Looking at sources of both versions it is really suspicious as it should be registered. Deeper dive into the code would be needed...
Anyway try using custom registration convention:
public class ClientConvention : IRegistrationConvention
{
public void Process(Type type, Registry registry)
{
if (type.IsClass && !type.IsAbstract && !type.IsGenericType &&
type.GetInterfaces().Contains(typeof(IClient)))
{
registry.For(typeof(IClient)).Use(type);
}
}
}
Configure it like this:
var container = new Container(
c => c.Scan(
s =>
{
s.ExcludeNamespace("StructureMap");
s.WithDefaultConventions();
s.Convention<ClientConvention>();
s.AddAllTypesOf<IMessageHandlers>();
}));
and this should work just fine.
The default type scanning will not pick up concrete types whose constructor functions contain primitive arguments like strings, numbers, or dates. The thinking is that you'd effectively have to explicitly configure those inline dependencies anyway.
"but that means I need to reference the project that Client is in, which I don't want to do."
Does that actually matter? I think you're making things harder than they have to be by trying to eliminate the assembly reference.

Unity Interception using auto wiring

I got Unity interception working using a HadlerAttribute and an instance of ICallHandler. To get it working all I have to do is decorate the class with the [Trace] attribute, and the interceptor works great.
[Trace]
public interface IPersonService
{
string GetPerson();
}
However I would like to have interception working for all my methods in a couple of assemblies. So I am using Unity AutoRegistration to set up my container as follows:
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
//container.AddNewExtension<UnityInterfaceInterceptionRegisterer>();
container.
ConfigureAutoRegistration().
ExcludeSystemAssemblies().
LoadAssemblyFrom(typeof(PersonService).Assembly.Location).
Include(If.ImplementsITypeName, Then.Register()).
ApplyAutoRegistration();
return container;
}
Works great, except when I attempt to setup global registration as per this post:
http://unity.codeplex.com/discussions/281022
I have a UnityContainerExtension configured as follows, where MVC4Unity is my DLL:
public class UnityInterfaceInterceptionRegisterer : UnityContainerExtension
{
protected override void Initialize()
{
base.Container.AddNewExtension<Interception>();
base.Container.Configure<Interception>().
AddPolicy("LoggingPolicy").
AddMatchingRule<AssemblyMatchingRule>
(new InjectionConstructor("MVC4Unity")).
AddCallHandler(new TraceCallHandler());
base.Context.Registering += new EventHandler<RegisterEventArgs>(this.OnRegister);
}
private void OnRegister(object sender, RegisterEventArgs e)
{
IUnityContainer container = sender as IUnityContainer;
if (e != null && e.TypeFrom != null && e.TypeFrom.IsInterface)
{
container.Configure<Interception>()
.SetInterceptorFor(e.TypeFrom, e.Name, new InterfaceInterceptor());
}
}
}
Unfortunately it is always throwing a StackOverflowException (!) when it goes into the OnRegister method.
The question then is, has anyone implemented assembly or even namespace wide interception using Unity, and was this the way to go?
[EDIT]
It seems that no matter what I add in the AddMatchingRule line below, that the OnRegister handler is invoked for all included assemblies as well! ( for example even the Microsoft.* namespace assemblies!)
base.Container.AddNewExtension<Interception>();
base.Container.Configure<Interception>().
AddPolicy("LoggingPolicy").
// see what other types of matchings rules there are!
AddMatchingRule<NamespaceMatchingRule>
(new InjectionConstructor("MVC4Unity.*")).
AddCallHandler(new TraceCallHandler());
base.Context.Registering += new EventHandler<RegisterEventArgs>(this.OnRegister);
I'm late with my answer, but maybe someone will find this useful.
If I understood the problem correctly you need to apply one matching rule to multiple assemblies. For these kind of tasks you can use AssemblyMatchingRule (MSDN).
container.Configure<Interception>()
.AddPolicy("logging")
.AddMatchingRule<AssemblyMatchingRule>(
new InjectionConstructor(
new InjectionParameter("YourAssemblyName")))
.AddCallHandler<LoggingCallHandler>(
new ContainerControlledLifetimeManager(),
new InjectionConstructor(), new InjectionProperty("Order", 1));
In your last code snippet i think you need to remove dot asterisk in the end of namespace in order to add MVC4Unity namespace to your NamespaceMatchingRule.
For additional information please check this link - Policy Injection MSDN

Error "More than one matching bindings are available" when using Ninject.Web.Mvc 2.0 and ASP.NET MVC 1.0

Recently I've switched to Ninject 2.0 release and started getting the following error:
Error occured: Error activating SomeController
More than one matching bindings are available.
Activation path:
1) Request for SomeController
Suggestions:
1) Ensure that you have defined a binding for SomeController only once.
However, I'm unable to find certain reproduction path. Sometimes it occurs, sometimes it does not.
I'm using NinjectHttpApplication for automatic controllers injection. Controllers are defined in separate assembly:
public class App : NinjectHttpApplication
{
protected override IKernel CreateKernel()
{
INinjectModule[] modules = new INinjectModule[] {
new MiscModule(),
new ProvidersModule(),
new RepositoryModule(),
new ServiceModule()
};
return new StandardKernel(modules);
}
protected override void OnApplicationStarted()
{
RegisterRoutes(RouteTable.Routes);
RegisterAllControllersIn("Sample.Mvc");
base.OnApplicationStarted();
}
/* ............. */
}
Maybe someone is familiar with this error.
Any advice?
I finally figured this issue out recently. Apparently, the NinjectHttpApplication.RegisterAllControllersIn() function doesn't do all of the proper bindings needed. It binds your concrete controller implementations to IController requests. For example, if you have a controller class called SampleMvcController, which inherits from System.Web.Mvc.Controller. It would do the following named binding during application start:
kernel.Bind<IController>().To(SampleMvcController).InTransientScope().Named("SampleMvc");
But when debugging the NinjectControllerFactory, I find that request are being made for the Ninject Kernel to return an object for the class "SampleMvcController", not for a concrete implementation of IController, using the named binding of "SampleMvc".
Because of this, when the first web request that involves the SampleMvcController is made, it creates a binding of SampleMvcController to itself. This is not thread safe though. So if you have several web requests being made at once, the bindings can potentially happen more than once, and now you are left with this error for having multiple bindings for the SampleMvcController.
You can verify this by quickly refreshing an MVC URL, right after causing your web application to restart.
The fix:
The simplest way to fix this issue is to create a new NinjectModule for your controller bindings, and to load this module during application start. Within this module, you self bind each of your defined controllers, like so:
class ControllerModule : StandardModule {
public override Load() {
Bind<SampleMvcController>().ToSelf();
Bind<AnotherMvcController>().ToSelf();
}
}
But if you don't mind changing the Ninject source code, you can modify the RegisterAllControllersIn() function to self bind each controller it comes across.
I have been dealing with this problem for months. I tried so many options but was unable to come to a solution. I knew that it was a threading problem because it would only occur when there was a heavy load on my site. Just recently a bug was reported and fixed in the ninject source code that solves this problem.
Here is a reference to the issue. It was fixed in build 2.1.0.70 of the Ninject source. The key change was in KernelBase.cs by removing the line
context.Plan = planner.GetPlan(service);
and replacing it with
lock (planner)
{
context.Plan = planner.GetPlan(service);
}
To use this new build with MVC you will need to get the latest build of Ninject then get the latest build of ninject.web.mvc. Build ninject.web.mvc with the new Ninject build.
I have been using this new build for about a week with a heavy load and no problems. That is the longest it has gone without a problem so I would consider this to be a solution.
Are you sure you really are creating a single completely new Kernel from scratch in your OnApplicationStarted every time it's invoked ? If you're not and you're actually creating it once but potentially running the registration bit twice. Remember that you're not guaranteed to only ever have one App class instantiated ever within a given AppDomain.
My answer was a bit more obvious.
I had declared the binding for one of my controllers more than once during refactor of my code.
I added this to my global.ascx.cs file:
public void RegisterAllControllersInFix(Assembly assembly)
{
RegisterAllControllersInFix(assembly, GetControllerName);
}
public void RegisterAllControllersInFix(Assembly assembly, Func<Type, string> namingConvention)
{
foreach (Type type in assembly.GetExportedTypes().Where(IsController))
Kernel.Bind(type).ToSelf();
}
private static bool IsController(Type type)
{
return typeof(IController).IsAssignableFrom(type) && type.IsPublic && !type.IsAbstract && !type.IsInterface;
}
private static string GetControllerName(Type type)
{
string name = type.Name.ToLowerInvariant();
if (name.EndsWith("controller"))
name = name.Substring(0, name.IndexOf("controller"));
return name;
}
Then called it from my OnApplicationStarted() method as follows:
RegisterAllControllersIn(Assembly.GetExecutingAssembly());
RegisterAllControllersInFix(Assembly.GetExecutingAssembly());
Difficult to know whether this fixed it though because it's so intermittent.

Resources