Quitar control de versión del TFS en soluciones c#

En este artículo voy a explicar como quitar el control de versión del TFS de las soluciones c# cuando ya no podemos hacerlo usando el IDE del Visual Studio.

Para ello lo vamos a realizar en varios pasos:
1.- Localizar nuestra solución, el fichero xxx.sln para eliminar la entrada GlobalSection
2.- Dentro de la carpeta de la solución, buscar los ficheros con extensión *.vssscc y *.vspscc para eliminiarlos
3.- Buscar todos los ficheros con extensión *.vdproj para modificar los valores SccProjectName,SccLocalPath,SccAuxPath,SccProvider y
eliminar todas las entradas que contengan BootstrapperCfg
Con esto ya tendremos la solución y los proyectos de la solución sin referencias al control de versiones del TFS
4.-Buscar todos los ficheros de proyecto con extensión *.csproj y de las claves SccProjectName, SccLocalPath, SccAuxPath, SccProvider quitar los valores SAK

Caso práctico:

1.- Editamos la solución (fichero .sln)
Localizamos la entrada GlobalSection para eliminarla.
GlobalSection(TeamFoundationVersionControl) = preSolution
SccNumberOfProjects = 2
SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
SccTeamFoundationServer = http://wktfs.wke.es:8080/tfs/spanishplatform
SccProjectUniqueName0 = Setup1\\Setup1.vdproj
SccProjectName0 = Setup1
SccLocalPath0 = Setup1
SccLocalPath1 = .
EndGlobalSection

2.- Borramos los ficheros *.vssscc, *.vspscc
(Se crean al ponerlo en control de versiones TFS)

3.- Buscar los proyectos *.vdproj para editar los ficheros.
Encontraremos esto:
"SccProjectName" = "8:SAK"
"SccLocalPath" = "8:SAK"
"SccAuxPath" = "8:SAK"
"SccProvider" = "8:SAK"

Dejarlo en:
"SccProjectName" = "8:"
"SccLocalPath" = "8:"
"SccAuxPath" = "8:"
"SccProvider" = "8:"

Encontraremos ahora BootstrapperCfg y eliminamos toda la sección en todos los modos de compilación

"BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}"
{
"Enabled" = "11:TRUE"
"PromptEnabled" = "11:TRUE"
"PrerequisitesLocation" = "2:1"
"Url" = "8:"
"ComponentsUrl" = "8:"
}

4.- Buscar todos los ficheros de proyecto con extensión *.csproj.
Buscar las claves:
SccProjectName quitarle el valor SAK
SccLocalPath quitarle el valor SAK
SccAuxPath quitarle el valor SAK
SccProvider quitarle el valor SAK

Visualizar y redirigir los procesos enviados a la consola de MS-DOS

En este artículo voy a explicar como poder visualizar y redirigir los procesos que se envían a la consola de MS-DOS cuando tenemos una organización de ejecución de procesos que se llaman los unos a los otros y éstos tienen que quedar registrados en ficheros, tanto los procesos realizados como los posibles errores producidos. Pero al mismo tiempo necesitamos visualizar por pantalla los procesos que se van realizando.

Un escenario de ejemplo podría ser el siguiente:
Un fichero bat/cmd tiene que registrar y visualizar lo que se está generando pero quien genera los procesos es otro bat/cmd principal.
Como que el primer proceso estamos indicando que queremos dejarlo registrado en ficheros, éste ya no es capaz de visualizar nada por pantalla, lo cual hace que no sepamos ver por donde va nuestro proceso y no nos podemos hacer una idea de cuanto va a tardar en finalizar; a no ser que editemos el fichero de procesos realizados.

Entonces, lo que yo planteo como solución es crear una pequeña aplicación (en este caso en c#) que nos permita capturar lo que se está procesando. (Lo que se está enviando a la consola y no se está visualizando)

La sintaxis de la invocación del contenido del fichero bat/cmd sería la siguiente:
CALL "Crear entorno" 2>RegistrarErrores.LOG | EJECUTABLEC# RegistrarProcesos.LOG

Explicación del comando anterior:
Primero, tenemos un fichero bat/cmd que contiene esa instrucción.
Segundo, «Crear entorno» es un fichero bat/cmd que tiene la lógica de los procesos a realizar.
Tercero, con el parámetro 2> indicamos que queremos tener registrado un fichero con los errores que se produzcan
Cuarto, con el parámetro | indicamos que queremos unir lo que se está capturando de los procesos realizados del fichero bat/cmd Crear entorno y que se está registrando en el EJECUTABLEC# y enviarlo a un fichero
NOTA: Es importante el orden de uso para este tiempo de unión, sino no importa el orden.
Quinto, generar el EJECUTABLEC#. En este caso he usado Visual Studio 2010.

Sigue leyendo

Complementos de Excel (archivos .xla)

He creado esta entrada, porque me ha parecido interesante explicar cómo se pueden documentar las funciones que generamos mediante un complemento de Excel. De esta forma facilitamos al usuario final el uso del mismo.
La idea consiste en usar la siguiente instrucción: Application.MacroOptions
(Esta instrucción registra nuestra función y la información de la misma.)

Ejemplo:

If Left(Application.Version, 2) > 12 Then
  Application.MacroOptions _
       Macro:=NombreFunc, _          'Nombre de la función
       Description:=DescFunc, _      'Descripción de la función
       Category:=Categoria, _        'Nombre de la categoría que exponemos
       ArgumentDescriptions:=DescArg 'Descripción de los parametros.
     'Un vector de n posiciones
Else
  Application.MacroOptions _
       Macro:=NombreFunc, _          'Nombre de la función
       Description:=DescFunc, _      'Descripción de la función
       Category:=Categoria           'Nombre de la categoría que exponemos
End If

Comentario:
Se revisa la versión de Excel porque las versiones anteriores a Microsoft Excel 2010 no dispone del parámetro ArgumentDescriptions por lo que no se pueden informar las descripciones de los parámetros de las funciones.
12.0 Excel 2007
14.0 Excel 2010
15.0 Excel 2013

Ahora, surge el problema de donde instanciarlo. La solución es hacerlo en el evento Workbook_Open ( ThisWorkBook) o en el evento Auto_Open() de un módulo.
Pero, independientemente del evento, primero hay que engañar al Excel indicando que no existe un complemento y posteriormente activándolo. Para ello usaremos las siguientes instrucciones:

Application.ScreenUpdating = False 'Desactivamos la actualización de pantallas
ThisWorkbook.IsAddin = False 'Indicamos que el libreo no se ejecuta como un complemento

Application.MacroOptions ..... 'Registramos la función

ThisWorkbook.IsAddin = True 'Activamos la actualización de pantallas
Application.ScreenUpdating = True 'Indicamos que el libreo se ejecuta como un complemento
ThisWorkbook.Saved = True 'Guardamos el libro para que no detecte cambios en él.

Sigue leyendo

Actualización del S.O. Windows 8 a Windows 8.1 con Borland Delphi 2006 (Update Pack 2) instalado previamente

Esta entrada hace referencia al problema de actualizar un s.o. Windows 8 a un Windows 8.1 cuando previamente ya se tenía instalado Borland Delphi 2006 (Update Pack 2 y los HotFix (BDS2006HotFixRollup2))

Dicho problema viene dado porque la actualización de Windows 8.1 daña varias entradas del registro que hacen referencia al Microsoft FrameWork 1.1.
Como que Borland Delphi 2006 utiliza para su propio IDE esta versión del FrameWork (al igual que otros programas antiguos), al arrancar el delphi no es capaz de detectar correctamente que éste producto ya está instalado y lo vuelve proponer para que se instale de nuevo. Tanto si aceptamos como si cancelamos, en ningún caso va a ser capaz de detectarlo correctamente.
(La reinstalación acaba dando error y aborta el proceso)
Si se opta por reparar/desinstalar el FrameWork 1.1 desde Agregar y Quitar programas del propio sistema operativo, aunque no de errores y parezca que se finaliza correctamente, en realidad o no se ha desinstalado en su totalidad o no se ha reparado realmente todas las entradas del registro.

Si se navega por internet para confirmar si FrameWork 1.1 es compatible con el sistema operativo Windows 8.1, el propio msd de Microsoft indica que este FrameWork es incompatible con estos sistemas operativos:

The .NET Framework 1.1 is not supported on the Windows 8, Windows 8.1, Windows Server 2012, or the Windows Server 2012 R2 operating systems. In some cases, the .NET Framework 1.1 is specifically identified as required for an application to run. In those cases, you should contact your independent software vendor (ISV) to have the application upgraded to run on the .NET Framework 3.5 SP1 or later version. For additional information, see Migrating from the .NET Framework 1.1.

link de Microsoft indicando incompatilibad

La única forma para poder reparar estas entradas es desinstalando el producto con una herramienta especial. Esta herramienta se llama dotnetfx_cleanup_tool y se puede descargar desde este link.

•http://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Components-PostAttachments/00-08-90-44-93/dotnetfx_5F00_cleanup_5F00_tool.zip

Otros links de interés

http://blogs.msdn.com/b/astebner/archive/2008/08/28/8904493.aspx

Reducir tamaño de la base de datos sql server

En este post voy hacer referencia en cómo reducir y compactar una base de datos de sql server mediante scripts.
Para ello, utilizaremos la instrucción DBCC SHRINKDATABASE y DBCC SHRINKFILE.

¿Cuando usar un comando u otro?
DBCC SHRINKDATABASE nos reduce el tamaño de todos los ficheros de datos y de todos los ficheros de log
DBCC SHRINKFILE no sólo reduce el fichero especificado, sino que puede agrupar todos los ficheros de datos y registro en un único fichero. Luego, si procede, se puede eliminar el resto de ficheros.

¿Cómo identifico los ficheros de datos y los ficheros de log?
Como norma general, los ficheros de datos tienen la extensión MDF (primary) y NDF (para los secundarios). Para los ficheros de log tienen la extensión LDF.

Existe varias formas de obtener los ficheros que componen una base de datos.

-- Para obtenerlo de un fichero backup usaremos la instrucción RESTORE FILELISTONLY 
RESTORE FILELISTONLY
FROM DISK= 'C:\Program Files\Microsoft SQL Server\MSSQL11\MSSQL\DATA\demo.bak' 

-- Para obtener todos los ficheros del servidor del sql server:
select * from sys.master_files

-- Para obtener los ficheros de la base de datos actual:
SP_HELPFILE
-- o
select * from sys.database_files
-- o
select * from sys.sysfiles

Usando SHRINKDATABASE y SHRINKFILE

-- Truncar la base de datos (ficheros de datos y log)
-- Si no especificamos nada, se ejecutará de forma implícita la opción NOTRUNCATE y posteriormente TRUNCATEONLY
-- por lo que se organiza las "páginas de datos" y se reduce el tamaño de la base de datos.
DBCC SHRINKDATABASE(N'Demo' ) 
-- Truncar la base de datos y dejar un 10% libre al finalizar
DBCC SHRINKDATABASE(N'Demo', 10 )

-- Para agruparlo en un único fichero de datos
DBCC SHRINKFILE (N'Demo' , EMPTYFILE)       
-- Para liberar espacio del fichero de datos del final del archivo
DBCC SHRINKFILE (N'Demo' , 0, TRUNCATEONLY) 
-- Para reducir el fichero datos a 82 MB
DBCC SHRINKFILE (N'Demo' , 82)              

-- Para reducir el fichero de log
ALTER DATABASE Demo
SET RECOVERY SIMPLE;
GO
-- Truncamos el fichero del log a 1 MB.
DBCC SHRINKFILE (Demo_Log, 1);
GO
ALTER DATABASE Demo
SET RECOVERY FULL;

Links de interés
http://msdn.microsoft.com/es-es/library/ms189493.aspx
http://msdn.microsoft.com/es-es/library/ms190488.aspx

Adoconnection con objetos COM

He generado este post, para hacer mención sobre cómo podemos trabajar con objetos de tipo TAdoConnection que se pasan desde Delphi por COM.
La idea consiste en pasar del objeto TAdoConnection, la propiedad ConnectionObject como un OleVariant.
Para recuperar esa propiedad, pongo como ejemplo, 2 snippets realizados en diferentes lenguajes.

1. Este snippet está desarrollado para los que trabajan en Borland Delphi.

acnTest:TADOConnection;
acnTest := TADOConnection.Create(nil);
acnTest.ConnectionObject := 
     (IUnknown((ObjetoCOM.PropiedadConnectionObjectDeTipoOleVariant)) as _Connection);

2. Este snippet está desarrollado para los que trabajan en .NET (c#)

Connection adocon = ObjetoCOM.PropiedadConnectionObjectDeTipoOleVariant;
ADODB.Command adocm = new Command();
adocm.ActiveConnection = adocon;
adocm.CommandText = "SenteciaSQL";
object aux = Type.Missing;
ADODB.Recordset rs = adocm.Execute(out aux, ref aux, 0);

Reflection I – Asignar atributos a los enumerados

Este pequeño bloque de código, muestra como añadir un atributo presonalizado (de tipo string) a un enumerado.
Personalmente lo uso para representar un valor de tipo string, de un campo de una tabla, en un enumerado en c#.


    // Enumerado
    enum TipoEnumeradoAcciones
    {
        [StringValue("R")]
        tipoaccionReunion = 0,
        [StringValue("C")]
       tipoaccionCita = 1,
        [StringValue("E")]
        tipoaccionEmail = 2,
    }

    // Clase que extiende de System.Attribute para poder añadir el atributo personalizado en el enumerado anterior.
    class StringValueAttribute : System.Attribute
    {
        private string _value;

        public StringValueAttribute(string value)
        {
            _value = value;
        }

        public string Value
        {
            get { return _value; }
        }

        // Método estático al que llamaremos para obtener el valor de la propiedad del enumerado
        public static string GetStringValue(Enum value)
        {
            Type type = value.GetType();
            FieldInfo fieldInfo = type.GetField(value.ToString());
            StringValueAttribute[] attribs = fieldInfo.GetCustomAttributes(
                typeof(StringValueAttribute), false) as StringValueAttribute[];
            return attribs.Length > 0 ? attribs[0].Value : null;
        }
    }

    // La llamada sería de este forma. 
    [TestClass]
    public class UnitTestNombreEnumerados
    {
        [TestMethod]
        public void LeerNombresEnumerados()
        {
            Assert.AreEqual(StringValueAttribute.GetStringValue(TipoEnumeradoAcciones.tipoaccionCita), "C");
            Assert.AreEqual(StringValueAttribute.GetStringValue(TipoEnumeradoAcciones.tipoaccionReunion), "R");
            Assert.AreEqual(StringValueAttribute.GetStringValue(TipoEnumeradoAcciones.tipoaccionEmail), "E");
        }
    }

Script sql server – Formatear número decimal

En una ocasión, tube que implementar un script para formatear un número decimal a un número concreto de decimales. Aprovechando este caso, he querido mencionarlo en mi blog para compartirlo en la red.

Antes de explicar como funciona la función que he creado en este script, quiero mencionar que el Sql Server, tiene una función llamada ROUND que nos permite redondear o truncar dependiendo de los parametros añadidos a la funcion. (entre otras variantes)

Función del script

Nombre: FormatearDecimal
Parametros:
1.- Número decimal / Número entero
2.- Número de decimales
3.- Truncar (0) / Rendonear (1)
(El redondeo se hace a la baja cuando es un 5 el último dígito significativo)
4.- Longitud total del Número. Si es inferior a la longitud del número, se añaden ceros delante.

create Function FormatearDecimal( @numero VARCHAR(20), @dec int, @redondear int, @longitudtotal int=0)
RETURNs VARCHAR(20)
AS
BEGIN
DECLARE @RESULT VARCHAR(20)  -- resultado a devolver
DECLARE @TEMP VARCHAR(20)    -- variable temporal para calculo
declare @posDecimal int      -- indicador de parte decimal
declare @incrementar int     -- valor a sumar en redondeo si no se truncan los decimales

-- inicialización de parametros
SET @RESULT = RTrim( LTrim( @numero))
SET @TEMP = ''
SET @incrementar = -1

-- buscamos decimal
set @posDecimal = CHARINDEX('.', @RESULT, 0)
if( @posDecimal = 0)
set @posDecimal = CHARINDEX(',', @result, 0)

if( @posDecimal = 0)
begin
-- no hay parte decimal
SET @TEMP = @RESULT+ ',' + REPLICATE('0', @dec)
end
else
begin
-- existe parte decimal
-- guardamos parte entera
SET @TEMP = SUBSTRING(@RESULT, 1, @posDecimal-1)

-- guardamos parte decimal
SET @RESULT = ltrim(rtrim(cast(SUBSTRING(@RESULT, @posDecimal+1, LEN( @RESULT)-@posDecimal) as varchar(20))))

if( @dec-LEN(@result) >= 0) begin
-- rellenamos tantos ceros como decimales se han pedido si no los tiene
SET @TEMP = @TEMP +  ',' + + @RESULT + REPLICATE('0', @dec-LEN(@result))
end
else
begin
-- aquí redondeamos o truncamos
if( @redondear = 0)
begin
-- truncamos
SET @TEMP = @TEMP +  ',' + SUBSTRING(@RESULT, 1, @dec)
end
else begin
-- redondeamos
set @incrementar = case
when cast(SUBSTRING(@RESULT, @dec+1,1) as int)  5 then  1
end
SET @TEMP = @TEMP +  ',' + cast(cast(SUBSTRING(@RESULT, 1, @dec) as int)+@incrementar as varchar(20))
end
end
end

-- mirarmos la longitud total
if( LEN(@TEMP) < @longitudtotal)
  SET @TEMP = REPLICATE('0', @longitudtotal-LEN(@TEMP)) + @TEMP

-- reasignamos variable temporal a la variable de tipo result
set @RESULT = @TEMP

RETURN @RESULT
END

Ejemplos de uso:

select dbo.FormatearDecimal(12,2, 0, 6)
select dbo.FormatearDecimal(12.066,2, 0, default)
select dbo.FormatearDecimal(12.06,3, 0, default)
select dbo.FormatearDecimal(12.06,1, 0, default)
select dbo.FormatearDecimal(12.06,1, 1, default)
select dbo.FormatearDecimal(12.346,2, 0, default)
select dbo.FormatearDecimal(12.346,2, 1, default)
select dbo.FormatearDecimal(12.346,3, 0, default)

012,00
12,06
12,060
12,0
12,1
12,34
12,35
12,346

Herramientas útiles para el PC (I)

En este apartado, indico una serie de aplicaciones (ya conocidas o no) que son gratuitas y que pueden ser de utilidad.
Estas aplicaciones són de un ámbito general, por lo que no hay una agrupación de las mismas.

– Ver ficheros hlp en windows 7
http://bitelia.com/2009/10/visualizar-archivos-hlp-windows-7/
– Herramienta UltraDefrag
Alternativa a defragmentar windows
– Herramienta CCleaner
Limpiar registro / pc
– Speccy
Ver componentes pc
– KeePass 2
Gestionar contraseñas
– Desintalador de aplicaciones de windows
http://www.revouninstaller.com/revo_uninstaller_free_download.html
Virtual CloneDrive
Generar unidades virtuales de ficheros iso
Avast
Antivirus free
EditPadPro, NotePad ++
Editor de texto con diferentes pluggins para programación
Cobian Backup
Copias de seguridad
Virtual Box, VMWare Player
Máquina virtual
Pdf Creator
Impresora para generar pdf
ExpressProfiler
Generar traza sql server
WinMerge
Herramienta para comparar ficheros, directorios, etc
Thunderbird
Cliente de correo electronico
Oppen Office
El equivalente de microsoft office
Textcrawler
Para buscar y reemplazar palabras en contenido de ficheros ASCII

INotifyPropertyChange

Esta interfaz nos sirve para poder informar a la parte cliente de que una propiedad ha cambiado.
Cuando implementamos dicha interfaz en nuestra clase, en el método set, debemos invocar un método dónde informaremos de que la propiedad ha cambiado.
Para ello podemos asignarle un literal con el mismo nombre de la propiedad (es case sensitive) o utilizar el attributo CallerMemberName en el parámetro del método. Este attributo nos abstrae de tener que indicar con un literal el nombre de la propiedad, por lo que evitaremos posibles errores a la hora de aisgnar el nombre de la propiedad.

Ejemplo:
Aquí al asignar el código se asigna automáticamente la descripción con el mismo valor que el código

//INotifyPropertyChanged => Notifica a la parte cliente que la propiedad ha cambiado.
public class Articulos : INotifyPropertyChanged
{
  string _codigo;
  public string Codigo
  {
    get { return _codigo; }
    set { _codigo = value;
          Descripcion = value; RaisePropertyChanged(); }
  }

  string _descripcion;
  public string Descripcion
  {
   get { return _descripcion; }
   set { _descripcion = value; RaisePropertyChanged(); }
  }

///
/// Implementación de la interface INotifyPropertyChanged
///
public event PropertyChangedEventHandler PropertyChanged;

///
/// Con el attributo CallerMemberName nos podemos de abstraer del nombre de la propiedad
/// a la hora de pasarlo en el evento RaisePropertyChanged
/// En vez de poner RaisePropertyChanged( "Codigo") lo dejamos como RaisePropertyChanged()
/// Parametro: que contiene la propiedad que se cambia
private void RaisePropertyChanged([CallerMemberName] string caller = "")
{
  if (PropertyChanged != null)
  {
    PropertyChanged(this, new PropertyChangedEventArgs(caller));
  }
}

 

///Code behind XAML

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplication1
{
    ///
    /// Interaction logic for MainWindow.xaml
    ///
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.Loaded += MainWindow_Loaded;
        }

        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            btnPulsar.Click += btnPulsar_Click;
        }

        void btnPulsar_Click(object sender, RoutedEventArgs e)
        {
            Articulos art = new Articulos();
            this.DataContext = art;

            art.Codigo = "22222";
        }
    }
}

 

/// Código XAML
<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="25"></RowDefinition>
            <RowDefinition Height="25"></RowDefinition>
            <RowDefinition Height="25"></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>

        <Button Name="btnPulsar" Content="Pulsar" ToolTip="Se asignará en descripción el código" Width="100" HorizontalAlignment="Left" Grid.Row="0"/>
        
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Grid.Row="1">
            <Label>Código:</Label>
            <TextBox Text="{Binding Codigo}" Width="100"/>
        </StackPanel>

        <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Grid.Row="2">
            <Label>Descripción:</Label>
            <TextBox Text="{Binding Descripcion}" Width="100"/>
        </StackPanel>
    </Grid>
</Window>

Ver referencias en:
http://msdn.microsoft.com/es-es/library/system.componentmodel.inotifypropertychanged.aspx