Wednesday, June 25, 2008

Over Communicate

Since early last year I've been meaning to point people to trace logging in .NET instead of using the logging facility in ILM, which might explain why I jumped at the opportunity to harp about it on the TechNet forum.

Last year I stumbled upon trace logging while doing some work using WCF. The log viewer they had was awesome, and I realized it wasn't tied to WCF in any way so it could be a great tool for logging in the ILM sync engine. For more info on the tool, check out:
Using the Service Trace Viewer Tool

As cool as the log viewer is, it is really just the tip of the logging iceberg. Tracing in .NET has some cool features, including:
  • Trace sources spew as much detail as possible in your code
  • Trace listeners only collect the detail they're interested in
  • Trace levels are configured in app config files
  • Trace output can be directed to a number of different formatters

The WCF contents in MSDN have some pretty good examples to start with.

Here is how it applies to ILM:

With your extension code:

  1. Use a TraceSource in your ILM extension code
  2. Call the TraceInfo event to output logging details in your code
  3. Compile the extension with the Trace flag on (it is on by default in Visual Studio)

Now your extension is able to spew log output, but nothing happens until you configure it:

  1. Add a System.Diagnostics section to the miiserver.exe.config file (assuming your extensions run in-process)
  2. Cycle the miiserver process (so it can read the config file)
  3. Check out the fruits of your logging labour

On a regular basis, you may choose to leave logging at a lower level to improve performance. Then during hard times, up the logging to Verbose to figure out what is going on in your extensions.

Saturday, June 21, 2008

When Reliable Sessions Aren't

As an Exchange 4.0 administrator I always wished they'd put the Outlook dev team on the wrong end of a very narrow network connection. This I thought was suitable torture and payback with the glimmer of hope that someday the app would be more reliable on network.

Having produced an XMA to consume web services using WCF I was confident to be standing on the shoulders of WS-ReliableMessaging giants, but my confidence proved to be just cocky.

In the XMA Export routines we have three main players:

1. Begin_Export (where we tend to open connections)
2. Export_Entry (where we tend to use connections)
3. End_Export (where we tend to close connections)

So what happens if the connection dies during Export_Entry? It does happen (although NEVER in my test environment, but I would like a test server co-hosted in my ideal location for the Outlook team). What to do when connections die?

The overall approach is to retry the connection. There are a few challenges in this approach, but overall it isn't that bad.

Exposing the Connection Details and ConfigurationParameters to Export_Entry
In order to retry the connection, you probably need access to the connection details (connectTo, user, password) and the configurationParameters, so any data required to create the connection needs to be available in Export_Entry.

Admitting Defeat
Retrying the connection for an unlimited number of tries won't do anybody any good. Impose some limit on the retries, and even consider making this limit configurable.

Each call to Export_Entry can throw an exception while allowing the rest of the export run to continue. This per-object failure is handy if the rest of the objects have a chance of succeeding.

In the 'connection limit exceeded' scenario, we know the remote side is just dead, and that the remaining exports should be stopped. This can be achieved by throwing the FatalEntryExportException. This specific exception stops the rest of the exports from processing, leaving the remaining exports as pending exports in the CS, ready to be tried again.

In the list of exceptions available in an XMA, the only one that stops the run is the FatalEntryExportException. The rest let the XMA continue processing other exports.

Friday, June 20, 2008

Export_Password, More Please!

Export_Password is a pretty neat attribute introduced for ILM Password Management. It is neat because it is the attribute you can set and forget, so no nagging export-not-reimported errors if you export it and don't expect it to come back (I've had pets like that).

It works really well when creating objects in an MA where you have a password extension, such as an XMA. In provisioning code you do something like this:

ManagementAgent = mventry.ConnectedMAs["ELMA"];
if (ManagementAgent.Connectors.Count == 0)
csentry = ManagementAgent.Connectors.StartNewConnector("person");
csentry["export_password"].StringValue = "is this thing on?"; csentry.CommitNewConnector();

It doesn't work so well if you are not provisioning a new object. If you try to use it on an existing connector you'll get an InvalidOperationException, so this will not work:

ManagementAgent = mventry.ConnectedMAs["ELMA"];
if (ManagementAgent.Connectors.Count == 1)
ManagementAgent.Connectors.ByIndex[0]["export_password"].StringValue = "is this thing on?";

If that worked then it would enable a scenario currently implemented in the Live@Edu solution where Import Attribute Flow can trigger a password reset in LiveID. It only really works because the MA doesn't do imports, thereby sidestepping the Export-Not-Reimported error.

If Export_Password worked on existing connectors then we'd have the same functionality, plus we wouldn't need to worry about Export-Not-Reimported.

I'll add it to my wish list unless somebody has some sneaky/cool alternatives.