Friday, 22 February 2008

This is the fifth of a series about how to go about using postcompilation in your solutions. You can read it as a tutorial on how to use PostSharp. I am very much new to that framework, but the power it provides could seriously change how you build your applications. While working on the EF contrib project, I had to dive into PostSharp, and I hope to share some of the things I learned along the way.

This post introduces the weaver, that will do exciting stuff for us.

The full table of contents:

  • Introducing Entity Framework Contrib- Easy IPoco implementation V 0.1
  • Part II, Postsharp Core versus Postsharp Laos
  • Part III, the compound aspect
  • Part IV, the PocoInterfaceSubaspect (composition aspect)
  • Part V, hooking up the weaver
  • Part VI, the EdmScalarWeaver
    Recap

    We wish to create an attribute that can be placed on top of our ordinary Poco class, that will magically transform it into a class that implements the 3 IPoco interfaces. These are needed by the Entity Framework to do it's work. We will use PostSharp to do this.
    Our previous post talked about the compound attribute and how it goes about implementing interfaces on classes for you.

    This post will look at how we are going to hook up a weaver to do more complex stuff, not directly supported by the provided Laos aspects.

    But first I want to clear up a statement I made here: 'I found it wildly confusing the first time I came across the two parts of postsharp. Laos is such a high-level abstraction, that you use it quite differently from Core. In the latter, you have to spinup your own weaver, in Laos you do not ever see a weaver. '
    It is not true that you do not ever see a weaver when using Laos. I should have been more clear: Laos offers a great deal of functionality that you can use without going into a weaver.

    We want to put custom attributes on our type that EF needs (the EDM scalar attributes on top of properties and the EDM type attribute that connects your type to a EDM type). Laos does not seem to have a ready-to-use aspect that provides that functionality, so we are going to need to hook into the weaver ourselves! How exciting!
    Thankfully, we can derive from TypeLevelAspectWeaver to make life easy enough.

    Hooking up a weaver

    The cool thing about using the weaver is, that you can put it in it's own assembly and not have to reference it in the assemblies that you are postcompiling. That is quite important, because the weaver depends on PostSharp.Core and there is another license attached to it.
    The PocoAttribute adds an aspect to the collection, like it did for the other aspects:

      1 public override void ProvideAspects(object element, LaosReflectionAspectCollection collection)
      2         {
      3             // Get the target type.
      4             Type targetType = (Type)element;
      5
      6 ....
    10             // inspect the complete class and add EDM scalar attributes to the properties
    11             collection.AddAspect(targetType, new EDMAttributesSubAspect(this.EDMContainerName, Name, NamespaceName, PathToConfigFile));
    .....
    12 }

    At line 11, the EDMAttributesSubAspect is added. This means that when Laos is ready to start working, it will check that aspect to see what it should do. Let's look at it now:

        [Serializable]
        internal class EDMAttributesSubAspect : ILaosTypeLevelAspect
        {
            #region fields and properties
            internal string EDMContainerName { get; set; }

            internal string TypeName { get; set; }
            internal string NamespaceName { get; set; }
            internal string PathToConfigFile { get; set; }
            #endregion

            #region ctor
            /// <summary>
            /// ctor
            /// </summary>
            /// <param name="EDMContainerName">the container name</param>
            /// <param name="NamespaceName">namespacename, can be null</param>
            /// <param name="TypeName">typename, can be null</param>
            public EDMAttributesSubAspect(string EDMContainerName, string TypeName, string NamespaceName, string PathToConfigFile)
            {
                this.EDMContainerName = EDMContainerName;
                this.TypeName = TypeName;
                this.NamespaceName = NamespaceName;
                this.PathToConfigFile = PathToConfigFile;
            } 
            #endregion

            #region ILaosTypeLevelAspect Members

            public void CompileTimeInitialize(Type type)
            {
            }

            public bool CompileTimeValidate(Type type)
            {
                return true;
            }

            public void RuntimeInitialize(Type type)
            {
            }

            #endregion

            #region ILaosWeavableAspect Members

            public int AspectPriority
            {
                get { return int.MinValue; }
            }

            #endregion 

        }

    You might be surprised to hear that this is the complete aspect!! Nothing that hints at what is to come.

    When such a thing happens, you might be stumped. But obviously you will immediately think to check the assemblyinfo file of the PostSharp4EF assembly:

    [assembly: PostSharp.Extensibility.ReferencingAssembliesRequirePostSharp("PocoTypeWeaver", "EntityFrameworkContrib.PostSharp4EF.Weaver")]
    [assembly: InternalsVisibleTo("EntityFrameworkContrib.PostSharp4EF.Weaver")]

    Okay, I was kidding. You wouldn't have thought of that. ;-)

    The first statement there, instructs PostSharp to look for a plugin, with name PocoTypeWeaver to process all assemblies that are referencing this assembly. It is just another way of expressing requirements. I could have put that inside the attribute. But I did not.

    The plugin file can be found in the weaver assembly. It is just a normal text file with naming convention that matches the entire assembly name + "psplugin". The contents of that file:

    <?xml version="1.0" encoding="utf-8" ?>
    <PlugIn xmlns="http://schemas.postsharp.org/1.0/configuration">
      <TaskType Name="PocoTypeWeaver" 
                Implementation="EntityFrameworkContrib.PostSharp4EF.Weaver.PocoEDMAttributesWeaverFactory, EntityFrameworkContrib.PostSharp4EF.Weaver">
      </TaskType>
    </PlugIn>

    Here you will see a task PocoTypeWeaver and a reference to an implementation of a weaver factory. So, our PocoAttribute needs the pocoTypeWeaver and it can get one through the use of a factory. But, since your client assembly will not have a reference to this weaver assembly (which contains this mapping file), we need some way to tell it where to look. Enter the psproj file that was put inside your client assembly:

    <Project xmlns="http://schemas.postsharp.org/1.0/configuration">
    	<SearchPath Directory="../EntityFrameworkContrib.PostSharp4EF.Weaver/bin/{$Configuration}"/>
    	<SearchPath Directory="{$SearchPath}" />
    	<Tasks>
    		<AutoDetect />
    		<Compile TargetFile="{$Output}" IntermediateDirectory="{$IntermediateDirectory}"  CleanIntermediate="false" />
    	</Tasks>
    </Project>

    This psproj file is used by postsharp to extend it's searchpath. This means that on machines that are building the solution, you will need to supply some path where PostSharp can find the just mentioned psplugin file.

    Please note: there are other ways to configure the searchpath and possibly better ways to setup a system like this. There is a default searchpath and you could also put your plugin file there.

    The weaver factory
        public class PocoEDMAttributesWeaverFactory : Task, ILaosAspectWeaverFactory
        {

            #region ILaosAspectWeaverFactory Members
            /// <summary>
            /// creates the weaver
            /// </summary>
            /// <param name="aspect">the EDMAttributesSubAspect that instantiated this factory</param>
            /// <returns>the weaver that will do the lowlever hardcore work</returns>
            public LaosAspectWeaver CreateAspectWeaver(PostSharp.Laos.ILaosAspect aspect)
            {
                if (aspect is EDMAttributesSubAspect)
                {
                    EDMAttributesSubAspect edmAttributesAspect = (EDMAttributesSubAspect)aspect;
                    return new PocoEDMAttributesWeaver(edmAttributesAspect.EDMContainerName);
                }

                return null;
            }

            #endregion
        }

    Nothing special there. Using a factory allows you to supply different weavers for different aspects.

    So, to recap: we attached a plugin that did not do much itself. We used the assemblyinfo to tell PostSharp it should always use a certain task when compiling assemblies that are referencing our attribute assembly. We used the psproj file to make PostSharp search in the right spot and we used a psplugin file to tell map the task name to an actual factory.
    The factory creates our weaver, and we will discuss that in the next post!

  • Saturday, 04 December 2010 03:06:54 (Romance Standard Time, UTC+01:00)
    The usage of payed eye can be a legitimate solution to make money over the internet. Paid survey is just a approach to having compensated in your opinion. You can expect to be executing surveys for enormous institutions like coca cola, Nike, eBay, Google, MacDonald etc.
    Saturday, 04 December 2010 03:18:05 (Romance Standard Time, UTC+01:00)
    One can find in fact numerous sport footwear brands that you really can unearth at any sneaker mart or footwear business. The most popular makes with regards to sports footwear are; Nike, Adidas, Reebok, Accel, And1, Converse, Vans, and many way more. Sports shoes almost always rely to the sports that you choose to have. Just about every sports sneaker has its very own identity and utilization.
    Comments are closed.