De bouwdatum weergeven

Ik heb momenteel een app die het buildnummer in het titelvenster weergeeft. Dat is goed en wel, behalve dat het niets betekent voor de meeste gebruikers, die willen weten of ze de nieuwste build hebben – ze hebben de neiging om ernaar te verwijzen als “van afgelopen donderdag” in plaats van build 1.0.8.4321.

Het plan is om de bouwdatum daar te plaatsen – Dus bijvoorbeeld “App gebouwd op 21/10/2009”.

Ik heb moeite om een ​​programmatische manier te vinden om de bouwdatum eruit te halen als een tekenreeks voor gebruik op deze manier.

Voor het buildnummer heb ik gebruikt:

Assembly.GetExecutingAssembly().GetName().Version.ToString()

na te hebben gedefinieerd hoe die tot stand kwamen.

Ik zou zoiets willen voor de compilatiedatum (en tijd, voor bonuspunten).

Aanwijzingen hier zeer gewaardeerd (excuseer woordspeling indien van toepassing), of nettere oplossingen…


Antwoord 1, autoriteit 100%

Jeff Atwood had een paar dingen te zeggen over dit probleem in Bepalend Bouwdatum op de harde manier.

De meest betrouwbare methode blijkt het ophalen van de tijdstempel van de linker uit de PE-headeringebed in het uitvoerbare bestand — wat C#-code (door Joe Spivey) daarvoor uit de opmerkingen bij het artikel van Jeff:

public static DateTime GetLinkerTime(this Assembly assembly, TimeZoneInfo target = null)
{
    var filePath = assembly.Location;
    const int c_PeHeaderOffset = 60;
    const int c_LinkerTimestampOffset = 8;
    var buffer = new byte[2048];
    using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
        stream.Read(buffer, 0, 2048);
    var offset = BitConverter.ToInt32(buffer, c_PeHeaderOffset);
    var secondsSince1970 = BitConverter.ToInt32(buffer, offset + c_LinkerTimestampOffset);
    var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
    var linkTimeUtc = epoch.AddSeconds(secondsSince1970);
    var tz = target ?? TimeZoneInfo.Local;
    var localTime = TimeZoneInfo.ConvertTimeFromUtc(linkTimeUtc, tz);
    return localTime;
}

Gebruiksvoorbeeld:

var linkTimeLocal = Assembly.GetExecutingAssembly().GetLinkerTime();

UPDATE: de methode werkte voor .Net Core 1.0, maar werkte niet meer na de release van .Net Core 1.1(geeft willekeurige jaren in het bereik 1900-2020)


Antwoord 2, autoriteit 35%

Voeg hieronder toe aan pre-build event-opdrachtregel:

echo %date% %time% > "$(ProjectDir)\Resources\BuildDate.txt"

Voeg dit bestand toe als bron,
nu heb je de tekenreeks ‘BuildDate’ in je bronnen.

Als u bronnen wilt maken, raadpleegt u Hoe u bronnen kunt maken en gebruiken in . NET.


Antwoord 3, autoriteit 26%

De weg

Zoals aangegeven door @c00000fd in de opmerkingen. Microsoft brengt hier verandering in. En hoewel veel mensen niet de nieuwste versie van hun compiler gebruiken, vermoed ik dat deze verandering deze aanpak ongetwijfeld slecht maakt. En hoewel het een leuke oefening is, zou ik mensen aanraden om gewoon een builddatum in hun binaire bestand in te sluiten op een andere manier die nodig is als het belangrijk is om de builddatum van het binaire bestand zelf bij te houden.

Dit kan worden gedaan met wat triviale codegeneratie, wat waarschijnlijk al de eerste stap in uw buildscript is. Dat, en het feit dat ALM/Build/DevOps-tools hierbij enorm helpen en de voorkeur verdienen boven al het andere.

Ik laat de rest van dit antwoord hier alleen voor historische doeleinden.

De nieuwe manier

Ik ben hierover van gedachten veranderd en gebruik momenteel deze truc om de juiste bouwdatum te krijgen.

#region Gets the build date and time (by reading the COFF header)
// http://msdn.microsoft.com/en-us/library/ms680313
struct _IMAGE_FILE_HEADER
{
    public ushort Machine;
    public ushort NumberOfSections;
    public uint TimeDateStamp;
    public uint PointerToSymbolTable;
    public uint NumberOfSymbols;
    public ushort SizeOfOptionalHeader;
    public ushort Characteristics;
};
static DateTime GetBuildDateTime(Assembly assembly)
{
    var path = assembly.GetName().CodeBase;
    if (File.Exists(path))
    {
        var buffer = new byte[Math.Max(Marshal.SizeOf(typeof(_IMAGE_FILE_HEADER)), 4)];
        using (var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read))
        {
            fileStream.Position = 0x3C;
            fileStream.Read(buffer, 0, 4);
            fileStream.Position = BitConverter.ToUInt32(buffer, 0); // COFF header offset
            fileStream.Read(buffer, 0, 4); // "PE\0\0"
            fileStream.Read(buffer, 0, buffer.Length);
        }
        var pinnedBuffer = GCHandle.Alloc(buffer, GCHandleType.Pinned);
        try
        {
            var coffHeader = (_IMAGE_FILE_HEADER)Marshal.PtrToStructure(pinnedBuffer.AddrOfPinnedObject(), typeof(_IMAGE_FILE_HEADER));
            return TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1) + new TimeSpan(coffHeader.TimeDateStamp * TimeSpan.TicksPerSecond));
        }
        finally
        {
            pinnedBuffer.Free();
        }
    }
    return new DateTime();
}
#endregion

Op de oude manier

Nou, hoe genereer je buildnummers? Visual Studio (of de C#-compiler) biedt in feite automatische build- en revisienummers als u het kenmerk AssemblyVersion wijzigt in b.v. 1.0.*

Wat er zal gebeuren is dat de build gelijk zal zijn aan het aantal dagen sinds 1 januari 2000 lokale tijd, en dat de herziening gelijk zal zijn aan het aantal seconden sinds middernacht lokale tijd, gedeeld door 2.

p>

zie Community-inhoud, Automatische build- en revisienummers

bijv. AssemblyInfo.cs

[assembly: AssemblyVersion("1.0.*")] // important: use wildcard for build and revision numbers!

Voorbeeldcode.cs

var version = Assembly.GetEntryAssembly().GetName().Version;
var buildDateTime = new DateTime(2000, 1, 1).Add(new TimeSpan(
TimeSpan.TicksPerDay * version.Build + // days since 1 January 2000
TimeSpan.TicksPerSecond * 2 * version.Revision)); // seconds since midnight, (multiply by 2 to get original)

Antwoord 4, autoriteit 17%

Voeg hieronder toe aan pre-build event-opdrachtregel:

echo %date% %time% > "$(ProjectDir)\Resources\BuildDate.txt"

Voeg dit bestand toe als bron, nu heb je de tekenreeks ‘BuildDate’ in je bronnen.

Na het invoegen van het bestand in de bron (als openbaar tekstbestand), heb ik het geopend via

string strCompTime = Properties.Resources.BuildDate;

Als u bronnen wilt maken, raadpleegt u Hoe u bronnen kunt maken en gebruiken in . NET.


Antwoord 5, autoriteit 14%

Een benadering die tot mijn verbazing nog niemand heeft genoemd, is het gebruik van T4-tekstsjablonenvoor het genereren van codes.

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System" #>
<#@ output extension=".g.cs" #>
using System;
namespace Foo.Bar
{
    public static partial class Constants
    {
        public static DateTime CompilationTimestampUtc { get { return new DateTime(<# Write(DateTime.UtcNow.Ticks.ToString()); #>L, DateTimeKind.Utc); } }
    }
}

Pluspunten:

  • Lokaal onafhankelijk
  • Maakt veel meer mogelijk dan alleen de tijd van compilatie

Nadelen:


Antwoord 6, autoriteit 9%

Veel goede antwoorden hier, maar ik heb het gevoel dat ik mijn eigen antwoorden kan toevoegen vanwege de eenvoud, prestaties (vergeleken met resource-gerelateerde oplossingen), cross-platform (werkt ook met Net Core) en het vermijden van tools van derden. Voeg gewoon dit msbuild-doel toe aan de csproj.

<Target Name="Date" BeforeTargets="BeforeBuild">
    <WriteLinesToFile File="$(IntermediateOutputPath)gen.cs" Lines="static partial class Builtin { public static long CompileTime = $([System.DateTime]::UtcNow.Ticks) %3B }" Overwrite="true" />
    <ItemGroup>
        <Compile Include="$(IntermediateOutputPath)gen.cs" />
    </ItemGroup>
</Target>

en nu heb je Builtin.CompileTimein dit project, bijvoorbeeld:

var compileTime = new DateTime(Builtin.CompileTime, DateTimeKind.Utc);

ReSharper zal het niet leuk vinden. Je kunt hem negeren of een gedeeltelijke klas aan het project toevoegen, maar het werkt hoe dan ook.

UPD: Tegenwoordig heeft ReSharper een optie op een eerste pagina met Opties: “MSBuild-toegang”, “Gegevens ophalen van MSBuild na elke compilatie”. Dit helpt bij de zichtbaarheid van gegenereerde code.


Antwoord 7, autoriteit 6%

Wat betreft de techniek van het ophalen van bouwdatum-/versie-informatie uit de bytes van een PE-header van een assembly, heeft Microsoft de standaard buildparameters gewijzigd, beginnend met Visual Studio 15.4. De nieuwe standaard omvat deterministische compilatie, waardoor een geldige tijdstempel en automatisch verhoogde versienummers tot het verleden behoren. Het tijdstempelveld is nog steeds aanwezig, maar wordt gevuld met een permanente waarde die een hash is van het een of ander, maar geen indicatie van de bouwtijd.

Hier vindt u gedetailleerde achtergrondinformatie

Voor degenen die een nuttige tijdstempel voorrang geven boven deterministische compilatie, is er een manier om de nieuwe standaardwaarde te negeren. U kunt als volgt een tag in het .csproj-bestand van de betreffende assembly opnemen:

 <PropertyGroup>
      ...
      <Deterministic>false</Deterministic>
  </PropertyGroup>

Bijwerken:
Ik onderschrijf de T4-tekstsjabloonoplossing die hier in een ander antwoord wordt beschreven. Ik gebruikte het om mijn probleem netjes op te lossen zonder het voordeel van deterministische compilatie te verliezen. Een waarschuwing hierover is dat Visual Studio de T4-compiler alleen uitvoert wanneer het .tt-bestand wordt opgeslagen, niet tijdens het bouwen. Dit kan lastig zijn als je het .cs-resultaat uitsluit van bronbeheer (omdat je verwacht dat het wordt gegenereerd) en een andere ontwikkelaar de code uitcheckt. Zonder opnieuw op te slaan, hebben ze het .cs-bestand niet. Er is een pakket op nuget (volgens mij AutoT4 genoemd) dat T4-compilatie onderdeel maakt van elke build. Ik ben de oplossing hiervoor nog niet tegengekomen tijdens de productie-implementatie, maar ik verwacht dat iets soortgelijks het goed zal maken.


Antwoord 8, autoriteit 5%

Voor .NET Core-projecten heb ik het antwoord van Postlagerkarte aangepast om het copyright-veld van de assembly bij te werken met de bouwdatum.

Csproj direct bewerken

Het volgende kan direct worden toegevoegd aan de eerste PropertyGroupin de csproj:

<Copyright>Copyright © $([System.DateTime]::UtcNow.Year) Travis Troyer ($([System.DateTime]::UtcNow.ToString("s")))</Copyright>

Alternatief: Visual Studio-projecteigenschappen

Of plak de innerlijke expressie rechtstreeks in het veld Copyright in het gedeelte Pakket van de projecteigenschappen in Visual Studio:

Copyright © $([System.DateTime]::UtcNow.Year) Travis Troyer ($([System.DateTime]::UtcNow.ToString("s")))

Dit kan een beetje verwarrend zijn, omdat Visual Studio de uitdrukking evalueert en de huidige waarde in het venster weergeeft, maar het projectbestand achter de schermen ook op de juiste manier bijwerkt.

Oplossing via Directory.Build.props

Je kunt het <Copyright>element hierboven in een Directory.Build.propsbestand in de root van je oplossing ploppen en het automatisch laten toepassen op alle projecten binnen de directory, ervan uitgaande dat elk project niet zijn eigen Copyright-waarde levert.

<Project>
 <PropertyGroup>
   <Copyright>Copyright © $([System.DateTime]::UtcNow.Year) Travis Troyer ($([System.DateTime]::UtcNow.ToString("s")))</Copyright>
 </PropertyGroup>
</Project>

Directory.Build.props: Pas uw build aan

Uitvoer

De voorbeelduitdrukking geeft u een copyright zoals dit:

Copyright © 2018 Travis Troyer (2018-05-30T14:46:23)

Ophalen

Je kunt de copyrightinformatie bekijken via de bestandseigenschappen in Windows, of deze tijdens runtime pakken:

var version = FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly().Location);
Console.WriteLine(version.LegalCopyright);

Antwoord 9, autoriteit 5%

Ik ben maar een C#-newbie, dus misschien klinkt mijn antwoord gek – ik geef de builddatum weer vanaf de datum waarop het uitvoerbare bestand voor het laatst is geschreven:

string w_file = "MyProgram.exe"; 
string w_directory = Directory.GetCurrentDirectory();
DateTime c3 =  File.GetLastWriteTime(System.IO.Path.Combine(w_directory, w_file));
RTB_info.AppendText("Program created at: " + c3.ToString());

Ik heb geprobeerd de File.GetCreationTime-methode te gebruiken, maar kreeg vreemde resultaten: de datum van het commando was 29-05-2012, maar de datum van de Window Explorer toonde 23-05-2012. Na het zoeken naar deze discrepantie ontdekte ik dat het bestand waarschijnlijk is gemaakt op 23-05-2012 (zoals weergegeven door Windows Verkenner), maar gekopieerd naar de huidige map op 2012-05-29 (zoals weergegeven door de opdracht File.GetCreationTime) – dus voor de zekerheid gebruik ik de opdracht File.GetLastWriteTime.

Zalek


Antwoord 10, autoriteit 3%

In 2018 werken sommige van de bovenstaande oplossingen niet meer of werken ze niet met .NET Core.

Ik gebruik de volgende aanpak die eenvoudig is en werkt voor mijn .NET Core 2.0-project.

Voeg het volgende toe aan uw .csproj in de PropertyGroup:

   <Today>$([System.DateTime]::Now)</Today>

Dit definieert een PropertyFunctionwaartoe u toegang hebt in uw pre build commando.

Uw pre-build ziet er zo uit

echo $(today) > $(ProjectDir)BuildTimeStamp.txt

Stel de eigenschap van de BuildTimeStamp.txt in op Embedded resource.

Nu kun je de tijdstempel zo lezen

public static class BuildTimeStamp
    {
        public static string GetTimestamp()
        {
            var assembly = Assembly.GetEntryAssembly(); 
            var stream = assembly.GetManifestResourceStream("NamespaceGoesHere.BuildTimeStamp.txt");
            using (var reader = new StreamReader(stream))
            {
                return reader.ReadToEnd();
            }
        }
    }

Antwoord 11, autoriteit 3%

De bovenstaande methode kan worden aangepast voor assemblages die al in het proces zijn geladendoor de afbeelding van het bestand in het geheugen te gebruiken (in plaats van het opnieuw uit de opslag te lezen):

using System;
using System.Runtime.InteropServices;
using Assembly = System.Reflection.Assembly;
static class Utils
{
    public static DateTime GetLinkerDateTime(this Assembly assembly, TimeZoneInfo tzi = null)
    {
        // Constants related to the Windows PE file format.
        const int PE_HEADER_OFFSET = 60;
        const int LINKER_TIMESTAMP_OFFSET = 8;
        // Discover the base memory address where our assembly is loaded
        var entryModule = assembly.ManifestModule;
        var hMod = Marshal.GetHINSTANCE(entryModule);
        if (hMod == IntPtr.Zero - 1) throw new Exception("Failed to get HINSTANCE.");
        // Read the linker timestamp
        var offset = Marshal.ReadInt32(hMod, PE_HEADER_OFFSET);
        var secondsSince1970 = Marshal.ReadInt32(hMod, offset + LINKER_TIMESTAMP_OFFSET);
        // Convert the timestamp to a DateTime
        var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
        var linkTimeUtc = epoch.AddSeconds(secondsSince1970);
        var dt = TimeZoneInfo.ConvertTimeFromUtc(linkTimeUtc, tzi ?? TimeZoneInfo.Local);
        return dt;
    }
}

Antwoord 12, autoriteit 3%

Ik doe gewoon:

File.GetCreationTime(GetType().Assembly.Location)

Antwoord 13, autoriteit 3%

Voor iedereen die de compileertijd nodig heeft in Windows 8 / Windows Phone 8:

   public static async Task<DateTimeOffset?> RetrieveLinkerTimestamp(Assembly assembly)
    {
        var pkg = Windows.ApplicationModel.Package.Current;
        if (null == pkg)
        {
            return null;
        }
        var assemblyFile = await pkg.InstalledLocation.GetFileAsync(assembly.ManifestModule.Name);
        if (null == assemblyFile)
        {
            return null;
        }
        using (var stream = await assemblyFile.OpenSequentialReadAsync())
        {
            using (var reader = new DataReader(stream))
            {
                const int PeHeaderOffset = 60;
                const int LinkerTimestampOffset = 8;
                //read first 2048 bytes from the assembly file.
                byte[] b = new byte[2048];
                await reader.LoadAsync((uint)b.Length);
                reader.ReadBytes(b);
                reader.DetachStream();
                //get the pe header offset
                int i = System.BitConverter.ToInt32(b, PeHeaderOffset);
                //read the linker timestamp from the PE header
                int secondsSince1970 = System.BitConverter.ToInt32(b, i + LinkerTimestampOffset);
                var dt = new DateTimeOffset(1970, 1, 1, 0, 0, 0, DateTimeOffset.Now.Offset) + DateTimeOffset.Now.Offset;
                return dt.AddSeconds(secondsSince1970);
            }
        }
    }

Voor iedereen die de compileertijd nodig heeft in Windows Phone 7:

   public static async Task<DateTimeOffset?> RetrieveLinkerTimestampAsync(Assembly assembly)
    {
        const int PeHeaderOffset = 60;
        const int LinkerTimestampOffset = 8;            
        byte[] b = new byte[2048];
        try
        {
            var rs = Application.GetResourceStream(new Uri(assembly.ManifestModule.Name, UriKind.Relative));
            using (var s = rs.Stream)
            {
                var asyncResult = s.BeginRead(b, 0, b.Length, null, null);
                int bytesRead = await Task.Factory.FromAsync<int>(asyncResult, s.EndRead);
            }
        }
        catch (System.IO.IOException)
        {
            return null;
        }
        int i = System.BitConverter.ToInt32(b, PeHeaderOffset);
        int secondsSince1970 = System.BitConverter.ToInt32(b, i + LinkerTimestampOffset);
        var dt = new DateTimeOffset(1970, 1, 1, 0, 0, 0, DateTimeOffset.Now.Offset) + DateTimeOffset.Now.Offset;
        dt = dt.AddSeconds(secondsSince1970);
        return dt;
    }

Opmerking: in alle gevallen loop je in een sandbox, dus je kunt alleen de compileertijd van assemblies krijgen die je inzet met je app. (d.w.z. dit werkt niet aan alles in de GAC).


Antwoord 14, Autoriteit 2%

De optie die hier niet wordt besproken, is om uw eigen gegevens in Assemblyinfo.cs te plaatsen, het veld “AssemblyinformationalVersion” lijkt gepast – we hebben een paar projecten waar we iets vergelijkbaar met een buildstap (maar ik ben niet helemaal blij met de manier die werkt, dus wil het niet echt reproduceren wat we hebben).

Er is een artikel over het onderwerp op codeproject: http://www.codeproject.com /Kb/dotnet/customizing_csproj_files.aspx


Antwoord 15, Autoriteit 2%

Ik had een universele oplossing nodig die met een Netstandard-project op een platform (IOS, Android en Windows) werkte.) Om dit te bereiken, besloot ik om automatisch een CS-bestand te genereren via een PowerShell-script. Hier is het PowerShell-script:

param($outputFile="BuildDate.cs")
$buildDate = Get-Date -date (Get-Date).ToUniversalTime() -Format o
$class = 
"using System;
using System.Globalization;
namespace MyNamespace
{
    public static class BuildDate
    {
        public const string BuildDateString = `"$buildDate`";
        public static readonly DateTime BuildDateUtc = DateTime.Parse(BuildDateString, null, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
    }
}"
Set-Content -Path $outputFile -Value $class

Sla het PowerScript-bestand op als GenbuildDate.PS1 en voeg het uw project toe. Voeg ten slotte de volgende regel toe aan uw pre-build-evenement:

powershell -File $(ProjectDir)GenBuildDate.ps1 -outputFile $(ProjectDir)BuildDate.cs

Zorg ervoor dat BuildDate.cs is opgenomen in uw project. Werkt als een kampioen op elk besturingssysteem!


Antwoord 16

Een andere, PCL-vriendelijke aanpak zou zijn om een ​​MSBUILD-inline-taak te gebruiken om de buildtijd in een tekenreeks te vervangen die wordt geretourneerd door een woning in de app. We gebruiken deze aanpak met succes in een app met Xamarin.Forms, Xamarin.Android en Xamarin.IOS-projecten.

bewerken:

Vereenvoudigd door alle logica in de SetBuildDate.targetsBestand te verplaatsen en met Regexin plaats van een eenvoudige string te vervangen, zodat het bestand kan worden gewijzigd door elke building zonder een “reset”.

De MSBUILD INLINE-taakdefinitie (opgeslagen in een SetBuildDate.Targets-bestand Lokaal naar het Xamarin.Forms-project voor dit voorbeeld):

<Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' ToolsVersion="12.0">
  <UsingTask TaskName="SetBuildDate" TaskFactory="CodeTaskFactory" 
    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v12.0.dll">
    <ParameterGroup>
      <FilePath ParameterType="System.String" Required="true" />
    </ParameterGroup>
    <Task>
      <Code Type="Fragment" Language="cs"><![CDATA[
        DateTime now = DateTime.UtcNow;
        string buildDate = now.ToString("F");
        string replacement = string.Format("BuildDate => \"{0}\"", buildDate);
        string pattern = @"BuildDate => ""([^""]*)""";
        string content = File.ReadAllText(FilePath);
        System.Text.RegularExpressions.Regex rgx = new System.Text.RegularExpressions.Regex(pattern);
        content = rgx.Replace(content, replacement);
        File.WriteAllText(FilePath, content);
        File.SetLastWriteTimeUtc(FilePath, now);
   ]]></Code>
    </Task>
  </UsingTask>
</Project>

De bovenstaande inline taak oproepen in het Xamarin.Forms csproj-bestand in doel BeforeBuild:

 <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
       Other similar extension points exist, see Microsoft.Common.targets.  -->
  <Import Project="SetBuildDate.targets" />
  <Target Name="BeforeBuild">
    <SetBuildDate FilePath="$(MSBuildProjectDirectory)\BuildMetadata.cs" />
  </Target>

De eigenschap FilePathis ingesteld op een bestand BuildMetadata.csin het Xamarin.Forms-project dat een eenvoudige klasse bevat met een tekenreekseigenschap BuildDate, waarin de bouwtijd zal worden vervangen:

public class BuildMetadata
{
    public static string BuildDate => "This can be any arbitrary string";
}

Voeg dit bestand BuildMetadata.cstoe aan het project. Het wordt bij elke build aangepast, maar op een manier die herhaalde builds (herhaalde vervangingen) mogelijk maakt, dus u kunt het naar wens opnemen of weglaten in broncodebeheer.


Antwoord 17

U kunt dit project gebruiken: https://github.com/dwcullop/BuildInfo

Het maakt gebruik van T4 om het tijdstempel van de bouwdatum te automatiseren. Er zijn verschillende versies (verschillende branches), waaronder een die je de Git Hash geeft van de momenteel uitgecheckte branch, als je van dat soort dingen houdt.

Disclosure: ik heb de module geschreven.


Antwoord 18

Een kleine update over het “New Way”-antwoord van Jhon.

U moet het pad bouwen in plaats van de CodeBase-string te gebruiken wanneer u met ASP.NET/MVC werkt

   var codeBase = assembly.GetName().CodeBase;
    UriBuilder uri = new UriBuilder(codeBase);
    string path = Uri.UnescapeDataString(uri.Path);

Antwoord 19

Je zou een project post-build event kunnen gebruiken om een ​​tekstbestand naar je doelmap te schrijven met de huidige datetime. U kunt de waarde dan tijdens runtime aflezen. Het is een beetje hacky, maar het zou moeten werken.


Antwoord 20

Ik weet het niet zeker, maar misschien helpt de Build Incrementer.


Antwoord 21

Ik heb de suggestie van Abdurrahim gebruikt. Het leek echter een raar tijdformaat te geven en voegde ook de afkorting voor de dag toe als onderdeel van de bouwdatum; voorbeeld: zo 24/12/2017 13:21:05.43. Ik had alleen de datum nodig, dus ik moest de rest elimineren met behulp van substring.

Na het toevoegen van de echo %date% %time% > "$(ProjectDir)\Resources\BuildDate.txt"voor de pre-build-gebeurtenis deed ik het volgende:

string strBuildDate = YourNamespace.Properties.Resources.BuildDate;
string strTrimBuildDate = strBuildDate.Substring(4).Remove(10);

Het goede nieuws is dat het werkte.


Antwoord 22

Een stapsgewijze volledige oplossing voor Visual Studio 2019, zoals ik wou dat ik die had gevonden toen ik jaren geleden begon.

Een tekstbronbestand toevoegen

Toegang tot de eigenschappen van uw project: selecteer uw project in de oplossingsverkenner en klik met de rechtermuisknop op -> eigenschappen of Alt+Enter. Kies op het tabblad Bronnen Bestanden (Ctrl+5). Voeg vervolgens bron toe / voeg nieuw tekstbestand toe. Typ in het pop-upbericht de naam van uw resource, bijvoorbeeld BuildDate: hiermee wordt een nieuw tekstbestand BuildDate.txtgemaakt in uw map Project/Resources, voeg het toe als Project-bestand en registreer het als een resource, die vervolgens toegankelijk is via Properties.Resourcesin C#, of My.Resourcesin VB.

Update het bronbestand automatisch elke keer dat u bouwt

Nu kunt u visuele studio vertellen om een ​​datum in dit bestand te schrijven, telkens wanneer het het project bouwt of opnieuw wordt opgebouwd. Ga hiervoor naar het tabblad Compileren van de projecteigenschappen, kies de gebeurtenissen op en kopieer / plak het volgende in het tekstvak “Pre-build evenement opdrachtregel”:

powershell -Command "((Get-Date).ToUniversalTime()).ToString(\"s\") | Out-File '$(ProjectDir)Resources\BuildDate.txt'"

Deze regel zal BuildDate.txt vinden en schrijven vandaag / NODUTC’s datum en tijd onder het ISO8601-formaat, zoals 2021-09-07T16:08:35

Verkrijg de buildatum op looptijd door het bestand

te lezen

U kunt deze datum vervolgens ophalen bij uw code op looptijd, via de volgende helper (C #):

DateTime CurrentBuildDate = DateTime.Parse(Properties.Resources.BuildDate, null, System.Globalization.DateTimeStyles.RoundtripKind);

Credits


Antwoord 23

U kunt een extra stap starten in het buildproces dat een datumstempel schrijft in een bestand dat vervolgens kan worden weergegeven.

Op het tabblad Projecten Eigenschappen Kijk naar het tabblad Build Events. Er is een optie om een ​​pre- of postbuild-opdracht uit te voeren.


Antwoord 24

Ik heb net pre-build gebeurtenisopdracht toegevoegd:

powershell -Command Get-Date -Format 'yyyy-MM-ddTHH:mm:sszzz' > Resources\BuildDateTime.txt

In de projecteigenschappen om een ​​resourcebestand te genereren dat dan eenvoudig uit de code leest.


Antwoord 25

Ik had moeilijkheden met de voorgestelde oplossingen met mijn project, een .NET Core 2.1-webtoepassing. Ik combineerde verschillende suggesties van hierboven en vereenvoudigde en maakte ook de datum om naar mijn vereiste formaat.

De opdracht ECHO:

echo Build %DATE:~-4%/%DATE:~-10,2%/%DATE:~-7,2% %time% > "$(ProjectDir)\BuildDate.txt"

De code:

Logger.Info(File.ReadAllText(@"./BuildDate.txt").Trim());

het lijkt te werken. De uitvoer:

2021-03-25 18:41:40,877 [1] INFO Config - Build 2021/03/25 18:41:37.58

Niets heel origineel, ik gecombineerde suggesties van hier en andere gerelateerde vragen en vereenvoudigd.


Antwoord 26

voor .NET 5 Ik heb deze methode met succes gebruikt. (Gevonden hier ).

Voeg dit toe aan het .csproj-bestand:

<SourceRevisionId>build$([System.DateTime]::UtcNow.ToString("yyyyMMddHHmmss"))</SourceRevisionId>

Methode voor het bouwen van de datum:

private static DateTime GetBuildDate(Assembly assembly)
{
    const string BuildVersionMetadataPrefix = "+build";
    var attribute = assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>();
    if (attribute?.InformationalVersion != null)
    {
        var value = attribute.InformationalVersion;
        var index = value.IndexOf(BuildVersionMetadataPrefix);
        if (index > 0)
        {
            value = value.Substring(index + BuildVersionMetadataPrefix.Length);
            if (DateTime.TryParseExact(value, "yyyyMMddHHmmss", CultureInfo.InvariantCulture, DateTimeStyles.None, out var result))
            {
                return result;
            }
        }
    }
    return default;
}

Gebruik:

var buildTime = GetBuildDate(Assembly.GetExecutingAssembly());
 buildTime = buildTime.ToLocalTime();

Antwoord 27

GetLastWriteTimewordt niet gewijzigd als u de assembly naar een andere locatie kopieert.

public static class AssemblyExtensions
{
    public static DateTime GetLinkerTime(this Assembly assembly)
    {
        return File.GetLastWriteTime(assembly.Location).ToLocalTime();
    }
}

Antwoord 28

Als dit een Windows-app is, kunt u gewoon het uitvoerbare pad van de toepassing gebruiken:
new System.IO.FileInfo(Application.ExecutablePath).LastWriteTime.ToString(“yyyy.MM.dd”)


Antwoord 29

het zou
Assembly execAssembly = Assembly.GetExecutingAssembly();
var creationTime = new FileInfo(execAssembly.Location).CreationTime;
// "2019-09-08T14:29:12.2286642-04:00"

Other episodes