Category Archives: Visual Studio 2013

Túl sok segédvonal Visual Studioban

Feltetted a Productivity Power Toolst talán mert jó kis függőleges segédvonalakat szerettél volna látni a szerkesztőben, de mielőtt bármit is beállítottál volna, megjelentek maguktól mindenhol?

vs-guidelines-too-much

Ráadásul bármennyire pontosan kattintasz rájuk, ki sem tudod kapcsolni őket, mert a Remove Guideline menüpont mindig inaktív?

vs-guidelines-menu-disabled

Íme a megoldás: ne a Column Guides, hanem a Structure Visualizert kapcsold ki, az a bűnös:

vs-guidelines-options

Ezzel persze pár tooltipet is elvesztesz, de legalább oda tehetsz segédvonalat, ahova csak szeretnél.

 

Technorati-címkék:

Visual Studio: Unable to check out the current file

Érdekes hibába futottam bele, miközben egy szolgáltatás referenciát próbáltam felvenni Visual Studioba. Az URL egy .svc fájlra mutatott, aminek a szerkezetét az Add Service Reference dialógusablak gond nélkül felismerte, ám az ablak bezárásakor a Studio a következő hibaüzenettel örvendeztetett meg:

Unable to check out the current file.  The file may be read-only or locked, or you may need to check the file out manually.

Bár az adott projekt történetesen valóban source control alatt volt, Git-ről lévén szó a “check out” kifejezés nem tűnt helyénvalónak. Az igazság az, hogy a fenti hibaüzenet teljesen rossz és semmi köze a verziókezelőhöz, és a megoldás az, hogy nem közvetlenül az Add Service Reference, hanem azon belül az Advanced gombra, majd az Add Web Reference gombra kattintva megjelenő dialógusablakot kell használni az adott szolgáltatás esetén.

 

Technorati-címkék: ,,

Kód futtatása tesztelés elején és végén

Aki Visual Studioban írt már unit teszteket, biztosan találkozott a [TestClass] és [TestMethod] attribútumokkal, amelyekkel a teszteket tartalmazó osztályokat és a konkrét teszteket meg tudjuk jelölni. Hasonlóképpen használhatunk attribútumokat olyan kódok jelölésére, amelyeknek a tesztek előtt vagy után kell lefutniuk:

A TestInitialize és TestCleanup attribútumokkal ellátott metódusok minden teszt előtt és után futnak le.

A ClassInitialize és ClassCleanup attribútumokkal ellátott metódusok az osztályban található első teszt futtatása előtt és az utolsó futtatása után futnak le.

Az AssemblyInitialize és AssemblyCleanup attribútumokkal ellátott metódusok a szerelvényben található első teszt futtatása előtt és az utolsó futtatása után futnak le.

Az utóbbiak különösen hasznosak tudnak lenni CI esetén.

 

Technorati-címkék: ,

Hány kérés kell egy authentikációhoz?

Adott egy webszolgáltatás, amiről tudjuk, hogy csak Basic hitelesítéssel érhető el, de ez nem gond, hiszen szerencsére .NET-ben a generált proxy osztály Credentials tulajdonságán keresztül könnyű beállítani a szükséges felhasználónevet és jelszót:

MyService ws = new MyService
{
    Credentials = new NetworkCredential( "user", "password" )
};

Az ember azt gondolná, hogy ennek hatására olyan HTTP kérés megy majd a webszolgáltatás felé, amely tartalmazza az authenkációhoz szükséges adatokat, de a valóságban sajnos nem ez történik. Először elmegy egy olyan kérés, amiben nincs Authorization fejléc, azután ha a szerver ezt zokon veszi és 401 Authenticate válasszal tér vissza, akkor a kliens küld egy újabb kérést, ezúttal mellékelve hozzá a felhasználónevet és a jelszót. Az eredmény tehát dupla forgalom. Ha ez nem szimpatikus, és persze miért is lenne az, akkor jól jöhet a PreAuthenticate tulajdonság:

MyService ws = new MyService
{
    Credentials = new NetworkCredential( "user", "password" ),
PreAuthenticate = true };

 

Technorati-címkék: ,

PHP-s webszolgáltatás hívása .NET-ből

Úgy alakult, hogy .NET-ből kellett egy PHP-ban készült webszolgáltatást meghívnom standard SOAP interfészen keresztül, de ismét bebizonyosodott, hogy a Simple Object Access Protocolban a “simple” egyszerűen nem igaz, ugyanis a két fél összereszelése nem ment teljesen simán.

A hívás eredményeként a kliens 400 Bad Request státuszkódot kapott vissza, ami önmagában nem sokat segített a hibakeresésben. Az Apache webszerver naplójában ugyan volt egy Invalid URI in request bejegyzés, de ez sem vitt közelebb a megoldáshoz.

Mint már oly sokszor, most is a Fiddler segített. Megnézve vele a HTTP forgalmat gyanús lett, hogy a kérésben szerepel egy Expect: 100-continue fejléc, amiről később kiderült, hogy a PHP-s webszolgáltatás nem tud vele mit kezdeni. Ez egy elég érdekes fejléc, arra találták ki, hogy a kliens megkérhesse a szervert, hogy még a body felküldése előtt kiértékelje a kérésben szereplő fejléc mezőket, és egy 100 Continue válasszal jelezze, ha a fejlécek alapján hajlandó lesz feldolgozni a kérést, és a kliens bátran küldheti a body-t (bővebben lásd RFC 2616 8.2.3). Magyarul a klasszikus kérés-válasz sorrendet szépen fel lehet vele borítani:

Kliens –> Szerver:

POST example.com HTTP/1.1
kérés fejlécek
Expect: 100-Continue

Szerver –> Kliens:

HTTP/1.1 100 Continue
válasz fejlécek

Kliens –> Szerver:

kérés body

Szerver –> Kliens:

HTTP/1.1 200 OK
válasz fejlécek
válasz body

A .NET kliens mindig elküldi az Expect: 100-Continue fejléc sort, hogy spóroljon a hálózati forgalommal, sajnos azonban a jelek szerint nem minden szerver támogatja ezt a csavarást. Ezt a viselkedést a ServicePointManager osztály Expect100Continue tulajdonsága segítségével lehet felüldefiniálni:

ServicePointManager.Expect100Continue = false;

Még az is lehet, hogy így lesz gyorsabb a kódunk, hiszen a HttpWebRequest osztály alapértelmezés szerint 350 milliszekundumot vár a Continue válaszra.

 

Technorati-címkék: ,,,

TFS adatbázis költöztetése másik szerverre

Előfordulhat, hogy a Team Foundation Serverünk adatbázisát át kell vinnünk másik gépre, például mert:

  • Frissítjük alatta a hardvert vagy a szoftvert (migration upgrade).
  • Szét szeretnénk osztani az adatokat több TFS szerver között (split).
  • Szeretnénk egy másolatot az éles adatokról teszteléshez.

A folyamat viszonylag egyszerű, de a sorrend fontos:

  1. Gondoskodjunk róla, hogy a célkörnyezetben egyező vagy frissebb verziószámú SQL Server legyen. Ez azért kell, mert az újabb SQL Serveren készült mentést a régebbiekre nem lehet visszaállítani.
  2. Gondoskodjunk róla, hogy a célkörnyezetben pontosan egyező verziószámú TFS legyen, beleértve nem csak a nagyobb javítócsomagokat, hanem minden hotfixet.
  3. A forrás szerveren:
    1. A TFS Admin Console-on állítsuk le a project collectiont (Stop Collection).
    2. A TFS Admin Console-on válasszuk le a leállított project collectiont (Detach Collection).
    3. Az SQL Server Management Studio segítségével készítsünk egy teljes mentést a project collection adatbázisáról.
  4. Vigyük át a mentést a cél szerverre.
  5. A cél szerveren:
    1. Az SQL Server Management Studio segítségével állítsuk vissza az adatbázis mentést egy új adatbázisba.
    2. A TFS Admin Console-on csatoljuk fel az adatbázist (Attach Collection).
    3. Szükség szerint módosítsuk a SharePoint és Report Server beállításokat.

Előfordulhat, hogy a cél szerveren nem sikerül felcsatolnunk az adatbázist, hanem az alábbi hibaüzenetet kapjuk:

TF254078: No attachable databases were found on the following instance of SQL Server: MyServer. Verify that both the name of the server and the name of the instance are correct and that the database was properly detached using the detach command in the Team Foundation Administration Console.

tfs-attach-db-not-found

A hibaüzenet egészen jó, ezeket kell ellenőrizni:

  • Valóban sikerül-e csatlakozni, méghozzá a TFS Service account nevében a megadott SQL Server példányhoz és azon belül az adatbázishoz.
  • Valóban azonos TFS verzió van-e a forrás és a cél környezetben.
  • Nem hagytuk-e ki a 3b. lépést, azaz az SQL mentés előtt rendesen leválasztottuk-e a TFS-ről az adatbázist.

A második és harmadik kritériumot a TFS úgy ellenőrzi, hogy először lekérdezi az SQL Serveren lévő adatbázisokat, majd mindegyiken lefuttatja az alábbi lekérdezést:

SELECT name, value 
FROM   sys.extended_properties 
WHERE  name LIKE 'TFS_%'

Azaz lekérdezi a “TFS_”-sel kezdődő egyedi tulajdonságait az adatbázisoknak. Ellenőrzésképpen ezt mi is megtehetjük a cél környezetben a Configuration adatbázison, és valami hasonlót kell kapnunk:

tfs-properties-configuration-db

Egy korrektül felcsatolt adatbázison:

tfs-properties-attached-db

És végül egy korrektül leválasztott adatbázison:

tfs-properties-detached-db

Ha nem találjuk a TFS_SNAPSHOT_STATE tulajdonságot Complete értékkel, akkor gyanakodjunk, hogy elfelejtettük a Detach Collection gombot megnyomni a TFS Admin Console-on.

 

Technorati-címkék: ,,

TFS adatbázis takarítása

Ha egy projekt adataira már nincs szükség, a Team Foundation Serverről többféleképpen is törölhetjük azokat:

  • A TFS Administration Console felületén a Team Projects fülön van egy Delete gomb.
  • Használhatjuk a tf.exe delete opcióját, ami gyorsan lefut, cserébe szinte csak annyit csinál, hogy töröltre állítja az elemeket, amiket szükség esetén az undelete segítségével visszaállíthatunk.
  • A tf.exe destroy opciója véglegesen törli az elemeket, futtatása után azokat már nem tudjuk visszaállítani. Hátránya, hogy csak a version control adatokat tud törölni.
  • A TFSDeleteProject.exe szintén parancssori eszköz, és nem csak a TFS adatbázisában, hanem a reporting adatbázisban és a SharePointban lévő adatokat is tudja törölni.

Az összes megközelítés közös jellemzője, hogy hiába törlünk ki sok adatot, a TFS SQL adatbázisának mérete nem fog csökkenni. Ennek pedig az az oka, hogy minden módszer hagy hátra maga után olyan adatokat, amikre már nincs szükség, méghozzá többnyire a Content táblában. Ezeknek a törléséért a TFS Background Job Agent által futtatott egyik job a felelős, ami viszont csak naponta fut.

Ha nem akarunk ennyit várni, akkor az egyik lehetőségünk, hogy a tf destroy futtatásakor használjuk a /startcleanup kapcsolót, ami azonnal elindítja a takarítást.

Egy másik lehetőség, hogy kicsit beletúrunk az adatbázisba és manuálisan indítjuk el azokat a tárolt eljárásokat, amik a takarítást végzik. Ha a Content tábla nagy:

EXEC prc_DeleteUnusedContent 1

Ha a Files tábla nagy:

EXEC prc_DeleteUnusedFiles 1, 0, 1000

Ez utóbbi tárolt eljárás sokáig is futhat, ezért találták ki neki a harmadik paramétert, amivel meg lehet határozni, hogy mekkora darabokban dolgozzon. Ennek megfelelően célszerű többször lefuttatni, illetve ha gyorsan fut, akkor a harmadik paraméter értékét lehet növelni.

Ez természetesen nem támogatott eljárás, de nálam bevált.

 

Technorati-címkék:

TFS work item típusok testreszabása

Az egyik legjobb dolog a TFS-ben, hogy a forráskód változását nem csak a changesetekhez írt kommentek dokumentálják, hanem minden változást feladatokhoz, work itemekhez rendelhetünk. A TFS ad nekünk néhány feladat típust (Bug, Task, Issue, User Story stb.), de persze előfordulhat, hogy ezek nem teljesen elégítik ki az igényeinket és jó lenne módosítani őket.

A work item típusok kezelésére hagyományosan a parancssoros witadmin.exe szolgál, amivel exportálhatjuk a típus definíciókat XML-be, majd módosítás után visszatölthetjük őket a szerverre. A módszer előnyre, hogy a módosított XML-t stílszerűen elmenthetjük a TFS-be 🙂

Aki a grafikus módszereket jobban kedveli, annak érdemes a nem támogatott, ám elég ütős TFS Power Toolst feltelepíteni. Telepítés után megjelenik a Tools menüben egy Process Editor menüpont, amivel megnyithatjuk a work item típus definícióját közvetlenül a szerverről:

vs-open-wit-from-server

Csak ki kell választanunk, hogy melyik projekt melyik típusát akarjuk szerkeszteni:

vs-select-work-item-type

És máris megkapjuk a típushoz tartozó tulajdonságok listáját:

vs-work-item-type-properties

Ha például zavaró, hogy az Assigned To mező mindig megjeleníti a szerver összes felhasználóját, akkor kiválaszthatjuk ezt a mezőt a listából, majd az Edit gombra kattintva módosíthatjuk azt. A felugró szerkesztő ablak második, Rules fülén látható a probléma forrása:

vs-field-definition

A gond a Team Foundation Server Valid Users csoportot jelentő VALIDUSER sor, ami tartalmazza az összes projekt összes felhasználóját. Ezt törölhetjük, és felvehetjük helyette az ALLOWEDVALUES szabályt, ahol felsorolhatjuk a választható elemeket. Praktikus felhasználói csoportot megadni, ahol szerver szintű csoportra [Global]\csoportnév, az aktuális projekt csoportjaira pedig [Project]\csoportnév formában hivatkozhatunk. Például:

vs-field-definition-allowedvalues

A Rule Type ablakban megjelenő lehetőségek teljes dokumentációja megtalálható az MSDN All FIELD XML elements reference oldalán.

Save hatására a módosítások közvetlenül a szerverre mentődnek vissza, de hogy a Studio is érzékelje őket, célszerű egy frissítést kérni a Team Explorer ablakban.

 

Technorati-címkék: ,,

UriFormatException TFS teszt e-mail küldésekor

A Team Foundation Server Administration Console egy igen barátságos alkalmazás. Látszik, hogy a felület tervezésekor végiggondolták a tipikus üzemeltetői feladatokat, ezért lehet például könnyen megváltoztatni a service accountot vagy a szerver URL-jét, ráadásul szinte minden beállítás mellett ott van kéznél egy Test gomb, amivel gyorsan kipróbálhatjuk, hogy jó értéket adtunk-e meg.

Az egyik hasznos funkció, hogy a levelezési beállítások mellett található egy Send Test Email funkció:

tfs-email-settings

Ha rákattintunk, akkor a felugró ablakban meg kell adnunk a teszt levél címzettjének e-mail címét és egy szöveget, ami bekerül a levélbe:

tfs-test-email

Ha szerencsénk van, akkor simán el is megy a levél:

tfs-test-email-success

Azonban előfordulhat, hogy nem sikerül a küldés, hanem az alábbi hibaüzenetet kapjuk:

Unable to connect to the TFS server to test email settings. Url = ‘/_api/_common/TestMailSettings?sendTo=myuser%40example.com&message=Test+email’. Exception = System.UriFormatException: Invalid URI: The format of the URI could not be determined.
   at System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind)
   at System.Net.WebRequest.Create(String requestUriString)
   at Microsoft.TeamFoundation.Admin.Console.Models.DlgSendTestMailViewModel.SendEmail()

tfs-test-email-error

Az ember ilyenkor átnézi az e-mail küldés beállításait, csakhogy a hibát jelen esetben nem ott kell keresni. Nyissuk meg a Change URLs ablakot, és ellenőrizzük, hogy a Server URL rovatban a Use localhost opció legyen kiválasztva:

tfs-change-urls

Az e-mail küldéses hiba ugyanis csak akkor jön elő, ha a második opciót választjuk, és localhost helyett a gép nevét adjuk meg a Use: rovatban. Akit érint, a Connecten szavazhat, hátha hamarosan kijavítják.

 

Technorati-címkék: ,

TFS 2005 frissítése 2013-ra adatbázis túrással

A tanszéken van egy régi source control szerverünk, ami Team Foundation Server 2005-t futtat, azt a bizonyos 1.0 verziót. Tekintve, hogy alatta már az operációs rendszer, az SQL Server és a SharePoint is kiöregedett, nem beszélve a hardverről, elhatároztam, hogy megfrissítem, méghozzá a 2013 verzióra. A dolog szépségét az adja, hogy nem lehet egyetlen lépésben 2005-ről 2013-ra frissíteni (ami nem is meglepő, hiszen volt köztük 3 verzió), hanem először 2010-re érdemes, ahonnan lehet 2013-ra:

tfs-2005-2013

A 2005-ről 2010-re frissítés trükkös, mert SQL-t és SharePointot is kell frissíteni, amihez nagy segítség a TFS Setup Support Team blogján található leírás és best practice gyűjtemény. A WSS 2.0-3.0 frissítéshez szintén van egy hasznos blog bejegyzés a TFS csapat blogjában.

A TFS frissítése elméletileg egy viszonylag egyszerű folyamat: el kell távolítani az előző verziót, de meg kell hagyni az adatbázisokat az SQL Serverben, majd fel kell telepíteni az új verziót, és a telepítő varázsló Upgrade opciójával csatlakozni kell a régi adatbázishoz, amit a telepítő meg fog frissíteni. Elméletben tényleg nem tűnik bonyolultnak, ráadásul Tim Elhajj Upgrade Team Foundation Server 2012: The Ultimate Upgrade Guide című 61 oldalas step-by-step képeskönyve is sokat segít.

A gyakorlat azonban kicsit más.

Kezdjük ott, hogy sajnos egyik leírásban sincs benne, hogy a TFS 2010 upgrade folyamatban van egy hiba, ami inkonzisztenciát okozhat az adatbázisban, ezért némileg trükközni kell a frissítés során. Erről Brian Harry TFS 2010 Upgrade Issue című cikkében olvashatunk, ahol a hotfix is megtalálható.

Ami azonban még zavaróbb, hogy a simán lefutó frissítés után nem sikerült csatlakoznom a szerverhez, amiről a különböző kliensek nagyon változatos hibaüzenetekkel tájékoztattak, például:

TF400324: Team Foundation services are not available from server MyServer\MyCollection. Technical information (for administrator): Unable to connect to the remote server.

Vagy:

TF205020: A connection could not be made to the following server: MyServer\MyCollection. This server was used during your most recent session, but it might be offline, or network problems might be preventing the connection. Contact the administrator for Team Foundation Server to confirm that the server is available on the network.

Vagy egyszerűen csak:

TF31002: Unable to connect to this Team Foundation Server

A csúcs az volt, amikor a szerveren futó Team System Web Access elérte az adatokat, de a távoli Visual Studio kliens nem tudott csatlakozni, pedig a Network Monitor szerint ment a forgalom szépen, csak épp HTTP 4xx és 5xx hibák jöttek a szerverről (ez egyébként az IIS logban is látszik). Volt olyan is, hogy sikerült csatlakozni a collectionhöz, a work itemeket sikerült is elérni, de a source controlban lévő fájlokat és azok történetét nem.

A különösen érdekes az volt a dologban, hogy a cél szerveren létrehozott új collectiont tökéletesen elérték a kliensek, tehát nem a rendszer szintű beállításokkal (pl. port, tűzfal, tanúsítvány) volt gond, hanem a frissített adatbázisban nem stimmelt valami. Lefuttattam a TFS 2013 Power Toys-ban lévő Best Practices Analyzert, de nem talált semmit sem szerver, sem collection szinten.

Mivel kifogytam az ötletekből, elővettem az SQL adatbázist közvetlenül. Néztem a forgalmat Profilerrel, illetve belenéztem a táblákba Management Studioval, és összehasonlítottam a frissen létrehozott, működő collection adatbázisát a nem működő, frissített adatbázis tartalmával. Így leltem rá a tbl_ServiceDefinition táblára, amiről ugyan dokumentációt nem találtam, de ránézésre a TFS webszolgáltatásaihoz tartozó .ASMX URL végpontokat tartalmazza. Érdekes módon míg az új adatbázisban többnyire minden cella ki volt töltve, addig a frissített adatbázisban a sorok jelentős részében a RelativePath mező értéke NULL volt. Vettem egy nagy levegőt, készítettem egy snapshotot a virtuális gépről, és megfrissítettem a tbl_ServiceDefinition tábla RelativeToSetting, RelativePath és IsSingleton oszlopait azokban a sorokban, ahol a RelativePath NULL volt, és az Identifier oszlopban lévő GUID alapján találtam egyező sort a működő adatbázisban. Íme a végeredmény:

tfs-service-definitions

A klienseken kitöröltem a Visual Studio Team Explorer cache mappát (C:\Users\felhasználónév\AppData\Local\Microsoft\Team Foundation), újra felvettem a szervert, ééééééééééés működött!

Hozzá kell tennem, hogy ez semmilyen szempontból nem jó módszer, nem támogatott és nem is javasolt. Aki hasonlóval küzd, valószínűleg sokkal jobban jár, ha a Microsoft hivatalos terméktámogatásához fordul!

Ezzel együtt ezek után már nem is volt annyira vészes a Configure Features varázsló és a process template-ek manuális frissítése.