Permission Bits in Base64 String

We’ve been kicking around some ideas of how to revamp user permissions in our application, and I was reflecting on how I’ve done it in the past. Previously, I worked on a client/server application where each user had a permission string that tracked all the rights they’d been granted, and global enumerations were used to identify which permissions and rights. I was explaining the approach to colleagues, and there was enough interest that I decided to recreate it.

Here’s the summary:

  • Each user has a Base64-encoded permission string
  • There’s an enumeration for the different modules; this identifies which byte in the permission string contains the rights
  • There’s an enumeration for the different rights which can be granted for a given module; these are used in bitwise operations to check or modify a user’s rights to a module

Enumerations

public enum Modules
{
    ModuleOne = 0,
    ModuleTwo = 1,
    ModuleThree = 2
}

public enum Permissions
{ 
    Create = 1,     // 0000 0001
    Read = 2,       // 0000 0010
    Update = 4,     // 0000 0100
    Delete = 8,     // 0000 1000
    Execute = 16    // 0001 0000
}

Granting Permission

Granting a permission is a simple as specifying the module and permission to grant. The module is used to identify the correct byte, and then a bitwise OR is performed to enable the corresponding permission bit.

string GrantPermission(string permissionString, Modules module, Permissions permission)
{
    if (permissionString == null)
    {
        permissionString = string.Empty;
    }

    var bytes = Convert.FromBase64String(permissionString);
    
    if (bytes.Length <= (int)module)
    {
        Array.Resize(ref bytes, (int)module + 1);
    }

    bytes[(int)module] |= (byte)permission;

    return Convert.ToBase64String(bytes);
}

Checking Permission

Checking a permission is very similar to granting except that we AND the permission mask. If the result isn’t zero, that means the user has the specified permission.

bool HasPermission(string permissionString, Modules module, Permissions permission)
{
    if (string.IsNullOrWhiteSpace(permissionString))
    {
        return false;
    }

    var bytes = Convert.FromBase64String(permissionString);

    if (permissionString.Length < (int)module)
    {
        return false;
    }

    var b = bytes[(int)module];

    return (b & (byte)permission) != 0;
}

Revoking Permission

Revoking a permission is similar as well. This time, we’ll invert the bits on the permission mask and AND it to the module permission byte so that all non-zero bits except the specified permission will remain the same.

string RevokePermission(string permissionString, Modules module, Permissions permission)
{
    if (permissionString == null)
    {
        permissionString = string.Empty;
    }

    var bytes = Convert.FromBase64String(permissionString);

    if (bytes.Length <= (int)module)
    {
        return permissionString;
    }

    bytes[(int)module] &= (byte)~permission;

    return Convert.ToBase64String(bytes);
}

Conclusion

This was just a quick & dirty re-implementation of something from the past. I haven’t put this code through the wringer, so there may be some bugs, and you could probably make it more developer-friendly by extracting it to its own class or moving this logic into some nice extension methods. It’s an efficient way to store and check permissions for a collection of modules. Depending on your needs, it might be a good fit. I’m also wondering if this could be used in a hybrid system–for example, perhaps it would make sense for different applications or scopes to have their own permission string within a larger system.

Advertisement

Simple .DistinctBy Extension

LINQ’s Distinct extension has largely been a disappointment to me. Sure, it’s nice when I’m working with a collection of integers, but more often than not, I’m working with a collection of objects and don’t have an IEqualityComparer<TSource> available to me. I know I could just create one, but I just want to use a lambda like just about everything else I do with LINQ!

To the internet!, right? I learned I could use the following trick to accomplish what I want:

collection
  .GroupBy(x => x.key)
  .Select(x => x.First());

Works like a charm, but I got tired of dot-GroupBy-dot-Select-ing and adding a comment about what I was doing for future maintainers, and I think it’s a lot better to just chuck it into an extension method.

public static IEnumerable<TSource> DistinctBy<TSource, TKey>(
    this IEnumerable<TSource> source, 
    Func<TSource, TKey> keySelector
{
    return
        source
            ?.GroupBy(keySelector)
            .Select(grp => grp.First());
}

Ahh, nice! Alternatively, could score this functionality by adding MoreLINQ to your project. On a neat side-note, you can also cherry-pick which MoreLINQ functionality you want by installing individual packages.

The Way of the Ninject

In recent months, I’ve come to be a big fan of Ninject. I’ve used Microsoft’s Unity Container and Object Builder in the past, but most of what I’d done previously just involved exposing dependencies as properties with lazily-loaded default implementations. I really dig Ninject because it’s so lightweight and easy to use, and it integrates really well with mocking frameworks like Rhino Mocks and Moq.

Getting started with Ninject is really easy and accomplished in just a few steps:

  1. Install the NuGet package
    Install-Package Ninject
  2. Create a module
  3. Create a kernel
  4. Get objects from the kernel

Let’s look at an example. Assume we have the following interfaces and classes.

public interface IFoo {
    void Run();
}

public class Foo : IFoo {
    private readonly IBar _bar;

    public Foo(IBar bar) {
        _bar = bar;
    }

    public void Run() {
        _bar.Print();
    }
}

public interface IBar {
    void Print();
}

public class Bar : IBar {
    public void Print() {
        Console.WriteLine("Yay!");
    }
}

We can create a NinjectModule to create an instance of IFoo like this.

public class FooModule : NinjectModule {
    public override void Load() {
        Bind<IFoo>().To<Foo>();
        Bind<IBar>().To<Bar>();
    }
}

Now, we need to tell our Ninject kernel to use our new module.

IKernel kernel = new StandardKernel(
    new FooModule());

And, finally, we use the kernel to request the objects we need. Note that Ninject does the work of figuring out the default implementation of IFoo (Foo) has a single constructor that accepts a dependency, IBar, and that the default implementation of the dependency is Bar.

class Program {
    static void Main(string[] args) {
        IKernel kernel = new StandardKernel(
            new FooModule());
        IFoo foo = kernel.Get<IFoo>();
        foo.Run();
        Console.ReadLine();
    }
}

Output:

Yay!

String Formatting with Regex

My latest favorite trick with regular expressions is to shortcut string formatting. We’ve all written some code like this:

if (/* string is not formatted a certain way */)
{
    /* make it formatted that way */
}

Now, there’s nothing wrong with that code, but for simple examples you could do it all in one step with a regular expression!

Here are a few examples:

// remove "www." from a domain if one exists
// domain.com     -> domain.com
// www.domain.com -> domain.com
Regex.Replace(input, @"^(?:www.)?(.+)$", "$1");

// format phone number
// 1234567890       -> 123-456-7890
// (123) 456-7890   -> 123-456-7890
// (123) 456 - 7890 -> 123-456-7890
Regex.Replace(input, @"^\(?(\d{3})\)?\s*(\d{3})\s*-?\s*(\d{4})$", "$1-$2-$3");

Yay, regular expressions!

A Better Table.CreateInstance() for SpecFlow

SpecFlow remains my top choice for automated integration testing. I love writing cute little cukes and putting them together in different ways to create different test scenarios. And one of my favorite cuke tricks is using tables to define an object, which I wrote about some time ago.

The CreateInstance<T> extension method provides an easy way to convert that table data into objects for testing, but I really think there should be a better way to populate child properties of complex objects.

Consider this example:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Address Address { 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; }
}

It would be nice if you could write a cuke like this:

Given a person
	| field          | value         |
	| firstName      | adam          |
	| lastName       | prescott      |
	| address.street | 123 number ln |
	| address.city   | anytown       |
	| address.state  | ny            |
	| address.zip    | 10000         |

And then convert it to a person like this:

[Given(@"a person")]
public void GivenAPerson(Table table)
{
    var person = table.CreateInstance<Person>();
    ScenarioContext.Current.Set(person);
}

But you can’t. Well, you can, but the address property won’t be populated. I didn’t like that, so I decided to grow my own. It works by identifying the child properties in the table and creating sub-tables, then using reflection to find and set the property on the result object. It works recursively, too, so you could even go n properties deep (i.e., address.state.abbreviation).

At its core, it’s just using CreateInstance<T> so you get all the niceties that go along with that. Note also that it only works with the 2-column, vertical tables with field and value columns. I called my extension method BuildInstance since CreateInstance was already taken. Here it is… Enjoy!

using System;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using TechTalk.SpecFlow;
using TechTalk.SpecFlow.Assist;

public static class TableExtensions
{
    public static T BuildInstance<T>(this Table table)
    {
        T result = table.CreateInstance<T>();

        // find sub-properties by looking for "."
        var propNames = table.Rows.OfType<TableRow>()
            .Where(x => x[0].Contains("."))
            .Select(x => Regex.Replace(x[0], @"^(.+?)\..+$", "$1"));

        foreach (var propName in propNames)
        {
            // look for matching property in result object
            var prop = typeof(T).GetProperty(
                propName,
                BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);

            if (prop != null)
            {
                // create sub-table with relevant rows (field == propName.something)
                var subTable = new Table("field", "value");
                var re = new Regex(string.Format(@"^{0}\.([^\.]*)$", propName), RegexOptions.IgnoreCase);
                table.Rows.OfType<TableRow>().Where(x => re.IsMatch(x[0]))
                    .Select(x => new[] { re.Replace(x[0], "$1"), x[1] })
                    .ToList()
                    .ForEach(x => subTable.AddRow(x));

                // make recursive call to create child object
                var createInstance = typeof(TableExtensions)
                    .GetMethod(
                        "BuildInstance",
                        BindingFlags.Public | BindingFlags.Static,
                        null,
                        CallingConventions.Any,
                        new Type[] { typeof(Table) },
                        null);
                createInstance = createInstance.MakeGenericMethod(prop.PropertyType);
                object propValue = createInstance.Invoke(null, new object[] { subTable });

                // assign child object to result
                prop.SetValue(result, propValue);
            }
        }

        return result;
    }
}

nullybool == true

It’s always been a pet peeve of mine to see conditions where a boolean variable is compared to a boolean value.

if (someBoolean == true) // ew!
{
    ...
}
if (someBoolean) // omg, better!
{
    ...
}

It bothers me because it’s redundant. You already have a true or false, do you really need to compare it to true or false to know if it’s true or false?

I picked up this little bugbear back in the VB6 world. As I moved into the .Net realm, I was introduced to a new spin on booleans: Nullable<bool>. At it’s core, it’s still a boolean though, right? So my peeve lived on.

if (nullybool.HasValue && nullybool.Value == true) // blech!
{
    ...
}
if (nullybool.HasValue && nullybool.Value) // omg, yes!
{
    ...
}
if (nullybool.GetValueOrDefault()) // OMG, EVEN BETTER!
{
    ...
}

But alas, I have just learned that comparing nullable booleans to boolean values is actually quite nice. It saves you a lot of .HasValue-ing. I am officially ending my lifelong campaign against removing “== true” and “== false” from any and all code I come across; I’m making exceptions for nully-bools.

if (nullybool.GetValueOrDefault()) // gettin' paid per keystroke?
{
    ...
}
if (nullybool == true) // noice!
{
    ...
}

Now, all that said, there is still a place for HasValue. Sometimes you need to know if the value has actually been set, but I won’t want to see any more nullybool.HasValue && nullybool.Value-business. I’m done with that! (And a new peeve is born…!)

Async/Await Crash Course

I’ve known about Microsoft’s asynchronous programming since hearing the announcement at PDC 2010. I’ve been aware of it, and I’ve dabbled here and there, but I haven’t really gotten into using it as part of my standard toolkit for a variety of reasons. First, it was that the product I was focused on could only use .Net Framework 3.5. Then I was on another product that used .Net 4.0, but we didn’t have much need for performance tuning.

But now I’m in a world where I have access to it AND a need for it–hooray! And so, with that, I present to you my crash course on asynchronous programming in c# using the async and await keywords.

Let me set up a scenario for my examples. Imagine a function that matches records between two systems. Data must be retrieved from each of the two systems before the matching can be performed.

Here’s what a fully-synchronous version of the problem might look like. Note that data is being loaded one-type and one-source at a time, followed by matching for that type.

public void DoMatching()
{
    var fooFromA = GetFooFromA();
    var fooFromB = GetFooFromB();
    Match(fooFromA, fooFromB);
    Console.WriteLine("{0} foo matched!", fooFromB.Count(x => x.IsMatch));
    
    var barFromA = GetBarFromA();
    var barFromB = GetBarFromB();
    Match(barFromA, barFromB);
    Console.WriteLine("{0} bar matched!", barFromB.Count(x => x.IsMatch));
}

public IEnumerable<Foo> GetFooFromA()
{
    var data = new Foo[] { new Foo(1), new Foo(2), new Foo(3) };
    return data;
}

public IEnumerable<Foo> GetFooFromB()
{
    var data = new Foo[] { new Foo(2), new Foo(3), new Foo(4) };
    return data;
}

public IEnumerable<Bar> GetBarFromA()
{
    var data = new Bar[] { new Bar("one"), new Bar("two"), new Bar("three") };
    return data;
}

public IEnumerable<Bar> GetBarFromB()
{
    var data = new Bar[] { new Bar("two"), new Bar("three"), new Bar("four") };
    return data;
}

public void Match(IEnumerable<Foo> fooFromA, IEnumerable<Foo> fooFromB)
{
    foreach (var foo in fooFromB)
    {
        if (fooFromA.Any(x => x.Id == foo.Id))
        {
            foo.IsMatch = true;
        }
    }
}

public void Match(IEnumerable<Bar> barFromA, IEnumerable<Bar> barFromB)
{
    foreach (var bar in barFromB)
    {
        if (barFromA.Any(x => x.Id == bar.Id))
        {
            bar.IsMatch = true;
        }
    }
}

public class Foo
{
    public int Id { get; set; }
    public bool IsMatch { get; set; }
    
    public Foo(int id)
    {
        Id = id;
    }
}

public class Bar
{
    public string Id { get; set; }
    public bool IsMatch { get; set; }
    
    public Bar(string id)
    {
        Id = id;
    }
}

The first thing we can do to optimize this code with async/await is to make the data retrieval methods asynchronous. This is done in just three steps:

  1. Change the return type to Task<T>
  2. Add async to the function declaration
  3. Use await to return the value

If the logic in your function blocks the CPU, like mine which just has a hard-coded result, you can make it async-friendly by executing it via Task.Run.

Here’s what the new, async version of my data-getters.

public async Task<IEnumerable<Foo>> GetFooFromA()
{
    return await Task.Run(() => new Foo[] { new Foo(1), new Foo(2), new Foo(3) });
}

public async Task<IEnumerable<Foo>> GetFooFromB()
{
    return await Task.Run(() => new Foo[] { new Foo(2), new Foo(3), new Foo(4) });
}

public async Task<IEnumerable<Bar>> GetBarFromA()
{
    return await Task.Run(() => new Bar[] { new Bar("one"), new Bar("two"), new Bar("three") });
}

public async Task<IEnumerable<Bar>> GetBarFromB()
{
    return await Task.Run(() => new Bar[] { new Bar("two"), new Bar("three"), new Bar("four") });
}

Okay, so that takes care of half the problem, but now we need to make sure the match functions are executed once the data they need is available. One way to do this would be to use the await keyword, like this:

var fooFromA = GetFooFromA();
var fooFromB = GetFooFromB();
Match(await fooFromA, await fooFromB);

But wait! We don’t want to do that because we’ll be preventing the data retrieval and matching of our Bar records while we process our Foo records. Instead, we can use Task.WhenAll to tell our match function to process once the data it needs becomes available.

var fooFromA = GetFooFromA();
var fooFromB = GetFooFromB();
Task.WhenAll(fooFromA, fooFromB).ContinueWith(t => 
{
    Match(fooFromA.Result, fooFromB.Result);
    Console.WriteLine("{0} foo matched!", fooFromB.Result.Count(x => x.IsMatch));
});

Note that in my ContinueWith block, I’m using the Result property of the asynchronous tasks. It’s safe to use the property since WhenAll makes sure they’re finished before getting there. If we wanted to be extra safe, we could check the status of the Task (t) that’s passed into our anonymous function–probably a good idea to verify that nothing went wrong while retrieving the data.

You’ll also notice that I moved the Console.WriteLine into the ContinueWith block. This needs to happen for two reasons. First, the code’s running asynchronously so the matching wouldn’t have occurred by the time the statement was run. Second, the collection might not be accessible if the task hadn’t completed; you could use the await keyword, but even then you could not guarantee that matching had finished.

So now we’re in business. The data retrievals all occur asynchronously, and matching begins as soon as the requisite data is received for each of our respective data types. We haven’t done anything with our DoMatching function, though. If we want to make it awaitable, we just need to keep track of our work tasks and make use of WhenAll again. Notice that we’ve added the async keyword to our method signature and that void has become Task.

public async Task DoMatching()
{
    var fooFromA = GetFooFromA();
    var fooFromB = GetFooFromB();
    var matchFoos = Task.WhenAll(fooFromA, fooFromB).ContinueWith(t => 
    {
        Match(fooFromA.Result, fooFromB.Result);
        Console.WriteLine("{0} foo matched!", fooFromB.Result.Count(x => x.IsMatch));
    });
    
    var barFromA = GetBarFromA();
    var barFromB = GetBarFromB();
    var matchBars = Task.WhenAll(barFromA, barFromB).ContinueWith(t => 
    {
        Match(barFromA.Result, barFromB.Result);
        Console.WriteLine("{0} bar matched!", barFromB.Result.Count(x => x.IsMatch));
    });
    
    await Task.WhenAll(matchFoos, matchBars);
}

Complete example:

void Main()
{
    DoMatching().Wait();
}

public async Task DoMatching()
{
    var fooFromA = GetFooFromA();
    var fooFromB = GetFooFromB();
    var matchFoos = Task.WhenAll(fooFromA, fooFromB).ContinueWith(t => 
    {
        Match(fooFromA.Result, fooFromB.Result);
        Console.WriteLine("{0} foo matched!", fooFromB.Result.Count(x => x.IsMatch));
    });
    
    var barFromA = GetBarFromA();
    var barFromB = GetBarFromB();
    var matchBars = Task.WhenAll(barFromA, barFromB).ContinueWith(t => 
    {
        Match(barFromA.Result, barFromB.Result);
        Console.WriteLine("{0} bar matched!", barFromB.Result.Count(x => x.IsMatch));
    });
    
    await Task.WhenAll(matchFoos, matchBars);
}

public async Task<IEnumerable<Foo>> GetFooFromA()
{
    return await Task.Run(() => new Foo[] { new Foo(1), new Foo(2), new Foo(3) });
}

public async Task<IEnumerable<Foo>> GetFooFromB()
{
    return await Task.Run(() => new Foo[] { new Foo(2), new Foo(3), new Foo(4) });
}

public async Task<IEnumerable<Bar>> GetBarFromA()
{
    return await Task.Run(() => new Bar[] { new Bar("one"), new Bar("two"), new Bar("three") });
}

public async Task<IEnumerable<Bar>> GetBarFromB()
{
    return await Task.Run(() => new Bar[] { new Bar("two"), new Bar("three"), new Bar("four") });
}

public void Match(IEnumerable<Foo> fooFromA, IEnumerable<Foo> fooFromB)
{
    foreach (var foo in fooFromB)
    {
        if (fooFromA.Any(x => x.Id == foo.Id))
        {
            foo.IsMatch = true;
        }
    }
}

public void Match(IEnumerable<Bar> barFromA, IEnumerable<Bar> barFromB)
{
    foreach (var bar in barFromB)
    {
        if (barFromA.Any(x => x.Id == bar.Id))
        {
            bar.IsMatch = true;
        }
    }
}

public class Foo
{
    public int Id { get; set; }
    public bool IsMatch { get; set; }
    
    public Foo(int id)
    {
        Id = id;
    }
}

public class Bar
{
    public string Id { get; set; }
    public bool IsMatch { get; set; }
    
    public Bar(string id)
    {
        Id = id;
    }
}

Database SpecFlow Scenarios and TransactionScope

My team has been using SpecFlow to verify that our data access components are working correctly. In an effort to write repeatable tests that won’t pollute the database, we’ve decided to wrap each scenario in a transaction.

Creating and rolling back the transactions is very simple to do with SpecFlow’s BeforeScenario & AfterScenario hooks.

using System.Transactions;

[Binding]
public class TransactionHooks
{
    private TransactionScope _transactionScope;

    [BeforeScenario]
    public void BeforeScenario()
    {
        _transactionScope = new TransactionScope();
    }

    [AfterScenario]
    public void AfterScenario()
    {
        _transactionScope.Dispose();
    }
}

By including these hooks, you’re placing your test scenarios in the loving embrace of a transaction scope. The act of instantiating the TransactionScope will update the ambient transaction that will be used by all subsequent code unless you explicitly tell it to do otherwise.

If you’re testing code that uses TransactionScope itself, using TransactionScopeOption.Required will allow the code to use the ambient transaction if one exists. Note that this is the default value, so it’s what you’re using if you’re not explicitly specifying an option. However, the other TransactionScopeOption values will cause code to execute outside your test scenario’s ambient transaction by either creating a new/different transaction (RequiredNew) or executing outside the transaction (Suppress).

Paste as Plain Text in Windows Store App

I was working on a Windows Store app that used a RichEditBox for text entry. Everything worked great until I pasted some formatted text into it. The dumb thing kept all the formatting! Okay, I guess that’s probably good since it would be pretty annoying if you wanted the formatting, but I didn’t.

Good news, though: it’s easy to remove that formatting and paste as plain text. So easy, in fact, that you can do it in a single line. RichEditBox has an ITextDocument property (Document) that has an ITextRange property (Selection). And guess what ITextRange has? A Paste method! However, this is where it got a little tricky for me because Paste takes an integer parameter, and it took me some googling to find a list of valid values. (Sorry, text-pasting enthusiasts, but you can’t use DataFormats in a Windows Store app.) In the end, I was able to find what I needed here.

Once you’ve got the code, you just hook up a handler to the RichEditBox’s Paste event and–voila!–pasting as plain text.

XAML:

<RichEditBox Paste="OnPaste" />

Code-behind:

private void OnPaste(object sender, TextControlPasteEventArgs e)
{
    var editBox = sender as RichEditBox;
    if (editBox.Document.CanPaste())
    {
        editBox.Document.Selection.Paste(1);
        e.Handled = true;
    }
}

Unit Test Sending Email with SmtpClient

I have a workflow activity that sends email (the code for this activity can be found here), and I wanted to write integration tests using SpecFlow. This creates an interesting problem. I don’t want to simply mock everything out, but I also don’t want to require a valid SMTP server and email addresses. I also want the test to pass or fail without having to check an email inbox.

Luckily, there are configuration options used by the SmtpClient class that can be used to create files when email messages are sent. This is accomplished by adding some simple code to your application configuration file. (Source here.)

<system.net>
    <mailSettings>
        <smtp deliveryMethod="SpecifiedPickupDirectory">
            <specifiedPickupDirectory pickupDirectoryLocation="C:\TempMail" />
        </smtp>
    </mailSettings>
</system.net>

This solution is easy and it works, but it creates another problem: I want my test to run automatically on other machines. I don’t want to hardcode a path into the config file because I could run into problems with user permissions or directory structure. I found this blog post that demonstrates how to change the directory programmatically. The only thing I didn’t like about that solution is that it requires the app.config change shown above. I modified the posted solution slightly so that the configuration file section is not needed. Here’s the result:

var path = GetTempPath();

// get mail configuration
var bindingFlags = BindingFlags.Static | BindingFlags.NonPublic;
var propertyInfo = typeof(SmtpClient)
    .GetProperty("MailConfiguration", bindingFlags);
var mailConfiguration = propertyInfo.GetValue(null, null);

// update smtp delivery method
bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic;
propertyInfo = mailConfiguration.GetType()
    .GetProperty("Smtp", bindingFlags);
var smtp = propertyInfo.GetValue(mailConfiguration, null);
var fieldInfo = smtp.GetType()
    .GetField("deliveryMethod", bindingFlags);
fieldInfo.SetValue(smtp, SmtpDeliveryMethod.SpecifiedPickupDirectory);

// update pickup directory
propertyInfo = smtp.GetType()
    .GetProperty("SpecifiedPickupDirectory", bindingFlags);
var specifiedPickupDirectory = propertyInfo.GetValue(smtp, null);
fieldInfo = specifiedPickupDirectory.GetType()
    .GetField("pickupDirectoryLocation", bindingFlags);
fieldInfo.SetValue(specifiedPickupDirectory, path);

Using this code, I’m able to change the email delivery method and specify the output path programmatically. In my SpecFlow test, I create a temporary directory, process and verify email files created by my workflow, and cleanup. It works like a charm!

%d bloggers like this: