Consider this pseudocode:

/*
	TData tabele of data to elaborate
*/
ConcurrentQueue<Exception> exceptions = new ConcurrentQueue<Exception>();
Parallel.ForEach(TData.AsEnumerable (),row =>
            {
                try
                {                    
                    using (WorItem p = new WorkItem(row,connectionstring))
                    {                        
                        p.DoWork();                        
                    }
                }
                catch (Exception ex)
                {                    
                    exceptions.Enqueue(ex);
                }
            });

Inside class WorkItem.DoWork, there are some database read with custom tableadapter and one finally write of results to db. The code inside DoWork code unexpectedly fail with error “Timeout expired” or “Failed to activate rows constraints…”. The failure is random. TData table contains about 50k rows. The code is executed on machin with 48 processors, connection pool contains between 20-30 concurrent pooled connection. The failure do not depends on the row, it’s totally random. If for some row i get some strange error, i the program run for that single row, no error is generated. So what to do to correct this error?

Solution 1:  disable connection pool. The problem is solved, but performance are very poor. Run time goes from 2 minutes and 30 seconds, to 16 minutes. Not good.

Solution 2: connection pool for every WorkItem object. In Ado.Net connection pool depends on connection string, so if you modify every connection for every object, connection pool is for object scope. But how modify the connection string on object basis. In connectionstring options there is App option. This option have no pratical effect, the only purpose of this option is that if you enlist the connection on the db server with sp_who, this name is shown as property of the connection. So if you modify the connection with some connectionstring=connectionstring+”App=”+hash(row), the connection pool occurs on per object basis. The drawback of this solution, is that in the destructor of the WorkItem objec (either with Finalize or Dispose) the connection pool must be cleared, with the simple call: SqlConnection.ClearPool(conn);. With this solution the excution time is more or less the same with unique connection pool. Connection pool size grows to 60-70 concurrent pooled connection.

Udate 3-5-2017

Solution 2 is not sufficient, in some heavvy load hour, the connection problem still is there. Be best solution is to open a single connection for every object, open the connection at the first use, en close the connection at Dispose of the WorkItem instance.

Dop il ICustomFromatter per scrivere numeri in lettere, ecco un’altro FormatProvider per scrivere un numero intero da cifre arabe in cifre romane:

public class RomanFormatProvider : IFormatProvider, ICustomFormatter
    {

        IFormatProvider _parent;

        public RomanFormatProvider() : this(CultureInfo.CurrentCulture) { }
        public RomanFormatProvider(IFormatProvider parent)
        {
            _parent = parent;
        }

        public object GetFormat(Type formatType)
        {
            if (formatType == typeof(ICustomFormatter)) return this;
            return null;
        }

        public string Format(string format, object arg, IFormatProvider prov)
        {

            if (arg == null || format != "RO")
                return string.Format(_parent, "{0:" + format + "}", arg);

            return ToRoman(arg.ToString());
        }

        private string ToRoman(string n)
        {
            StringBuilder r = new StringBuilder();

            int i = 0;
            foreach (var c in n)
            {
                r.Append(calcDigit(int.Parse(c.ToString()), n.Length  - i - 1));
                i++;
            }
            return r.ToString();
        }

        class Level
        {
            public Level(string i, string v, string x)
            {
                this.i = i;
                this.v = v;
                this.x = x;
            }
            public string i { get; set; }
            public string v { get; set; }
            public string x { get; set; }

        }

        static Level[] levels = new RomanFormatProvider.Level[] {
            new Level("I", "V", "X"),
            new Level("X", "L", "C"),
            new Level("C", "D", "M")
        };

        string calcDigit(int d, int l)
        {
            string str;
            if (l > 2)
            {
                str = "";
                for (var k = 1; k <= d * Math.Pow (10, l - 3); k++)
                    str += "M";
                return str;
            }
            else
                switch (d)
                {
                    case 1:
                        return levels[l].i;
                         
                    case 2:
                        return levels[l].i + levels[l].i;
                         
                    case 3:
                        return levels[l].i + levels[l].i + levels[l].i;
                       
                    case 4:
                        return levels[l].i + levels[l].v;
                       
                    case 5:
                        return levels[l].v;
                       
                    case 6:
                        return levels[l].v + levels[l].i;
                       
                    case 7:
                        return levels[l].v + levels[l].i + levels[l].i;
                       
                    case 8:
                        return levels[l].v + levels[l].i + levels[l].i + levels[l].i;
                       
                    case 9:
                        return levels[l].i + levels[l].x;
                        
                    default:
                        return "";
                        
                }
        }
    }

Con questo CustomFormatter è possibile scrivere semplicemente:

RomanFormatProvider fr = new RomanFormatProvider();
s = string.Format(fr, "Il numero {0} in lettere è {0:RO}", 1971);
Console.WriteLine(s);

Il cui output è:

Il numero 1971 in lettere è MCMLXXI

 

Il framework .Net offre diversi strumenti per scrivere o leggere in vari tipi dati da/verso stringhe. Una conversione molto particolare è quella di scrivere un numero invece che in cifre a parole, ad esempio 1234 in milleduecentotrentaquattro. Un modo per eseguire questa conversione in maniera integrata con il resto del framework è quella di implementare le interfacce IFormatProvider e ICustomFormatter. Partendo dall’idea di base fornita da Joseph Albahari nel suo C# 6 in a nutshell ho realizzato una classe che esegue la conversione per la lingua italiana:

 

public class WordyFormatProviderITA : IFormatProvider, ICustomFormatter
    {

        IFormatProvider _parent;    

        public WordyFormatProviderITA() : this(CultureInfo.CurrentCulture) { }
        public WordyFormatProviderITA(IFormatProvider parent)
        {
            _parent = parent;
        }

        public object GetFormat(Type formatType)
        {
            if (formatType == typeof(ICustomFormatter)) return this;
            return null;
        }

        public string Format(string format, object arg, IFormatProvider prov)
        {
            // If it's not our format string, defer to the parent provider:
            if (arg == null || format==null || !format.StartsWith("W"))
                return string.Format(_parent, "{0:" + format + "}", arg);

            int c = format.IndexOf(".") == -1 ? 2 : int.Parse(format.Replace("W.",""));
            if (arg is double || arg is float || arg is decimal )
            {
                decimal num = Convert.ToDecimal(arg);
                long parteIntera = (long)Decimal.Truncate(num);
                int parteDecimale = (int)(Math.Round(num - parteIntera, c) * (decimal)Math.Pow(10,c));
                return convertNumberToReadableString(parteIntera) + "/" + parteDecimale.ToString();
            }            
            long l = 0;
            if (long.TryParse(arg.ToString(), out l))
            {
                return convertNumberToReadableString(l);
            }
            return "Invalid argument";
        }

        static readonly string[] unita = { "zero", "uno", "due", "tre", "quattro", "cinque", "sei", "sette", "otto", "nove", "dieci", "undici", "dodici", "tredici", "quattordici", "quindici", "sedici", "diciassette", "diciotto", "diciannove" };
        static readonly string[] decine = { "", "dieci", "venti", "trenta", "quaranta", "cinquanta", "sessanta", "settanta", "ottonta", "novanta" };

        public string convertNumberToReadableString(long num)
        {
            StringBuilder result = new StringBuilder();
            long mod = 0;
            long i = 0;
            
            if (num > 0 && num < 20)
            {
                result.Append( unita[num]);
            }
            else
            {
                if (num < 100)
                {
                    mod = num % 10;
                    i = num / 10;
                    switch (mod)
                    {
                        case 0:
                            result.Append(decine[i]);
                            break;
                        case 1:
                            result.Append(decine[i].Substring(0, decine[i].Length - 1));
                            result.Append(unita[mod]);
                            break;
                        case 8:
                            result.Append(decine[i].Substring(0, decine[i].Length - 1));
                            result.Append(unita[mod]);
                            break;
                        default:
                            result.Append(decine[i] + unita[mod]);
                            break;
                    }
                }
                else
                {
                    if (num < 1000)
                    {
                        mod = num % 100;
                        i = (num - mod) / 100;
                        switch (i)
                        {
                            case 1:
                                result.Append("cento");
                                break;
                            default:
                                result.Append(unita[i]);
                                result.Append("cento");
                                break;
                        }
                        result.Append(convertNumberToReadableString(mod));
                    }
                    else
                    {
                        if (num < 10000)
                        {
                            mod = num % 1000;
                            i = (num - mod) / 1000;
                            switch (i)
                            {
                                case 1:
                                    result.Append("mille");
                                    break;
                                default:
                                    result.Append(unita[i]);
                                    result.Append("mila");
                                    break;
                            }
                            result.Append(convertNumberToReadableString(mod));
                        }
                        else
                        {
                            if (num < 1000000)
                            {
                                mod = num % 1000;
                                i = (num - mod) / 1000;
                                switch ((num - mod) / 1000)
                                {
                                    default:
                                        if (i < 20)
                                        {
                                            result.Append(unita[i]);
                                            result.Append("mila");
                                        }
                                        else
                                        {
                                            result.Append(convertNumberToReadableString(i));
                                            result.Append("mila");
                                        }
                                        break;
                                }
                                result.Append(convertNumberToReadableString(mod));
                            }
                            else
                            {
                                if (num < 1000000000)
                                {
                                    mod = num % 1000000;
                                    i = (num - mod) / 1000000;
                                    switch (i)
                                    {
                                        case 1:
                                            result.Append("unmilione");
                                            break;

                                        default:
                                            result.Append(convertNumberToReadableString(i));
                                            result.Append("milioni");

                                            break;
                                    }
                                    result.Append(convertNumberToReadableString(mod));
                                }
                                else
                                {
                                    if (num < 1000000000000)
                                    {
                                        mod = num % 1000000000;
                                        i = (num - mod) / 1000000000;
                                        switch (i)
                                        {
                                            case 1:
                                                result.Append("unmiliardo");
                                                break;

                                            default:
                                                result.Append(convertNumberToReadableString(i));
                                                result.Append("miliardi");

                                                break;
                                        }
                                        result.Append(convertNumberToReadableString(mod));
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return result.ToString() ;
        }
    }

La funzione convertNumberToReadableString è stata presa da qui. Avendo questa classe tra le proprie utility, è possibile scrivere semplicemente: 

WordyFormatProviderITA f = new WordyFormatProviderITA();
var s = string.Format(f, "Il numero {0} in lettere è {0:W.4}", 9233234.8778);
Console.Write(s);

Che fornisce l’output:

Il numero 9233234,8778 in lettere è novemilioniduecentotrentatremiladuecentotrentaquattro/8778

Il formato è attivato dalla stringa W, nel caso di tipi reali può essere seguito dal parametro .n, dove n è il numero delle cifre dopo la virgola che si vuole stampare come /XX. Insomma è il formato di solito utilizzato sugli assegni.

Tentando di installare un sito su IIS 8 su una macchina Windows 10, ottenevo l’errore:

Errore HTTP 404.17 – Not Found
Il contenuto richiesto sembra essere uno script e non verrà fornito dal gestore di file statici.

Il sito è realizzato con Asp.Net 3.5, per cui ha bisogno del filtro Asp.Net 2.0, che evidentemente non era installato. Utilizzando il comando

c:\Windows\Microsoft.NET\Framework64\v2.050727\aspnet_regiis.exe -ir

Il problema è sparito. Ovviamente se si è su una macchina 32 bit utilizzare la versione 32 bit del comando.

Nel caso si debba utilizzare oggetti WMI da C# o altri linguaggi .NET, può essere utile conoscere MgmtClassGen.exe. Questo tool permette di ottenere una classe tipizzata per interagire con gli oggetti WMI. Ad esempio con l’esecuzione:

MgmtClassGen.exe Win32_Service /L CS /O some.namespace /N root\cimv2 /P ServiceProxy.cs

si otterrà una semplice classe che permette di interagire con tutti i servizi presenti sulla macchina locale o remota. Il codice generato è molto più immediato rispetto a dover fare le query WMI manualmente.

Un notevole risparmio di tempo.

Un ottimo tool per qualsiasi crash di sistema Windows è Karpersy Rescue Disk. Controllare i file, eventuali virus, c’è anche un editor del registro di sistema, che vi può salvare in casi estremi.

Con l’introduzione di Android Marshmallow, Google ha introdotto il concetto di Adoptable storage, che permette di utilizzare una scheda SD come parte della memoria interna del telefono. La SD deve essere la più veloce supportata dal telefono, per non avere un degrado delle prestazioni. La SD può essere dedicata in parte o del tutto a questa funzionalità.
Sui telefoni Honor con la EMUI 4.0, è stata introdotta questa funzionalità, ma non è attivabile, come su altri prodotti, in maniera diretta dall’interfaccia. Bisogna smanettare un po’.

Prima di cominciare bisogna dotarsi di:
1. una SD almeno classe 10;
2. un PC con una presa USB;
3. un cavetto USB-micro USB;
4. Hi-Suite installato sul computer;

5. Minimal ADB and fastboot;

6. Abilitare la modalità sviluppatore sul telefono e abilitare il Debug USB;

Una volta che tutto è pronto:

  1. connettere il telefono al PC
  2. si aprirà la Hi-Suite o apritela voi;
  3. a questo punto verrà chiesto di autorizzare la connessione al telefono della suite; compare una richiesta di autorizzazione sul telefono, date l’autorizzazione permanente; a questo punto chiudete Hi-Suite
  4. andate nella cartella di ADB and Fastboot e lanciate il comando adb shell;
  5. nella shell di comandi che compare digitare il comando: sm list-disks
  6. uscirà qualcosa del tipo disk:179:128
  7. a questo punto date il comando sm partition disk:179:128 private dove 179:128 dovrà essere il risultato del comando precedente; con questo comando tutta la sd sarà usata come memoria adoptable; dando il comando sm partition disk:179:128 mixed 50 sarà utilizzata solo metà SD;
  8. dare il comando sm list-volumes all se tra le righe stampate ci sono anche le righe  emulated:179:130 mounted null e private:179:130 mounted b6a58e7f-1dbf-4db5-95ab-19bf365e1a55 è andato tutto ok;
  9. andate sul telefono impostazioni->impostazioni avanzate->memoria->sd card-> tasto menù scegliere migra i dati;
  10. riavviare il telefono;

Tutto qui.

Ci sono però delle cose da sapere: la EMUI continuerà a mostrare 0 come spazio disponibile sulla memoria interna e sulla SD; alcune app, dopo l’installazione non si avvieranno subito, bisogna prima riavviare il telefono;

Con l’arrivo dell’Anniversary Update di Microsoft Edge, sono finalmente arrivate le estensioni. Ma al momento il numero di estensioni presenti nello store è veramente esiguo. Ma chi è un po’ più smanettone può convertire in proprio le estensioni di Chrome, attraverso il programma Microsoft Edge Extension Convertor Toolkit. Ho provato a convertire EditThisCookie, una delle estensioni di Chrome che preferisco, e il processo a parte un unico errore da sistemare a mano è stato immediato.

Quando si ha a che fare con i dataSet o dataTable tipizzati, si può ricevere l’errore (all’atto della select):

“Impossibile attivare i vincoli. Una o più righe contengono valori che violano il vincolo non-null, unique o foreign-key.”

o anche la sua versione inglese

“Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints”

Senza nessun’altra indicazione. Ma c’è un modo per sapere qual’è la colonna in errore e qual’è esattamente la violazione. Basta iterare sulla collezione GetErrors, presente sul datatable. Ad esempio (VB.NET):

Try
   Me.Adapter.Fill(dataTable)
Catch ex As Exception
   Dim err As DataRow() = dataTable.GetErrors
   Dim msg As New StringBuilder
   For Each e In err
       msg.AppendLine(e.RowError)
   Next
End Try

In questo modo la variabile msg conterrà tutte le colonne con un errore e il tipo di errore.