Hugoware

The product of a web developer with a little too much caffeine

Posts Tagged ‘Delegates

Using Delegates As Parameters

with 2 comments

I’m not sure the community stance on passing around delegates as arguments but personally I love it. I think there is something magical about the way you can provide instructions on how how to do something and then pass it into another method and let it do its job without needing to think about it. It is almost like writing a code template and then filling in the blanks with the specifics of what you need.

Using delegates as arguments can simplify code and in some cases reduce it. This post goes over a sample scenario where you might use delegates as arguments instead of writing multiple functions to perform different tasks.

Simple Resource Loader

Let’s pretend we have a class that is responsible for loading and saving files from an external resource. We could write a class like the one below.


//handles loading resources for the application
public static class ResourceLoader {

    //returns the bytes for a resource
    public static byte[] LoadBytes(string resource) {
        string path = ResourceLoader._GetResourcePath(resource);
        return File.ReadAllBytes(path);
    }

    //returns a xml document resource
    public static XDocument LoadXmlDocument(string resource) {
        string path = ResourceLoader._GetResourcePath(resource);
        return XDocument.Load(path);
    }

    //returns a bitmap resource
    public static Bitmap LoadBitmap(string resource) {
        string path = ResourceLoader._GetResourcePath(resource);
        return Bitmap.FromFile(path) as Bitmap;
    }

    //returns the string text for a resource
    public static string LoadText(string resource) {
        string path = ResourceLoader._GetResourcePath(resource);
        return File.ReadAllText(path);
    }

    //generates a path to a resource
    private static string _GetResourcePath(string file) {
        return Path.Combine(@"c:\path\to\files\", file);
    }

}

Nothing is really wrong with this code. If we need to add a new type to this class then we simply create a new method and plug it in. Additionally, each of the methods could use some sort of exception handling in case the conversion doesn’t go so well. As you can imagine, the more try catch blocks we add, the larger this class starts to get.

However, if you think about it, all of these resources could be handled roughly the same way. They all need a way to convert bytes to whatever type you’re wanting.

Using A Delegate To Fill In The Blank

So instead, lets address this problem using a delegate to handle the conversion of bytes to the type that we need.


//handles loading resources for the application
public static class ResourceLoader {

    //returns the bytes for a resource
    public static T Load<T>(string resource, Func<byte[], T> convert) {

        //find the correct path
        string path = Path.Combine(@"c:\path\to\files\", resource);
        byte[] bytes = File.ReadAllBytes(path);

        //attempt convert the file
        try {
            return convert(bytes);
        }
        //if it fails, forward the error to the caller
        catch (Exception ex) {
            throw new FormatException(
                string.Format(
                    "Could not load resource '{0}' as a type {1}", 
                    resource, typeof(T).Name
                    ), ex);
        }

    }

}

Great — Now we can provide any method we want to format the bytes and then return the type we’re looking for. So for example, instead of calling ResourceHandler.LoadBitmap we can use our new method as shown below.


Bitmap bitmap = ResourceLoader.Load("test.jpg", (bytes) => {
    using (MemoryStream stream = new MemoryStream(bytes)) {
        return Bitmap.FromStream(stream) as Bitmap;
    }
});

Pretty slick, right? …oh, wait… this code is longer and more difficult to use… This can’t be right!

Bringing The Concept Together

Clearly, the example above isn’t improving anything for us. The code is longer and requires that we write the same functionality for reading a resource in multiple places. Even though this code is more flexible, it also requires more work. So instead, lets write some definitions of common conversions as part of our class.


//handles loading resources for the application
public static class ResourceLoader {

    //Load<T>(resource, convert)
    //snip...

    //converts bytes to a bitmap
    public static readonly Func<byte[], Bitmap> AsBitmap = (bytes) => {
        using (MemoryStream stream = new MemoryStream(bytes)) {
            return Bitmap.FromStream(stream) as Bitmap;
        }
    };

    //converts bytes to a xml document
    public static readonly Func<byte[], XDocument> AsXml = (bytes) => {
        using (MemoryStream stream = new MemoryStream(bytes)) {
            using (StreamReader reader = new StreamReader(stream)) {
                return XDocument.Parse(reader.ReadToEnd());
            }
        }
    };

    //converts bytes to a string
    public static readonly Func<byte[], string> AsText = (bytes) => {
        return Encoding.UTF8.GetString(bytes);
    };

    //simply returns the byte array
    public static readonly Func<byte[], byte[]> AsBytes = (bytes) => bytes;

}

Now, instead of needing to manually create a delegate to handle the conversion process we can write code like the example below.

 
//Loads a resource by passing the static delegate that is part of the class we created
Bitmap bitmap = ResourceLoader.Load("test.jpg", ResourceLoader.AsBitmap);
 

By using delegates as an argument we allow our loading function to be flexible enough to accept other methods for performing the conversion (that we can create as we need them) or the common conversion methods that we added as part of the class.

You’ll also notice that we don’t need to declare the generic type we’re wanting to have returned since it can be inferred from the return type of the delegate we pass in! (so cool… to me at least)

Of course, there is about a hundred different ways to can already load resources in .NET but you could apply this same concept many other areas of applications you develop.

How could you use delegates to create “templates” for code?

Advertisements

Written by hugoware

January 13, 2010 at 1:58 am

Keep Your Website Alive (Don’t Let IIS Recycle Your Website)!

with 2 comments

Have you ever opened a page for one of your websites and it lags for awhile before it finally shows a page but then all of your following requests are quick? If you were to look up the problem you’d find that often it ends up having to do with IIS meeting an idle time limit and shuts down your site. There is even some software you can purchase to fix the problem for you.

But who wants to spend money on something like that? Especially when we can solve this ourselves — even for Hosted Environments!

Stayin’ Alive — (ack! bad pun again!)

If you happened to check out that software above then you can probably glean what it does just from the title. I’d rather not devote my personal machine to something like that so lets see if we can’t approach this from an alternative route.

private static void _SetupRefreshJob() {

    //remove a previous job
    Action remove = HttpContext.Current.Cache["Refresh"] as Action;
    if (remove is Action) {
        HttpContext.Current.Cache.Remove("Refresh");
        remove.EndInvoke(null);
    }

    //get the worker
    Action work = () => {
        while (true) {
            Thread.Sleep(60000);
            //TODO: Refresh Code (Explained in a moment)
        }
    };
    work.BeginInvoke(null, null);

    //add this job to the cache
    HttpContext.Current.Cache.Add(
        "Refresh",
        work,
        null,
        Cache.NoAbsoluteExpiration,
        Cache.NoSlidingExpiration,
        CacheItemPriority.Normal,
        (s, o, r) => { _SetupRefreshJob(); }
        );
}

If we place this bit of code in the Global.asax and call it when Application_Start() is raised, we can basically start a job that keeps our website alive. You could just as easily use a Thread to host the refresh method but for this example we simply used an Action delegate (but if you are using an earlier version of .NET then you might HAVE to use a Thread to do this).

Once our application starts the refresh job is also started and is saved to the cache. In this example we’re using 60 seconds, but you can change this to be as often as you like.

So How Can We Keep It Fresh?

So how about an example of some code we can use? Here is a simple example that could keep our website alive. Replace the //TODO: in the example above with something like the following.

WebClient refresh = new WebClient();
try {
    refresh.UploadString("http://www.website.com/", string.Empty);
}
catch (Exception ex) {
    //snip...
}
finally {
    refresh.Dispose();
}

This snippet uses a WebClient to actually make an HTTP call to our website, thus keeping the site alive! We could do any number of things from this code like updating local data or get information from external resource. This can be used to keep our site alive and our content refreshed, even if we’re using a Hosted Environment!

It is worth nothing that might not actually need to do an HTTP call back to your website. It is possible that using any method will keep your website from being killed off (but I haven’t tested it yet so let me know what happens if you try it). This example, however, has been tested and works quite well with my provider.

Written by hugoware

August 19, 2009 at 2:34 am