Jeg har længe haft dette emne på listen over ting, jeg kunne skrive et par ord om på dotninjas.dk, og så sent som i dag fik jeg en mail fra en kollega, der ikke kunne få et af mine programmer til at køre, fordi programmet fejlagtigt påstod, at nogle filstier på netværkshares ikke fandtes. Problemet var, at han kørte programmet som administrator.

Ironisk nok kan man på Windows 7 komme ud for, at administrator elevation lader til at give begrænsede muligheder, når man tilgår netværkshares.  Dette er en velkendt “feature” i Windows 7, og der findes et workaround.  Løsningen er manuelt at rette i registry, som beskrevet i linket nederst.

En god tommelfingerregel er aldrig at kræve UAC elevation for sine applikationer.  Men selv Visual Studio kræver nogle gange elevation.  Det er f.eks. nødvendigt, når man vil køre ASP.NET web sites på den rigtige IIS (i stedet for IIS Express), eller man ønsker at bruge debugfunktionaliteten attach to process.

I så fald kan det workaround, der er beskrevet i følgende TechNet artikel, være nyttigt:

http://technet.microsoft.com/en-us/library/ee844140(v=ws.10).aspx

CodeMaid er for alle os, der gør en dyd ud af at arrangere sin kode pæn og læsbar. Desværre ved vi jo også af erfaring, at man ikke skal være langt inde i et projekt før der bliver fokuseret mere at skidtet virker og kan leveres til tiden, end at koden kan læses næste gang man har næsen nede i linjerne i en given del af applikationen.

Jeg har længe brugt StyleCop til at forcere ensartet kodestil, men nogle gange er det noget trivielt at flyttet rundt på metoder, slette blanke linjer m.v. for at tilfredsstille StyleCop. Dette er heldigvis én af CodeMaids mange features, og yderligere kan metoder, felter etc. sorteres alfabetisk, så navigationen bliver endnu lettere.

Når man så er i gang med at rydde op i sin kode, så kan man også kaste et blik på den McCabe complexity score, som beregnes. Den siger noget om hvor kompleks en metode er og vil give en god indikation af hvor en refaktorering er nødvendig (eller hvor man skal starte sit code review).

Du finder CodeMaid som Visual Studio Extension her. Selvom den aktuelle version pt. er 0.4.2 så er den stabil og fungerer upåklageligt i VS2010.

Jeg har for lang tid siden skrevet et indlæg på dotninjas om, hvordan man laver en single file generator (også kaldet et custom tool) til Visual Studio.  Desværre ligger det så lang tid tilbage, at jeg ikke kan grave et link frem.  En single file generator benyttes mange steder til at genere kode ud fra indholdet af en anden fil.  For eksempel benyttes det af Entity Framework til at lave klasser ud fra en XML fil som vist på billedet herunder, hvor Custom Tool er sat til “EntityModelCodeGenerator”.

CustomTool

For at lave en Single File Generator skal man implementere nogle bestemte COM interfaces og registrere sin dll på en bestemt måde i registry, og metoden fra min gamle (bortkomne) artikel har fungeret fint indtil fornylig, hvor jeg langt om længe fik mig en Windows 7 64 bit boks på arbejdet.  Jeg har prøvet alt på den maskine både med Wow32To64, og hvad ved jeg.  Men VS 2010 blev ved med fuldstændig at ignorere mit gamle custom tool.

På MSDN er der dokumentation af, hvordan man laver Single File Generators, og der findes også et sample i VS SDK’en, som beskriver, hvordan man kan lave en Single File Generator vha. VS Extensions.  Eksemplet virker fint, men det er ikke særlig godt beskrevet.  Især er det ikke beskrevet, hvordan man sætter projektet op til at blive kompileret helt korrekt, så registry entries bliver genereret korrekt.  Det håber jeg, at dette indlæg kan råde bod på.

Målet er at lave en Single File Generator, der nemt kan distribueres vha. af en .vsix pakke, så den nemt kan installeres som en Visual Studio Extension.  Dette er noget nemmere end min gamle metode, hvor der skulle registreres en dll vha. regasm.exe.

Det er en forudsætning, at man har Visual Studio Service Pack 1 samt Visual Studio SDK Service Pack 1 installeret.  Når SDK’en er installeret, er der adgang til et par VS projekttemplates, som kan bruges til at lave VS Extensions.  Til at lave en Single File Generator, skal man bruge den template, der hedder “VSIX Project”.

vsixproject

Efter projektet er oprettet, skal man først tilføje nogle referencer til en række dll’er for at få fat i de rigtige COM interfaces.  Det drejer sig om følgende:

  • EnvDTE
  • EnvDTE80
  • Microsoft.VisualStudio.Designer.Interfaces
  • Microsoft.VisualStudio.OLE.Interop
  • Microsoft.VisualStudio.Shell.10.0
  • Microsoft.VisualStudio.Immutable.10.0
  • Microsoft.VisualStudio.Interop
  • Microsoft.VisualStudio.Interop.8.0
  • Microsoft.VisualStudio.Interop.9.0
  • Microsoft.VisualStudio.Interop.10.0
  • VSLangProj
  • VSLangProj2
  • VSLangProj80

Det er muligt, at nogle enkelte referencer ikke er nødvendige.  Det har jeg ikke testet.  Det er i øvrigt vigtigt, at alle referencer har “Embed Interop Types” sat til “False”.

EmbedInteropType

Med det ovennævnte sample følger nogle standardimplementationer af to interfaces IVsSingleFileGenerator og IObjectWithSite.  Det nemmeste er at bruge disse implementationer, så vi kopierer BaseCodeGenerator.cs og BaseCodeGeneratorWithSite.cs.  Bemærk, at BaseCodeGenerator indeholder nogle Trace.WriteLine statements, man skal fjerne for at kompilere, hvis man kopierer de to klasser direkte fra eksempelkoden.

Dernæst tilføjes filen CodeGeneratorRegistrationAttribute.cs, som kommer med SDK’en, og som standard ligger under “C:\Program Files (x86)\Microsoft Visual Studio 2010 SDK SP1\VisualStudioIntegration\Common\Source\CSharp\RegistrationAttributes\”.  Denne klasse indeholder en implementation af en custom attribute, som VS benytter til at generere de nødvendige registry entries i en såkaldt .pkgdef fil.  Mere om det om lidt.

Det er nu tiden til at implementere selve kodegenereringen.  Dette gøres ved at tilføje en klasse, som skal nedarve fra BaseCodeGeneratorWithSite.

    [ComVisible(true)]
    [Guid("A4008ECD-02C6-418F-A0BD-083461479064")]
    [CodeGeneratorRegistration(typeof(DotNinjasCodeGenerator), 
        "DotNinjas sample C# code generator", 
        vsContextGuids.vsContextGuidVCSProject, 
        GeneratesDesignTimeSource = true)]
    [ProvideObject(typeof(DotNinjasCodeGenerator))]
    public class DotNinjasCodeGenerator : BaseCodeGeneratorWithSite
    {
        protected override byte[] GenerateCode(string inputFileContent)
        {
            return Encoding.ASCII.GetBytes("// Some generated code goes here");
        }
    }

Ikke overraskende er det metoden GenerateCode, der kaldes af VS, når man kører sit custom tool.  Parameteren inputFileContent vil indeholde indholdet af den fil, som vores custom tool bliver anvendt på.

Bemærk den imponerende række attributes på klassen.

Klassen skal nødvendigvis være COM visible og dermed også have en Guid attribute (husk også at gøre hele assembly COM visible).  CodeGeneratorRegistration benyttes som nævnt til at generere de nødvendige registry settings automatisk.  Disse registry settings ryger i en .pkgdef fil.  Bemærk vsContextGuids.vsContextGuidVCSProject som angiver, at vores kodegenerator vil generere C# kode.  ProvideObject fortæller VS, hvilken klasse der skal oprettes til at generere koden.  Det er et krav, at klassen markeret med ProvideObject skal have en default constructor.  Bemærk at det lidt overraskende er ProvideObjectAttribute, der bestemmer navnet på vores generator.  Dvs. i dette eksempel er det “DotNinjasCodeGenerator”, der skal benyttes som navnet på vores custom tool i VS.

Projektet er nu klar til at kompilere, og der kommer ganske rigtigt en .vsix fil ud som resultat.  Desværre er det ikke nok.  Der mangler en dll og der mangler en .pkgdef fil med de nødvendige registry entries.  For mig var det lidt et mysterium, hvordan jeg fik disse filer genereret, men det kræver, at man redigerer direkte i .csproj filen.  Så start din favorit csproj editor (såsom notepad) og slet følgende linjer:

    <GeneratePkgDefFile>false</GeneratePkgDefFile>
    <IncludeAssemblyInVSIXContainer>false</IncludeAssemblyInVSIXContainer>
    <IncludeDebugSymbolsInVSIXContainer>false</IncludeDebugSymbolsInVSIXContainer>
    <IncludeDebugSymbolsInLocalVSIXDeployment>false</IncludeDebugSymbolsInLocalVSIXDeployment>
    <CopyBuildOutputToOutputDirectory>false</CopyBuildOutputToOutputDirectory>
    <CopyOutputSymbolsToOutputDirectory>false</CopyOutputSymbolsToOutputDirectory>

GeneratePkgDefFile skal væk, så vi får vores .pkgdef fil, og CopyBuiltOutputToOutputDirectory forhindrer, at der bliver kompileret en dll.  Tilføj desuden følgende PropertyGroup i .csproj filen og gem den:

  <PropertyGroup>
    <RegisterOutputPackage>true</RegisterOutputPackage>
    <RegisterWithCodebase>true</RegisterWithCodebase>
  </PropertyGroup>

Efter reload af den nye projektfil, vil en kompilering give følgende output:

projectoutput

Man kan nu teste pakken ved at trykke F5 for debug, hvilket vil starte en ny instans af VS, hvor man kan afprøve vores custom tool.  Vi vil i stedet prøve vores vores custom tool i den virkelige verden.  Så start med at lukke alle instanser af VS og dobbeltklik på .vsix filen og tryk “Install”.  Dette vil installere vores custom tool som en VS Extension, og ved opspart af VS vil man ganske rigtigt kunne finde DotNinjasSingleFileGenerator som installeret extension.  Ønsker man at angive en lidt mere sigende beskrivelse end bare “Empty VSIX project”, kan det gøre ved at rette i source.extension.vsixmanifest filen i VS.

extension

For at teste DotNinjasSingleFileGenerator, opret et nyt C# projekt, tilføj en fil af en type, som normalt ikke benyttes i et C# projekt (f.eks. en .txt fil men ikke en .cs fil) og angiv DotNinjasCodeGenerator som custom tool, da det var DotNinjasCodeGenerator, der blev angivet som type til ProviderObjectAttribute.

customtoolinaction

Højreklik på din fil og vælg “Run custom tool”, hvilket vil resultere i en .cs fil indholdende den genererede kode.

Jeg er egentlig fint tilfreds med de farver Visual Studio 2008/2010 anvender til syntax farvning, men hvis man er til andre farver kan man jo starte med andres farveschemaer. ScottGu twittede et tip om studiostyles.info, hvor man kan dele schemaer.

Et par af schemaerne mindede mig om mine første programmeringssessioner i folkeskolens edb-lokale, fx det monokrome PDP-11

Eller de klassiske Commodore 64 farver;

Jeg har lidt overvejet en af schemaerne med sort baggrund - de ser jo rigtig kodeagtig cool ud, men bliver man ikke træt i øjnene af at se på en sort skærm?

Tilmeld dig her

 Ja, yderligere introduktion af Scott Guthrie behøves vel ikke, men har du sovet under en sten de sidste mange år, så start med at se dokumentaren om Visual Studio på channel 9. Dokumentaren kan i øvrigt også anbefales selvom du kender både ScottGu og Visual Studio :-)

 Ses vi?

Nogle gange kan man være heldig at finde lidt skjult guld gemt i andre blogindlæg.

 I et indlæg om XML i VB.Net forklarer Jim O’Neil hvordan man kan installere et lille addin til Visual Studio, der gør det muligt at indsætte XML fra udklipsholderen til VS som C# kode. Addin'et findes som eksemplet "LinqSamples/PasteXmlAsLinq" i C:\Programmer\Microsoft Visual Studio 9.0\Samples\1033\CSharpSamples.zip, og skal blot kompileres og flyttes til mappen C:\Documents and Settings\[brugernavn]\Dokumenter\Visual Studio 2008\Addins

Dermed bliver et fragment fra det klassiske books.xml eksempel:

    1    <book id="bk110">

    2       <author>O'Brien, Tim</author>

    3       <title>Microsoft .NET: The Programming Bible</title>

    4       <genre>Computer</genre>

    5       <price>36.95</price>

    6       <publish_date>2000-12-09</publish_date>

    7       <description>Microsoft's .NET initiative is explored in

    8       detail in this deep programmer's reference.</description>

    9    </book>

Konverteret til:

    1 XElement xml = new XElement("book",

    2     new XAttribute("id", "bk110"),

    3     new XElement("author", "O'Brien, Tim"),

    4     new XElement("title", "Microsoft .NET: The Programming Bible"),

    5     new XElement("genre", "Computer"),

    6     new XElement("price", "36.95"),

    7     new XElement("publish_date", "2000-12-09"),

    8     new XElement("description",

    9         "Microsoft's .NET initiative is explored in \n" +

   10         "      detail in this deep programmer's reference."

   11     )

   12 );

 

Når det indsættes via menuen Edit -> "Paste XML as XElement", der er synlig, når udklipsholderen indeholder XML. Praktisk Smile