PostSharp AOP - Unable to apply aspect to mscorlib System.IO.StreamReader members - postsharp

**I'm using PostSharp Express... not sure that would make a difference in this instance though.
I've got an OnMethodBoundary->OnEntry aspect that successfully multicasts at the assembly level to class members in my own code, but when I attempt to apply it to mscorlib System.IO.StreamReader members, no dice. Based on the searching I've done on the PostSharp web site, here on SO, and on Google, I can't tell what the correct way to go about this is with the current version of PostSharp. Does anyone know? Hopefully I'm just missing something simple :\
Here's the aspect followed by multicast attribute I'm using:
namespace Test.Aspects {
[AttributeUsage(AttributeTargets.Assembly)]
[MulticastAttributeUsage(MulticastTargets.Method, AllowMultiple = false)]
[Serializable]
public class PatchStreamReaderAttribute : OnMethodBoundaryAspect {
public override void OnEntry(MethodExecutionArgs args) {
System.Threading.Thread.Sleep(1000);
}
}
}
[assembly: PatchStreamReader(AttributeTargetMembers = "ReadLine", AttributeTargetAssemblies = "mscorlib", AttributeTargetTypes = "System.IO.StreamReader")]

Usually, when you apply an aspect in a given assembly, PostSharp will modify that assembly during its build process. This, of course, cannot happen for mscorlib or, in fact, for any 3-rd party library you reference but do not build from source code.
This is why PostSharp uses different approach when applying aspects to the referenced assemblies using AttributeTargetAssemblies. Instead of modifying the target 3-rd party assembly, PostSharp will modify the calls from your assembly to the target assembly.
This, of course, gives you less options of where you can inject your code. For example, PostSharp can detect the call to the library's method and inject the aspect around that call. But you cannot inject the aspect around the static or instance constructor of the type from the library.
You also need to pay attention to the AttributeTargetTypes property when applying the aspect. For example, you want to apply the aspect on the calls to the StreamReader.ReadLine() method. This virtual ReadLine() method is originally declared on the TextReader class and StreamReader overrides the method. If you look at the IL, then the method call looks like this:
callvirt instance string [mscorlib]System.IO.TextReader::ReadLine()
This means you need to set AttributeTargetTypes property to "System.IO.TextReader" to apply the aspect to the ReadLine() method.

Related

Resolution of ILifetimeService fails in autofac 4.6.2

We're refactoring an older system to use DI. Sadly, some of the "core" components that are used all over everywhere have injection unfriendly constructors (descriptions, for example), so we have to use ServiceLocator to create them. Refactoring them is very impractical at this time.
We're trying to create the unfriendly classes by injecting ILifetimeScope into the appropriate place, but are getting the following exception:
No constructors on type 'Autofac.Core.Registration.ScopeRestrictedRegistry' can be found with the constructor finder 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder'.
If I cheat and use the "Update" method on the ContainerBuilder and then register the container as the LifetimeScope, the resolution works successfully, however, given that Update is obsolete, it's not something I want to do.
Can anyone help?
Edit: I'm not doing anything special. Build up is standard:
builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces();
this.Container = builder.Build();
builder = new ContainerBuilder();
builder.RegisterInstance(this.Container);
builder.RegisterInstance(this.Container).As<ILifetimeScope>();
builder.Update(this.Container);
Without these lines
builder = new ContainerBuilder();
builder.RegisterInstance(this.Container);
builder.RegisterInstance(this.Container).As<ILifetimeScope>();
builder.Update(this.Container);
any class with an ILifetimeScope dependency fails with the error above.
public class MyClass : IMyClass
{
public MyClass(ILifetimeScope scope)
{
...
}
}
I'm actually thinking that this is a bug in the Autofac Framework, so I'm hoping that someone from the team will be able to tell me more.
ILifetimeScope is supposed to automatically be available.

Resolve Views through IoC or MEF instead of using SelectedAssemblies() method

I use Caliburn.Micro with Spring.net instead of the default simple IoC. My custom Bootstrapper (derrived from Caliburn's BootstrapperBase) is working and I can define the ViewModels within Spring.net. But the the Views are still resolved by reflection (name convention) from the execution assembly. I used the following method of the Bootstrapper to add Assemblies for resolving the Views for the ViewModels.
protected override IEnumerable<Assembly> SelectAssemblies()
{
// hmm, want to change the way how the view is resolved... how to do this?
// ... use IoC or MEF for this task instead?
return new[]
{
// don't want to add every dll here
this.GetType().Assembly,
Assembly.Load("MyViewModels.Assembly")
};
}
How to change the behaviour of resolving views and using IoC or MEF for this task?
The Problem is that the Bootstrapper has no virtual method to override which resolves a requested view. What is the starting point to change this behaviour? I thought there must exist something like
protected virtual Control ResolveViewForModel(Type modelType) {...}
Thanks for any hints.
First of all, I don't know caliburn.micro so this might be wrong.
Looking at the ViewLocator method LocateTypeForModelType it seems that it asks the AssemblySource for available types which should be checked against the View-naming conventions.
Since all of the above are static classes I suspect there is no way to inherit and override that behaviour. Since they are static, one could just add assemblies to the public observable dictionary - which feels a little bit of a hack and SelectAssemblies seems like the proper way.
However, it seems to me that since there are conventions for resolving Views and ViewModels one could do the same for assemblies which brings us to the question: how do you decide which assemblies to scan for ViewModels/Views.
That strategy can be built into the SelectAssemblies method.
If you want to change how caliburn.micro finds the right views in those assemblies, effectively changing/adding to the exisiting conventions, there is an explanation in their wiki.
To finally answer your question: "Resolve Views through IoC or MEF instead of using SelectedAssemblies() method": Imo this kind of defeats the philosophy of Caliburn.Micro:
Caliburn.Micro uses conventions to resolve views from given assemblies - trying to use an IoC container instead of a name / namespace based convention contradicts that approach.

Detecting the cause of a circular dependency in Unity

Is it possible to configure Unity to either detect a circular reference or to intercept the type resolver to display some debugging information?
Example
Here are a couple of interfaces and classes which are dependent upon each other
public interface IThing1 { }
public class Thing1 : IThing1
{
private IThing2 _thing2;
public Thing1(IThing2 thing2)
{
_thing2 = thing2;
}
}
public interface IThing2 { }
public class Thing2 : IThing2
{
private IThing1 _thing1;
public Thing2(IThing1 thing1)
{
_thing1 = thing1;
}
}
Castle Windsor
If these two types are configured in Castle Windsor it will throw an exception and provide some debug information to find the circular reference:
Castle.MicroKernel.CircularDependencyException: Dependency cycle has been detected when trying to resolve component 'CircularIoC.Thing1'.
The resolution tree that resulted in the cycle is the following:
Component 'CircularIoC.Thing1' resolved as dependency of
component 'CircularIoC.Thing2' resolved as dependency of
component 'CircularIoC.Thing1' which is the root component being resolved.
Unity
If Unity is configured to resolve these types like so
private static void ResolveWithUnity()
{
var container = new UnityContainer();
container.RegisterType<IThing1, Thing1>();
container.RegisterType<IThing2, Thing2>();
var thing = container.Resolve<IThing1>();
container.Dispose();
}
The call to container.Resolve<> will cause a StackOverflowException.
This is the documented behaviour but it would be nice to have some more useful information. Is there any customisation that will provide more information about the circular reference?
Alternatively is there any way to hook in to the type resolver process to emit some debugging information? I am thinking of decorating the main type resolver to output the name of the type being resolved. This will provide some feedback and a pointer to dependency that is causing the circular reference.
While I know that changing to a different IoC would solve the problem, this is not unfortunately an option.
Unity sadly doesn't support this (incredibly important) feature.
If you are willing to put your back into it, you can implement a smart decorator using some elbow grease.
What you will need is to override all Registration methods and build and update a data structure for the dependencies (dependency graph).
Then write a method that preforms DFS to detect a circular dependency, you can either use it as a finalizer for the registration process, that will detect pre-resolving if circular dependencies are possible, or use it per resolve for the specific type requested.
As you can see, it's a lot of work...
Another option, is just to wrap up with a decorator the resolve methods and catch the StackOverflowException, analyze it to make sure it resulted from the resolving process, and build a proper circular dependency exception.

Library assembly IoC setup

I am working in a project that has two main parts: a class library assembly and the main application. Both are using Castle Windsor for IoC and both manually setup their list of of components in code (to aid refactoring and prevent the need for a config file). Currently the main application has code like this:
public static void Main()
{
// Perform library IoC setup
LibraryComponent.Init();
// Perform application IoC setup
IoC.Register<IXyz, Abc>("abc");
// etc, etc, ...
// Start the application code ...
}
However the call to initialise the library doesn't seem like a good solution. What is the best way to setup a class library that uses an IoC container to decouple its internal components?
Edit:
Lusid proposed using a static method on each public component in the library that would in turn make the call to initialise. One possible way to make this a bit nicer would be to use something like PostSharp to do this in an aspect-oriented way. However I was hoping for something a bit more elegant ;-)
Lusid also proposed using the AppDomain.AssemblyLoad event to perform custom steps at load time, however I am really after a way to avoid the client assembly from requiring any setup code.
Thanks!
I'm not sure if I'm understanding exactly the problem you are trying to solve, but my first guess is that you are looking for a way to decouple the need to call the Init method from your main application.
One method I've used in the past is a static constructor on a static class in the class library:
static public class LibraryComponent {
static LibraryComponent() {
Init();
}
}
If you have multiple class libraries, and would like a quick and dirty way of evaluating all of them as they are loaded, here's a (kinda hairy) way:
[STAThread]
static void Main()
{
AppDomain.CurrentDomain.AssemblyLoad += new AssemblyLoadEventHandler(CurrentDomain_AssemblyLoad);
}
static void CurrentDomain_AssemblyLoad(object sender, AssemblyLoadEventArgs args)
{
IEnumerable<Type> types = args.LoadedAssembly.GetTypes()
.Where(t => typeof(IMyModuleInterface).IsAssignableFrom(t));
foreach (Type t in types)
{
doSomethingWithType(t);
}
}
The Where clause could be anything you want, of course. The code above would find any class deriving from IMyModuleInterface in each assembly that gets loaded into the current AppDomain, and then I can do something with it, whether it be registering dependencies, maintaining an internal list, whatever.
Might not be exactly what you are looking for, but hopefully it helps in some way.
You could have a registration module. Basically LibraryComponent.Init() function takes an IRegistrar to wire everything up.
The IRegistrar could basically have a function Register(Type interface, Type implementation). The implimentor would map that function back to their IOC container.
The downside is that you can't rely on anything specific to the container your using.
Castle Windsor actually has a concept called facilities that are basically just ways of wrapping standardised pieces of configuration. In this model, you would simply add the two facilities to the container and they would do the work.
Of course, this wouldn't really be better than calling a library routine to do the work unless you configured the facilities in a configuration file (consider binsor). If you are really allergic to configuration files, your current solution is probably the best.

XmlSerializer can't find EntityObject even though its referenced

I hope that someone can help me with this problem that I've been having with XmlSerializer.
I've already looked through this thread: http://social.msdn.microsoft.com/Forums/en-US/asmxandxml/thread/551cee76-fd80-48f8-ac6b-5c22c234fecf/
The error I am getting is:
System.InvalidOperationException: Unable to generate a temporary class (result=1).
error CS0012: The type 'System.Data.Objects.DataClasses.EntityObject' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Data.Entity, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.
I've made sure that my unit test has a reference to System.Data.Entity, so it is able to compile at least. I've also in the app.config made an assembly binding to System.Data.Entity.
Here's my rough class structure
[Serializable]
[XmlRoot(Namespace = XmlSupport.MyNamespace, ElementName = XmlSupport.WantToSerialize)]
[XmlInclude(typeof(WantToSerializeBaseClass)]
[XmlInclude(typeof(EntityObject)]
[XmlInclude(typeof(MyEntityObjectSubClass)]
public class WantToSerialize : WantToSerializeBaseClass, IXmlSerializable (I've tried putting this on the baseclass and the current class)
{
// methods and classes
// I've included XmlIncludes for all the classes that this class has a reference too
// even though in the WriteXml it just uses .NET base classes
}
The WantToSerializeBaseClass makes use of some generics, but I've decorated it with XmlIncludes for (EntityObject, and any other classes it makes reference to as well).
the calling code:
var serializerWrite = new XmlSerializer(typeof (WantToSerialize), XmlSupport.ITNNamespace);
fails
However if I do:
var serializerWrite = new XmlSerializer(typeof (WantToSerialize), new Type[] {typeof(EntityObject)});
it is succesfull.
Any thoughts would be most helpful.
UPDATED
I've tracked the problem down to a method in the WantToSerializeBaseClass
public abstract void ConvertFromEntity<TtoCopy>(TtoCopy toCopy) where TtoCopy : MyEntityObjectSubClass;
Where MyEntityObjectSubClass is a subclass of EntityObject, that adds a few methods that I want on my entity objects. The MyEntityObjectSubClass looks like this:
[Serializable]
[XmlInclude(typeof(EntityObject))]
public abstract class MyEntityObjectSubClass : EntityObject, IMyEntityObjectSubClass
Again any thoughts would be great
If you don't have any code that requires a reference at compile time then that reference won't be included in the built assembly. You can use a tool like Reflector to check whether the reference is making it into your assembly.
One thing you can try is adding a static method to WantToSerialize that creates the XmlSerializer. The assembly containing WantToSerialize must already have a good reference to EntityObject, so this should solve the problem.
I have this same problem too (in VB). what I found is that you can use the generic parameter, but it errors because the type MyEntityObjectSubClass is in another assembly. If you remove the type restriction on the generic parameter it will work fine.
I believe this to be an error in the framework itself. I've submitted a feedback ticket to microsoft. I attached a VB.net
I ended up removing the generic code and it worked fine.
I realize this is an older question but for posterity's sake set the CopyLocal parameter on the .dll reference to True.