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");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.
settings.MyProperty
Data Access:
myDataSet = DatabaseFactory.CreateDatabase("Sales").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.
ExecuteDataSet("GetOrdersByCustomer", myCustomerId );
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);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.
cacheMgr = factory.GetCacheManager("SmallInMemoryPersistence");
cacheMgr.Add("key", "cache");
cacheMgr.Remove("key");
cacheMgr.Dispose();
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)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.
{
bool shouldRethrow = ExceptionPolicy.HandleException(ex, "policyname");
if (shouldRethrow)
{
throw ex;
}
}
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");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.
bool shouldRethrow = ExceptionPolicy.HandleException(mx, "policyname");
Crypto:
Cryptographer.EncryptSymmetric("dpapiSymmetric1", "plain text");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.
Cryptographer.DecryptSymmetric("dpapiSymmetric1", encrypted,);
Cryptographer.CreateHash(hashInstance, plainTextString);
Security:
factory = new AuthenticationProviderFactory();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.
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
}
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.