Hey,
some time ago I faced some problems with the Vault-API in the eventhandler. As always, the problems were discovered only on the customer side. After some analysis we found the reason for the issuese: The Problems occured only in a replicated environment.
And here is my eventhandler class for the Vault 2013 Server:
[assembly: ApiVersion("5.0")] [assembly: ExtensionId("some guid here")] public class Eventhandler : IWebServiceExtension { internal EventHandler<CheckinFileCommandEventArgs> CheckInEventhandl; internal EventHandler<AddFileCommandEventArgs> AddEventhandl; internal EventHandler<DeleteFileCommandEventArgs> DelEventhandl; internal EventHandler<MoveFileCommandEventArgs> MoveEventhandl; private WebServiceManager _webSvcMgr; public void OnLoad() { AddEventhandlers(); } ... void AddFileEventPost(object sender, AddFileCommandEventArgs e) { … } void CheckinFileEventPost(object sender, CheckinFileCommandEventArgs e) { … } void MoveFileEventPost(object sender, MoveFileCommandEventArgs e) { … } void DelFileEventPre(object sender, long fMid, DeleteFileCommandEventArgs e) { … } void DelFilesEventPre(object sender, DeleteFileCommandEventArgs e) { foreach (var fileMasterId in e.FileMasterIds) { DelFileEventPre(sender,fileMasterId,e); } } … private void AddEventhandlers() { CheckInEventhandl = CheckinFileEventPost; AddEventhandl = AddFileEventPost; DelEventhandl = DelFilesEventPre; MoveEventhandl = MoveFileEventPost; DocumentService.CheckinFileEvents.Post += CheckInEventhandl; DocumentService.AddFileEvents.Post += AddEventhandl; DocumentService.DeleteFileEvents.Pre += DelEventhandl; DocumentService.MoveFileEvents.Post += MoveEventhandl; } private void RemoveEventhandlers() { DocumentService.CheckinFileEvents.Post -= CheckInEventhandl; DocumentService.AddFileEvents.Post -= AddEventhandl; DocumentService.DeleteFileEvents.Pre -= DelEventhandl; DocumentService.MoveFileEvents.Post -= MoveEventhandl; } }
( And I have installed the latest version of the sdk-assemblies: v 17.0.62.0 )
Problem 1)
When I work with my VaultExplorer-Client on the replicated environment (there is no difference if I work on Publisher or on Subscriber) I realized that some of the events becomes fired twice!
This is the result of my analysis:
– AddFileEvent (POST): becomes fired 2 times
– CheckinFileEvent (POST): becomes fired 1 time
– MoveFileEvent (POST): becomes fired 2 times
– DeleteFileEvent (PRE): becomes fired 1 time
I analyzed, that both events have always different Event-Id (GUID)
This problem is reproducible and happens only in a replicated environment!
Problem 2)
Scenario:
PUBSLISHER adds a file and changes the ownership to him.
SUBSCRIBER changes the ownership of a folder to the Subscriber.
PUBLISHER moves his file to the Subscriber
In This scenario the move-event becomes blocked with an Error-message, but the movefile-event was fired anyway! This means we have a problem, because the file doesn’t become moved, but the event was fired!
Solutions:
Problem 1)
In fact, here we are talking about an API issue, where we a workaround: You have to overload the pre-event AND the post-event. Then you have to remember that the pre-event was called allready. So you can check later if you are running in the first Post-event, and the second post-event can be terminated.
Do like this:
1) create a internal variable where you are chaching the pre events:
public class Eventhandler : IWebServiceExtension { internal Dictionary<long,FileInfos> DeleteFileCache; ...
2) overload also the Pre-event and create a cache functionality for it:
void DelFilesEventPre(object sender, DeleteFileCommandEventArgs e) { foreach (var fileMasterId in e.FileMasterIds) { DelFileEventCache(sender, fileMasterId, e); } } void DelFileEventCache(object sender, long fMid, DeleteFileCommandEventArgs e) { SetWebSrvMngr(sender); if (!DeleteFileCache.ContainsKey(fMid)) { DeleteFileCache.Add(fMid, FileInfo); } else { Logger.Log.WarnFormat("A file with this MasterId was allready found in the cache (Mid: {0} )! Stopping ...", fMid); } }
3) And now create the post functionality and check if the pre-function was fired allready. If we are in the second post event, just return:
void DelFilesEventPost(object sender, DeleteFileCommandEventArgs e) { foreach (var fileMasterId in e.FileMasterIds) { DelFileEventPost(sender,fileMasterId,e); } } void DelFileEventPost(object sender, long fMid, DeleteFileCommandEventArgs e) { if(!DeleteFileCache.ContainsKey(fMid)) { Logger.Log.ErrorFormat("Failed to find the file in the cache (Mid: {0} )! Stopping ...",fMid); return; } DeleteFileCache.Remove(fMid); //do your stuff here ... }
Problem 2)
Always check the Status property on the EventArgs during a Post. See here:
void CheckinFileEventPost(object sender, CheckinFileCommandEventArgs e) { if(!CheckEventStatus(sender, e)) return; ... } private bool CheckEventStatus(object sender, WebServiceCommandEventArgs eventArgs) { if(eventArgs.Status!=EventStatus.SUCCESS) { return false; } return true; }
I hope this was helpful for you as a Vault-Eventhandler developer :)