Programmers Unlimited

Knowledge is power

  • PostSharp Principals
  • My Articles
  • Projects
  • Archives
  • About

It’s ok to mock a Person

Posted by programmersunlimited on February 2, 2012
Posted in: General. 1 comment

Update

I worked up a video on Typemock. Check it out.

Original Post

Ok, that’s a bad attempt at a humorous pun, but it’s still a valid statement. TDD exploded a few years ago and has gained tremendous following and prestige in the development community. I’ve never actually practiced TDD other than tutorials and more recently I’ve been doing TDD katas. If you haven’t done a TDD kata, I recommend it. I’ve learned about myself that I over think the requirements causing me to spend time on a solution I don’t need (YAGNI principal). I’m working on that though thanks to the TDD katas.

I’m a bit late to the unit testing and TDD game but I have a large need for it at the moment, so when I had the chance to grab a copy of TypeMock’s Isolator at the Inland Empire .NET Users Group, I jumped on it. I’ve been playing around with it and it’s pretty cool to say the least.

Why do we need mocks?

Mocks are needed to isolate a specific method for testing. Methods can have external dependencies that, for whatever reason, are not appropriate to have in the unit test. The best example of this is a method that makes a database call via a repository. Actually having database calls in a unit test is not a great idea. For one thing it’s slow. But really it’s pointless. If the database connection fails for whatever reason, the test will fail. You might think that this is a good thing but it isn’t. Database connectivity is an integration test, not a unit test.

Anyway, the point is to isolate methods. TypeMock Isolator makes this pretty easy. Mocking frameworks have come a long way in the last 2 years and TypeMock is pretty impressive. Let’s take a look at a few examples.

Mocking Bird

When will my attempts at humor end? Sorry. The stage is pretty typical. An order processor needs to get the order and update the sales tax based on the order total. The repository makes a call to authenticate on instantiation. CalculateTax just does some math based on the order’s state and returns the value. Very pointless but this is a blog, not a real world application Winking smile

public class OrderProcessor
{
    public decimal CalculateTax(int orderId)
    {
        OrderRepository rpo = new OrderRepository();
        var ord = rpo.GetOrder(orderId);

        var taxRates = new Dictionary()
        {
            { "CA", 0.50m }, //Bastards!
            { "NV", 0.0685m }
            };

        return ord.OrderTotal * taxRates[ord.address.State];
    }
}

public sealed class Security
{
    public static bool Authenticate()
    {
        throw new NotImplementedException();
    }
}

public class OrderRepository
{
    public OrderRepository()
    {
        if (!Security.Authenticate())
        {
            throw new InvalidOperationException("Could not authenticate user");
        }
    }
    public Order GetOrder(int id)
    {
        throw new NotImplementedException();
    }
}

public class Order
{
    public int OrderId { get; set; }
    public Address address { get; set; }
    public decimal OrderTotal { get; set; }
    public decimal Shipping { get; set; }
    public decimal Tax { get; set; }
}

public class Address
{
    public string Street { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Zip { get; set; }
}

Nothing special. Notice that the repo and security don’t do anything, but throw exceptions instead. This doesn’t matter since we don’t care about those actions anyway. We are only interested in making sure the sales tax is calculated correctly.

Now let’s see the code for our test.

[TestMethod()]
public void OrderProcessor_CalculateSalesTaxForCalifornia()
{
    Order fakeOrder = new Order()
    {
        OrderTotal = 100.00m,
        Shipping = 25.00m,
        OrderId = 10,
        address = new Address()
        {
            State = "CA"
        },
    };

    Isolate.WhenCalled(() => Security.Authenticate()).WillReturn(true);

    var repo = Isolate.Fake.Instance();
    Isolate.Swap.AllInstances().With(repo);
    Isolate.WhenCalled(() => repo.GetOrder(0)).WillReturn(fakeOrder);

    OrderProcessor target = new OrderProcessor();
    int orderId = 10;
    decimal expected = 50.0m;
    decimal actual;
    actual = target.CalculateTax(orderId);
    Assert.AreEqual(expected, actual);
}

First we new up a dummy order populating the needed data. Then we use Isolator to specify that whenever a call to Security.Authenticate() is made, it will intercept it and return true. This way we can always test our method without needing to bother with setting up credentials, etc etc etc. We don’t care about security, it has nothing to do with sales tax!

Then we create a fake repository object using Isolator.Fake. Then, using Isolator.Swap, we tell Isolator that anytime a new instance of OrderRepository is instantiated, we replace it with our fake instance. Then we specify that anytime the GetOrder method is called on the fake repo instance, we will intercept and return our dummy order instance.

Finally, we instantiate a copy of OrderProcessor and make a call to CalculateTax. We assert that the returned value matches what we expect it to be.

Conclusion

Even though a call to the CalculateTax method requires a call to the database and a security check, we were able to isolate the tax calculation logic by mocking up the dependencies. I like the way Isolator works because you don’t have to specifically code your classes for unit testing/IoC/DI in order to pass in the fakes and mock objects.

There is plenty more that TypeMock Isolator will do so make sure you check out their documentation.

  • More

What I’ve learned by presenting at code camps

Posted by programmersunlimited on January 30, 2012
Posted in: General. 1 comment

Last year, out of no where, I decided that I wanted to present at the San Diego Code Camp after receiving the email announcing it. I had never attended a code camp but I wanted to go. Why I wanted to present, not having any previous experience with code camps, is beyond me. I’m a very shy person.

I knew that I wanted to present about aspect oriented programming since I had already done a user group session about it and I was pretty familiar with the topic. But for some reason, I wanted to do another session (yes, two sessions!) on parallel programming.

Presenting: Then

I had enough time to build my slide decks, notes and examples but I still found myself making last minute changes. I was not prepared. I did not practice at all. I had pages of notes that I thought I could just read from. Bad idea. The first session on AOP went ok because I was already very familiar with the material, but the parallel programming session was a flop in my opinion. I stuttered, lost my train of thought and was confusing the audience. Even worse, I went 15 minutes over and I wasn’t even 1/2 done with my material. People started leaving.

Presenting: Now

Last weekend was the Fullerton code camp in which I also had two sessions. With 2 previous code camps under my belt, and a mass of user group sessions and an entire PluralSight course, I still found myself making last minute changes to the slide decks and notes but I nailed both of my sessions. I received many compliments on both sessions which was not entirely surprising. This is not to say that I’m being arrogant, but I made several changes to my approach and I was expecting them to pay off. It did.

Preparing: Then

Having no speaking experience, I really didn’t know what you needed to do other than makes some slides and do some examples. I’ll be standing in front of a crowd of people who all attended knowing I would be speaking. Some of them are just there for the swag, but still they expect a good performance. I can’t hide behind anything. I’m there face to face with 5-100 people.

Slides

My slide decks were basically for me, not for the audience. I made my slide decks packed with text. I thought the more info I put in there, the better. This is a big mistake. First of all, the audience isn’t going to read all of that text (if they can even see it). Second of all, they are looking at ME, not my slides.

I found myself reading the slides instead of talking to the audience. This makes for a poor performance.

Notes

I have a problem when it comes to vocalizing my thoughts. Sometimes I get things mixed up as they come out or I forget how I wanted to verbalize a thought. To help this, I had pages and pages of notes. I thought I could address my notes at any time and make sure I hit the nail on the head. Wrong! I had paragraphs of notes which made it hard to find specific points quickly so I lost my place and I lost which page I was on. Big mess. Confused myself and confused the audience.

After realizing the flaws on this approach I moved to a very succinct bullet point list with all the points I wanted to make in a specific order. It was easier to find my place, stay on track but did nothing to help me remember how to say what I wanted to say and I left out large chunks of information that I really needed to deliver to the crowd.

Confidence

Being a shy person, it was hard for me to get up in front of people. I don’t like being the center of attention. Knowing that I have a problem with verbalizing my thoughts, I was nervous even more than normal. I was not confident that I knew the material well enough to not have my notes and slides as crutches. I stuttered, said “uh” a lot and was always forgetting what I wanted to say.

Practice

Biggest reason I was not confident is because I didn’t practice. Sure, I would read my notes over and over but I never practiced saying anything out loud. I never liked to hear myself. Voice recordings, video, voicemail, it doesn’t matter. I don’t like listening to myself talk. It’s weird. You get what you pay for and that’s the truth of it.

Preparing Now

Things have changed. I’ve learned a lot since doing my first speaking session 3 years ago. But it’s taken a long time and a lot of embarrassment.

Slides

My slide decks are barren. They have become my list of bullet points. They offer only a hint on what I’m currently blabbering about or they display some diagram or example that I’m explaining. Some people have asked me to send them my slides before the session, and I do, but really it’s pointless because the slides have no context now.

This works. The audience doesn’t care about your slides, they’re looking at you. The slides are just there for reference and whenever I feel lost I can quickly glace at the screen as I’m changing slides. I make it look like I’m just making sure the slide actually changed Winking smile

Notes

I have combined the two previous techniques on notes. First I create my list of bullet points; the things I wants to talk about. Then from that list, I create the slides. Then I write out detailed scripts on each point/slide. Up to 10 pages for some topics.

The difference is now I use that script to practice, not a reference during a live session.

Practice

No, I don’t like talking to myself and I don’t like hearing myself. Heck, I don’t even sing out loud to my favorite songs. But, they only way (for me at least) to really practice and get it down is speak out loud. This is where the script comes in. I start by reading it quietly to myself to check for any weirdness. Then I read it out loud. After making any changes, I read it out loud again. Then I read it as I’m flipping through my slide deck as if I’m doing a real session. I do this as many times as I need to. Then I’ll glance over it just before a session is going to start. Now I don’t need to do this and when I realize that, it means I’ve prepared enough.

Confidence

Confidence isn’t affected by stage fright. It’s affected by how well you know your material. The more confident you are, the better you will perform. You’ve already done this (assuming you practiced enough). You know how it turns out so just do it again. The only difference is that some people might be watching you. The audience is attracted to confidence. Even if you’re full of crap, you can BS your way through a tough session by showing confidence. This is how salesman sell crowds.

Tips

Be prepared. Don’t wait until the last minute to check if you have a cable. If you have a mac, you should have the correct converter cable. The audience might not have one you can use so don’t bother to ask. Know what your setup will require. This is usually a VGA cable. Have HDMI only? Well I’m sorry but the majority of projectors you’re going to be presenting on will be VGA so go buy an adapter or use an old laptop.

Show up early enough to figure out the lighting. Some places leave you to fend for yourself and it can be tough to figure out the lighting and AV systems.

Practice! This should be obvious, but you really must practice. More than once. If you can do a video of yourself or even an audio recording, you will benefit from it. You can see any weird ticks you have and hear how many times you say “Um” or “Uh”. If you’re confident (practiced enough) then you should be fluid and won’t need to use filler words.

Practicing also help you nail the timing. You only get a certain amount of time. You don’t want to go over and you don’t want to go under. Going over leaves out points that need to be made and the audience feels obligated to stay until you finish which upsets them because they want to go to their next session. Going under feels like a rip-off. They came for the show not the previews.

Address the audience. Ask them questions, get them involved. This helps you loosen up and feel less nervous. I like to start off by asking about their experience with the specific session topic. It makes them feel comfortable with you. This can be hard to do if you’re not confident though. Try a few things and see what works. Be sure to talk to the audience, not just one person. Move around, come out from behind the podium. Stepping away from the podium shows confidence. You shouldn’t need to be there unless you’re doing a demo.

Get some equipment. I highly recommend getting a presentation mouse. It’s a small device that let’s you go back and forth on slides without being at the podium. I believe this has improved my presentations tremendously. I’m not rushing back and forth to the podium to change slides so I am free to roam and talk.

A laser pointer is also a great tool. Sometimes the projector screens are pretty high up and you can’t point out specific things unless you go back to the podium and use the mouse.

Don’t do live code! The audience doesn’t want to see you write code. They want points, content and action. This is a time waster. Especially when you make mistakes and have to figure them out. Don’t copy and paste either. Open the completed project and walk through the code. If you go to fast, it doesn’t matter. You can always send them the code and they can go over it later.

Conclusion

Everyone has their own personality. I’ve seen many great speakers of all different types. Some of them were witty and energetic and others were plain Jane. Be yourself. If you know what you’re talking about and you’ve practiced your material, things will be fine.

Don’t be discouraged when you have a bad session. Sometimes they just don’t work out. Oh well. I’m just now finding my groove and it’s working. But I still have a lot to learn.

I’ve had many flops, regardless of how nice the audience is after, I know I sucked and I fix the things I did wrong so next time will be a little better.

  • More

PostSharp with projects targeted at x64

Posted by programmersunlimited on January 27, 2012
Posted in: General. Leave a Comment

I’ve been working with a project that processes a large set of data so I’m targeting x64 only. I needed to apply my performance and logging aspects to check execution times of each method but when I went to compile I received a build error from PostSharp

“Platform mismatch. You cannot run PostSharp on a 64-bit application from a 32-bit operating system.”

It was obvious that PostSharp was trying to run it’s post processor in x86 mode because my OS is 64-bit and the project is targeting x64 only. The question was “how do I tell PostSharp to work in x64 mode?”. The answer to resolving this issue is pretty easy because the developers at SharpCrafters have come through once again with great tooling for their product. You simply need to go into the project properties and click on the PostSharp tab, then set the “Processor Architecture” to x64. After that, you’re good to go.

ps-tab

What else can you do in here? Well you can also enable/disable PostSharp, enable/disable support for obfuscation and pass in additional properties to PostSharp just to name a few.

If you don’t have the latest version of PostSharp, grab it from PostSharp 2.1 and if you’re new to AOP or PostSharp, have a look at PostSharp Principals to quickly get to speed with PostSharp.

  • More

DataTables != Thread Safe

Posted by programmersunlimited on January 26, 2012
Posted in: General. 2 comments

The title of this post might seem really silly considering MSDN specifically says they aren’t thread safe, but there’s more to it than that. It says DataTables are not thread safe for WRITE operations which is a major ‘”Duh” statement, but in reality they are not safe for some read operations. I’ve been having some strange issues with DataRows in parallel loops so I started to investigate.

I saw a post stating that DataTable.Select() is actually a write operation so it isn’t thread safe and requires a lock. I don’t see anything on MSDN about this. So I got to thinking and that’s when I opened up dotPeek. What did I find?

DataTable.NewRow() is not thread safe! The point of this method is to create a new row with the same schema as the table. According to MSDN you have to then add that row to the table’s DataRowCollection, it is not automatically added to the row collection when calling NewRow(). This, for the most part, is a read operation which would be thread safe. BUT, at one point in the internals, a call to NewRow(int) is made which creates the new record object, then sets that record to a class scoped field before passing it along to a DataRowBuilder. This is where it is no longer thread safe.

I was seeing so many problems because I was using NewRow() in a parallel loop and data was being corrupted at the end. This was why. To combat this, I generated a cache of new rows before the parallel loop, in a ConcurrentBag<DataRow> and then use a TryTake() inside of the loop. No more problems.

  • More

Change Request Pattern – Parallelism and non thread safe collections

Posted by programmersunlimited on January 24, 2012
Posted in: General. Leave a Comment

My current project makes heavy use of DataTables and parallel processing via the TPL. DataTables are not thread safe and really bite the dust hard when asked to do more than one thing at once.

My project breaks up operations that need to be performed on a DataTable into groups that can be executed concurrently. In total that are about 15 groups each with 2-5 concurrent processes. Each process works with certain columns on a DataRow but still, the DataTable can’t handle more than one change request at a time or it just has a stroke. It’s very annoying. I could easily combat this by using POCOs instead of DataTables but it isn’t an option. So how do I do it? Using what I call the Change Request pattern.

The concept is simple, there are operations reading and making changes to each row in the DataTable. Usually data correction, number crunching, etc. Instead of writing the new value back to the DataColumn, it queues up the change in a thread safe collection using a POCO to describe what has to change. When the operations in the group have finished, the changes are processed one-by-one in a thread safe manner.

private void DoWork(DataTable table)
{
    var chgcrd = new ChangeCoordinator(table);
   
    Task t1 = Task.Factory.StartNew(new Action(() => { UpdateColumn1(table, chgcrd); }));
    Task t2 = Task.Factory.StartNew(new Action(() => { UpdateColumn2(table, chgcrd); }));

    Task.WaitAll(t1, t2);

    chgcrd.ProcessChanges();
}

private void UpdateColumn2(DataTable table, ChangeCoordinator changes)
{
    Parallel.For(0, table.Rows.Count, new Action<int>((i) =>
    {
        int oldValue = table.Rows[i].Field<int>("column2");
        int newValue = oldValue * 5;
        long rowId = table.Rows[i].Field<long>("id");

        changes.ScheduleChange(new ChangeRequest(rowId, "column2", newValue));
    }));
}

private void UpdateColumn1(DataTable table, ChangeCoordinator changes)
{
    Parallel.For(0, table.Rows.Count, new Action<int>((i) =>
    {
        int oldValue = table.Rows[i].Field<int>("column1");
        int newValue = oldValue * 2;
        long rowId = table.Rows[i].Field<long>("id");

        changes.ScheduleChange(new ChangeRequest(rowId, "column1", newValue));                
    }));
}

public class ChangeRequest
{
    public long ID { get; set; }
    public string Column { get; set; }
    public object Value { get; set; }

    public ChangeRequest(long id, string column, object value)
    {
        this.ID = id;
        this.Column = column;
        this.Value = value;
    }
}

public class ChangeCoordinator
{  
    public ChangeCoordinator(DataTable table) 
    {
        _table = table;
    }

    private ConcurrentBag<ChangeRequest> _changes = new ConcurrentBag<ChangeRequest>();
    private DataTable _table;

    public void ScheduleChange(ChangeRequest request)
    {
        _changes.Add(request);
    }

    public void ProcessChanges()
    {
        ChangeRequest cr;
            
        while(_changes.TryTake(out cr)) 
        {
            var row = _table.Rows.Find(cr.ID);
            if (row == null) { continue; }

            row[cr.Column] = cr.Value;
        }

        _table.AcceptChanges();            
    }
}

The code is a dumbed down version of what I’ve implemented, just to show the basic concept. The applications are numerous but I chose to use the DataTable example because it’s a thorn in my side at the moment.

  • More

Indexing DataTables

Posted by programmersunlimited on January 24, 2012
Posted in: General. Leave a Comment

That’s right, I’m still using DataTables. Why? Because they best fit the requirements for what I am doing. I’m also taking advantage of parallel processing via the TPL. A lot of the operations I need to do would be much easier via PLINQ and POCO’s such as joins, grouping and searching.

Because I’m working with many disparate DataTables and the join predicates are complex it just isn’t feasible (performance wise) to use DataRelation. To get a working prototype I decided to just use nested loops to find matching DataRows but I’ve found that nested loops when using the TPL results in poor performance and is generally a bad idea when working with large item sets anyway.

Normally I would build a HashTable and create a key from each row based on the columns in the predicate, then use that to match rows with a single loop. However, when using parallel loops, one has to take care to avoid concurrency/multi-threading issues that arise with non thread safe collections. Dictionary<K,V> is normally satisfactory when using them, but they are not thread safe. ConcurrentDictionary<K,V> would seem like an obvious candidate to replace the normal dictionary, but it buckles under the pressure. Memory consumption goes through the roof even for simple, small data processing and performance takes a serious hit.

Another issue with my row key by column approach is that the code has to be written each time and normally I use string concatenation for the keys. Instead, I wanted a nice way to build an index that I can easily query, but I also wanted a generic solution so any key could be used.

I went with the following method

public static Dictionary<TKey, List<DataRow>> BuildIndex<TKey>(this DataTable source, Func<DataRow, TKey> processRow)
{
    ConcurrentBag<Index<TKey, DataRow>> indexBag = new ConcurrentBag<Index<TKey, DataRow>>();

    Parallel.For(0, source.Rows.Count, new Action<int>((i) =>
        {
            indexBag.Add(new Index<TKey, DataRow>()
            {
                Key = processRow(source.Rows[i]),
                Row = source.Rows[i]
            });

        }));

    var result = (from i in indexBag
                    group i by i.Key into g
                    select g
                        ).ToDictionary(c => c.Key, d => d.Select(e=>e.Row).ToList() );

    return result;
}

private class Index<TKey, URow>
{
    public TKey Key { get; set; }
    public URow Row { get; set; }
}

This method  takes in a generic type TKey to define the index key and then requires a predicate to build the key from each row. The performance of this is excellent. The generic Index model is simply a nice way to organize the keys as things are being built. I chose to return a dictionary because I’m satisfied with the performance and functionality and since it’s only being used for reading and not writing, we don’t need a thread safe collection. I could have easily went with a IEnumerable<Index<TKey,URow>> but why bother?

Since this ends up as an extension method, using it is pretty simple.

private void Loop(DataTable table1, DataTable table2)
{
    //Build index for table2
    var idx = table2.BuildIndex<Tuple<int, long, int>>((dr) =>
    {
        return new Tuple<int, long, int>(
            dr.Field<int>("userid"),
            dr.Field<long>("orderid"),
            dr.Field<int>("domainid"));
    });

    //Loop over table1
    Parallel.For(0, table1.Rows.Count, new Action<int>((i) =>
    {
        var rowKey = new Tuple<int, long, int>(
            table1.Rows[i].Field<int>("userid"),
            table1.Rows[i].Field<long>("orderid"),
            table1.Rows[i].Field<int>("domainid"));

        if (idx.ContainsKey(rowKey))
        {
            //Exists
        }
        else
        {
            //Doesn't exist
        }
    }));
}

private void Join(DataTable table1, DataTable table2)
{
    //Build index for table1
    var idx1 = table1.BuildIndex<Tuple<int, long, int>>((dr) =>
    {
        return new Tuple<int, long, int>(
            dr.Field<int>("userid"),
            dr.Field<long>("orderid"),
            dr.Field<int>("domainid"));
    });

    //Build index for table2
    var idx2 = table2.BuildIndex<Tuple<int, long, int>>((dr) =>
    {
        return new Tuple<int, long, int>(
            dr.Field<int>("userid"),
            dr.Field<long>("orderid"),
            dr.Field<int>("domainid"));
    });

    //Do a join
    var joined = from i in idx1
                    join j in idx2 on i.Key equals j.Key
                    select new { Key = i.Key, t1Rows = i.Value, t2Rows = j.Value };

}

Tuples are great to use as keys because they’re immutable and have a smaller footprint than strings (generally speaking).

Conclusion: If I could use POCOs instead of DataTables I certainly would but for now I do what I can. I find the indexing method I’ve come up with a great way to work around performance and threading issues (even when only reading) of DataTables.

I’m interested in hearing your thoughts.

  • More

Learn T4 with my PluralSight course

Posted by programmersunlimited on January 18, 2012
Posted in: General. Leave a Comment

My new course on T4 (Text Template Transformation Toolkit) has gone live and it’s ready for your viewing pleasure. If you have any feed back, please send it to me.

T4 Templates on PluralSight.com

This course introduces T4, Microsoft’s code generation tool that comes with Visual Studio. The Text Template Transformation Toolkit dynamically produces text of any type and is used for code and document generation.

Discover how to reduce development time, bugs and maintenance by building reusable templates. This course covers T4 template building blocks, extending templates with custom functionality and debugging the template execution process.

MVC and Entity Framework, among others, can be customized and extended through T4 templates. It also covers, how to customize MVC controllers using the default templates and the MVCScaffolding package, and customizing entities by adding validation attributes.

Dustin tops it all off with real world uses of T4 including generating, and automatically synchronizing, code based on external resources, and combining T4 with other technologies to produce powerful templates.

  • More

Exposing internal methods in 3rd party assemblies for external use

Posted by programmersunlimited on August 16, 2011
Posted in: General. Leave a Comment

To start out, I’m going to state that I don’t condone this, but if you need it then you need it. I expect to get some nasty comments about pattern violation this or encapsulation that so go ahead and send them in. This is just an extension of my previous post about modifying 3rd party assemblies and the power of PostSharp.

The Evil API

I was working with an API recently that had me using ILSpy to figure anything out. At some point I needed to make use of some code while inheriting a class and overriding a virtual method. So I copied out some code from ILSpy into Visual Studio when I realized that an important method call was broken because that method was internal only. DOH! Due to reasons I won’t explain, I didn’t actually modify the assembly, I just went another way, but if I could have I would have just exposed the method.

Here is our own little evil API

namespace Example.API
{
    public class Calculator
    {
        public int ProcessValue(int x)
        {
            return SuperSpecialCalculation(x, x);
        }

        internal int SuperSpecialCalculation(int x, int y)
        {
            return x + y;
        }

    }
}

Two methods, a public and an internal. We need access to the internal!

The Apsect and Provider

I’m sure there are better ways, but I decided to just introduce a public method using the same signature as the internal method and it will just act as a wrapper. So we need an aspect that imports the expected internal method (target) and introduces our wrapper method. Then we need a provider to tell PostSharp where to apply our aspect. For more information on aspect providers, see PostSharp Principals day 12 & day 13. For more information on introduction, see PostSharp Principals day 13 & day 14.

namespace InternalToPublic
{
    //Aspect Provider
    public class AspectProvider : IAspectProvider
    {
        public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
        {
            List<AspectInstance> targets = new List<AspectInstance>();

            var targetType = ((Assembly)targetElement).GetTypes().FirstOrDefault(c => c.Name.Equals("Calculator"));

            if (targetType == null) { return targets; }

            targets.Add(new AspectInstance(targetType, new ExposeSuperSpecialCalculation()));

            return targets;
        }

    }

    //Aspect
    [Serializable]
    public class ExposeSuperSpecialCalculation : InstanceLevelAspect
    {
        [ImportMember("SuperSpecialCalculation", IsRequired = true, Order = ImportMemberOrder.BeforeIntroductions)]
        public Func<int, int, int> InternalMethod;

        [IntroduceMember]
        public int SuperSpecialCalculationPublic(int x, int y)
        {
            return InternalMethod(x, y);
        }
    }
}

Modify!

Just as in the previous post, we run a batch file to do the modifications to the assembly.

@"C:\Program Files (x86)\PostSharp 2.1\Release\postsharp.4.0-x86-cil.exe" "Example.API.dll" /p:AspectProviders=InternalToPublic.AspectProvider,InternalToPublic /p:Output=output\Example.API.dll
@copy /y InternalToPublic.dll .\Output
@copy /y PostSharp.dll .\Output
@pause

Test

Now we just need to make sure it’s all working. Create a new project and reference the modified Example.API.dll, InternalToPublic.dll and PostSharp.dll.

namespace Example.TestApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Example.API.Calculator c = new API.Calculator();
            Console.WriteLine(c.ProcessValue(10));
            Console.WriteLine(c.SuperSpecialCalculationPublic(10, 20));
            Console.ReadKey();
        }
    }
}

The output is as expected

20
30

kick it on DotNetKicks.com

  • More

PostSharp: Why are my arguments null?!

Posted by programmersunlimited on August 1, 2011
Posted in: General. Leave a Comment

I see this question a lot. The developer has created an aspect and when they are stepping through they are seeing that the advice method arguments are null. The most common example of this is the MethodExecutionArgs.Exception. We can easily reproduce this “issue”.

Example

If you compile this code and step through it, the args parameter will be null.

[LogAspect]
class Program
{
    static void Main(string[] args)
    {
        throw new Exception("test exception");
    }
}

[Serializable]
public class LogAspect : OnExceptionAspect
{
    public override void OnException(MethodExecutionArgs args)
    {
        Console.Write("There was an error");
    }
}

PostSharpNullArgs1

So what’s going on? Well if you use ILSpy and look at the compiled result, you’ll see that PostSharp uses optimizations that include ignoring unused properties.

PostSharpNullArgsILSpy1

See how the OnException method has been decorated with multiple MethodExecutionAdviceOptimizations flags? The entire list for this aspect is:

MethodExecutionAdviceOptimization(
MethodExecutionAdviceOptimizations.IgnoreGetMethod 
| MethodExecutionAdviceOptimizations.IgnoreSetFlowBehavior
| MethodExecutionAdviceOptimizations.IgnoreGetArguments
| MethodExecutionAdviceOptimizations.IgnoreSetArguments
| MethodExecutionAdviceOptimizations.IgnoreGetInstance 
| MethodExecutionAdviceOptimizations.IgnoreSetInstance
| MethodExecutionAdviceOptimizations.IgnoreGetException 
| MethodExecutionAdviceOptimizations.IgnoreGetReturnValue
| MethodExecutionAdviceOptimizations.IgnoreSetReturnValue 
| MethodExecutionAdviceOptimizations.IgnoreGetMethodExecutionTag
| MethodExecutionAdviceOptimizations.IgnoreSetMethodExecutionTag 
| MethodExecutionAdviceOptimizations.IgnoreEventArgs
)

Notice the IgnoreGetException flag? That’s why it’s null when stepping through the aspect. Change the aspect to

[LogAspect]
class Program
{
    static void Main(string[] args)
    {
        throw new Exception("test exception");
    }
}

[Serializable]
public class LogAspect : OnExceptionAspect
{
    public override void OnException(MethodExecutionArgs args)
    {
        Exception e = args.Exception; //Now we're using Exception so it won't be null
        Console.Write("There was an error");
    }
}

and rebuild. When you step through this time, args is not null and neither is args.Exception.

PostSharpNullArgs2

Looking at ILSpy again, you no longer see the IgnoreGetException flag.

MethodExecutionAdviceOptimization(
MethodExecutionAdviceOptimizations.IgnoreGetMethod
| MethodExecutionAdviceOptimizations.IgnoreSetFlowBehavior
| MethodExecutionAdviceOptimizations.IgnoreGetArguments
| MethodExecutionAdviceOptimizations.IgnoreSetArguments
| MethodExecutionAdviceOptimizations.IgnoreGetInstance
| MethodExecutionAdviceOptimizations.IgnoreSetInstance
| MethodExecutionAdviceOptimizations.IgnoreGetReturnValue
| MethodExecutionAdviceOptimizations.IgnoreSetReturnValue
| MethodExecutionAdviceOptimizations.IgnoreGetMethodExecutionTag
| MethodExecutionAdviceOptimizations.IgnoreSetMethodExecutionTag
)

Answer

So why are the arguments null? Because you’re not using them.

kick it on DotNetKicks.com

  • More

Applying aspects to 3rd party assemblies using PostSharp

Posted by programmersunlimited on July 27, 2011
Posted in: General. 5 comments

[Related Article: Introduction to Aspect Oriented Programming and PostSharp]

There is undocumented functionality in PostSharp 2.1 (2.1.2.3 or higher) that allows us to apply aspects to assemblies that we don’t have the source code for. I’m going to show you how this works, but first I have state that this functionality is undocumented because it isn’t officially supported by PostSharp. Proceed at your own risk.

Setup

If you do not have PostSharp 2.1.2.3 (at this point it’s CTP 3) then get it and install it. We will create two projects, a console project that we’ll be using as our dummy and a class library that is going to hold our aspect provider. I highly recommend that you read through the PostSharp Principals series if you are not familiar with PostSharp or aspect providers.

We will also have a folder called ‘Lab’ which we’ll store all our needed files in. Create the Lab folder and then create a subfolder under Lab called Output.

Note: I’m targeting .NET 4.0.

Code

The proceeding code is going to be our dummy executable that we will apply aspects to. Go ahead and start a new console project in Visual Studio called DummyApp. No need to reference PostSharp or any other assemblies. Replace the code in Program.cs with the following:

namespace DummyApp
{
    class Program
    {
        static void Main(string[] args)
        {
            ExampleClass ec = new ExampleClass();

            ec.Method1();
            ec.Method2();

            Console.ReadKey();
        }
    }

    public class ExampleClass
    {
        public void Method1()
        {
            Console.WriteLine("Method1()");
        }

        public void Method2()
        {
            Console.WriteLine("Method2()");
        }
    }
}

Build the project and copy DummyApp.exe to the Lab folder.

Now for the aspect provider. Create a new class library project and call it MyProviders. Add a reference to PostSharp. Add a new class file and name it TraceAspect.cs. Add the following code:

[Serializable]
public class SomeTracingAspect : IOnMethodBoundaryAspect
{
    public void OnEntry(MethodExecutionArgs args)
    {
        Console.WriteLine("Entering method: {0}.{1}", args.Method.DeclaringType.Name, args.Method.Name);
    }

    public void OnException(MethodExecutionArgs args)
    {
    }

    public void OnExit(MethodExecutionArgs args)
    {
        Console.WriteLine("Exiting method: {0}.{1}", args.Method.DeclaringType.Name, args.Method.Name);
    }

    public void OnSuccess(MethodExecutionArgs args)
    {
    }

    public void RuntimeInitialize(MethodBase method)
    {
    }

}

Our aspect is nothing special, just an aspect that implements IOnMethodBoundary and we are just adding code to the OnEntry and OnExit advices.

Add another class file and name it TraceAspectProvider.cs then add the following code:

public class TraceAspectProvider : IAspectProvider
{
    readonly SomeTracingAspect aspectToApply = new SomeTracingAspect();

    public IEnumerable ProvideAspects(object targetElement)
    {
        Assembly assembly = (Assembly)targetElement;

        List instances = new List();
        foreach (Type type in assembly.GetTypes())
        {
            ProcessType(type, instances);
        }

        return instances;
    }

    private void ProcessType(Type type, List instances)
    {
        foreach (MethodInfo targetMethod in type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly))
        {
            instances.Add(new AspectInstance(targetMethod, aspectToApply));
        }

        foreach (Type nestedType in type.GetNestedTypes())
        {
            ProcessType(nestedType, instances);
        }
    }
}
 

This is how we tell PostSharp what targets to work with and what aspects to apply to those targets. We implement the IAspectProvider interface and satisfy its required ProvideAspects method. PostSharp invokes the ProvideAspects method passing in a System.Reflection.Assembly instance for the target assembly we’re trying to modify. Using reflection, we’ll get all of the types in the target assembly and process each one by calling our ProcessType method.

In the ProcessType method, we again use reflection to discover all of the methods in the given type that are public and not static. For each applicable method we create a new AspectInstance and add it to the instances list that we’ll be giving back to PostSharp for processing. Then we do some recursion to process any nested types.

When we create a new AspectInstance, we’re passing in to the first parameter the System.Reflection.MethodInfo instance we received from GetMethods(). This parameter can take System.Type, most of the System.Reflection types such as FieldInfo, EventInfo etc and also PostSharp.Reflection.LocationInfo. If we were attempting to apply a LocationInterception aspect, we would pass in a System.Reflection.PropertyInfo type for our intended target.

The second parameter requires an instance of IAspect that will be applied to the target. This is where we supply our desired aspect. We’ve declared and instantiated a class member of type SomeTracingAspect for this purpose so we supply this instance to satisfy the parameter.

Build the project and copy the MyProviders.dll and PostSharp.dll to the Lab folder.

Modify!

Now we’re all ready to go. The last step is to actually perform the transformations. To do this we just need to run the PostSharp command line interface with some specific options. I recommend creating a batch file to do this because it could be a lot of typing.

@"C:\Program Files (x86)\PostSharp 2.1\Release\postsharp.4.0-x64-cil.exe" "DummyApp.exe" /p:AspectProviders=MyProviders.TraceAspectProvider,MyProviders /p:Output=output\DummyApp.exe /attach
@copy /y MyProviders.dll .\Output
@copy /y PostSharp.dll .\Output
@pause

Your PostSharp path may vary. You will also need to choose the correct version of PostSharp CIL executable to run. If you’re working with assemblies targeting .NET 3.5 then use the 2.0 version. If you’re working with assemblies targeting .NET 4.0 then use the 4.0 version and of course, choose the appropriate architecture type (x86, x64). For example:

  • postsharp.2.0-x86-cil.exe
  • postsharp.2.0-x64-cil.exe
  • postsharp.4.0-x86-cil.exe
  • postsharp.4.0-x64-cil.exe

The first argument we pass in is the path to the target, DummyApp.exe. The target doesn’t have to be an executable, it can be a library (DLL).

Next we tell PostSharp which aspect provider to use. We do this using the /P argument which allows us to set PostSharp properties (Usage: /P:name=value). Of course we want to use the aspect provider we just built so we specify the fully qualified type name followed by a comma then the assembly name.

PostSharp requires an Output to be provided so we use the /P argument again this time setting the ‘Output’ property to our destination. We don’t want to modify the source so we tell PostSharp to put the result in the output folder.

Optionally we can specify the /attach argument which allows us to attach to Visual Studio to step through the provider (in case there are issues).

When we run the batch file, PostSharp goes to work. When it’s done we see that the output folder has a copy of DummyApp.exe. When we run it we see that our aspect has been applied.

Entering method: ExampleClass.Method1
Method1()
Exiting method: ExampleClass.Method1
Entering method: ExampleClass.Method2
Method2()
Exiting method: ExampleClass.Method2

We can also use ILSpy to look at the resulting assembly.

DummyApp-ILSpy

In another post we’ll go over applying an EventInterceptionAspect based aspect and how to setup project build options to automatically run this process.

kick it on DotNetKicks.com

  • More

Posts navigation

← Older Entries
  • MCTS, PostSharp MVP, PluralSight author, Developer Advocate
  • My Videos

    Isolating Code - A quick intro to Typemock Isolator

    Introduction to T4 Templates (series)
  • RSS MashThis.IO

    • An error has occurred; the feed is probably down. Try again later.
  • PostSharp Principals

    Day 1 – OnExceptionAspect

    Day 2 - Applying Aspects with Multicasting Part 1

    Day 3 - Applying Aspects with Multicasting Part 2

    Day 4 - OnMethodBoundaryAspect

    Day 5 - Visual Studio Add-ins

    Day 6 Your code after PostSharp

    Day 7 Interception Aspects – Part 1

    Day 8 Interception Aspects – Part 2

    Day 9 Aspect Lifetime & Scope Part 1

    Day 10 Aspect Lifetime & Scope Part 2

    Day 11 – EventInterceptionAspect

    Day 12 – Aspect Providers, Part 1

    Day 13 – Aspect Providers, Part 2

    Day 14 – Introducing Members and Interfaces, Part 1

    Day 15 – Introducing Members and Interfaces, Part 2

Blog at WordPress.com. Theme: Parament by Automattic.
Follow

Get every new post delivered to your Inbox.

Join 181 other followers

Powered by WordPress.com