2/18/2005

CinDnug 2-20-05

Doug Rohrer, of Avanade Inc employ, presented an overview of the Microsoft Enterprise Library (entlib).

Apparently Avanade are the original writers of these libraries as the copyright at the top of the source indicates. Oh did I mention that we get the source? The license allows you to modify for your own use but you can not redistribute your alternations and you must leave any existing copyright notice at the top if you do not change the code.


// Copyright © Microsoft Corporation. All rights reserved.
// Adapted from ACA.NET with permission from Avanade Inc.
// ACA.NET copyright © Avanade Inc. All rights reserved.

This is a library of "application blocks" that are intended to help developers with the basic plumbing of an application. A block is just a subset of a library which is akin to an assembly. In java terms its just a jar. I don't know why "block" replaced "library".

Doug writes about the entlib in his blog.

Doug Rohrer's Blog

Download it here after some registration steps:

Microsoft Enterprise Library

I am afraid that I arrived 30 minutes late so missed a couple of the initial block descriptions but the website doc is good. These are the blocks in the entlib

o Configuration Application Block
o Data Access Application Block
o Caching Application Block
o Exception Handling Application Block
o Logging & Instrumentation Application Block
o Cryptography Application Block
o Security Application Block

One the most interesting features of this library is that it comes with source. When you download it you get a selfextracting exe that unloads the source to your disk and, with compile checkbox checked, proceeds to compile the library in place. Having the source available makes this a far more valuable resource since we can not only use it but also learn from the code.

All the libraries use the Configuration block and most use the Logging block so there is a good synergy between them all. They all have good factory abstractions so its simple to replace the various providers with your own implementations. Each folder in the source contains a Test directory where NUnit tests sit.

Here is a simple sample of each.

Logging:

    Logger.Write("My message", "someMessageCategory");
Each write can optionally, specify a category that can be configured in the configuration file and drives where the message is written to.

There is no method level distinction between error, warning, info and debug messages. There is also no class level message filtering. You could use the category names for either but not both.

This being a class level API, instead of instance level, its flexibility is limited. A simple improvement would be to allow us to create our own reference to the logger and then we can choose to make it an instance or static property.

So, compared to Log4Net (http://logging.apache.org/log4net/), this solution is not adequate.

Configuration:

    settings = (MySettingsType)ConfigurationContext.GetConfiguration("section name");
settings.MyProperty
The advantage of this package over the built-in App.config is that you can select the storage type. This seems like a good solution for .Net app config loading.

Data Access:

     myDataSet = DatabaseFactory.CreateDatabase("Sales").
ExecuteDataSet("GetOrdersByCustomer", myCustomerId );
I missed the comments on this one but the code snippet looks simple enough. I asked Doug after the presentation about support for Transactions but he didn't have any concrete information.

Longer term I am more interested in libraries like NHibernate (http://nhibernate.sourceforge.net/) that support a full Object/Relational mapping solution. Then you can look into Spring for .Net (http://sourceforge.net/projects/springnet/) and abstract your transaction management out of your code completely.

Caching:

    factory = new CacheManagerFactory(Context);
cacheMgr = factory.GetCacheManager("SmallInMemoryPersistence");

cacheMgr.Add("key", "cache");
cacheMgr.Remove("key");

cacheMgr.Dispose();
The location of a cache can be configured as in-memory or in-database so it can be used within a clustered environment. It supports various cache ageing algorithms that allow you to control how stale you data gets.

I am unsure about this library. With a IDictionary type interface you are limited in the types of data that you can cache. Not that you can't store anything but that you can't get it back as easily. Say I wanted to store a row from a dataset, what would I use for a key? It would have to be the unique key to the row but if that is a compound key I would have to come up with a string representation of that information.

I am sure that there are some good uses this library can be put to but with caching being such a complex layer I am not sure that it is flexible enough for the more complex applications.

Exception Handling:

    catch (Exception ex)
{
bool shouldRethrow = ExceptionPolicy.HandleException(ex, "policyname");
if (shouldRethrow)
{
throw ex;
}
}
The goal here is to centralize the processing from all our catch blocks. The HandleException method reads configuration where a set of exception handlers are configured. You can relate a list of handlers to a policyname that can log, write to the event log or add you own custom handler.

The biggest downside to this approach is that you loose all your context logging. Most exception handlers are going to format a message that includes information from the local context that will help debug the problem. The only way I can see to add this feature and still use this exception handler is to wrap the thrown exception in your own exception and pass that in.
        MyException mx = new MyException(ex, "Context specific message");   
bool shouldRethrow = ExceptionPolicy.HandleException(mx, "policyname");
I question whether the function that I want to perform in my exception handlers should be abstracted to the configuration file level. Certainly, common code should be extracted into some application specific class but to standardize that and push it all the way to a config file seems unnecessary and not very useful.

Crypto:

    Cryptographer.EncryptSymmetric("dpapiSymmetric1", "plain text");
Cryptographer.DecryptSymmetric("dpapiSymmetric1", encrypted,);

Cryptographer.CreateHash(hashInstance, plainTextString);
Doug also demoed encrypting with sha1 and it was as simple. This is going to be really easy and will, hopefully, ensure that every programmer gets comfortable with this subject matter and uses it. There is way too much data out there that is not secure because the average programmer doesn't know how to use the cryptography api.

Security:

    factory = new AuthenticationProviderFactory();
IAuthenticationProvider provider = factory.GetAuthenticationProvider();

if (provider.Authenticate(new NamePasswordCredential("Fred", "password"), out identity))
{
// Woohoo
}

factory = new AuthorizationProviderFactory();
provider = factory.GetAuthorizationProvider();

if (provider.Authorize(principle, context))
{
// Woohoo
}
A simple authorization and authentication abstraction that will simplify your login pages and access checks in your code. You can plug in your own providers and perform application specific checks as needed.

Conclusion:

Some of these seem to be very useful libraries that I expect to start using in my current project.

A possible improvement that could be made to the distribution would be to formalize the mock classes that are used. The "Test" folders are full of mock classes that help prove that various pieces of functionality work. When I am testing my code I will have to concoct some mock configuration to drive the various paths though my code. If the library supplied some mock implementations it would save me from writing my own.

Thanks Doug for a great presentation.

2/11/2005

Cold basement

My office is in my basement. Yes, a little corner of a cold dark hole in the ground. Winter makes it intensley cold with one electric heater making my body hot on one side and leaving the other blue.

Still, it beats trecking through the snow to a small dark cube.

Cincinnati doesn't get too cold in the winter, not compared to the more northern areas. However, this is my home and that gives me the right to whine about it a little.

The view from our back window is nice after a fresh snow. The last snow was windless so produced some excellent depth on the individual branches.



2/06/2005

Referencing EXE assemblies in VS.net

The problem, as discussed in the CinDnug use group, was that a VS.net project that contains tests can not reference a project that generates an exe. The only design solution is to make the exe code a one liner that calls a main dll but this has quite an impact on other design decisions.

When you try to add a reference from a dll project to an exe project in VS.net you get a warnings stating that the reference target has to be a dll. You can solve this problem with some judicious editing of your .csproj file.

Editing your .csproj file will show references declared like this


<Reference
Name = "ProtoTabBack"
Project = "{6292AE62-0514-40F7-99C0-C2C181BF9A15}"
Package = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"
/>
<Reference
Name = "TabulatorFront"
AssemblyName = "TabulatorFront"
HintPath = "..\TabulatorFront\bin\debug\TabulatorFront.exe"
/>

Note there are two types of declarations here. The first type uses the package project guid that you can find in your .sln file in the following format. The first guid is the Package and the second the Project.

Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TabulatorFront",
"TabulatorFront\TabulatorFront.csproj",
"{DD6F402B-1823-489F-AC6C-B9B8FE18391D}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject

Using this "project reference" in your .csproj file results in VS.net flagging the reference with a little yellow triangle and saying that it has to be a .dll file.

However, using the second Reference format and referring to the exe file directly works. I am now able to code to and link my tests with the exe project code, utilize existing test infrastructure to write tests against UI code and keep my test code out of my production deployments.

Thanks James for the suggestion.

2/03/2005

Robust code

Trying to get people to stop hard coding expected results in tests is not easy.


IList rowList = db.GetSomeRows()
Assert.Equals(4, rowList.Count);

EEEEEEkkkkkkk

Code is like poetry
blowing in the wind,
beaten from left and right
crashed and regularly skinned,
choose the best of parchment
to ward against the eternal din.