Das Problem
Bei einem Kunden war dies besonders störend, da eines der Projekte (eine große Sammlung an Schemas) gern bis zu fünf Minuten für eine Build gebraucht hat, aber nur sehr selten geändert wurde.
Die Ursache
Ursache für dieses Verhalten ist ein „Fix“, den Microsoft in BizTalk eingebaut hat, da unter sehr speziellen Umständen Projekte nicht neugebaut wurden. Also wurde entschieden, dass von nun an jedes BizTalk-Projekt immer gebaut wird. Selbstverständlich kann ein solches Projekt immer noch per Rebuild zum Bauen gezwungen werden, aber Microsoft ist einen anderen Weg gegangen: Mit jeder Build wird das Datum der letzten Änderung der zum Projekt gehörenden .btproj.user-Datei aktualisiert, womit das Projekt als nicht mehr aktuell gilt und neu gebaut werden muss. Dieses Verhalten lässt sich nicht abschalten.
Die Lösung
Die Lösung ist also, zu verhindern, dass Visual Studio das Datum der letzten Änderung anpasst.
Was nicht funktioniert
Es gibt seit MS-DOS 1.0 das Read-Only-Attribut, um Dateien als schreibgeschützt zu markieren. Allerdings hat es sich dabei schon immer eher um eine Empfehlung, als eine tatsächliche Vorschrift gehandelt. Auch in diesem Fall wird das Attribut schlicht ignoriert und sogar gelöscht.
Zum Glück gibt es in Windows NT schon seit 1995 Access Control Lists, mit denen Benutzern der Zugriff auf einzelne Dateien gestattet oder verweigert werden kann. Praktischerweise kann man sich sogar selbst den Zugriff auf eine Datei verweigern – auch wenn man sich als Besitzer der Datei jederzeit wieder Zugriffsrechte geben kann. Das geht grundsätzlich auch, allerdings ist es gar nicht so einfach, die passenden Rechte für mehr als eine Datei zu setzten. Obwohl die Rechteverwaltung im Windows Explorer funktioniert, verschwindet die Registerkarte „Sicherheit“, mit der man Rechte setzen kann, wenn man mehrere Dateien auswählt. Der findige Windows-Nutzer würde nun mit
icacls.exe *.btproj.user /R /deny domain\user:w
versuchen, die Schreibrechte bei allen .btproj.user-Dateien zu entfernen. Das funktioniert im Prinzip auch, allerdings setzt icacls auch noch ein paar Bits mehr, so dass die Dateien danach auch nicht mehr lesbar sind. Das macht Visual Studio sehr unglücklich.
Was tatsächlich funktioniert
Es gibt .NET-Methoden, die gerade das tun, was wir wollen. Diese lassen sich je nach persönlicher Vorliebe in C♯ oder PowerShell nutzen, die folgenden Beispiele werden in C♯ gegeben. Angenommen, dass sich in file der Dateiname und in user der Benutzername einschließlich Domain befindet, können wir mit
var acl = File.GetAccessControl(file);
die ACLs der Datei auslesen. Danach passen wir mit
acl.AddAccessRule(new FileSystemAccessRule(user, FileSystemRights.Write, AccessControlType.Deny));
die ACLs an und setzen sie abschließend mit
File.SetAccessControl(file, acl);
Nun kann Visual Studio das Datum der Datei nicht mehr ändern und versucht somit nicht mehr, das Projekt ohne weitere Änderungen neu zu bauen. Das Zurücksetzen ist deutlich simpler und mit icalcs zu bewerkstelligen, man führt einfach
icacls *.btproj.user /R /remove:d domain\user
aus, um alle Zugriffsbeschränkungen für den Benutzer zu entfernen.
Tipps
In C♯ lassen sich Benutzer und Domain mit Environment.UserName bzw. Environment.UserDomainName auslesen. Das geht natürlich auch in der PowerShell, hier kann man aber auch einfach $env:USERNAME bzw. $env:USERDOMAIN verwenden.
Fallstricke
Es wäre natürlich langweilig, wenn die Dinge so einfach wären. Mindestens zwei Dinge sind zu beachten:
1. Änderungen an der Projektdatei ziehen immer eine Änderung an der .btproj.user-Datei nach sich, auch wenn die Datei sich nicht effektiv ändert. Dazu muss man wie oben beschrieben die Dateien wieder freigeben, sonst lässt sich die Projektdatei nicht speichern. Visual Studio zeigt her fälschlich an, dass die .btproj-Datei nicht geschrieben werden kann, erst wenn man im „Speichern unter“-Dialog ohne Änderung des Namens auf Speichern drückt kommt die korrekte Fehlermeldung. Das sollte bei Source Control nicht zu Problemen führen, da man die .btproj.user-Datei ohnehin nicht einchecken sollte.
2. Bei Verwendung von XSLT muss man gesondert aufpassen. Während Visual Studio oder MSBuild von irrelevanten Updates an der .btproj.user-Datei zu einem Rebuild des Projekts motiviert werden, gilt das nicht für Änderungen an den XSLT-Dateien. Ein ähnliches Verhalten kann man bei „Test Map“ beobachten, wo die relevante XSLT-Datei vor dem Testen nicht gespeichert wird. Eventuell ist es sinnvoll, Maps-Projekte generell von der obigen Behandlung auszuschließen – in unserem konkreten Fall wurden wir von einem großen, vielreferenzierten Schema-Projekt gebremst. Wie so oft muss man hier messen und danach entscheiden.
3. Auf manchen Systemen hat man überraschenderweise nicht genug Rechte, um sich selbst die Rechte zu entziehen. Dann gibt man seinem Benutzer auf dem obersten Verzeichnis einfach per Windows Explorer „Full Control“-Rechte und versucht es nochmal.
Dies ist ein quiTeq-Tipp von QUIBIQ Berlin.