Aspect Oriented Programming with StructureMap.DynamicInterception - c#

I implemented a console app that uses DynamicInterception on structure map, I follow the example on the page StructureMap DynamicInterception.
Now I'm trying to pass the code to a asp.net MVC site but I get the following error
Decorator Interceptor failed during object construction. See the inner exception:
1.) DynamicProxyInterceptor of ITSector.Site.Core.Controllers.HomeController with interception
behaviors: ITSector.Library.Aspect.LoggerInterceptor
2.) ITSector.Site.Core.Controllers.HomeController
3.) Instance of ITSector.Site.Core.Controllers.HomeController
4.) Container.GetInstance(ITSector.Site.Core.Controllers.HomeController)
The inner exception is:
Specified type is not an interface
Parameter name: interfaceToProxy
With the stacktrace:
at Castle.DynamicProxy.ProxyGenerator.CreateInterfaceProxyWithTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, Object target, ProxyGenerationOptions options, IInterceptor[] interceptors)
at Castle.DynamicProxy.ProxyGenerator.CreateInterfaceProxyWithTarget[TInterface](TInterface target, IInterceptor[] interceptors)
at lambda_method(Closure , IBuildSession , IContext )
I use the Structure.MVC5.Update nuget as the Dependency Resolver.
Can anyone give me any hint on how to implement it to intercept calls on controller methods.
Thanks.

StructureMap is expecting an interface in the For<T>() method, but you're passing it HomeController, which is a concrete class.
You have a couple of options to get it working. You can attach your LoggerInteceptor to all controllers with For<IController>(). If you only want to attach the logger to some of your controllers, you can create a new interface specifically for the logged controllers, like For<ILoggedController>(), and ensure the desired controllers inherit from ILoggedController.

Related

Do TypeConverters need to be registered with the DI?

I have a mapping in my WebApi project:
cfg.CreateMap(typeof(Source<>), typeof(Destination), MemberList.Destination)
.ConvertUsing(typeof(SourceConverter<>));
And the converter itself:
internal class SourceConverter<T> : ITypeConverter<Source<T>, Destination>
where T : struct, IConvertible
{
public Destination Convert(SourceConverter<T> exception, Destination error, ResolutionContext ctx)
{
return new Destination();
}
}
And when I try to map, I'm getting the following exception:
The requested service 'SourceConverter`1[[MyEnum, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.
Do the converters need to be registered with the DI?
No, you can see an example in the official documentation here: https://docs.automapper.org/en/stable/Custom-type-converters.html
Your error is elsewhere.

Health check for AddDbContextCheck by TContextService and TContextImplementation

I'm setup my DBContext by TContextService and TContextImplementation options.
Something like this:
services.AddDbContext<IMyDbContext, MyDbContext>(options => options.UseNpgsql(myDatabaseConnectionString));
I try to enable health check from Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore
When I try to use this code
services.AddHealthChecks().AddDbContextCheck<MyDbContext>()
I got from health end point response that
InvalidOperationException: Unable to resolve service for type 'MyDbContext' while attempting to activate 'Microsoft.Extensions.Diagnostics.HealthChecks.DbContextHealthCheck`1[MyDbContext]'.
Microsoft.Extensions.DependencyInjection.ActivatorUtilities+ConstructorMatcher.CreateInstance(IServiceProvider provider)
Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance(IServiceProvider provider, Type instanceType, object[] parameters)
Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetServiceOrCreateInstance(IServiceProvider provider)
Do you know any method to use two options TContextService and TContextImplementation for health check by Entity Framework?
You seem to have hit a case where the two cannot work together. I think you have two options:
First is to register the DbContext directly and then just resolve the interface from this registration.
services.AddDbContext<MyDbContext>(options => options.UseNpgsql(myDatabaseConnectionString));
services.AddTransient<IMyDbContext>(c=>c.GetRequiredService<MyDbContext>());
Another option is to implement the health check functionality yourself. Which is not exactly hard.
See : EntityFrameworkCoreHealthChecksBuilderExtensions.cs and DbContextHealthCheck.cs

Bot Framework v4.4.3 Update Skill Manifest Template

The document here says update skill manifest but does not specify how to add a new skill in the manifest file.
I have the following in the main dialog:
case MasterCollectionsLuis.Intent.PlayVideo:
{
turnResult = await dc.BeginDialogAsync(nameof(Water.PlayVideo.PlayVideoDialog));
break;
}
And have a base for PlayVideo and the Dialog itself as shown by the example SampleDialog and SampleDialogBase.
When I load the manifest file at http://localhost:1205/api/skill/manifest:
An unhandled exception occurred while processing the request.
InvalidOperationException: Unable to resolve service for type 'MasterCollections.Dialogs.Water.PlayVideo.PlayVideoDialog' while attempting to activate 'MasterCollections.Dialogs.MainDialog'.
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, bool throwIfCallSiteNotFound)
Dependency Injection error
That error is to do with the dependency injection pipeline, without setting your Startup.cs file my best guess is that you haven't wired up PlayVideoDialog in there.
In your Startup.cs file you will have a section where you register your Dialogs against the dependency injection service provider like so:
services.AddTransient<CancelDialog>();
services.AddTransient<EscalateDialog>();
services.AddTransient<MainDialog>();
You simply need to add another line each time you add a new Dialog:
services.AddTransient<MyNewDialog>();
In your case you would have PlayVideoDialog in place of MyNewDialog.
Also make sure that you are not passing a PlayVideoDialog parameter into the constructor of MainDialog as this is not how Dialogs work, you should instead call the AddDialog(new PlayVideoDialog(...)) method inside the constructor of MainDialog.
Skills manifest question
I haven't created a skill myself but there is additional documentation which may or may not be helpful about adding skill support, adding skills, and the skills manifest file itself.
In the documentation that you linked it states:
this has been pre-populated with the Skill ID and name and a sample action which you can modify at this stage if required
which leads me to believe you can manually modify this file to fit your requirements, but you don't have to modify it if there are no changes required.

Can't get RhinoMocks to emit a mock that follows the generic type restriction rules

So, using NUnit and RhinoMocks:
//Defines basic behavior of all persistable domain objects
public interface IDomainObject {...}
//defines domain objects specific to the Security DB
public interface ISecurityDomainObject : IDomainObject {...}
//Defines a basic transactional data Repository; there are multiple implementors
//which each close TRest to the interface that defines their DB's domain classes
public interface IRepository<TRest> : IDisposable where TRest:IDomainObject
{
IUnitOfWork BeginUnitOfWork();
void CommitUnitOfWork(IUnitOfWork unitOfWork);
void RollBackUnitOfWork(IUnitOfWork unitOfWork);
void Save<T>(T domainObject, IUnitOfWork unitOfWork) where T : class, TRest;
IQueryable<T> QueryFor<T>(IUnitOfWork unitOfWork) where T :class, TRest;
}
public interface ISecurityRepository:IRepository<ISecurityDomainObject> {}
public class SecurityRepository:ISecurityRepository
...
//This line breaks when run in an NUnit test
var securityRepository = MockRepository.GenerateMock<ISecurityRepository>();
...
The error I get is:
System.TypeLoadException : Method 'Save' on type 'ISecurityRepositoryProxyb8e21deb3cb04067a01ac5b63f7045af' from assembly 'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' tried to implicitly implement an interface method with weaker type parameter constraints.
at System.Reflection.Emit.TypeBuilder.TermCreateClass(RuntimeModule module, Int32 tk, ObjectHandleOnStack type)
at System.Reflection.Emit.TypeBuilder.CreateTypeNoLock()
at System.Reflection.Emit.TypeBuilder.CreateType()
at Castle.DynamicProxy.Generators.Emitters.AbstractTypeEmitter.BuildType()
at Castle.DynamicProxy.Generators.InterfaceProxyWithTargetGenerator.GenerateCode(Type proxyTargetType, Type[] interfaces, ProxyGenerationOptions options)
at Castle.DynamicProxy.DefaultProxyBuilder.CreateInterfaceProxyTypeWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options)
at Castle.DynamicProxy.ProxyGenerator.CreateInterfaceProxyTypeWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options)
at Castle.DynamicProxy.ProxyGenerator.CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, IInterceptor[] interceptors)
at Rhino.Mocks.MockRepository.MockInterface(CreateMockState mockStateFactory, Type type, Type[] extras)
at Rhino.Mocks.MockRepository.CreateMockObject(Type type, CreateMockState factory, Type[] extras, Object[] argumentsForConstructor)
at Rhino.Mocks.MockRepository.DynamicMock(Object[] argumentsForConstructor)
at Rhino.Mocks.MockRepository.<>c__DisplayClass7`1.<GenerateMock>b__6(MockRepository r)
at Rhino.Mocks.MockRepository.CreateMockInReplay(Func`2 createMock)
at Rhino.Mocks.MockRepository.GenerateMock(Object[] argumentsForConstructor)
at CSHD.Tests.Unit.Presentation.LoginTests.TestAuthenticationFails() in LoginTests.cs: line 138
When attempting to generate the mock against the concrete class, I get a similar error, this time on the QueryFor() method. If I attempt to redefine the methods that use TRest in the ISecurityRepository interface, I get a "System.BadImageFormatException : An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)" which looks like a step backwards.
I think the core problem is that RhinoMocks is getting confused by the generic parameters being used as generic type restrictions. I have no clue exactly where it's being confused and therefore I don't know how or if I can unconfuse it. I have adequate integration test coverage that I could ignore these failing unit tests if I absolutely have to, but obviously I'd rather fix them if I can. Your thoughts?
It looks like this is a known issue caused by Castle.DynamicProxy that is fixed in the latest trunk of that project, but still broken in the latest Rhino Mocks release:
http://groups.google.com/group/rhinomocks/browse_thread/thread/2c1b53bf66b77b8e/ad09a6cd1e304a93
If you're feeling adventurous you can build your own Rhino Mocks with the latest DynamicProxy and it should be fixed.
Looks like Castle Dynamic Proxy (which Rhino Mocks uses for proxy generation) is not generating the proxy class correctly given the way that you've defined your generic arguments. You can generate a proxy (and hence a mock) if you define your IRepository like this instead:
public interface IRepository<T> : IDisposable where T : class, IDomainObject
{
IUnitOfWork BeginUnitOfWork();
void CommitUnitOfWork(IUnitOfWork unitOfWork);
void RollBackUnitOfWork(IUnitOfWork unitOfWork);
void Save(T domainObject, IUnitOfWork unitOfWork);
IQueryable<T> QueryFor(IUnitOfWork unitOfWork);
}
If you really need it defined the other way, you'll have to file a bug with Rhino Mocks.

Mocking a type with an internal constructor using Moq

I'm trying to mock a class from the Microsoft Sync Framework. It only has an internal constructor. When I try the following:
var fullEnumerationContextMock = new Mock<FullEnumerationContext>();
I get this error:
System.NotSupportedException: Parent
does not have a default constructor.
The default constructor must be
explicitly defined.
This is the stack trace:
System.Reflection.Emit.TypeBuilder.DefineDefaultConstructorNoLock(MethodAttributes
attributes)
System.Reflection.Emit.TypeBuilder.DefineDefaultConstructor(MethodAttributes
attributes)
System.Reflection.Emit.TypeBuilder.CreateTypeNoLock()
System.Reflection.Emit.TypeBuilder.CreateType()
Castle.DynamicProxy.Generators.Emitters.AbstractTypeEmitter.BuildType()
Castle.DynamicProxy.Generators.ClassProxyGenerator.GenerateCode(Type[]
interfaces, ProxyGenerationOptions options)
Castle.DynamicProxy.DefaultProxyBuilder.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy,
ProxyGenerationOptions options)
Castle.DynamicProxy.ProxyGenerator.CreateClassProxyType(Type classToProxy, Type[] additionalInterfacesToProxy,
ProxyGenerationOptions options)
Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy,
ProxyGenerationOptions options, Object[] constructorArguments,
IInterceptor[] interceptors)
Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy,
ProxyGenerationOptions options, IInterceptor[] interceptors)
Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, IInterceptor[]
interceptors)
Moq.Mock1.<InitializeInstance>b__0()
Moq.PexProtector.Invoke(Action action)
Moq.Mock1.InitializeInstance()
How can I work round this?
You cannot mock a type that does not have a public constructor because Moq will not be able to instantiate an object of that type. Depending on what you are trying to test, you have a few options:
If there's a factory object or some other way of obtaining instances of FullEnumerationContext perhaps you can use that (sorry, I'm not familiar with the sync framework)
You could use private reflection to instantiate a FullEnumerationContext, but then you would not be able to mock methods on it.
You could introduce an interface and/or wrapper object that's mockable that the code under test could invoke. The runtime implementation would delegate to the real FullEnumerationContext, while your test-time implementation would perform whatever action you need.
I am not really an expert on Moq, but I think you need to specify the arguments for the constructor. In Rhino Mocks you would specify them like this:
var fullEnumerationContextMock = new Mock<FullEnumerationContext>(arg1, arg2);
It is probably similar in Moq.
Actually you can. Open your AssemblyInfo.cs file and add the following line at end,
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
Based on the answers from marcind I've created an interface (IFullEnumerationContext) which I mock and then I've got two overloads of the method I am trying to test, one that takes the FullEnumerationContext and another that takes IFullEnumerationContext. It doesn't feel great, but it does work. Any better suggestions or improvements would be welcome.
public override void EnumerateItems(FullEnumerationContext context)
{
List<ItemFieldDictionary> listItemFieldDictionary = EnumerateItemsCommon();
context.ReportItems(listItemFieldDictionary);
}
public void EnumerateItems(IFullEnumerationContext context)
{
List<ItemFieldDictionary> listItemFieldDictionary = EnumerateItemsCommon();
context.ReportItems(listItemFieldDictionary);
}
In your System Under Test project you need:
protected internal constructor visibility in your SUT class (e.g. FullEnumerationContext)
AssemblyInfo.cs should expose their internals to the test project:
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

Categories

Resources