none
Improvements and bug fixes in the FIM RC1 Web Service client.

All replies

  • Enumeration responses do not include the total number of matching objects

    When you run an Enumerate request, the response does not get the total count of objects that matched the query filter, which is an important piece of information if the total number of results is higher than the limit on the number of returned objects.

    To add this missing feature, you must add an EnumerationDetail class as follows:

        [XmlRoot]
        public class EnumerationDetail {
            [XmlElement()]
            public int Count;
        }
     
    Then you need to modify the EnumerateResponse class to add that element (file EnumerationResponse.cs). Here I'm also adding a "convenience" property that will store the total number of results:

        [XmlRoot(Namespace = Constants.WsEnumeration.Namespace)]
        public class EnumerateResponse : PullResponse {

            [XmlElement(Namespace = Constants.Rm.Namespace)]
            public EnumerationDetail EnumerationDetail;

            [XmlIgnore()]
            public int? Count {
                get {
                    if (null == EnumerationDetail) {
                        return null;
                    } else {
                        return EnumerationDetail.Count;
                    }
                }
            }
        }

    And finally you have to go to the WsEnumerationClient.cs file and add a message header to request for the count information (add the lines in bold to the Enumerate method inside the lock block):

            public EnumerateResponse Enumerate(EnumerationRequest request) {
                // code omitted for brevity ...
                lock (request) {
                    enumerateRequest = Message.CreateMessage(MessageVersion.Default, Constants.WsEnumeration.EnumerateAction, request, new ClientSerializer(typeof(EnumerationRequest)));
                    MessageHeader includeCount = MessageHeader.CreateHeader("IncludeCount",Constants.Rm.Namespace,null);
                    enumerateRequest.Headers.Add(includeCount);
                }
                // code omitted for brevity ...
            }


    Paolo Tedesco - http://espace.cern.ch/idm
    Monday, October 19, 2009 2:46 PM
  • Comparing RmReference objects with a null reference as a left-side operator causes a NullReferenceException

    If you compare an RmReference object against a null reference on the left side of the comparison operator, you get a NullReferenceException, e.g:

                RmReference a = SomeOperation();
                if (null != a) { // crashes

    You can fix this by re-defining the == and != operators of the RmReference class as follows:

            public static bool operator ==(RmReference attrib1, RmReference attrib2) {
                if (attrib1 as object == null)
                    return (attrib2 as object == null);
                if (attrib2 as object == null)
                    return false;
                return attrib1.CompareTo(attrib2) == 0;
            }

            public static bool operator !=(RmReference attrib1, RmReference attrib2) {
                if (attrib1 as object == null)
                    return (attrib2 as object != null);
                if (attrib2 as object == null)
                    return true;
                return attrib1.CompareTo(attrib2) != 0;
            }


    Paolo Tedesco - http://espace.cern.ch/idm
    Monday, October 19, 2009 2:51 PM
  • Love it!

    Tuesday, October 20, 2009 4:52 PM
  • IsMultiValue property of RmAttributeValue class returns true whenever the attribute has a value

    RmAttributeValue stores values internally as a list, and IsMultiValue property is defined as

        public bool IsMultiValue {
            get {
                return this.isMultiValue || this.values.Count > 0;
            }
        }
    

    Thus it returns true when at least one value is stored. The property should be defined as

        public bool IsMultiValue {
            get {
                return this.isMultiValue || this.values.Count > 1;
            }
        }
    

    Paolo Tedesco - http://espace.cern.ch/idm
    Friday, October 23, 2009 11:37 AM
  • CopyTo method of RmList makes a copy the wrong way round

    The CopyTo method in RmList is defined as follows:

        public void CopyTo(T[] array, int arrayIndex) {
            int j = arrayIndex;
            for (int i = 0; i < array.Length; i++) {
                this.values[j] = this.ConvertTo(array[i]);
                j++;
            }
        }
    

    This actually is copying the array into the list, while it should be the opposite. If you try to initialize a List with the contents of an RmList the code will crash.

    I think that the correct implementation of the method should be like this:

        public void CopyTo(T[] array, int arrayIndex) {
            for (int i = 0; i < this.values.Count; i++) {
                array[i + arrayIndex] = this.ConvertFrom(this.values[i]);
            }
        }
    


    Paolo Tedesco - http://espace.cern.ch/idm
    Monday, October 26, 2009 5:08 PM
  • I had a problem with multi-valued attributes when I didn't call RefreshSchema() on the DefaultClient.  I realized that this method is pretty much required before using the client, so I refactored the constructors so that it's always called.  Please refer to my blog post:

    http://c--shark.blogspot.com/2010/01/multi-valued-attributes-arent-multi.html
    Wednesday, January 06, 2010 10:29 PM
  • I encountered a NullReferenceException when I tried to enumerate enumeration results more than once, so I added a more helpful exception to the EnumerationResultEnumerator with the message, "The query results cannot be enumerated more than once."

    http://c--shark.blogspot.com/2010/01/nullreferenceexception-in.html
    Thursday, January 07, 2010 11:09 PM
  • Hi Joe,
    thank you very much for your posts!

    Cheers,
    Paolo

    Paolo Tedesco - http://cern.ch/idm
    Friday, January 08, 2010 9:27 AM
  • Methods in ClientBase-derived classes and "using" statement

    The using statement can create some problems in case the communication object is in a faulted state, as an "extra" exception might be thrown on the closing brace of the using statement, thus hiding the original exception (and true cause of the error), as described in these links:
    In case you get an error saying "the communication object, system.servicemodel.channels.servicechannel, cannot be used for communication because it is in the faulted state" , then you might need to refactor these methods of the RC1 client to remove the 'using' statement:
    • WsEnumerationClient.Enumerate
    • WsEnumerationClient.Pull
    • WsTransferClient.Get
    • WsTransferClient.Put
    • WsTransferClient.Delete
    • WsTransferFactoryClient.Create
    For more details, and a possible solution, see this blog post .

    Paolo Tedesco - http://cern.ch/idm
    Monday, January 11, 2010 2:25 PM
  • Trying to enumerate resources with the FIM Web Service passing the credentials of a user that is not able to authenticate (domain, account name and SID not properly set in FIM) causes an exception with this message:

    System.ServiceModel.Security.MessageSecurityException: No signature message parts were specified for messages with the 'http://schemas.microsoft.com/2006/11/IdentityManagement/DirectoryAccess/fault' action.

    The fault message has not been deserialized by the client, which makes the error hard to troubleshoot (to see the error details one must look at the soap message in the server logs, if message logging is enabled).

    The client is unable to deserialize the fault because of a missing FaultContractAttribute in the IEnumerate interface:

    namespace Microsoft.ResourceManagement.Client.WsEnumeration {

        [System.CodeDom.Compiler.GeneratedCodeAttribute ("System.ServiceModel" , "3.0.0.0" )]

        [System.ServiceModel.ServiceContractAttribute (Namespace = Constants .WsEnumeration .Namespace, ConfigurationName = Constants .WsEnumeration .Enumerate)]

        public interface IEnumerate {

            [System.ServiceModel.OperationContractAttribute (Action = Constants .WsEnumeration .EnumerateAction, ReplyAction = Constants .WsEnumeration .EnumerateResponseAction)]

            // ... more FaultContractAttributes ...

            // ADD THIS ATTRIBUTE TO DESERIALIZE EXCEPTIONS CORRECTLY:

            [System.ServiceModel.FaultContractAttribute (typeof (Faults.UnwillingToPerformFault ), Action = Constants .Imda .Fault, ProtectionLevel = System.Net.Security.ProtectionLevel .EncryptAndSign, Name = Constants .Imda .UnwillingToPerform, Namespace = Constants .Imda .Namespace)]

            Message Enumerate(Message request);

     

            // ....

        }

    }

    At this point, the error message received will be the correct one:

    System.ServiceModel.FaultException: The endpoint could not dispatch the request.


    Paolo Tedesco - http://cern.ch/idm
    Friday, February 12, 2010 8:56 AM
  • Error in Value property setter in RmAttributeValue class

    In the RmAttributeValue class, the Value property setter is as follows:

     

            public IComparable Value {

                // get accessor omitted

                set {

                    lock (this .values) {

                        if (this .values.Count > 0 ) {

                            if (value == null ) {

                                this .values.Clear();

                            } else {

                                this .values.Add(value );

                            }

                        } else {

                            this .values.Add(value );

                        }

                    }

                }

            }

    Thus, setting the value of an attribute whose value is already set incorrectly results in a new value being added to the internal collection, as shown by this example:

                RmAttributeValue value = new RmAttributeValue ();

                value.Value = "one" ;

                value.Value = "two" ;

                // now:

                // value.IsMultiValue == true

                // value.Values.Count == 2

    The code should be modified as follows:

            public IComparable Value {

                // get accessor omitted

                set {

                    lock (this .values) {

                        this .values.Clear();

                        if (value != null ) {

                            this .values.Add(value );

                        }

                    }

                }

            }


    Paolo Tedesco - http://cern.ch/idm
    Monday, March 22, 2010 1:31 PM
  • Can we just start a CodePlex project for managing and maintaining this code?

    It would be nice to have a central repository of bugs and patches for client.

     

    -Jeremy

    Tuesday, March 23, 2010 11:05 PM
  • Hi Jeremy,

    that's something I want to do since a while... I'll start the CodePlex project asap and post the details here.

    Cheers,

    Paolo


    Paolo Tedesco - http://cern.ch/idm
    Wednesday, March 24, 2010 10:43 AM
  • Hi Paolo,

    Any luck on this?

    I am going to go after the password reset functionality and would like to start with the most up to date code and be able to contriute back what I develop.

     

    -Jeremy

    Friday, March 26, 2010 12:58 AM
  • It looks like we need to interact with the Alternate endpoint in order to act as the Anonymous User.

    Here are my changes to the Web Service client so that the Alternate endpoint functions. They may not be pretty but they work!!

     

    public class DefaultClient : IDisposable
        {
            // underlying clients
            WsTransferClient wsTransferClient;
            WsTransferFactoryClient wsTransferFactoryClient;
            MexClient mexClient;
            WsEnumerationClient wsEnumerationClient;
            AlternateClient alternateClient;

            public DefaultClient()
            {
                this.wsTransferClient = new WsTransferClient();
                this.wsTransferFactoryClient = new WsTransferFactoryClient();
                this.wsEnumerationClient = new WsEnumerationClient();
                this.mexClient = new MexClient();
                this.alternateClient = new AlternateClient();

                this.resourceFactory = new RmResourceFactory();
                this.requestFactory = new RmRequestFactory();
            }

     

    /// <summary>
            /// Saves changes made to an object recorded by the transaction to the service.
            /// </summary>
            /// <param name="transaction">The transaction object which recorded changes made to a Resource object.</param>
            /// <returns>True upon successful operation.</returns>
            public bool Put(RmResourceChanges transaction)
            {
                return Put(transaction, "Resource", String.Empty);
            }

            public bool Put(RmResourceChanges transaction, String endpoint,String NTLMCreds)
            {
                           
                if (transaction == null)
                {
                    throw new ArgumentNullException("transaction");
                }

                PutResponse response;

                switch (endpoint)
                {
                    case "Resource":
                        PutRequest resourceEPrequest = this.requestFactory.CreatePutRequest(transaction);
                        response = this.wsTransferClient.Put(resourceEPrequest);
                        if (response == null)
                            return false;
                        else
                            return true;
                        break;
                    case "Alternate":
                        if (NTLMCreds == null || NTLMCreds == String.Empty)
                            throw new ArgumentNullException("NTLMCreds");
                        else
                        {
                            PutRequest alternateEPrequest = this.requestFactory.CreatePutRequest(transaction, "Alternate", NTLMCreds);
                            response = this.alternateClient.Put(alternateEPrequest);
                            if (response == null)
                                return false;
                            else
                                return true;
                        }
                        break;
                    default:
                        throw new Exception("We don't know how to put to this endpoint");

                }
            }

    /// <summary>
            /// Constructs a put request based on the changes tracked in the transaction.
            /// </summary>
            /// <param name="transaction">The transaction object which tracked the changes made to an object.</param>
            /// <returns></returns>
            public virtual PutRequest CreatePutRequest(RmResourceChanges transaction)
            {
                return CreatePutRequest(transaction, "Resource", String.Empty);
            }

            public virtual PutRequest CreatePutRequest(RmResourceChanges transaction, String endpoint, String NTLMCreds)
            {

                if (transaction == null)
                {
                    throw new ArgumentNullException("transaction");
                }

                RmResource rmObject = transaction.RmObject;
                if (rmObject == null)
                {
                    throw new InvalidOperationException("transaction does not have rmObject");
                }

                lock (rmObject)
                {

                    PutRequest putRequest = new PutRequest();

                    switch (endpoint)
                    {
                        case "Resource":
                            putRequest.ResourceReferenceProperty = new ResourceReferenceProperty(rmObject.ObjectID.ToString());
                            break;
                        case "Alternate":
                            if (NTLMCreds == null || NTLMCreds == String.Empty)
                                throw new ArgumentNullException("NTLMCreds");
                            else
                                putRequest.ResourceReferenceProperty = new ResourceReferenceProperty(NTLMCreds);
                            break;
                        default:
                            throw new Exception("We do not know how to create a Put request for this Endpoint");
                    }

                    if (String.IsNullOrEmpty(rmObject.Locale) == false)
                    {
                        putRequest.ResourceLocaleProperty = new ResourceLocaleProperty(new System.Globalization.CultureInfo(rmObject.Locale));
                    }

    Friday, March 26, 2010 9:21 AM
  • For the most part, the alternate endpoint is exactly the same as the ResourceTransfer endpoint...

    so u can do something like...

                this.wsTransferClient = new WsTransferClient();
                this.wsTransferAlternateClient = new WsTransferClient();
                this.wsTransferAlternateClient.Endpoint.Address = new EndpointAddress(
                    new Uri(this.wsTransferClient.Endpoint.Address.Uri, Constants.Endpoint.Alternate),
                    this.wsTransferClient.Endpoint.Address.Identity,
                    this.wsTransferClient.Endpoint.Address.Headers);

     

    and for your Put() implementation, it seems like you are breaking the model of separating the Client and the ObjectModel.

    i believe the caller should pass in an correct object...

    i.e.

                // Create Anonymouse RmPerson and set ObjectID to Domain\User
                // The ObjectID attribute will become ResourceReferenceProperty in the message header
                user = new RmPerson();
                RmReference domainAndUsername = new RmReference();
                domainAndUsername.SetValueWithNocheck(
                    string.Format("{0}\\{1}", userCred.Domain, userCred.UserName));
                user.ObjectID = domainAndUsername;

                // Set ResetPassword to true
                transaction = new RmResourceChanges(user);
                transaction.BeginChanges();
                user.ResetPassword = true;

                client.Put(transaction, true);


    The FIM Password Reset Blog http://blogs.technet.com/aho/
    Saturday, March 27, 2010 2:41 AM
  • Finally...

    http://fim2010client.codeplex.com/

    The code right now needs some additional work, and I also had to introduce a breaking change (I'll provide more details on the codeplex page).

    Plese contact me if you are interested in participating.

    Cheers,

    Paolo


    Paolo Tedesco - http://cern.ch/idm
    Saturday, March 27, 2010 4:34 PM
  • For the most part, the alternate endpoint is exactly the same as the ResourceTransfer endpoint...

    so u can do something like...

                this.wsTransferClient = new WsTransferClient();
                this.wsTransferAlternateClient = new WsTransferClient();
                this.wsTransferAlternateClient.Endpoint.Address = new EndpointAddress(
                    new Uri(this.wsTransferClient.Endpoint.Address.Uri, Constants.Endpoint.Alternate),
                    this.wsTransferClient.Endpoint.Address.Identity,
                    this.wsTransferClient.Endpoint.Address.Headers);

     

    and for your Put() implementation, it seems like you are breaking the model of separating the Client and the ObjectModel.

    i believe the caller should pass in an correct object...

    i.e.

                // Create Anonymouse RmPerson and set ObjectID to Domain\User
                // The ObjectID attribute will become ResourceReferenceProperty in the message header
                user = new RmPerson();
                RmReference domainAndUsername = new RmReference();
                domainAndUsername.SetValueWithNocheck(
                    string.Format("{0}\\{1}", userCred.Domain, userCred.UserName));
                user.ObjectID = domainAndUsername;

                // Set ResetPassword to true
                transaction = new RmResourceChanges(user);
                transaction.BeginChanges();
                user.ResetPassword = true;

                client.Put(transaction, true);


    The FIM Password Reset Blog http://blogs.technet.com/aho/


    Thanks Anthony.

    This does look cleaner.

    However, for the DefaultClient, we still need to teach it how to use the Alternate endpoint. No? So we either need to overload the Put method or teach the Put method how to tell the difference based on the ReferenceID or create a PutAlternate method.

    Thoughts?

    -Jeremy

    Monday, March 29, 2010 4:13 PM
  • There are two approach

    overload the put

    original

    Put(........)

    add one

    Put(....., bool useAlternate)

     

    While i personally think that fit into the current model better, who really cares about Put?

    i.e. do u prefer to see something like MPRClient.Update(my new MPR object) or DefaultClient.Put(Transaction)?

    while i extend that client for SSPR (sorry, can't release code), i believe i just add a few methods in the DefaultClient

    1. DefaultClient.InitResetPassword(user)

    2. DefaultClient.GetXamlToken(...)

    3. DefaultClient.ResetPassword(...)

     

    again, that's just me and a few of my colleague believe is the right thing in the long run... we believe should be lifing in a typed world... instead of just "Message Put(Message m)" which is essentially the same as "object Put(object o)". I personally prefer a strongly typed interface...

     

    again, it's just a design decision that u can others have to figure/agree upon collaboratively


    The FIM Password Reset Blog http://blogs.technet.com/aho/
    Monday, March 29, 2010 6:34 PM
  •  I agree,

    I will add a method for ResetPassword that will call the correct Put. I was just thinking about the underlying method as well.

     

    -Jeremy

    Monday, March 29, 2010 11:29 PM
  • Hi Community,

    I have made a minor improvement necessary for me to distinguish between replacement and adds/removals of attribute values in the RmResourceChanges.cs. The problem I faced was that when I replaced the value of a single-valued attribute with another value by using the RmResourceChanges Class (--> changes.BeginChanges(), client.Put(changes), changes.AcceptChanges()) there were two events generated:
    - a delete attribute value
    - an add attribute value

    This looks like this in FIM:

     The changes I made in the RmResourcesChanges.cs (function GetDifference): 

            private static IList<RmAttributeChange> GetDifference(Dictionary<RmAttributeName, RmAttributeValue> attributes1, Dictionary<RmAttributeName, RmAttributeValue> attributes2)
            {
                IList<RmAttributeChange> changedAttributes = new List<RmAttributeChange>();
                foreach (KeyValuePair<RmAttributeName, RmAttributeValue> item1 in attributes1)
                {
                    if (attributes2.ContainsKey(item1.Key) == false)
                    {
                        foreach (IComparable value1 in item1.Value.Values)
                        {
                            changedAttributes.Add(new RmAttributeChange(item1.Key, value1, RmAttributeChangeOperation.Add));
                        }
                    }
                    else
                    {
                        RmAttributeValue rmValue2 = attributes2[item1.Key];
    
                        //BEGIN MY CHANGES
                        if (item1.Value.Values.Count == 1 && rmValue2.Values.Count == 1 &&
                            !rmValue2.IsMultiValue && !(item1.Value.Values[0].Equals(rmValue2.Values[0])))
                        {
                            //It is a REPLACE
                            changedAttributes.Add(new RmAttributeChange(item1.Key, item1.Value.Values[0], RmAttributeChangeOperation.Replace));
                        }
                        else
                        {
                        //END MY CHANGES
                            foreach (IComparable value1 in item1.Value.Values)
                            {
                                if (rmValue2.Values.Contains(value1) == false)
                                {
                                    changedAttributes.Add(new RmAttributeChange(item1.Key, value1, RmAttributeChangeOperation.Add));
                                }
    
                            }
                            foreach (IComparable value2 in rmValue2.Values)
                            {
                                if (item1.Value.Values.Contains(value2) == false)
                                {
                                    changedAttributes.Add(new RmAttributeChange(item1.Key, value2, RmAttributeChangeOperation.Delete));
                                }
                            }
                        
                    }
                }
    Edit: mhm the IsMultiValued does not help me here as it only returns true if there is more than one value or not - but it does not say anything about if the attribute in general is defined as multivalued attribute or not. Any suggestions on this topic how we could check this?
    Thursday, April 01, 2010 4:11 PM
  • Hi Hugo00,

    Thanks for your contribution!

    I had the same problem and solved it in a different way. 

    Basically, since the operations must be different for single valued (replace) and multi valued attributes (add and remove) I wanted to have the information about the attribute type (single or multi) to be decided at the moment of the attribute creation, and not have - for example - a multi valued attribute considered as single valued only because it was constructed with a single value.

    I chose to create two different classes for single and multi valued attributes, so the check for "IsMultivalued" becomes 100% reliable; of course, this breaks backward compatibility with previous code.

    If you want, you can download the code from Codeplex and have a look, I would really like to know your opinion (note that there are some discussions in the project). Please note that the code is still a work in progress.

    Thanks,

    Paolo


    Paolo Tedesco - http://cern.ch/idm
    Friday, April 02, 2010 9:03 AM
  • Awesome! Thank you Paolo!
    Rainer

    Sunday, April 04, 2010 6:36 AM
  • OK,

    I am at a crossroads with the Sample Client.

    It seems that the Microsoft.ResourceManagement DLL DOES define quite a few of the objects that are required in order to interact with the FIM STS. So far, I have been building up all of the object types natively in the Sample Client in order to serialize and deserialize our interactions with the STS. As such, we now have 10 or more new objects in the Sample Client associated with STS interactions.

    Because I am not a WCF developer, this has taken some time and isn't very pretty.

    So the question is: continue down this path so that there is no dependency between the Sample Client and the Microsoft.ResourceManagement DLL, or remove the custom objects and reference the ones provided by MS.

    I have been told that one of the original goals of the sample client was to develop a client that does not depend on the ResourceManagement  DLL.

    Thoughts on this?

    -Jeremy

    Wednesday, April 07, 2010 8:52 PM
  • Did you considered to use the FIMAutomation from managed code? I still have not worked with this, but in my understanding FIMAutomation can be used from managed code to do basic interactions with FIM Service similar to what is available in Sample Client, probably without the need to build custom classes.

    Andrea

    Wednesday, April 07, 2010 9:28 PM
  • The FIMAutomation is really designed to work with Config Migration Tool... since it performs basic CRUD operations, it's often scripted to do different stuff.

    But there are certain limitations, e.g. u don't know the Count of an enumeration without fetching all objects, no STS support, etc


    The FIM Password Reset Blog http://blogs.technet.com/aho/
    Wednesday, April 07, 2010 9:55 PM
  • Hi Jeremy,

    what about starting a new discussion on CodePlex about this issue? It looks like you are digging rather deeply into the password reset / Secure Token Service issue, so we might have a more technical discussion there, and maybe keep this thread for "simpler" fixes?

    What are the objects in the Microsoft.ResourceManagement.dll that you are referring to? Why is it important to avoid a dependency to Microsoft.ResourceManagement?

    Cheers


    Paolo Tedesco - http://cern.ch/idm
    Thursday, April 08, 2010 8:30 AM
  • Hi Paolo,

    I wanted to post here because there are still a lot of people who have input on/ideas about  the sample client that still have not joined the codeplex project.

    This question is not really technical in nature but more about the long-term direction we will take with the client and I want to make sure there is input from the largest number of people.

    As Anthony stated, the original goal of the Sample Client was to implement a FIM Service client without linking to the ResourceManagement DLL. Now that the code is open source and is taking on a life of its own, we have the opportunity to decide if that is still the goal.

    Specifically, there are several objects in the Resourcemanagement DLL including:

    microsoft.resourcemangement.webservices.wstrust.requestsecuritytokenresponsetype

    microsoft.resourcemanagement.webservices.client.contextualsecuritytoken

    microsoft.resourcemanagement.webservices.wsresourcemanagement.authenticationchallengetype

    microsoft.resourcemanagement.webservices.wsresourcemanagment.authenticationchallengeresponsetype

    And others...

    That I have now duplicated in the Sample Client in order to properly serialize and deserialize them when forming messages to the STS.

    As it stands, my work is mostly done and I will probably post what I have with the objects I have created. As I stated in my last post, it's not pretty. So when it comes time to re-factor my work I would like some input on using the objects in the ResourceManagement DLL or not.

    -Jeremy

    Thursday, April 08, 2010 4:36 PM
  • Hi Jeremy,

    as you prefer...

    Personally, I'm completely against replicating classes from Resourcemanagement to the client.

    I don't really see a reason to avoid a dependency from Resourcemanagement, but if there is a good reason to do so, then maybe we could separate the parts depending from Resourcemanagement in a new assembly, so that the "basic" client assemblies still don't depend from it.

    I add another class from the Resourcemanagement dll to your list of useful classes: Microsoft.ResourceManagement.WebServices.WSResourceManagement.RequestParameter, as the RequestParameter attribute of the Request class contains the XML serialization of objects of that type.

    Cheers


    Paolo Tedesco - http://cern.ch/idm
    Friday, April 09, 2010 9:57 AM
  • if u want to prove anyone can build a replacement of MS SQL (just from protocal documentation) then they should build something totally independent of MS SQL.

    Same thing applies when Joe first wanted to prove that anyone can build something from scratch to talk to FIM Service (i.e. to replace the WS Client FIM itself uses)

     

    but now, obviously, u guys and him are trying to achieve something totally different

    Friday, April 09, 2010 6:18 PM
  • OK,

    Changes to the Sample Client to support Password Reset are posted on the Codeplex Project.

    Check this discussion for details on the changes:

    http://fim2010client.codeplex.com/Thread/View.aspx?ThreadId=208916

     

    -Jeremy

    Monday, April 12, 2010 1:50 AM
  • Hi.


    What is the best practice for storing user credentials in custom workflows?

    Monday, May 03, 2010 7:54 AM
  • Hi Hartwal.

    The best practice is not to do it. The workflow will be run with the requestor's credential, and you should configure the system so that the requestor is allowed to perform the operations made by the workflow.

    If you want to discuss this further, then maybe you could start a new discussion, as this does not really concern the web service client.

    Cheers,
    Paolo


    Paolo Tedesco - http://cern.ch/idm
    Monday, May 03, 2010 8:08 AM
  • Hi Community,

    I have tested the PasswordResetExample. There is a minor bug that leads to an infinite loop if the number of questions defined is equal to the number of questions asked.
    In QAGateQuestionAsker.cs, Function PickRandomQuestion, Line 78:
    pick = randNum.Next(1, numberOfQuestions + 1)

    Is there any news regarding step 13 of http://fim2010client.codeplex.com/Thread/View.aspx?ThreadId=208916 (so that the user can reset his password)?

    Keep up the perfect work!!

    Best regards,
    Rainer

    Tuesday, June 15, 2010 11:15 AM
  • Hi Rainer,

    Thanks for the bug report.

    In the future, please post bug reports or feature requests on the CodePlex project so we can track them there.

    No ETA on the final step to this. Hopefully I can get some time in the next few weeks.

     

    -Jeremy

    Tuesday, June 15, 2010 2:31 PM
  • Hi Jeremy,

    sorry for the post in the wrong thread. But the thing is that I want to keep this thread up. In fact it should be made sticky!!! On Tuesday I attended the Customer Focused Design for FIM 2010 in Germany and many companies require a better possibility to customize the portal and to provide password self reset for external employees.

    Currently this can only be realized with ASP.Net and using your Webservice Client. I just do not understand why MS does not officially support it. What I've seen so far it is even possible to implement a web-based password self reset portal with your client...

    Best regards,
    Rainer

    Thursday, June 24, 2010 8:22 AM
  • Hi Rainer,

    Going forward, I think that bug reports or issues with the client should be handled on the Codeplex site. It is easier to track them there and targets an audience who can resole them.

    We can post major updates or improvements to the client on this thread.

    I think we should start new threads in this forum when a new use or concept for the client is discovered.

     

    -jeremy

    Thursday, June 24, 2010 8:40 PM
  • Hi Rainer,
    thank you very much for the bug report and for the solution; I tested it, and it seems to work.

    I opened a bug on codeplex; I agree with Jeremy that the project's page is the best place to handle these things.

    Cheers,
    Paolo


    Paolo Tedesco - http://cern.ch/idm
    Monday, June 28, 2010 3:32 PM