52 votes

Visual Studio 2017 fonctionne-t-il avec les contrats de code ?

Je viens d'installer la nouvelle version de Visual Studio 2017 Enterprise (RC). J'ai du mal à le faire fonctionner avec Contrats de code Cependant. Je n'ai aucun problème à utiliser les contrats de code avec Visual Studio 2015. Est-ce que quelque chose m'échappe ?

0 votes

Quelqu'un de Microsoft pourrait-il faire un commentaire ?

0 votes

Quelqu'un de l'équipe Microsoft VS ??? VS2017 fonctionne-t-il avec CodeContracts ?

3 votes

Question officielle sur github "CodeContracts ne fonctionne pas dans VS2017" #476 est ouvert, ainsi que Support de Visual Studio 2017 #451

27voto

Jeremy Caney Points 779

Comme d'autres l'ont fait remarquer, Microsoft n'a pas donné la priorité aux contrats de code et à ses le soutien à long terme reste incertain (bien qu'il y ait a il y a eu quelques discussion en cours sur l'intégration au niveau de la langue via Roslyn).

A partir de 11 mars 2017 Cependant, le contributeur communautaire Yaakov a, au moins, mis à jour le code source pour inclure le Cibles de construction de Visual Studio 2017 (merci !). Cette version supporte à la fois la vérification statique lors de la compilation, ainsi que la validation à l'exécution à l'aide de CCRewrite .

Note : Cette version ne pas fournir un support de configuration via le le volet des propriétés du projet . En tant que tel, les contrats de code devront être configurés en ajoutant manuellement les propriétés appropriées à l'élément csproj fichier. Voir la réponse de @crimbo ci-dessous pour un liste complète des propriétés .

Malheureusement, bien que ces mises à jour aient été fusionnées dans la branche de code principale, elles ne sont pas reflétées dans la version de l'UE. Distribution sur le marché ou le fonctionnaire Paquet NuGet . En tant que tel, vous devez télécharger et compiler l'application code source à partir du référentiel (ce qui est facile ; il suffit d'utiliser la commande BuildCC.bat ).

Important : L'analyse statique pour les contrats de code a une dépendance codée en dur à l'égard de .NET 3.5 qui n'est plus installé par défaut, ni dans l'un, ni dans l'autre. Windows 10 ou Visual Studio 2017 . Vous devrez donc vous assurer que cette "fonctionnalité" est activée (ou le télécharger séparément ) ; sinon, vous obtiendrez une erreur de compilation.

Alternativement, à partir de 15 juin 2017 -et mis à jour ultérieurement le 6 février 2018-contributeur. Igor Bek a inclus cette mise à jour dans son Paquet NuGet donc l'approche la plus simple est d'ajouter simplement CodeContracts.MSBuild à votre packages.config via :

Install-Package CodeContracts.MSBuild -Version 1.12.0

Contexte : Igor Bek a d'abord rassemblé ce paquet en tant que preuve de concept pour l'équipe des contrats de code Il a ensuite servi de base à l'élaboration du paquet officiel NuGet (en v1.10.10126.2). Comme Microsoft n'a pas mis à jour le paquet officiel NuGet, le sien est maintenant le plus à jour.

Compte tenu de l'état actuel du support, je n'encouragerais pas les gens à adopter les contrats de code pour de nouveaux projets, mais cela devrait assurer la rétrocompatibilité pour les développeurs qui ont déjà investi dans les contrats de code pour des projets .NET Framework existants.

1 votes

Pour information : j'ai vérifié que ces informations étaient toujours d'actualité au moment de ce commentaire. J'ai modifié le commentaire pour faire un lien vers une mise à jour ultérieure du paquet NuGet d'Igor Bek, qui a été publié depuis que j'ai soumis cette réponse.

14voto

user6706499 Points 121

À l'heure où nous écrivons ces lignes, il n'existe pas de définition de contrat pour VS2017, mais vous pouvez contourner ce problème en utilisant les éléments suivants Paquet Nuget DotNet.Contracts :

  • Naviguez vers le répertoire du paquet nuget de CodeContracts ( DotNet.Contracts.1.10.20606.1\MsBuild )
  • Copiez le v14.0 dossier
  • Renommez-le en v15.0

Tout devrait se construire comme prévu.

0 votes

Merci pour la réponse. Il semble que je doive revenir à la base... comment utilisez-vous le paquet nuget de CodeContracts dans VS2015 ? Avez-vous besoin d'installer un composant supplémentaire (par exemple Contracts.devlab9ts.msi) ?

0 votes

Sans installer Contracts.devlab9ts.msi, je ne vois pas l'onglet "Contrats de code" dans les propriétés du projet.

0 votes

User6706499 - comment avez-vous réussi à le faire fonctionner ? devez-vous installer Contracts.devlab9ts.msi ?

7voto

Edin Points 1368

Il n'existe actuellement aucune version de Contrats de code pour .NET qui prend en charge Visual Studio 2017. Cependant, le problème peut être résolu si vous copiez le fichier cible suivant

C:\Program Files (x86)\MSBuild\4.0\Microsoft.Common.Targets\ImportAfter\CodeContractsAfter.targets

à l'emplacement ImportAfter de votre MSBuild VS2017 :

C:\Program Files (x86)\Microsoft Visual Studio\2017\#YourVS2017Product#\MSBuild\15.0\Microsoft.Common.targets\ImportAfter

Remarque : remplacez #VotreVS2017Product# par le nom de votre produit VS2017 dans le chemin ci-dessus, par exemple Community.

Cela vous permettra de construire avec Code Contracts dans VS2017, mais ne résoudra pas le problème de l'onglet CC qui n'apparaît pas dans les paramètres du projet. Pour cela, vous devrez toujours passer à VS2015.

0 votes

Merci Edin. Cela signifie-t-il que toutes les fonctionnalités des contrats de code fonctionneront, si un projet est déjà configuré pour les utiliser ?

0 votes

Oui, exactement, mais je vous suggère de faire quelques tests pour vous assurer que vos dlls ont été réécrits avec CC.

0 votes

Merci Edin. Nous avons décidé de passer à autre chose, étant donné l'avenir incertain de Microsoft CC. Il nous a fallu environ une semaine pour remplacer Microsoft CC par un mini cadre CC développé en interne afin de préserver les concepts CC et la plupart de ses fonctions. Cependant, les contrats d'interface nous manquent vraiment - je crois que vous voyez ce que je veux dire.

7voto

crimbo Points 572

Les raisons pour lesquelles les contrats de code ne fonctionnent pas dans VS 2017 sont les suivantes :

  1. Les fichiers MSBuild des contrats de code ne sont pas importés dans l'arbre des fichiers MSBuild de VS 2017 (facile à corriger).
  2. L'interface de configuration des contrats de code n'est pas présente dans les propriétés du projet VS 2017 (facilement corrigé en incluant CodeContracts msbuild properties)

Les questions sur l'avenir de CodeContracts sont certainement valables, mais vous pouvez mettre en œuvre ce qui suit pour permettre aux projets existants qui utilisent CodeContracts de construire dans VS 2017 :

  1. Ajoutez le contenu de C:\Program Files (x86)\MSBuild\14.0\Microsoft.Common.Targets\ImportAfter\CodeContractsAfter.targets à vos fichiers csproj (soit directement, soit indirectement via une importation). L'approche la plus basique consiste à ajouter ceci à votre fichier csproj :

    <PropertyGroup>
      <CodeContractsInstallDir Condition="'$(CodeContractsInstallDir)'==''">C:\Program Files (x86)\Microsoft\Contracts\</CodeContractsInstallDir>
    </PropertyGroup>
    <Import Condition="'$(CodeContractsImported)' != 'true' AND '$(DontImportCodeContracts)' != 'true'" Project="$(CodeContractsInstallDir)MsBuild\v$(VisualStudioVersion)\Microsoft.CodeContracts.targets" />

Notez que le premier PropertyGroup ne devrait pas être nécessaire si CodeContracts est installé, parce que CodeContractsInstallDir doit être spécifié comme une variable d'environnement. Dans ce cas, vous pouvez vous en sortir en ajoutant simplement

<Import Condition="'$(CodeContractsImported)' != 'true' AND '$(DontImportCodeContracts)' != 'true'" Project="$(CodeContractsInstallDir)MsBuild\v$(VisualStudioVersion)\Microsoft.CodeContracts.targets" />

à vos fichiers *.csproj.

  1. Spécifiez toutes les propriétés de CodeContracts dans votre fichier *.csproj (directement ou indirectement via Import). Par exemple

    <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    
    <!-- Code Contracts settings -->
    <PropertyGroup>
      <CodeContractsAssemblyMode>1</CodeContractsAssemblyMode>
      <CodeContractsEnableRuntimeChecking>True</CodeContractsEnableRuntimeChecking>
      <CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
      <CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
      <CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
      <CodeContractsRuntimeSkipQuantifiers>False</CodeContractsRuntimeSkipQuantifiers>
      <CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
      <CodeContractsNonNullObligations>False</CodeContractsNonNullObligations>
      <CodeContractsBoundsObligations>False</CodeContractsBoundsObligations>
      <CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations>
      <CodeContractsEnumObligations>False</CodeContractsEnumObligations>
      <CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions>
      <CodeContractsInferRequires>False</CodeContractsInferRequires>
      <CodeContractsInferEnsures>False</CodeContractsInferEnsures>
      <CodeContractsInferObjectInvariants>False</CodeContractsInferObjectInvariants>
      <CodeContractsSuggestAssumptions>False</CodeContractsSuggestAssumptions>
      <CodeContractsSuggestRequires>True</CodeContractsSuggestRequires>
      <CodeContractsSuggestEnsures>False</CodeContractsSuggestEnsures>
      <CodeContractsSuggestObjectInvariants>False</CodeContractsSuggestObjectInvariants>
      <CodeContractsDisjunctiveRequires>False</CodeContractsDisjunctiveRequires>
      <CodeContractsRunInBackground>True</CodeContractsRunInBackground>
      <CodeContractsShowSquigglies>False</CodeContractsShowSquigglies>
      <CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
      <CodeContractsEmitXMLDocs>True</CodeContractsEmitXMLDocs>
      <CodeContractsCacheAnalysisResults>True</CodeContractsCacheAnalysisResults>
      <CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
      <CodeContractsReferenceAssembly>Build</CodeContractsReferenceAssembly>
      <CodeContractsAnalysisWarningLevel>0</CodeContractsAnalysisWarningLevel>
    </PropertyGroup>
    
    <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
    </PropertyGroup>
    
    <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
      <CodeContractsRuntimeCheckingLevel>ReleaseRequires</CodeContractsRuntimeCheckingLevel>
    </PropertyGroup>
    
    </Project>

Si vous avez plus de quelques projets, je vous recommande de les placer dans un paquet nuget privé et de référencer ce paquet nuget dans chacun de vos projets. Les paramètres des contrats de code (de l'étape 2) peuvent aller dans votre fichier mycompany.codecontracts.props, et les cibles des contrats de code (de l'étape 1) peuvent aller dans votre fichier mycompany.codecontracts.targets.

Plus d'informations sur l'empaquetage des propriétés/cibles de msbuild dans un paquet nuget ici : https://docs.microsoft.com/en-us/nuget/create-packages/creating-a-package#including-msbuild-props-and-targets-in-a-package

Je suis prêt à fournir un exemple sur GitHub si l'intérêt est suffisant.

0 votes

@crimbo : Merci pour cette réponse détaillée. Mettre cela en place ne semble pas blesser rien pendant le processus de compilation, mais il ne semble pas non plus exécuter correctement CCRewrite. Ainsi, au moment de l'exécution, j'obtiens l'erreur suivante : "Un assemble (probablement " ") doit être réécrit à l'aide des réécritures binaires des contrats de code (CCRewrite) car il appelle Contract.Requires<TEception> et le symbole CONTRACTS_FULL est défini." Est-ce attendu ? Existe-t-il un scénario dans Visual Studio 2017 qui prend en charge CCRewrite ?

1 votes

@crimbo FYI : J'ai contourné le problème ci-dessus en utilisant la nouvelle version de l'outil CodeContracts.MSBuild NuGet, qui comprend les mises à jour des contrats de code nécessaires à la prise en charge de Visual Studio 2017 (au moins en termes de processus MSBuild). Avec cela en place, je vois à la fois l'analyse de code statique ainsi que la réécriture avoir lieu. Cela atténue également la nécessité de modifier les cibles de construction dans les contrats de code, ou de les importer manuellement dans le fichier csproj fichier.

1 votes

@JeremyCaney : J'ai également essayé le paquet NuGet CodeContracts.MSBuild. Cela gère essentiellement l'étape 1 ci-dessus, mais ne gère pas l'étape 2 (il ne l'a pas fait pour moi). ccrewrite ne s'est pas exécuté à moins que les propriétés CodeContracts ne soient définies. Elles peuvent être configurées dans VS 2015 via l'interface utilisateur des paramètres du projet (qui les ajoute à votre .csproj) ; ou elles peuvent être ajoutées manuellement ou importées depuis un fichier.

1voto

Michael Freidgeim Points 4002

J'ai trouvé que les approches suggérées ici n'étaient pas simples, en particulier qu'elles nécessitaient des changements sur les machines de chaque développeur et sur le serveur de construction également.

J'ai décidé de créer mon propre très simplifié version de Contract.Requires() qui ne nécessitera qu'un remplacement global de la using dans les classes appelantes.

using MYCommon.Diagnostics; //System.Diagnostics.Contracts;

Quand/si System.Diagnostics.Contracts sera disponible pour VS 2017 et .NetStandard, il sera facile de revenir à la bonne version.

La classe actuelle est :

    /// <summary>
    ///   Contract.Requires(config != null); in VS 2017 not throw  ArgumentNullException
    /// The class is workaround for https://stackoverflow.com/questions/40767941/does-vs2017-work-with-codecontracts 
    /// </summary>
    public class Contract
    {
        public static void Requires(bool condition, string message = null)
        {
            Requires<ArgumentNullException>(condition, message);
        }
        public static void Requires<TException>(bool condition, string message=null) where TException:Exception , new ()
        {
            if (!condition)
            {
                //https://stackoverflow.com/questions/41397/asking-a-generic-method-to-throw-specific-exception-type-on-fail/41450#41450
                var e=default(TException);
                try
                {
                    message = message ?? "Unexpected Condition"; //TODO consider to pass condition as lambda expression
                    e =  Activator.CreateInstance(typeof(TException), message) as TException;
                }
                catch (MissingMethodException ex)
                {
                    e = new TException();
                }
                throw e;
            }
        }
    }

La limitation essentielle est que l'utilisation typique Contract.Requires(param1!=null); ne me permet pas de lancer l'exception avec le nom du paramètre, et une meilleure utilisation est un peu plus longue :

Contract.Requires<ArgumentNullException>(param1!=null, "param1 is null");

2 votes

Il s'agit d'une stratégie efficace si votre principale préoccupation est la validation en cours d'exécution pour les éléments suivants Requires() . Et il pourrait être étendu pour supporter Assert() , Assume() , Exists() et ForAll() sans trop d'efforts. S'ils sont nécessaires, cependant, il sera peu pratique (sans refactoring majeur des appelants) de supporter Ensures() , Invariant() , Result() ou ValueAtReturn() en utilisant cette approche. En d'autres termes, cela ne fonctionne vraiment que comme un raccourci pour valider les préconditions.

1 votes

Malheureusement, le manque de soutien de Ensure rend cette question discutable. D'autre part, le blanc Require est facile, Ensure est extrêmement difficile.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X