سؤال

لدي حاليا التطبيق عرض بناء عدد في عنوان النافذة.هذا جيد إلا أنه لا يعني شيئا أن معظم المستخدمين الذين تريد أن تعرف إذا كان لديك أحدث بناء - أنها تميل إلى الرجوع إلى أنها "يوم الخميس الماضي" بدلا من بناء 1.0.8.4321.

الخطة هو وضع تاريخ البناء هناك بدلا من ذلك - حتى "التطبيق المدمج في 21/10/2009" على سبيل المثال.

أنا تكافح من أجل العثور على طريقة برمجية لسحب بناء التاريخ باعتباره سلسلة نصية عن استخدام مثل هذا.

من أجل بناء عدد اعتدت:

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

بعد تحديد كيف جاء.

أريد شيئا مثل هذا ترجمة في تاريخ (و الوقت للحصول على نقاط المكافأة).

مؤشرات هنا محل تقدير كبير (عذر التورية إذا كان ذلك مناسبا) ، أو أكثر إتقانا حلول...

هل كانت مفيدة؟

المحلول

جيف أتوود كان عدد قليل من الأشياء أن أقول حول هذه المسألة في تحديد تاريخ بناء الطريق الصعب.

الأسلوب الأكثر موثوقية تبين أن استرداد رابط الزمني من PE header المضمنة في الملف القابل للتنفيذ-بعض التعليمات البرمجية C# (جو سبيفي) على أن من التعليقات على جيف المادة:

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;
}

استخدام على سبيل المثال:

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

تحديث:الأسلوب كان يعمل .صافي النواة 1.0, ولكن توقفت عن العمل بعد .صافي الأساسية 1.1 الإفراج عن(يعطي عشوائية سنوات في 1900-2020 المدى)

نصائح أخرى

إضافة أدناه إلى ما قبل بناء سطر الأوامر الحدث:

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

إضافة هذا الملف ك الموارد، الآن لديك سلسلة "تاريخ بنية" في الموارد الخاصة بك.

لخلق موارد، انظر كيفية إنشاء واستخدام الموارد في. NET .

الطريقة

وكما أشار @ c00000fd في تعليقات . مايكروسوفت تغير هذا. وبينما كثير من الناس لا تستخدم أحدث نسخة من المترجم لهم وأظن أن هذا التغيير يجعل هذا النهج سيئة مما لا شك فيه. وعلى الرغم من انها متعة ممارسة أوصي الناس لتضمين مجرد تاريخ بناء إلى ثنائي من خلال بأي وسيلة أخرى ضرورية إذا من المهم أن تتبع تاريخ بناء ثنائي نفسها.

ويمكن القيام بذلك مع بعض رمز جيل تافهة والتي ربما هي الخطوة الأولى في بناء السيناريو الخاص بك بالفعل. هذا، وحقيقة أن ALM / بناء / DevOps أدوات تساعد كثيرا مع هذا، وينبغي أن فضلت أي شيء آخر.

أترك بقية هذه الإجابة هنا لأغراض تاريخية فقط.

الطريقة الجديدة

ولقد غيرت رأيي حول هذا الموضوع، وتستخدم حاليا هذه الخدعة للحصول على تاريخ البناء الصحيح.

#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

تحليل الطريقة القديمة

حسنا، كيف يمكنك أن تولد بناء الأرقام؟ ل Visual Studio (أو C # مترجم) يوفر في الواقع أرقام الإنشاء والمراجعة التلقائية إذا قمت بتغيير سمة AssemblyVersion إلى مثل 1.0.*

وماذا سيحدث هو أن هو أن بناء سوف يكون مساويا لعدد الأيام منذ 1 يناير 2000 بالتوقيت المحلي، وإعادة النظر ليكون مساويا لعدد الثواني منذ منتصف الليل بالتوقيت المحلي، مقسوما على 2.

ورؤية المحتوى المجتمع، تلقائي بناء وأرقام مراجعة

ومنها مثلا. AssemblyInfo.cs

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

وSampleCode.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)

إضافة أدناه إلى ما قبل بناء سطر الأوامر الحدث:

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

إضافة هذا الملف ك الموارد، والآن لديك سلسلة "تاريخ بنية" في الموارد الخاصة بك.

وبعد إدخال الملف إلى الموارد (كملف نصي العام)، والوصول إليها عبر

string strCompTime = Properties.Resources.BuildDate;

لخلق موارد، انظر كيفية إنشاء واستخدام الموارد في. NET .

نهج واحد الذي أنا مندهش أن لا أحد قد ذكر بعد استخدام T4 النص قوالب للحصول على رمز جيل.

<#@ 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); } }
    }
}

الايجابيات:

  • لغة مستقلة
  • تسمح الكثير أكثر من مجرد وقت التجميع

سلبيات:

وفيما يتعلق تقنية سحب بناء المعلومات تاريخ / نسخة من وحدات البايت من رأس PE التجمع، ومايكروسوفت قد تغيرت المعلمات بناء الافتراضية بداية مع Visual Studio 15.4. يتضمن الافتراضي الجديد تجميع القطعية، الأمر الذي يجعل طابع زمني صالح وأرقام الإصدار متزايد تلقائيا شيئا من الماضي. مجال زمني لا تزال موجودة ولكن يحصل شغل مع قيمة دائمة هو تجزئة شيء أو غيرها، ولكن ليس أي إشارة إلى وقت الإنشاء.

بعض خلفية مفصلة هنا

وبالنسبة لأولئك الذين يعطون الاولوية طابع زمني المفيد على تجميع حتمية، ليس هناك وسيلة لتجاوز الافتراضي الجديد. يمكنك تضمين علامة في ملف .csproj للجمعية الفائدة كما يلي:

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

تحديث: أؤيد حل T4 قالب النص الوارد وصفها في إجابة أخرى هنا. اعتدت أن حل قضية بلدي نظيفة دون أن تفقد صالح تجميع القطعية. واحد الحذر في ذلك هو أن Visual ستوديو يعمل فقط مترجم T4 عندما يتم حفظ الملف .tt، وليس في وقت الإنشاء. وهذا يمكن أن يكون محرجا إذا ما استثنينا .cs تنجم عن التحكم بالمصادر (منذ كنت تتوقع أن تكون ولدت) والشيكات مطور آخر من التعليمات البرمجية. دون resaving، لن يكون لديها ملف .cs. وهناك حزمة على nuget (أعتقد أن يسمى AutoT4) أن يجعل تجميع T4 جزء من كل بناء. أنا لم تواجه حتى الآن حل لهذه خلال نشر الإنتاج، ولكن أتوقع شيئا من هذا القبيل لجعل هذا الحق.

وأنا مجرد C # مبتدئ ولذلك ربما يكون جوابي الصوت سخيفة - I عرض التاريخ بناء من تاريخ الملف القابل للتنفيذ وآخر كتابي ل:

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());

ولقد حاولت استخدام طريقة File.GetCreationTime ولكن حصلت على نتائج غريبة: كان التاريخ من الأمر 2012-05-29، لكن أظهر التاريخ من نافذة إكسبلورر 2012-05-23. بعد البحث عن هذا التناقض وجدت أن الملف تم إنشاؤها على الأرجح 2012-05-23 (كما هو موضح من قبل مستكشف ويندوز)، ولكن نسخها إلى المجلد الحالي في 2012/5/29 (كما هو موضح من قبل القيادة File.GetCreationTime) - لذلك أن تكون على الجانب الآمن أستخدمه قيادة File.GetLastWriteTime.

وZalek

لشخص يحتاج للحصول على وقت الترجمة في ويندوز 8 / هاتف ويندوز 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);
            }
        }
    }

لشخص يحتاج للحصول على وقت الترجمة في هاتف ويندوز 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;
    }

ملحوظة: في جميع الحالات التي تقوم بتشغيل في رمل، لذلك عليك أن تكون قادرا على الحصول على وقت الترجمة من التجميعات التي تقوم بنشر مع التطبيق الخاص بك فقط. (لن بمعنى أن هذا لا تعمل على أي شيء في GAC).

الأسلوب أعلاه يمكن أنب الجمعيات تحميلها بالفعل في عملية باستخدام ملف صورة في الذاكرة (بدلا من إعادة قراءته من التخزين):

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;
    }
}

والخيار لم تناقش هنا هو لادخال البيانات الخاصة بك إلى AssemblyInfo.cs، يبدو حقل "AssemblyInformationalVersion" المناسب - لدينا عدة مشاريع حيث كنا نفعل شيئا من هذا القبيل كخطوة البناء (ولكن أنا لست تماما سعيدة مع الطريقة التي يعمل لذلك لا تريد حقا أن إنتاج ما لدينا).

وهناك مقال عن هذا الموضوع على codeproject: http://www.codeproject.com /KB/dotnet/Customizing_csproj_files.aspx

لمشاريع الصافي الأساسية، وتكييفها الجواب Postlagerkarte لتحديث الحقل التجمع حقوق التأليف والنشر مع تاريخ البناء.

مباشرة تحرير csproj

ويمكن إضافة ما يلي مباشرة إلى PropertyGroup لأول مرة في csproj:

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

بديل: البصرية ستوديو خصائص المشروع

وأو لصق التعبير الداخلي مباشرة في مجال حق المؤلف في القسم حزمة من خصائص المشروع في Visual Studio:

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

وهذا يمكن أن يكون مربكا بعض الشيء، بسبب Visual Studio سيقيم التعبير وعرض القيمة الحالية في النافذة، ولكنها ستكون أيضا تحديث ملف المشروع بشكل مناسب وراء الكواليس.

على مستوى الحل عبر Directory.Build.props

ويمكنك صوت نزول المطر العنصر <Copyright> أعلاه في ملف Directory.Build.props في الجذر الحل، وأنها تطبق تلقائيا على جميع المشاريع ضمن الدليل، على افتراض كل مشروع لا تقدم قيمة حقوق التأليف والنشر الخاصة بها.

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

وDirectory.Build.props: تخصيص الإنشاء الخاصة بك

ناتج

وسوف التعبير سبيل المثال تعطيك حق المؤلف مثل هذا:

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

استرجاع

ويمكنك عرض معلومات حقوق النشر من خصائص الملف في ويندوز، أو الاستيلاء عليها في وقت التشغيل:

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

Console.WriteLine(version.LegalCopyright);

والكثير من الإجابات كبيرة هنا ولكن أشعر أنني يمكن أن تضيف بلدي بسبب البساطة والأداء (مقارنة الحلول المتعلقة بالموارد ل) عبر منصة (يعمل مع صافي الأساسية جدا)، وتجنب أي أداة 3rd الطرف. فقط إضافة هذا الهدف msbuild إلى csproj.

<Target Name="Date" BeforeTargets="CoreCompile">
    <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>

والآن لديك Builtin.CompileTime أو new DateTime(Builtin.CompileTime, DateTimeKind.Utc) إذا كنت في حاجة إليها على هذا النحو.

وReSharper ليس ستعمل مثل ذلك. يمكنك تجاهله أو إضافة فئة جزئية في المشروع أيضا ولكنه يعمل على أي حال.

في 2018 بعض من الحلول السابقة لا تعمل بعد الآن أو لا تعمل مع صافي الأساسية.

وأنا استخدم الطريقة التالية التي هي بسيطة ويعمل لبلدي الأساسية. NET المشروع 2.0.

وإضافة ما يلي إلى .csproj الخاص داخل PropertyGroup:

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

وهذا يعرف PropertyFunction التي يمكنك الوصول إليها في حياتك قبل بناء الأوامر.

ولديك ما قبل بناء يشبه هذا

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

وتعيين الخاصية من BuildTimeStamp.txt إلى الموارد المضمنة.

والآن يمكنك أن تقرأ الطابع مثل هذا الوقت

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();
            }
        }
    }

وأنا في حاجة إلى الحل الشامل التي عملت مع مشروع NETStandard على أي منصة (دائرة الرقابة الداخلية، الروبوت، ويندوز). ولتحقيق ذلك، قررت لإنشاء ملف CS عبر برنامج نصي بوويرشيل تلقائيا. هنا هو السيناريو بوويرشيل:

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

وحفظ الملف PowerScript كما GenBuildDate.ps1 وإضافته المشروع. وأخيرا، أضف السطر التالي إلى الحدث ما قبل البناء:

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

تأكد يتم تضمين تأكد BuildDate.cs في المشروع. يعمل مثل بطل على أي نظام تشغيل!

وأنا فقط القيام به:

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

ويمكنك استخدام هذا المشروع: https://github.com/dwcullop/BuildInfo

وويستفيد T4 لأتمتة الطابع الزمني تاريخ الإنشاء. هناك العديد من إصدارات (الفروع المختلفة) بما في ذلك واحد والتي تمنحك بوابة تجزئة فرع سحبه حاليا من، إذا كنت في هذا النوع من الشيء.

والإفصاح: لقد كتبت وحدة

هل يمكن استخدام الحدث المشروع بعد بناء لكتابة ملف نصي إلى الدليل الهدف الخاص بك مع التاريخ والوقت الحالي. هل يمكن بعد ذلك قراءة قيمة في وقت التشغيل. انها hacky قليلا، ولكن ينبغي لها أن تعمل.

ولست متأكدا، ولكن ربما بناء Incrementer يساعد.

مختلفة, PCL-نهج ودية سيكون لاستخدام MSBuild مضمنة المهمة بديلا بناء الزمن في السلسلة التي تم إرجاعها بواسطة الخاصية على التطبيق.نحن نستخدم هذا الأسلوب بنجاح في التطبيق الذي لديه Xamarin.أشكال Xamarin.الروبوت ، Xamarin.دائرة الرقابة الداخلية المشاريع.

تحرير:

مبسطة عن طريق تحريك كل من المنطق في SetBuildDate.targets ملف باستخدام Regex بدلا من سلسلة بسيط استبدال بحيث يمكن تعديل ملف كل بناء من دون "إعادة تعيين".

على MSBuild مضمنة تعريف المهمة (المحفوظة في SetBuildDate.أهداف الملفات المحلية إلى Xamarin.أشكال المشروع على سبيل المثال):

<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>

الاحتجاج أعلاه مضمنة المهمة في Xamarin.أشكال ملف csproj في الهدف 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>

على FilePath يتم تعيين الخاصية إلى BuildMetadata.cs الملف في Xamarin.أشكال المشروع الذي يحتوي على فئة بسيطة مع خاصية سلسلة BuildDate, في أي وقت البناء سيتم استبداله:

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

إضافة هذا الملف BuildMetadata.cs إلى المشروع.سيتم تعديله من قبل كل بناء ، ولكن بطريقة تتيح تكرار يبني (تكرار بدائل) ، لذلك قد تشمل أو إسقاطها في مصدر عنصر التحكم كما تريد.

وعملية تحديث صغير على الاجابة "الطريق الجديد" من جون.

وتحتاج لبناء مسار بدلا من استخدام سلسلة تعليمات البرمجة الأساسية عند العمل مع ASP.NET/MVC

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

هل يمكن إطلاق خطوة إضافية في عملية الإنشاء أن يكتب تاريخ الطوابع إلى ملف ومن ثم يمكن عرضها.

في خصائص المشاريع التبويب نظرة على علامة التبويب الأحداث بناء. هناك خيار لتنفيذ أمر بناء ما قبل أو ما بعد.

واعتدت اقتراح عبد الرحيم و. ومع ذلك، يبدو أن إعطاء تنسيق وقت غريب، وأضاف أيضا اختصار لهذا اليوم كجزء من تاريخ بناء؛ مثال: الأحد 2017/12/24 13: 21: 05.43. أنا في حاجة فقط مجرد تاريخ لذلك اضطررت لقضاء بقية باستخدام فرعية.

وبعد إضافة echo %date% %time% > "$(ProjectDir)\Resources\BuildDate.txt"to حالة ما قبل البناء، وأنا فعلت ما يلي:

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

والخبر السار هنا هو أنه يعمل.

إذا هذا هو التطبيق ويندوز، يمكنك فقط استخدام مسار التطبيق قابل للتنفيذ: جديد System.IO.FileInfo (Application.ExecutablePath) .LastWriteTime.ToString ( "YYYY.MM.DD")

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top