.NET Framework hoy y mañana

En ciertas ocasiones, más habituales de lo que uno desearía, te encuentras en la obligación de interactuar con componentes antiguos… muy antiguos… si hablamos de un COM en Visual Basic 6 nos remitimos 20 años atrás. Si la evolución del software y hardware cada 6 meses puede ser notable, en algunos ámbitos la adopción de ciertos hitos tecnológicos lleva décadas.

Existe una mejora y facilidad de uso entre los Common Language Runtime (CLR), aunque Microsoft le encanta cambiar y variar los nombres (Project K, vNext…) , intentaremos resumir…

Actualmente la definición de .NET Standard intenta facilitar a los desarrolladores una API común para aplicaciones de escritorio, móvil, juegos y cloud, tenemos por un lado Full Framework y por otro lado Core Framework, dos ramas con diferentes propósitos.

  • Full Framework es monolítica, instalas todo o nada solo para Windows
  • Core Framework es modular, puedes referenciar solo las partes que utilices para entorno Windows, Linux o Mac, además es Open Source y con web/Cloud en mente inicialmente.
  • Dejamos Xamarin como multiplataforma a partir de la evolución de Mono (Linux) cuando Microsoft no quería llevar .NET fuera de Windows (eran otros tiempos sin iOS ni Android…)

A futuro Microsoft parece querer unificar toda su tecnología sobre C# en .NET Core: Entity (ORM), WPF, MVC, SignalR, MVC, Web API… pero hasta entonces tenemos largos años de Full Framework todavía ¿cuantos?

 

Antivirus vs Visual Studio Team Services Agent + SonarQube

En entornos de trabajo corporativo en los que se utiliza TFS como herramienta de desarrollo, el análisis estático de código fuente ayuda a obtener métricas sobre calidad de software, para grandes y pequeños proyectos; un punto de partida en el que comparar convenciones sobre: estilo, seguridad, mantenibilidad, complejidad, duplicidad…

En el caso de las compilaciones lanzadas contra el agente de Visual Studio para Team Services, Microsoft lleva tiempo apostando por el Open Source (suena raro todavía decirlo), la automatización del proceso es sencilla.

Nuestro agente VSTS instalado descargará el código fuente configurado en la compilación, en nuestro caso una de las tareas dentro de este flujo, se integra con el anális de SonarQube mediante su plugin correspondiente. Donde obtenemos repetidamente errores:

Después de comprobar permisos, reinstalar agente, configuración del gateway de conexión TFS-SonarQube el enemigo silencioso… el antivirus, en este caso Panda, detectaba: por un lado el archivo temporal generado por el agente como posible Exploit genérico; por la otra parte, el ejecutable creado durante el análisis de código estático bloqueado…

 

Varias preguntas:

¿Por qué la generación de código fuente desde el agente crea un archivo temporal con el mismo nombre, algún tipo de GUID o similar, en todas las ejecuciones?

¿Por qué la heurística cloud (+hardening) de Panda lo analiza, remite y marca como confiable pero lo sigue bloqueando?

ACTUALIZADO: después de comunicar con Panda se solucionó en la segunda actualización específica para este problema.

Depuración de errores en servicios WCF

Windows Communication Foundation agrega eventos en el registro de Windows de manera predeterminada, por seguridad, depuración, mantenibilidad… es posible utilizar mecanimos adicionales con las trazas.

Añadiendo la siguiente configuración de diagnóstico en nuestro web.config o app.exe.config:

<configuration>  
   <system.diagnostics>  
      <sources>  
            <source name="System.ServiceModel"   
                    switchValue="Information, ActivityTracing"  
                    propagateActivity="true">  
            <listeners>  
               <add name="traceListener"   
                   type="System.Diagnostics.XmlWriterTraceListener"   
                   initializeData= "D:\log\registro.svclog" />  
            </listeners>  
         </source>  
      </sources>  
   </system.diagnostics>  
</configuration>

Posible errores no visibles, dificiles de acotar o reproducir aparecen claros y detallados, hasta el más sencillo que se nos puede pasar por alto:

en System.Runtime.Serialization.DataContract.DataContractCriticalHelper.ThrowInvalidDataContractException(String message, Type type)
   en WriteresultadoOperacionToXml(XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , ClassDataContract )
   en System.Runtime.Serialization.ClassDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context)
   en System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
   en System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
   en System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
   en System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
   en System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
   en System.Runtime.Serialization.XmlObjectSerializer.WriteObject(XmlDictionaryWriter writer, Object graph)
   en System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameterPart(XmlDictionaryWriter writer, PartInfo part, Object graph)
   en System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameter(XmlDictionaryWriter writer, PartInfo part, Object graph)
   en System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeBody(XmlDictionaryWriter writer, MessageVersion version, String action, MessageDescription messageDescription, Object returnValue, Object[] parameters, Boolean isRequest)
   en System.ServiceModel.Dispatcher.OperationFormatter.SerializeBodyContents(XmlDictionaryWriter writer, MessageVersion version, Object[] parameters, Object returnValue, Boolean isRequest)
   en System.ServiceModel.Dispatcher.OperationFormatter.OperationFormatterMessage.OperationFormatterBodyWriter.OnWriteBodyContents(XmlDictionaryWriter writer)
   en System.ServiceModel.Channels.BodyWriterMessage.OnWriteBodyContents(XmlDictionaryWriter writer)
   en System.ServiceModel.Channels.Message.OnWriteMessage(XmlDictionaryWriter writer)
   en System.ServiceModel.Channels.BufferedMessageWriter.WriteMessage(Message message, BufferManager bufferManager, Int32 initialOffset, Int32 maxSizeQuota)
   en System.ServiceModel.Channels.TextMessageEncoderFactory.TextMessageEncoder.WriteMessage(Message message, Int32 maxMessageSize, BufferManager bufferManager, Int32 messageOffset)
   en System.ServiceModel.Channels.HttpOutput.SerializeBufferedMessage(Message message, Boolean shouldRecycleBuffer)
   en System.ServiceModel.Channels.HttpOutput.Send(TimeSpan timeout)
   en System.ServiceModel.Channels.HttpPipeline.EmptyHttpPipeline.SendReplyCore(Message message, TimeSpan timeout)
   en System.ServiceModel.Channels.HttpPipeline.EmptyHttpPipeline.SendReply(Message message, TimeSpan timeout)
   en System.ServiceModel.Channels.HttpRequestContext.OnReply(Message message, TimeSpan timeout)
   en System.ServiceModel.Channels.RequestContextBase.Reply(Message message, TimeSpan timeout)
   en System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.Reply(MessageRpc& rpc)

Se transforma en algo tal que así:

 

Referencias:

  • Configurando seguimiento: enabling tracing
  • Editor gráfico de configuración WCF: bindings, behaviors, services and diagnostics
    NOTA: la ruta puede variar al ejecutable del SDK según versión, por ejemplo
    C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.2 Tools

Visual Studio 201X + Fall Creators Update

Lo que a priori puede parecer alarmante, en equipos de desarrollo con Visual Studio instalado, después de instalar la actualización para Windows 10 Fall Creators Update:

[ArgumentOutOfRangeException: El argumento especificado está fuera del intervalo de valores válidos.
Nombre del parámetro: site]
   System.Web.HttpRuntime.HostingInit(HostingEnvironmentFlags hostingFlags, PolicyLevel policyLevel, Exception appDomainCreationException) +280

 

Se soluciona sencillamente volviendo a instalar IIS desde el Panel de control\Programas\Programas y características en «Activar o desactivar las características de Windows»

 

Podremos volver a depurar proyectos web en tiempo real sin necesidades de reiniciar. Por algún motivo desconocido durante el proceso se desactiva.

 

Sintaxis en servicios WCF asíncronos

A la hora de generar servicios escalables que aprovechen el procesamiento en paralelo algunos detalles sintácticos deben realizarse literalmente. La nomenclatura puede perderse por el camino generando errores en el momento de ejecutar los servicios:

Your begin method must take an AsyncCallback and an object as the last two arguments and return an IAsyncResult.

Signatura no válida del método Begin asincrónico para el método miFuncionAsyncIniciar en el tipo de XXXX. El método Begin debe tomar AsyncCallback y un objeto como los dos últimos argumentos y devolver IAsyncResult

 

El procedimiento debe tener asociadas la tareas iniciando con el nombre Begin con los dos últimos parámetros AsynCallBack y object:

 

public interface IEjemplo
{

    [OperationContractAttribute]
    string MiFuncion(string mensaje, int otroParametro);

    [OperationContractAttribute(AsyncPattern = true)]
    IAsyncResult BeginMiFuncion(string mensaje, int otroParametro, AsyncCallback callback, object asyncState);

    //No se especifica OperationContractAttribute para el método de finalización.
    string EndMiFuncion(IAsyncResult result);

}

La documentación esta clara pero la traducción puede generar confusión con un sencillo erros de sintaxis obligatoria. 

 

How to: Implement an Asynchronous Service Operation

Sessions, Instancing, and Concurrency

 

Ejemplo completo de una excepción tipo:

 

System.InvalidOperationException: Signatura no válida del método Begin asincrónico para el método UnirAsyncIniciar en el tipo de ServiceContract XXXXXX. El método Begin debe tomar AsyncCallback y un objeto como los dos últimos argumentos y devolver IAsyncResult.
   en System.ServiceModel.Description.ServiceReflector.IsBegin(OperationContractAttribute opSettings, MethodInfo method)
   en System.ServiceModel.Description.TypeLoader.CreateOperationDescription(ContractDescription contractDescription, MethodInfo methodInfo, MessageDirection direction, ContractReflectionInfo reflectionInfo, ContractDescription declaringContract)
   en System.ServiceModel.Description.TypeLoader.CreateOperationDescriptions(ContractDescription contractDescription, ContractReflectionInfo reflectionInfo, Type contractToGetMethodsFrom, ContractDescription declaringContract, MessageDirection direction)
   en System.ServiceModel.Description.TypeLoader.CreateContractDescription(ServiceContractAttribute contractAttr, Type contractType, Type serviceType, ContractReflectionInfo& reflectionInfo, Object serviceImplementation)
   en System.ServiceModel.Description.TypeLoader.LoadContractDescriptionHelper(Type contractType, Type serviceType, Object serviceImplementation)
   en System.ServiceModel.Description.ContractDescription.GetContract(Type contractType, Type serviceType)
   en System.ServiceModel.ServiceHost.CreateDescription(IDictionary`2& implementedContracts)
   en System.ServiceModel.ServiceHostBase.InitializeDescription(UriSchemeKeyedCollection baseAddresses)
   en System.ServiceModel.ServiceHost..ctor(Type serviceType, Uri[] baseAddresses)
   en Microsoft.Tools.SvcHost.ServiceHostHelper.CreateServiceHost(Type type, ServiceKind kind)
   en Microsoft.Tools.SvcHost.ServiceHostHelper.OpenService(ServiceInfo info)