Realizziamo un progetto plugin con compilazione per diverse versioni di Revit/AutoCAD

Realizziamo un progetto plugin con compilazione per diverse versioni di Revit/AutoCAD

Quando si sviluppano plugin per applicazioni CAD (nel mio caso questi sono AutoCAD, Revit e Renga) nel tempo, appare un problema: vengono rilasciate nuove versioni dei programmi, è necessario apportare modifiche alle API e nuove versioni dei plug-in.

Quando hai un solo plugin o sei ancora un principiante autodidatta in questa materia, puoi semplicemente fare una copia del progetto, modificare i posti necessari al suo interno e assemblare una nuova versione del plugin. Di conseguenza, le successive modifiche al codice comporteranno un aumento multiplo del costo del lavoro.

Man mano che acquisisci esperienza e conoscenza, troverai diversi modi per automatizzare questo processo. Ho percorso questo percorso e voglio dirti cosa ho finito e quanto è conveniente.

Innanzitutto, diamo un'occhiata a un metodo ovvio e che utilizzo da molto tempo.

Collegamenti ai file di progetto

E per rendere tutto semplice, visivo e comprensibile, descriverò tutto utilizzando un esempio astratto di sviluppo di plugin.

Apriamo Visual Studio (ho la versione Community 2019. E sì, in russo) e creiamo una nuova soluzione. Chiamiamolo MySuperPluginForRevit

Realizziamo un progetto plugin con compilazione per diverse versioni di Revit/AutoCAD

Realizzeremo un plugin per Revit per le versioni 2015-2020. Creiamo quindi un nuovo progetto nella soluzione (Net Framework Class Library) e chiamiamolo MySuperPluginForRevit_2015

Realizziamo un progetto plugin con compilazione per diverse versioni di Revit/AutoCAD

Dobbiamo aggiungere collegamenti all'API Revit. Certo, possiamo aggiungere collegamenti a file locali (dovremo installare tutti gli SDK necessari o tutte le versioni di Revit), ma seguiremo subito la strada giusta e collegheremo il pacchetto NuGet. Puoi trovare parecchi pacchetti, ma userò il mio.

Dopo aver collegato il pacchetto, fare clic con il tasto destro sulla voce "riferimenti" e seleziona la voce "Sposta packages.config in PackageReference...»

Realizziamo un progetto plugin con compilazione per diverse versioni di Revit/AutoCAD

Se all'improvviso a questo punto inizi a farti prendere dal panico, perché nella finestra delle proprietà del pacchetto non ci sarà alcun elemento importante "Copia localmente", che dobbiamo assolutamente impostare sul valore falso, quindi niente panico: vai alla cartella con il progetto, apri il file con l'estensione .csproj in un editor conveniente per te (io uso Notepad++) e trova lì una voce sul nostro pacchetto. Adesso appare così:

<PackageReference Include="ModPlus.Revit.API.2015">
  <Version>1.0.0</Version>
</PackageReference>

Aggiungi una proprietà ad esso tempo di esecuzione. Risulterà così:

<PackageReference Include="ModPlus.Revit.API.2015">
  <Version>1.0.0</Version>
  <ExcludeAssets>runtime</ExcludeAssets>
</PackageReference>

Ora, quando si crea un progetto, i file del pacchetto non verranno copiati nella cartella di output.
Andiamo oltre: immaginiamo immediatamente che il nostro plugin utilizzerà qualcosa dell'API Revit, che è cambiata nel tempo con il rilascio di nuove versioni. Bene, oppure dobbiamo semplicemente cambiare qualcosa nel codice a seconda della versione di Revit per la quale stiamo realizzando il plugin. Per risolvere tali differenze nel codice, utilizzeremo i simboli di compilazione condizionale. Apri le proprietà del progetto, vai alla scheda “montaggio" e nel campo "Notazione di compilazione condizionale"scriviamo R2015.

Realizziamo un progetto plugin con compilazione per diverse versioni di Revit/AutoCAD

Tieni presente che il simbolo deve essere aggiunto sia per la configurazione Debug che per quella Release.

Ebbene, mentre siamo nella finestra delle proprietà, andiamo subito alla scheda “applicazione" e nel campo "Spazio dei nomi predefinito» rimuovere il suffisso _2015in modo che il nostro spazio dei nomi sia universale e indipendente dal nome dell'assembly:

Realizziamo un progetto plugin con compilazione per diverse versioni di Revit/AutoCAD

Nel mio caso, nel prodotto finale, i plugin di tutte le versioni vengono inseriti in un'unica cartella, quindi i nomi dei miei assembly rimangono con il suffisso del modulo _20х. Ma puoi anche rimuovere il suffisso dal nome dell'assembly se i file dovrebbero trovarsi in cartelle diverse.

Andiamo al codice del file Classe1.cs e simulare del codice lì, tenendo conto delle diverse versioni di Revit:

namespace MySuperPluginForRevit
{
    using Autodesk.Revit.Attributes;
    using Autodesk.Revit.DB;
    using Autodesk.Revit.UI;

    [Regeneration(RegenerationOption.Manual)]
    [Transaction(TransactionMode.Manual)]
    public class Class1 : IExternalCommand
    {
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
#if R2015
            TaskDialog.Show("ModPlus", "Hello Revit 2015");
#elif R2016
            TaskDialog.Show("ModPlus", "Hello Revit 2016");
#elif R2017
            TaskDialog.Show("ModPlus", "Hello Revit 2017");
#elif R2018
            TaskDialog.Show("ModPlus", "Hello Revit 2018");
#elif R2019
            TaskDialog.Show("ModPlus", "Hello Revit 2019");
#elif R2020
            TaskDialog.Show("ModPlus", "Hello Revit 2020");
#endif
            return Result.Succeeded;
        }
    }
}

Ho subito preso in considerazione tutte le versioni di Revit superiori alla versione 2015 (che erano disponibili al momento in cui scrivo) e ho subito tenuto conto della presenza di simboli di compilazione condizionale, che vengono creati utilizzando lo stesso modello.

Passiamo al clou principale. Creiamo un nuovo progetto nella nostra soluzione, solo per la versione del plugin per Revit 2016. Ripetiamo tutti i passaggi sopra descritti, rispettivamente, sostituendo il numero 2015 con il numero 2016. Ma il file Classe1.cs eliminare dal nuovo progetto.

Realizziamo un progetto plugin con compilazione per diverse versioni di Revit/AutoCAD

File con il codice richiesto - Classe1.cs – ce l’abbiamo già e dobbiamo solo inserirne un collegamento in un nuovo progetto. Esistono due modi per inserire i collegamenti:

  1. Lungo – fare clic con il tasto destro sul progetto e selezionare “aggiungere"->"Elemento esistente", nella finestra che si apre, trova il file richiesto e al posto dell'opzione "aggiungere"seleziona l'opzione"Aggiungi come connessione»

Realizziamo un progetto plugin con compilazione per diverse versioni di Revit/AutoCAD

  1. Короткий – direttamente nel solution explorer, seleziona il file desiderato (o anche file, o anche intere cartelle) e trascinalo in un nuovo progetto tenendo premuto il tasto Alt. Mentre trascini, vedrai che quando premi il tasto Alt, il cursore del mouse cambierà da un segno più a una freccia.
    UPD: Ho fatto un po' di confusione in questo paragrafo: per trasferire più file è necessario tenere premuto Maiusc + Alt!

Dopo aver eseguito la procedura, avremo un file nel secondo progetto Classe1.cs con l'icona corrispondente (freccia blu):

Realizziamo un progetto plugin con compilazione per diverse versioni di Revit/AutoCAD

Quando modifichi il codice nella finestra dell'editor, puoi anche scegliere in quale contesto di progetto visualizzare il codice, il che ti consentirà di vedere il codice modificato sotto diversi simboli di compilazione condizionale:

Realizziamo un progetto plugin con compilazione per diverse versioni di Revit/AutoCAD

Creiamo tutti gli altri progetti (2017-2020) utilizzando questo schema. Trucchetto: se trascini i file in Solution Explorer non dal progetto di base, ma dal progetto in cui sono già inseriti come collegamento, non devi tenere premuto il tasto Alt!

L'opzione descritta è abbastanza buona fino al momento di aggiungere una nuova versione del plugin o fino al momento di aggiungere nuovi file al progetto: tutto ciò diventa molto noioso. E recentemente mi sono improvvisamente reso conto di come risolvere tutto con un progetto e stiamo passando al secondo metodo

La magia delle configurazioni

Dopo aver finito di leggere qui, potresti esclamare: “Perché hai descritto il primo metodo, se l’articolo tratta subito del secondo?!” E ho descritto tutto per rendere più chiaro il motivo per cui abbiamo bisogno di simboli di compilazione condizionale e in quali punti i nostri progetti differiscono. E ora ci diventa più chiaro esattamente quali differenze nei progetti dobbiamo implementare, lasciando solo un progetto.

E per rendere tutto più evidente, non creeremo un nuovo progetto, ma apporteremo delle modifiche al nostro attuale progetto creato nel primo modo.

Quindi, prima di tutto, rimuoviamo tutti i progetti dalla soluzione tranne quello principale (che contiene direttamente i file). Quelli. progetti per le versioni 2016-2020. Apri la cartella con la soluzione ed elimina lì le cartelle di questi progetti.

Abbiamo un progetto rimasto nella nostra decisione - MySuperPluginForRevit_2015. Apri le sue proprietà e:

  1. Nella scheda "applicazione"rimuovi il suffisso dal nome dell'assembly _2015 (il motivo sarà chiaro più avanti)
  2. Nella scheda "montaggio» rimuovere il simbolo di compilazione condizionale R2015 dal campo corrispondente

Nota: l'ultima versione di Visual Studio presenta un bug: i simboli di compilazione condizionale non vengono visualizzati nella finestra delle proprietà del progetto, sebbene siano disponibili. Se riscontri questo problema tecnico, devi rimuoverli manualmente dal file .csproj. Tuttavia, dobbiamo ancora lavorarci, quindi continua a leggere.

Rinominare il progetto nella finestra Esplora soluzioni rimuovendo il suffisso _2015 e quindi rimuovere il progetto dalla soluzione. Ciò è necessario per mantenere l'ordine e i sentimenti dei perfezionisti! Apriamo la cartella della nostra soluzione, rinominiamo la cartella del progetto allo stesso modo e carichiamo nuovamente il progetto nella soluzione.

Apri il gestore della configurazione. Configurazione statunitense Rilasciare in linea di principio non sarà necessario, quindi lo elimineremo. Creiamo nuove configurazioni con nomi che ci sono già familiari R2015, R2016, ..., R2020. Tieni presente che non è necessario copiare le impostazioni da altre configurazioni e non è necessario creare configurazioni di progetto:

Realizziamo un progetto plugin con compilazione per diverse versioni di Revit/AutoCAD

Vai alla cartella con il progetto e apri il file con estensione .csproj in un editor a te conveniente. A proposito, puoi anche aprirlo in Visual Studio: devi scaricare il progetto e quindi l'elemento desiderato sarà nel menu contestuale:

Realizziamo un progetto plugin con compilazione per diverse versioni di Revit/AutoCAD

La modifica in Visual Studio è addirittura preferibile, poiché l'editor allinea e richiede istruzioni.

Nel file vedremo gli elementi Gruppo di proprietà – in cima c’è quello generale, poi vengono le condizioni. Questi elementi impostano le proprietà del progetto quando viene creato. Il primo elemento, che è senza condizioni, imposta proprietà generali e gli elementi con condizioni, di conseguenza, modificano alcune proprietà a seconda delle configurazioni.

Vai all'elemento comune (primo). Gruppo di proprietà e guarda l'immobile Nome Assemblea – questo è il nome dell’assemblea e dovremmo averlo senza suffisso _2015. Se è presente un suffisso, rimuoverlo.

Trovare un elemento con una condizione

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">

Non ne abbiamo bisogno: lo eliminiamo.

Elemento con condizione

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

sarà necessario per lavorare nella fase di sviluppo e debug del codice. Puoi modificare le sue proprietà in base alle tue esigenze: impostare diversi percorsi di output, modificare i simboli di compilazione condizionale, ecc.

Ora creiamo nuovi elementi Gruppo di proprietà per le nostre configurazioni. In questi elementi dobbiamo solo impostare quattro proprietà:

  • Percorso di uscita – cartella di output. Ho impostato il valore predefinito binR20xx
  • DefinisciCostanti – simboli di compilazione condizionale. Il valore deve essere specificato TRACCIA;R20х
  • TargetFrameworkVersion – versione della piattaforma. Versioni diverse dell'API di Revit richiedono la specifica di piattaforme diverse.
  • Nome Assemblea – nome dell'assembly (ovvero nome del file). Puoi scrivere il nome esatto dell'assembly, ma per versatilità consiglio di scrivere il valore $(AssemblyName)_20хх. Per fare ciò, abbiamo precedentemente rimosso il suffisso dal nome dell'assembly

La caratteristica più importante di tutti questi elementi è che possono essere semplicemente copiati in altri progetti senza modificarli affatto. Più avanti nell'articolo allegherò tutto il contenuto del file .csproj.

Ok, abbiamo capito le proprietà del progetto: non è difficile. Ma cosa fare con le librerie di plug-in (pacchetti NuGet). Se guardiamo oltre, vedremo che le librerie incluse sono specificate negli elementi Gruppo di articoli. Ma sfortuna: questo elemento elabora erroneamente le condizioni come elemento Gruppo di proprietà. Forse questo è anche un problema tecnico di Visual Studio, ma se specifichi diversi elementi Gruppo di articoli con le condizioni di configurazione e inserire diversi collegamenti ai pacchetti NuGet all'interno, quindi quando si modifica la configurazione, tutti i pacchetti specificati vengono collegati al progetto.

L'elemento ci viene in aiuto Scegli, che funziona secondo la nostra solita logica se-allora-altro.

Utilizzo dell'elemento Scegli, impostiamo diversi pacchetti NuGet per diverse configurazioni:

Tutti i contenuti csproj

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0"  ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProjectGuid>{5AD738D6-4122-4E76-B865-BE7CE0F6B3EB}</ProjectGuid>
    <OutputType>Library</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>MySuperPluginForRevit</RootNamespace>
    <AssemblyName>MySuperPluginForRevit</AssemblyName>
    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
    <FileAlignment>512</FileAlignment>
    <Deterministic>true</Deterministic>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>binDebug</OutputPath>
    <DefineConstants>DEBUG;R2015</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'R2015|AnyCPU' ">
    <OutputPath>binR2015</OutputPath>
    <DefineConstants>TRACE;R2015</DefineConstants>
    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
    <AssemblyName>$(AssemblyName)_2015</AssemblyName>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'R2016|AnyCPU' ">
    <OutputPath>binR2016</OutputPath>
    <DefineConstants>TRACE;R2016</DefineConstants>
    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
    <AssemblyName>$(AssemblyName)_2016</AssemblyName>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'R2017|AnyCPU' ">
    <OutputPath>binR2017</OutputPath>
    <DefineConstants>TRACE;R2017</DefineConstants>
    <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
    <AssemblyName>$(AssemblyName)_2017</AssemblyName>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'R2018|AnyCPU' ">
    <OutputPath>binR2018</OutputPath>
    <DefineConstants>TRACE;R2018</DefineConstants>
    <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
    <AssemblyName>$(AssemblyName)_2018</AssemblyName>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'R2019|AnyCPU' ">
    <OutputPath>binR2019</OutputPath>
    <DefineConstants>TRACE;R2019</DefineConstants>
    <TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
    <AssemblyName>$(AssemblyName)_2019</AssemblyName>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'R2020|AnyCPU' ">
    <OutputPath>binR2020</OutputPath>
    <DefineConstants>TRACE;R2020</DefineConstants>
    <TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
    <AssemblyName>$(AssemblyName)_2020</AssemblyName>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="System" />
    <Reference Include="System.Core" />
    <Reference Include="System.Xml.Linq" />
    <Reference Include="System.Data.DataSetExtensions" />
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Data" />
    <Reference Include="System.Net.Http" />
    <Reference Include="System.Xml" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Class1.cs" />
    <Compile Include="PropertiesAssemblyInfo.cs" />
  </ItemGroup>
  <Choose>
    <When Condition=" '$(Configuration)'=='R2015' ">
      <ItemGroup>
        <PackageReference Include="ModPlus.Revit.API.2015">
          <Version>1.0.0</Version>
          <ExcludeAssets>runtime</ExcludeAssets>
        </PackageReference>
      </ItemGroup>
    </When>
    <When Condition=" '$(Configuration)'=='R2016' ">
      <ItemGroup>
        <PackageReference Include="ModPlus.Revit.API.2016">
          <Version>1.0.0</Version>
          <ExcludeAssets>runtime</ExcludeAssets>
        </PackageReference>
      </ItemGroup>
    </When>
    <When Condition=" '$(Configuration)'=='R2017' ">
      <ItemGroup>
        <PackageReference Include="ModPlus.Revit.API.2017">
          <Version>1.0.0</Version>
          <ExcludeAssets>runtime</ExcludeAssets>
        </PackageReference>
      </ItemGroup>
    </When>
    <When Condition=" '$(Configuration)'=='R2018' ">
      <ItemGroup>
        <PackageReference Include="ModPlus.Revit.API.2018">
          <Version>1.0.0</Version>
          <ExcludeAssets>runtime</ExcludeAssets>
        </PackageReference>
      </ItemGroup>
    </When>
    <When Condition=" '$(Configuration)'=='R2019' ">
      <ItemGroup>
        <PackageReference Include="ModPlus.Revit.API.2019">
          <Version>1.0.0</Version>
          <ExcludeAssets>runtime</ExcludeAssets>
        </PackageReference>
      </ItemGroup>
    </When>
    <When Condition=" '$(Configuration)'=='R2020' or '$(Configuration)'=='Debug'">
      <ItemGroup>
        <PackageReference Include="ModPlus.Revit.API.2020">
          <Version>1.0.0</Version>
          <ExcludeAssets>runtime</ExcludeAssets>
        </PackageReference>
      </ItemGroup>
    </When>
  </Choose>
  <Import Project="$(MSBuildToolsPath)Microsoft.CSharp.targets" />
</Project>

Tieni presente che in una delle condizioni ho specificato due configurazioni tramite O. In questo modo il pacchetto richiesto verrà collegato durante la configurazione Mettere a punto.

E qui abbiamo quasi tutto perfetto. Carichiamo nuovamente il progetto, abilitiamo la configurazione di cui abbiamo bisogno, chiamiamo la voce “ nel menu contestuale della soluzione (non del progetto)Ripristina tutti i pacchetti NuGet"e vediamo come cambiano i nostri pacchetti.

Realizziamo un progetto plugin con compilazione per diverse versioni di Revit/AutoCAD

E a questo punto sono arrivato a un vicolo cieco: per raccogliere tutte le configurazioni contemporaneamente, potremmo utilizzare l'assemblaggio batch (menu "montaggio"->"Costruzione in batch"), ma quando si cambia configurazione, i pacchetti non vengono ripristinati automaticamente. E durante l'assemblaggio del progetto, anche questo non accade, anche se, in teoria, dovrebbe. Non ho trovato una soluzione a questo problema utilizzando mezzi standard. E molto probabilmente anche questo è un bug di Visual Studio.

Pertanto, per l'assemblaggio in batch, si è deciso di utilizzare uno speciale sistema di assemblaggio automatizzato Nuke. In realtà non lo volevo perché penso che sia eccessivo in termini di sviluppo di plugin, ma al momento non vedo nessun'altra soluzione. E alla domanda “Perché Nuke?” La risposta è semplice: lo usiamo al lavoro.

Quindi, vai alla cartella della nostra soluzione (non al progetto), tieni premuto il tasto Shift e fai clic con il pulsante destro del mouse su uno spazio vuoto nella cartella - nel menu contestuale seleziona la voce "Apri la finestra di PowerShell qui'.

Realizziamo un progetto plugin con compilazione per diverse versioni di Revit/AutoCAD

Se non lo hai installato Nuke, quindi prima scrivi il comando

dotnet tool install Nuke.GlobalTool –global

Ora scrivi il comando Nuke e ti verrà richiesto di configurare Nuke per il progetto attuale. Non so come scriverlo più correttamente in russo - in inglese verrà scritto Impossibile trovare il file .nuke. Vuoi impostare una build? [sì/no]

Premere il tasto Y e poi ci saranno le voci di impostazione diretta. Abbiamo bisogno dell'opzione più semplice utilizzando MSBuild, quindi rispondiamo come nello screenshot:

Realizziamo un progetto plugin con compilazione per diverse versioni di Revit/AutoCAD

Andiamo in Visual Studio, che ci chiederà di ricaricare la soluzione, poiché ad essa è stato aggiunto un nuovo progetto. Ricarichiamo la soluzione e vediamo che abbiamo un progetto costruire in cui siamo interessati ad un solo file - Build.cs

Realizziamo un progetto plugin con compilazione per diverse versioni di Revit/AutoCAD

Apri questo file e scrivi uno script per creare il progetto per tutte le configurazioni. Bene, oppure usa il mio script, che puoi modificare in base alle tue esigenze:

using System.IO;
using Nuke.Common;
using Nuke.Common.Execution;
using Nuke.Common.ProjectModel;
using Nuke.Common.Tools.MSBuild;
using static Nuke.Common.Tools.MSBuild.MSBuildTasks;

[CheckBuildProjectConfigurations]
[UnsetVisualStudioEnvironmentVariables]
class Build : NukeBuild
{
    public static int Main () => Execute<Build>(x => x.Compile);

    [Solution] readonly Solution Solution;

    // If the solution name and the project (plugin) name are different, then indicate the project (plugin) name here
    string PluginName => Solution.Name;

    Target Compile => _ => _
        .Executes(() =>
        {
            var project = Solution.GetProject(PluginName);
            if (project == null)
                throw new FileNotFoundException("Not found!");

            var build = new List<string>();
            foreach (var (_, c) in project.Configurations)
            {
                var configuration = c.Split("|")[0];

                if (configuration == "Debug" || build.Contains(configuration))
                    continue;

                Logger.Normal($"Configuration: {configuration}");

                build.Add(configuration);

                MSBuild(_ => _
                    .SetProjectFile(project.Path)
                    .SetConfiguration(configuration)
                    .SetTargets("Restore"));
                MSBuild(_ => _
                    .SetProjectFile(project.Path)
                    .SetConfiguration(configuration)
                    .SetTargets("Rebuild"));
            }
        });
}

Torniamo alla finestra di PowerShell e scriviamo di nuovo il comando Nuke (puoi scrivere il comando Nuke indicando quanto richiesto Target. Ma ne abbiamo uno Target, che viene eseguito per impostazione predefinita). Dopo aver premuto il tasto Invio ci sentiremo dei veri hacker, perché, come in un film, il nostro progetto verrà assemblato automaticamente per diverse configurazioni.

A proposito, puoi utilizzare PowerShell direttamente da Visual Studio (menu "Vista"->"Altre finestre"->"Console di gestione pacchetti"), ma sarà tutto in bianco e nero, il che non è molto conveniente.

Questo conclude il mio articolo. Sono sicuro che sarai in grado di individuare tu stesso l'opzione per AutoCAD. Spero che il materiale qui presentato trovi i suoi "clienti".

Grazie!

Fonte: habr.com

Aggiungi un commento