Friday, October 03, 2008

.NET Remoting with IIS and Kernel Mode Authentication

Working on an XMA lately I ran into an issue trying to use an object with .NET Remoting hosted on IIS7 (Windows Server 2008 x64). Turns out that IIS7 has a feature called Kernel Mode Authentication.

When .NET Remoting is configured to Negotiate the authentication type, it caused an error with the XMA. Turning off Kernel Mode Authentication fixed the problem.

Changing the authentication type probably would have worked too.

Thursday, September 11, 2008

ILM 2 Beta3 Metadirectory Services with SQL 2008

Short blog post to note that I'm running SQL Server 2008 in a LAB ENVIRONMENT this week with ILM 2 Beta 3 Metadirectory Services.

I EXPECT THIS IS NOT SUPPORTED YET, so don't try this at home.

I expected the installation's SQL check to stop the installation but to my delight it passed. Haven't hit any snags yet, using the ADMA, some file MAs and an XMA.

Monday, September 08, 2008

Writing to the CSEntry During Export_Entry()

A while back I posted about writing the Anchor attribute to the CSEntry during the Export_Entry() routine in an XMA.

Recently I've done a little more work on it to narrow it down. There are some things to know about the scenario.

1. It only works with an XMA
no other MA has an Export_Entry() method, so that is fair.

2. It only works with the LDIF and DSML file types in an XMA
Those are the only two that support DNs, so that is fair.

3. Sometimes It Isn't Optional
If you set your anchor in MV.Provision, then you are not required to it during Export_Entry(). So if your MV.Provision method has code that resembles the code below, then you do not need to set the Anchor during Export_Entry():

// "GUID" is the anchor attribute on this 'LDIF XMA'
if (mventry.ObjectType == "Person" & mventry.ConnectedMAs["LDIF XMA"].Connectors.Count == 0)
{
CSEntry csentry = mventry.ConnectedMAs["LDIF XMA"].Connectors.StartNewConnector("Person");
csentry["GUID"].StringValue = Guid.NewGuid().ToString();
csentry.DN = mventry.ConnectedMAs["LDIF XMA"].EscapeDNComponent(string.Format("CN={0}", Guid.NewGuid().ToString()));
csentry.CommitNewConnector();
}

If you do NOT set the anchor in MV.Provision, then you need to set it during Export_Entry() otherwise you'll recieve an error at Export time with the error message:
"The anchor attributes were not set in export entry"

4. You Can Also Rename During Export_Entry()
If during Generate_Import() you use the object's Anchor in to construct the DN, then on Import you will see Renames. This is normal, because you've set the DN to one thing in your MV.Provision code, then Imported it as something else. This only works because you have the Anchor to track the objects. If you don't change the DN then you shouldn't see Renames.

NOTE (thanks for this Rob): renames during Export_Entry() are only possible if the anchor was not set in MV.Provision. The CSEntry's anchor is only writable when it has not been set in Provision code.

Finally, this post serves to upgrade the previous post's psuedo-code to sample code:

public void ExportEntry(
ModificationType modificationType,
string[] changedAttributes,
CSEntry csentry
)
{
// I might have code here to insert a row into SQL, then return the Unique ID as a String
// but instead I'm just going to pretend by generating a new GUID
String newAnchor = Guid.NewGuid().ToString();
// During ExportEntry() you wouldn't think that CSEntry is writable, but it is
// In fact, if I don't do this, then ILM will throw an exception on Export, with an error message of:
// "The anchor attributes were not set in export entry."
csentry["GUID"].StringValue = newAnchor;
// Output my entry to a file, which I'll then consume on Import
file.WriteLine("DN: ", csentry.DN.ToString());
file.WriteLine("ObjectClass: Person");
file.WriteLine("GUID: {0}", newAnchor); // --> This is my new anchor getting sent to the file
file.WriteLine();
}

Friday, September 05, 2008

Grippy Debugger with VS 2008

Thanks Ahmad for the tip in getting Visual Studio 2008 to hit my breakpoints in ILM.

Turns out VS 2008 is a bit picky regarding the type of code to debug.
The default is 'Automatic' which for ILM means:
  • T-SQL Code
  • Managed Code

Choosing the option to select only 'Managed' got VS 2008 hitting my breakpoints again.

EDIT: this worked for XMA debugging, but still isn't working for Rules Extensions debugging. Arg!

EDIT: for rules extension debugging in ILM2 Beta3, you need to attach to the mmsscrpt.exe process, not the miiserver.exe process as usual. Yay!

Monday, August 18, 2008

Locking the ILM Database

Seems that most blog entries trumpet the brilliance of the blogger. This post, not so much.

In short:
never create files in the .\Extensions folder unelss you have a VERY good reason. Doing so can make ILM very busy since it watches this folder for changes. Anytime the folder contents change, ILM sucks up the folder contents into the ILM database. Do it a couple times and you'll probably get away with it. Do this a lot, and you'll see locks and retries, and things will perform miserably. Make it happen on every password set operation, and you're just asking for it.

Longer story:
My favorite tool is my handy XMA and this time I have managed to use it to bring ILM to its knees. Oops. An XMA I'm working on was happily running imports, exports and password sync but the constraints changed forcing me to do some of the import work during my export routines. This work introduced a neat little bug which I'll desribe here in hopes of somebody not doing the same thing. If I get to do another ILM extensibility talk next year, I think this little nugget will make my 'worst practices' slide.

So my Export routines had to be changed to produce the Import file (another blog post). All worked fine, so it seemed. The exports ran and did their work while also producing the delta import file.

Things started to go wrong when we saw another file appear in the Extensions folder. A search of the Export code turned up no reference to this file, so I thought my XMA was innocent. Also, all of our tests were passing without issue. Performance was a little slow at times on perf tests but we could easily blame the web service since it was the obvious choke point. A while later, we saw this file getting created so much that it had to be generated by my XMA.

Another look at the code and pouring over trace logs revealed the file was being created by our XMA's password extension. Even worse, it was getting created on every password set. So if created 5000 objects, that file was getting created 5000 files, which was asking ILM to copy the Extensions folder to the ILM database 5000 times. Bob Tucker was kind enough to show me the SQL Profiler log indicating that this was happening, A LOT.

The fix was simple, but the lesson an embarassing one. No trumpeting for me, just a dunce cap this time around.

Monday, August 04, 2008

ILM Drop Files and the XMA 'ChangedAttributes' Array

Drop files were one of my favourite features in MMS 3.0 when I first saw it, largely because everything in MMS 2.2 was based on files (except for the ADMA). Why are drop files cool? They are cool because they are the same format across all managment agents in ILM, and contain the same kinds of data, so you can easily use them for reporting. It gets better, you can also create a drop file on one machine, then play it into an MA on another machine. Great for trying to repro a rules problem.

A couple years ago I stumbled upon an issue where drop files worked but caused an issue in my XMA. The result was that I had to decide on drop files, or the feature in the XMA I was trying to use.

First a quick look a the XMA's ExportEntry() method:
public void ExportEntry(
ModificationType modificationType,
string[] changedAttributes,
CSEntry csentry
)
{
//
// TODO: Remove this throw statement if you implement this method
//
System.Diagnostics.Debugger.Launch();
throw new EntryPointNotImplementedException();
}


The code snippet above is the code generated by the ILM UI, except I have placed in a line to raise the debugger for me. Pretty plain so far, so I'm not introducing any bugs of my own.

Now the problem. Notice the changedAttributes array. When drop files are NOT turned on, this array behaves normally. You can expect to see in there a list of attributes that are changed. One might use this to send changed attributes to the target system.

Turning on drop files in an XMA causes this array to be empty. I can repro this by watching the array in the debugger using an Export run profile to turn drop files on and off.

Drop files turned on causes the array to have no items (looks like a bug).
Drop files turned off causes the array to have items (expected behaviour).

Moral of the story is, drop files good, bug in XMA not so good, proceed with caution and use the features accordingly. If you really need this one solved, raise it to PSS and let them know somebody needs this fixed.

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.

FatalEntryExportException
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.