I'm having an application which keeps track of appointments in Exchange using the EWS API. Using the property .ItemId is bad, because though it's unique, it's likely to change (Exchange web services: why is ItemId not constant? [continued]). For tracking items, this is a bad situation. Therefore I use the property Appointment.ICalUid.
This property also doesn't always looks the same and as far I can see, it somehow changes. I've logged some changes. At first a record is created with the following .ICalUID:
5fc22493-7212-4c44-9cd6-971c3bae28af
Then the next time I look up the records in Exchange the same item returns another .ICalUID:
040000008200E00074C5B7101A82E00800000000F01883C1D49AD101000000000000000010000000C321E8A40C6DE948836C422E2DA8610C
Why do I have at first a string returned of 36 characters and later on a string of 190 characters long? Why is this value changing?
Edit:
That the short id is created when using an Android phone connected to the Exchange Server, and the long ID is created using Outlook on Windows 10 with Outlook 2013. But it changes somehow?
This is because the RFC for iCal doesn't define the format or length of the Uid https://www.rfc-editor.org/rfc/rfc5545 just that it has to be globally unique. That means its down to implementer eg some people use a guid, some use a guid and domain etc. Exchange/Outlook uses a GOID format in particular PidLidCleanGlobalObjectId https://msdn.microsoft.com/en-us/library/office/cc839502.aspx and PidLidGlobalObjectId https://msdn.microsoft.com/en-us/library/office/cc815676.aspx (which are typically generated by the Exchange server when the appointment is created) .
So you should expect different formats and I generally recommend you use the PidLidCleanGlobalObjectId extended property rather then the icaluid property because this will always returns consistent as once its set Exchange will never change this property where the strongly typed property can be inconsistent in certain cases like you seeing. (as a general rule it should return the GOID).
Cheers
Glen
Related
I am trying fetch the whenChanged attribute for a user record from Active Directory using the DirectorySearcher class.
It seems the value is changed during or maybe after it is fetched because it is not the same as the value I can see in LDAP.
E.g. For my own profile the value in LDAP reads: 11/29/2022 5:10:21 Eastern Standard Time but after fetching this value through my code, it says 11/29/2022 10:10:24. Please note it is not 10:10 as per my system clock.
The obvious conclusion is that it is a time zone issue. But my system is in EST too. Also the difference in time is different for different users.
Does anyone know why this is happening?
There are a couple things going on.
As mentioned by Selvin, the value is always stored in GMT, which explains the 5-hour difference.
The value is not replicated between domain controllers, which explains the 3-second difference.
To explain the second point in more detail, let's take an example where a user's title is updated. When that update happens, the whenChanged attribute is updated on the DC where the change was made. Then when the new title value is replicated to another DC, that other DC updates the whenChanged attribute to the time when the replication happened. Because of that, the whenChanged value will be different on each DC.
The whenChanged values will usually be pretty close, but they can differ significantly. For example, when you logon, the lastLogon attribute is updated on the DC you authenticated to, along with whenChanged. However, lastLogon is not replicated, so the whenChanged value on all the other DCs will not get updated. That is, unless it's time to update the lastLogonTimestamp value, in which case that will replicate.
So if you're checking the value, make sure you're reading from the same DC. With DirectoryEntry, you can specify the DC you want to use in the LDAP path:
var user = new DirectoryEntry("LDAP://dc1.example.com/CN=someuser,OU=Users,DC=example,DC=com"
, null, null, AuthenticationTypes.ServerBind);
The use of AuthenticationTypes.ServerBind is because the documentation says:
Specifying a server name without also specifying this flag results in unnecessary network traffic.
Or you can get the DC that DirectoryEntry automatically found by using:
var dc = user.Options.GetCurrentServerName();
I'm trying to read task details from a mpp file using net.sf.mpxj library. However, when trying to read custom fields, I get a byte array which I do not know what to do with! It is not the exact value of the custom field from that specific task. Can anyone tell me what to do?
ProjectReader reader = new MPPReader();
ProjectFile project = reader.read(#"C:\EPM\test2.mpp");
foreach (net.sf.mpxj.Task task in project.Tasks)
{
var Value = task.GetFieldByAlias("My Custom Field Name");
}
The "Value" will be a byte array and I do not know how to get the real value from it.
UPDATED ANSWER:
As of MPXJ 10.7.0 you can retrieve correctly typed values for enterprise custom fields. You'll also find a CustomFieldDataType attribute as part of the CustomField class which indicates what type you'll be retrieving.
(One interesting "gotcha" is that if your MPP file contains an enterprise custom field which is based on a lookup table, i.e. the user can only select from a fixed set of values, the user-visible text is NOT stored in the MPP file. You'll only get back a GUID representing the value the user has selected. Microsoft Project itself has this same issue... if you open the MPP file when you're not connected to Project Server, these values will appears as blanks...)
ORIGINAL ANSWER:
The main problem is unfortunately that MPXJ doesn't currently offer the same level of support for Enterprise Custom Fields as it does for other fields. While it is able to identify Enterprise Custom Fields and the aliases they've been given, at the moment it is only able to read the raw bytes representing the field data.
Enterprise Custom Fields are not as commonly used as other field types so there hasn't been as much time invested in locating the definitions of these fields in the MPP file. The field definition will contain the type information necessary to convert from the raw bytes to the expected data type.
Improved support for Enterprise Custom Fields is on the "to do" list for MPXJ.
I'm developing a win forms application using AxosoftAPI.NET. I've implemented functionality to search for Items like Tasks, Defects, Incidents and Projects.
I can also check whether an Item has attachments. Now I need to know how to check if an Item (Task or Defect) has an Install or Testing Note attached to it. I searched in Axosoft's developers website but couldn't find anything helpful. How can I achieve this in C# using AxosoftAPI.NET?
Install and Testing Notes are not standard fields in Axosoft so are most likely Custom Fields that were added by your team. All custom fields should be returned when getting items, however large text fields, are only returned when getting a single item, rather then getting lists of items.
From the developer.axosoft.com page regarding the GET multiple and specifying the columns parameter :
(comma seperated string) Containins the names of the columns to return for each item. Defaults to all columns. However, please note that for performance reasons long text fields (such as 'Description') are not returned by this API call. To get the values of long text fields, use the GET /defects/{id} call to retrieve a single item.
So I am building a new WPF application and I started on my first data entry screen. What maxlength do you normally set for your string fields? I got caught out in my last app my making some of the fields too short.
The string fields will be persisted to a sql server compact db via entity framework.
There are some other posts on StackOverlfow discussing this. You might find this one most helpful: List of standard lengths for database fields.
If you know that the field is used for a first name then you know there's no first name that is longer than 200 chars, then don't make it larger than that. As you can see in the post linked above, there's a link to a catalog that suggests first names are in general not longer than 35 chars.
Fields that you don't know what they will contain such as free text (description or such), just make them the maximum size possible. Better safe than sorry!
I’m currently working on a project where we need to archive and trace all the modified data’s.
When a modification surrender, we have to kept theses information
Who has modified the data?
When?
And … that’s why I’m asking this question: Keep the previous
and the new value of the data.
Quickly, I have to trace every modification for every data.
Example :
I have a name field why the value “Morgan”.
When I modify this value, I have to be able to say to the user that the 6th of January, by XXX, the value changed from “Morgan” to “Robert” …
I have to find a clean and generic method to do this because a large amount of data is concerned by this behavior.
My program is in C# (.NET 4) and we are using Sql Server 2008 R2 and NHibernate for the object mapping.
Do you any ideas, experience or solution about how to do a thing like that?
I am a little confused about at what point you want to have the old vs new data available. But, this can be done within a database trigger as in the following question:
trigger-insert-old-values-values-that-was-updated
NHibernate Envers its what you want :)
You must use NHibernate 3.2+ (3.2 is the current release).
Its easy like
enversConf.Audit<Person>();
You can get info here and here
I've been in the same situation as you. I ended up doing in this way:
Save an ActivityEntry in the database containing an identity column (if you have multiple objects that change), an action-indicator (could be "User changed firstname", as a int), date field, userId and most important a parameter field.
Combining the values from the parameter field and the action-indicator I'm able to make strings like "{0} changed {1}'s firstname from {2} to {3}" where my parameter values could be "John;Joe".
I know it feels kinda wrong saving these totally loosely typed values in the database, but I believe it's the only way around, without having a copy of each table.