code-contracts visual-studio-2017

code contracts - ¿VS2017 funciona con CodeContracts?



code-contracts visual-studio-2017 (5)

Acabo de instalar el recién lanzado Visual Studio 2017 Enterprise (RC). Sin embargo, tengo problemas para que funcione con Microsoft CodeContracts. No tengo ningún problema para usar CodeContract con VS2015. ¿Me estoy perdiendo de algo?


Actualmente no existe una versión de Code Contracts para .NET que admita Visual Studio 2017. Sin embargo, el problema se puede solucionar si copia el siguiente archivo de destino

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

a la ubicación ImportAfter de su MSBuild VS2017:

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

Nota: Reemplace # YourVS2017Product # con su nombre de producto VS2017 en la ruta anterior, por ejemplo, Community.

Esto le permitirá construir con Contratos de código en VS2017, pero no resolverá el problema de la pestaña CC que no se muestra en la Configuración del proyecto. Para eso, todavía tendrá que cambiar a VS2015.


Como han señalado otros, Microsoft no ha priorizado los Contratos de Código y su soporte a largo plazo sigue sin estar claro (aunque ha habido alguna discusión en curso sobre la integración a nivel de lenguaje a través de Roslyn).

A partir del 11 de marzo de 2017 , sin embargo, el colaborador de la comunidad Yaakov ha actualizado, al menos, el código fuente para incluir los objetivos de compilación de Visual Studio 2017 (¡gracias!). Esta versión proporciona soporte para la comprobación estática durante la compilación, así como la validación en tiempo de CCRewrite mediante CCRewrite .

Nota : Esta compilación no proporciona soporte de configuración a través del panel de propiedades del proyecto . Como tal, los contratos de código deberán configurarse agregando manualmente las propiedades apropiadas al archivo csproj . Vea la respuesta de @cristbo arriba para obtener una lista completa de propiedades .

Desafortunadamente, aunque estas actualizaciones se han fusionado en la rama del código maestro, no se reflejan en la distribución del mercado o en el paquete NuGet oficial. Como tal, necesita descargar y compilar el código fuente del repositorio (lo cual es fácil, solo use el archivo BuildCC.bat provisto).

Importante : El análisis estático para Contratos de código tiene una dependencia codificada en .NET 3.5, que ya no está instalado de manera predeterminada en Windows 10 o Visual Studio 2017. Como tal, querrá asegurarse de que esta "característica" esté habilitada. (o descárguelo por separado ); de lo contrario, obtendrá un error en tiempo de compilación.

Alternativamente, a partir del 15 de junio de 2017 , Igor Bek ha incluido esta actualización en su Paquete NuGet , por lo que el enfoque más simple es simplemente agregar ''CodeContracts.MSBuild'' a su packages.config través de:

Install-Package CodeContracts.MSBuild -Version 1.9.10714.3

Antecedentes : Igor Bek primero colocó este paquete como una prueba de concepto para el equipo de Contratos de Código , y luego fue la base para el paquete NuGet oficial (en v1.10.10126.2). Dado que Microsoft no ha actualizado el paquete NuGet oficial, el suyo ahora es el más actualizado.

Dado el estado actual de soporte, no recomendaría a las personas que adopten contratos de código para nuevos proyectos, pero esto debería proporcionar compatibilidad con versiones anteriores para desarrolladores que ya hayan invertido en contratos de código para proyectos de .NET Framework existentes.


En este momento de la escritura, no hay definiciones de contrato para VS2017, pero puede solucionarlo con lo siguiente si usa el paquete Nuget DotNet.Contracts :

  • Navegue hasta el directorio del paquete codeContracts nuget ( DotNet.Contracts.1.10.20606.1/MsBuild )
  • Copia la carpeta v14.0
  • Renombrarlo a v15.0

Todo debería desarrollarse como se espera.


Encontré que los enfoques sugeridos aquí no eran sencillos, en particular que requerirían los cambios en las máquinas de cada desarrollador y en el servidor de compilación también.

Decidí crear mi propia versión muy simplificada de Contract.Requires() que solo requerirá el reemplazo global de la declaración using en las clases de llamante.

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

Cuando / si System.Diagnostics.Contracts estará disponible para VS 2017 y .NetStandard, será fácil volver a la versión correcta.

La clase real es:

/// <summary> /// Contract.Requires(config != null); in VS 2017 not throw ArgumentNullException /// The class is workaround for https://.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://.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 limitación esencial es ese uso típico Contract.Requires(param1!=null); no me permite lanzar la excepción con el nombre del parámetro, y un mejor uso es un poco más largo:

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


Las razones por las que los contratos de código no funcionan en VS 2017 son:

  1. Contratos de código Los archivos de MSBuild no se importan en el árbol VS 2017 de los archivos de msbuild (fácil de arreglar)
  2. La IU de configuración de contratos de código no está presente en las propiedades de proyecto de VS 2017 (se puede arreglar fácilmente mediante las propiedades include de CodeContracts msbuild)

Ciertamente, las preguntas sobre el futuro de CodeContracts son válidas, pero puede implementar lo siguiente para habilitar los proyectos existentes que usan CodeContracts para construir en VS 2017:

  1. Agregue los contenidos de C:/Program Files (x86)/MSBuild/14.0/Microsoft.Common.Targets/ImportAfter/CodeContractsAfter.targets a sus archivos csproj (ya sea directa o indirectamente a través de una importación). El enfoque más básico es agregar esto a su archivo 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" />

Tenga en cuenta que el primer PropertyGroup no debería ser necesario si CodeContracts está instalado, b / c CodeContractsInstallDir debe especificarse como una variable de entorno. En ese caso, puede escaparse simplemente agregando

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

a sus archivos * .csproj.

  1. Especifique todas las propiedades de CodeContracts en su archivo * .csproj (directa o indirectamente a través de Importar). P.ej:

    <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 tiene más de unos pocos proyectos, le recomiendo ponerlos en un paquete nuget privado y hacer referencia a ese paquete nuget en cada uno de sus proyectos. La configuración de contratos de código (desde el paso 2) puede ir en su archivo mycompany.codecontracts.props, y los objetivos de contratos de código (desde el paso 1) pueden ir en su archivo mycompany.codecontracts.targets.

Más información sobre el empaquetado de las propiedades / objetivos de msbuild en un paquete nuget aquí: https://docs.microsoft.com/en-us/nuget/create-packages/creating-a-package#including-msbuild-props-and-targets-in-a-package

Estoy dispuesto a dar un ejemplo en GitHub si hay suficiente interés.