Predica.FimCommunication code samples

Hi, it’s Maciek again here with some FIM .NET developer goodies.

As I promised in my previous post, our FimCommunication library is now available on GitHub!

It’s time to see how it works. Bear in mind that we follow the KISS principle when we can. Therefore it was not our intention to create a, for example, full- blown LINQ provider for FIM. It could be fun, but its usefulness is questionable. You’re welcome to implement it and send us a pull request if you wish :).

Basic usage

These are some short code snippets for performing the basic operation with our FimClient:

[sourcecode language=”csharp”]
//XPath Query
var client = new FimClient();
var allPeople = client.EnumerateAll("/Person");
//Find by id
var person = (RmPerson)_client.FindById(personId);
[/sourcecode]

If no object with this ID is found, null will be returned.

Create

[sourcecode language=”csharp”]
var newPerson = new RmPerson()
{
FirstName = "person first name"
};
_client.Create(newPerson);
[/sourcecode]

Update

[sourcecode language=”csharp”]
var person = (RmPerson)_client.FindById(personId);
var personChanges = new RmResourceChanges(person);
persponChanges.BeginChanges();
person.LastName = "new last name";
_client.Update(personChanges);
[/sourcecode]

Delete

[sourcecode language=”csharp”]
var personToDelete = new RmPerson {
ObjectID = new RmReference(personId)
};
_client.Delete(personToDelete);
[/sourcecode]

Paging

Original fim2010client does not provide an easy access to executing paged queries, so we introduced it in our library. You can use it like this:

[sourcecode language=”csharp”]
var first10People = _client.EnumeratePage(
"/Person", Pagination.FirstPageOfSize(10), SortingInstructions.None
);

var second3People = _client.EnumeratePage(
/Person", new Pagination(1, 3), SortingInstructions.None
);

var allPeople = _client.EnumeratePage(
"/Person", Pagination.All, SortingInstructions.None
);
[/sourcecode]

Filtering

We created a little infrastructure code around filtering logic. For example you could create an xpath query like this:

Simple filtering

[sourcecode language=”csharp”]
var firstNameFilter = new Filter(
RmPerson.AttributeNames.FirstName.Name, "John", FilterOperation.Equals
);

var lastNameFilter = new Filter(
RmPerson.AttributeNames.LastName.Name, "mit", FilterOperation.Contains
);

var createdFilter = new Filter(
RmResource.AttributeNames.CreatedTime.Name, "2012-04-18",
FilterOperation.Equals, AttributeTypes.DateTime
);

string xpath = "/Person["+ firstNameFilter.ComposeXPath()
+ " and "
+ lastNameFilter.ComposeXPath()
+ " and "
+ createdFilter.ComposeXPath()
+ "]";

var enumerateAll = _client.EnumerateAll(xpath).ToList();
[/sourcecode]

It requires manually joining conditions with correct and/or operators, but we did not need anything more complex, like grouping conditions in some aggregator filters.

“Contains” operation

“Contains” filter operation is particularly interesting as it uses a workaround to “cheat” FIM, which by default does not handle “contains” XPath function properly. The above filter produces the following result:

[sourcecode language=”csharp”]
/Person[FirstName = ‘John’ and starts-with(LastName, ‘%mit’) and CreatedTime >= ‘2012-04-18T00:00:00’ and CreatedTime <= ‘2012-04-18T23:59:59’]
[/sourcecode]

Filtering by references

You can also use a special “reference” syntax to filter objects by their references. This sample filter will look for people that have managers with first name equal to “Mary”:

[sourcecode language=”csharp”]
var managerFirstNameFilter = new Filter(
"[ref]Manager,Person,FirstName", "Mary", FilterOperation.Equals
);

var query = "/Person[" + managerFirstNameFilter.ComposeXPath() + "]";
[/sourcecode]

Result XPath query:

[sourcecode language=”csharp”]
/Person[Manager=/Person[FirstName = ‘Mary’]]
[/sourcecode]

You can browse more Filter usage samples in FilterTests class available here.

Sorting

Paging and sorting kind of complete each other, so it has to be simple. We introduced our own sorting structures to be used like here:

[sourcecode language=”csharp”]
var peopleSortedDescByFirstName = _client.EnumeratePage<RmPerson>("/Person"
, Pagination.All
, new SortingInstructions(RmPerson.AttributeNames.FirstName.Name, SortOrder.Descending)
);
[/sourcecode]

It can be joined with paging:

[sourcecode language=”csharp”]
var thirdPageOfPeopleSortedAscByLastName = _client.EnumeratePage<RmPerson>("/Person"
, new Pagination(Pagination.FirstPageIndex + 2, 4)
, new SortingInstructions(RmPerson.AttributeNames.LastName.Name, SortOrder.Ascending)
);
[/sourcecode]

Sorting unit tests can be found here.

Selecting attributes to fetch

One thing we’ve learned along the way is that loading “full” objects from FIM can have negative impact on performance. It is often required to fine tune the query so that it fetches only a few selected attributes. Diagnostic logs described in previous post can help pin-point such performance-critical locations.

One attribute is particularly important: object type. It is required, because ResourceTypeFactory would not know what type it should construct if this value was missing. But you don’t have to worry about that, it’s been taken care of by the FimClient internals, this attribute is always fetched whether you requested it or not.

[sourcecode language=”csharp”]
var peopleWithFirstName = _client.EnumerateAll(
"/Person"
, new AttributesToFetch(RmPerson.AttributeNames.FirstName.Name)
);

var attributes = new AttributesToFetch(RmPerson.AttributeNames.LastName.Name)
.AppendAttribute(RmPerson.AttributeNames.AccountName.Name);

var peopleWithSelectedAttributes = _client.EnumeratePage(
"/Person"
, Pagination.All
, SortingInstructions.None
, attributes
);
[/sourcecode]

Full behavior of AttributesToFetch class can be viewed by browsing it’s tests.

This concludes the usage scenarios of our FIM communication library. Let us know what you think about it. Any suggestions, ideas?

Blog picture: (cceisenrah

Category: Development
  • rcgneo says:

    Hello,

    I downloaded your code and am currently trying to run all test cases you have in Visual Studio 2012. I have 28 test cases failing because of Syste.ServiceModel.SecurityNegotiationException. saying that the caller was not authenticated by the service.

    I am running from my client which is off site from the FIM server but I am VPNed in. Would this be the problem?

    I tried to create a FimClient with “url” and “credentials” passed in but still not working.

    Any help would be appreciated.

    2012-10-16 at 22:39
  • Maciej Aniserowicz says:

    Hi rcgneo,
    This should not be a problem, I have successfully used FimClient with FIM being installed on a remote machine.
    Please try to:
    1) modify client creation routine in FimIntegrationTestBase.cs
    2) remove WCF configuration from app.config if you pass FIM URL and credentials manually

    I cannot reproduce this issue, but I hope it helps. Please let me us know if the problem persists. Maybe paste some initialization code, too?

    2012-10-18 at 06:27
    • rcgneo says:

      Maciej,

      Thanks for your suggestion. I did suggestion #2 and it worked. :)

      Another question is, if I need to do a small project with FIM for a client, can I use this open source client? Or do I have to write my own? I just want to make sure there is no issues there.

      Thanks,

      2012-11-01 at 22:48
      • tonyszko says:

        Hi, As Maciej wrote you can use it – this is why we’ve contributed it to community at the first place. One ask then – if you will do this and you can share your feedback on it it would be highly appreciated by a team – but this is suggestion, not requirement ;). Enjoy

        2012-11-09 at 12:49
  • Maciej Aniserowicz says:

    Sure, go ahead, we open sourced it so that anyone can use it :) .
    If you find any way to improve/extend it, I suggest forking the project on GitHub. I will accept pull requests that seem reasonable, this way we can share ideas and code.
    Good luck!

    2012-11-06 at 14:34
  • Jakub Gutkowski says:

    In Update method, it should be:

    var person = (RmPerson)_client.FindById(personId);
    var personChanges = new RmResourceChanges(person);

    persponChanges.BeginChanges(); // this line is missing

    person.LastName = “new last name”;

    _client.Update(personChanges);

    Cheers :)

    2012-11-15 at 17:18
  • MikeB says:

    Interesting library and thank you for posting it.

    Maybe I am missing something, but how would one approve a FIM request through the FIMClient? Or do you intend that approvals should use the DefaultClient? I’m wondering if there ought to be an Approve method that calls the DefaultClient’s Approve method.

    2014-04-09 at 14:04
    • Tomasz Onyszko says:

      MikeB – actually I can’t recall if we have used it for approvals as well. Probably this is why it is missing there. But good point – I will look into it. Of course contribution to project is highly welcome :)

      2014-04-24 at 16:50
  • Leo says:

    We use this library and it works great for our project.

    We’ve had to extend it in some places, but that’s easy because it’s open source.

    2014-04-23 at 16:26
    • Tomasz Onyszko says:

      We’re glad that it was useful. For extension to library – in the spirit of open source we would of course encourage and appreciate contribution to this project :).

      2014-04-24 at 16:48
  • Erich says:

    The GitHub project hasn’t been updated in over 2 years. Does it work with FIM 2012?

    If so, I have to assume too that coding with this library improves performance over trying to extract information from FIM using the FIMAutomation Powershell snapin (because that is S-L-O-W).

    Unfortunately, I’m just a lowly PowerShell user and not a developer, and I know nothing about C#.

    What is the possibility that someone will develop a PowerShell module/snapin that can use more efficient code (like from this library) to retrieve (at least) information from FIM?

    Thanks.

    2015-02-02 at 20:46
  • Tomek Onyszko says:

    Hi

    It was not updated but it is still good :) – we still use it internally and I know some people use it as well. No problem with current version of FIM.
    Using this client library makes export much faster :) .. we came from hours of export to literally minutes of export of large FIM data sets.

    if you just need to export some data send us your e-mail in comment here or through our contact form at http://www.predica.pl – I think we can help you with some tool :)

    2015-02-26 at 21:34
  • Erich says:

    Tomek,

    It has been a long time since you offered (I’ve been swamped in other projects.), but if you are still willing to help, I would be truly grateful. My preference would be for something more generic that everyone would find more helpful (e.g. not glacially slow) than MS’s FIMAutomation snapin, but I’ll accept any help available.

    What I am trying to do is generate a list that I can work with in PowerShell of all the groups which a user is an owner. This is the PowerShell code I am using:

    $FIMfilter = “/Person[AccountName=’$($SAMname)’]”
    $FIMexport = Export-FIMConfig -uri $FIMURI -onlybaseresources -customconfig (“$FIMfilter”)
    $FIMuserID = $FIMexport.ResourceManagementObject.ObjectIdentifier.substring(9)
    $FIMfilter = “/Group[Owner=’$FIMuserID’]”
    $FIMexport = Export-FIMConfig -uri $FIMURI -onlybaseresources -customconfig (“$FIMfilter”)

    I am further interested in building lists of the users in each of those groups (for comparison to AD), but that is secondary. I don’t want to ask too much of you. :-)

    Thanks.

    PS – I would have thought the email I am required to enter in the “details” section would be available to you, but nonetheless, it is my name at albany.edu

    2015-09-17 at 21:33

Leave a Reply