DotNet


How to convert XHTML to PDF in C#

Envoyer Imprimer PDF
Note des utilisateurs: / 21
MauvaisTrès bien 
There are no translations available.

In this blog post I will illustrate how you could convert an XHTML page into PDF using the flying-saucer library. This is a Java library so we need to first step would be to convert it to a .NET assembly.

I will use the IKVM.NET Bytecode Compiler (ikvmc.exe) for this purpose. So go ahead and download both the flying-saucer library and the IKVM project. Then run the following command:

ikvmc.exe -target:library -out:CoreRenderer.dll iText-2.0.8.jar core-renderer.jar

This will generate the CoreRenderer.dll assembly which could be used. And finally we would create an application which would use it inside a console application:


One last step is to ensure that you have referenced the following assemblies:

todelka


Those assemblies are part of the IKVM project and have dependencies on many other assemblies that are included with it. So the final folder should contain all those:

todelka2

And that’s pretty much all. When you run the console application it should generate the output PDF file.

Mise à jour le Mercredi, 02 Mars 2011 22:36
 

Uploading multiple files with C#

Envoyer Imprimer PDF
Note des utilisateurs: / 16
MauvaisTrès bien 
There are no translations available.

Have you ever been in a situation where you needed to upload multiple files to a remote host and pass additional parameters in the request? Unfortunately there’s nothing in the BCL that allows us to achieve this out of the box.

We have the UploadFile method but it is restricted to a single file and doesn’t allow us to pass any additional parameters. So let’s go ahead and write such method. The important part is that this method must comply with RFC 1867 so that the remote web server can successfully parse the information.

First we define a model representing a single file to be uploaded:

    public class UploadFile
    {
        public UploadFile()
        {
            ContentType = "application/octet-stream";
        }
        public string Name { get; set; }
        public string Filename { get; set; }
        public string ContentType { get; set; }
        public Stream Stream { get; set; }
    }

And here’s a sample UploadFiles method implementation:

    public byte[] UploadFiles(string address, IEnumerable<UploadFile> files, NameValueCollection values)
    {
        var request = WebRequest.Create(address);
        request.Method = "POST";
        var boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x", NumberFormatInfo.InvariantInfo);
        request.ContentType = "multipart/form-data; boundary=" + boundary;
        boundary = "--" + boundary;

        using (var requestStream = request.GetRequestStream())
        {
            // Write the values
            foreach (string name in values.Keys)
            {
                var buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine);
                requestStream.Write(buffer, 0, buffer.Length);
                buffer = Encoding.ASCII.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\"{1}{1}", name, Environment.NewLine));
                requestStream.Write(buffer, 0, buffer.Length);
                buffer = Encoding.UTF8.GetBytes(values[name] + Environment.NewLine);
                requestStream.Write(buffer, 0, buffer.Length);
            }

            // Write the files
            foreach (var file in files)
            {
                var buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine);
                requestStream.Write(buffer, 0, buffer.Length);
                buffer = Encoding.UTF8.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"{2}", file.Name, file.Filename, Environment.NewLine));
                requestStream.Write(buffer, 0, buffer.Length);
                buffer = Encoding.ASCII.GetBytes(string.Format("Content-Type: {0}{1}{1}", file.ContentType, Environment.NewLine));
                requestStream.Write(buffer, 0, buffer.Length);
                file.Stream.CopyTo(requestStream);
                buffer = Encoding.ASCII.GetBytes(Environment.NewLine);
                requestStream.Write(buffer, 0, buffer.Length);
            }

            var boundaryBuffer = Encoding.ASCII.GetBytes(boundary + "--");
            requestStream.Write(boundaryBuffer, 0, boundaryBuffer.Length);
        }

        using (var response = request.GetResponse())
        using (var responseStream = response.GetResponseStream())
        using (var stream = new MemoryStream())
        {
            responseStream.CopyTo(stream);
            return stream.ToArray();
        }
    }

And here’s a sample usage:

 

    using (var stream1 = File.Open("test.txt", FileMode.Open))
    using (var stream2 = File.Open("test.xml", FileMode.Open))
    using (var stream3 = File.Open("test.pdf", FileMode.Open))
    {
        var files = new[] 
        {
            new UploadFile
            {
                Name = "file",
                Filename = "test.txt",
                ContentType = "text/plain",
                Stream = stream1
            },
            new UploadFile
            {
                Name = "file",
                Filename = "test.xml",
                ContentType = "text/xml",
                Stream = stream2
            },
            new UploadFile
            {
                Name = "file",
                Filename = "test.pdf",
                ContentType = "application/pdf",
                Stream = stream3
            }
        };

        var values = new NameValueCollection
        {
            { "key1", "value1" },
            { "key2", "value2" },
            { "key3", "value3" },
        };
        
        byte[] result = UploadFiles("http://localhost:1234/upload", files, values);
    }

 

 

 

 

 

In this example we are uploading 3 values and 3 files to the remote host.

Next time I will show how to improve this code by adding an asynchronous version using the TPL library in .NET 4.0.

Mise à jour le Samedi, 22 Janvier 2011 01:25
 

Playing with FindFirstFile and FindNextFile

Envoyer Imprimer PDF
Note des utilisateurs: / 13
MauvaisTrès bien 
There are no translations available.

Enumerating files in .NET is easy. Everybody knows the GetFiles method and you may be tempted to write code like this:

 

    var files = Directory.GetFiles(@"c:\windows\system32", "*.dll");
    foreach (var file in files)
    {
        Console.WriteLine(file);
    }

 

But if you look closer you will notice that this method returns an array of strings. This could be problematic if the directory you search contains lots of files. The method will block until it performs the search and once it finishes it will load all the results into memory. It would be much better if it just returned an IEnumerable. That’s exactly what the EnumerateFiles method does in .NET 4.0. Unfortunately in .NET 3.5 there’s nothing for the job.

 

In this post I will show how to implement this functionality using the FindFirstFile and FindNextFile functions.

 

We start by defining the native function prototypes:

    internal sealed class Win32Native
    {
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct WIN32_FIND_DATA
        {
            public uint dwFileAttributes;
            public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
            public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
            public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
            public uint nFileSizeHigh;
            public uint nFileSizeLow;
            public uint dwReserved0;
            public uint dwReserved1;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
            public string cFileName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
            public string cAlternateFileName;
        }

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern SafeFindHandle FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool FindNextFile(SafeFindHandle hFindFile, out WIN32_FIND_DATA lpFindFileData);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool FindClose(IntPtr hFindFile);
    }

You may notice the SafeFindHandle class used in the method signatures. This is just a simple class deriving from SafeHandle that will make sure that unmanaged handle is correctly closed:

 

    [SecurityCritical]
    internal class SafeFindHandle : SafeHandleZeroOrMinusOneIsInvalid
    {
        [SecurityCritical]
        public SafeFindHandle() : base(true)
        { }

        [SecurityCritical]
        protected override bool ReleaseHandle()
        {
            return Win32Native.FindClose(base.handle);
        }
    }

 

As the documentation states the handle created by FindFirstFile needs to be closed with FindClose function. And finally the implementation of the EnumerateFiles method:

 

    public static class DirectoryExtensions
    {
        public static IEnumerable<string> EnumerateFiles(string path, string searchPattern)
        {
            // TODO: validate input parameters
            
            string lpFileName = Path.Combine(path, searchPattern);
            Win32Native.WIN32_FIND_DATA lpFindFileData;
            var handle = Win32Native.FindFirstFile(lpFileName, out lpFindFileData);
            if (handle.IsInvalid)
            {
                int hr = Marshal.GetLastWin32Error();
                if (hr != 2 && hr != 0x12)
                {
                    throw new Win32Exception(hr);
                }
                yield break;
            }

            if (IsFile(lpFindFileData))
            {
                var fileName = Path.Combine(path, lpFindFileData.cFileName);
                yield return fileName;
            }

            while (Win32Native.FindNextFile(handle, out lpFindFileData))
            {
                if (IsFile(lpFindFileData))
                {
                    var fileName = Path.Combine(path, lpFindFileData.cFileName);
                    yield return fileName;
                }
            }

            handle.Dispose();
        }

        private static bool IsFile(Win32Native.WIN32_FIND_DATA data)
        {
            return 0 == (data.dwFileAttributes & 0x10);
        }
    }

The method could be used like this:

    class Program
    {
        static void Main(string[] args)
        {
            var files = DirectoryExtensions.EnumerateFiles(@"c:\windows\system32", "*.dll");
            foreach (var file in files)
            {
                Console.WriteLine(file);
            }
        }
    }
Mise à jour le Mercredi, 19 Mai 2010 21:21
 

Manipulations de matrices avec du code non sécurisé

Envoyer Imprimer PDF

La classe Matrix

Dans cet article nous allons comparer 2 méthodes qui traitent de multiplication de matrices en .Net | C#.

Nous commençons par la définition de la classe matrice :  Matrix

    class Matrix
{
private readonly double[,] _matrix;
public Matrix(int dim1, int dim2)
{
_matrix
= new double[dim1, dim2];
}

public int Height { get { return _matrix.GetLength(0); } }
public int Width { get { return _matrix.GetLength(1); } }

public double this[int x, int y]
{
get { return _matrix[x, y]; }
set { _matrix[x, y] = value; }
}
}

Multiplications de matrices

Voici le premier algorithme de multiplication de matrice qui réalise l’opération de manière standard.

    public static Matrix NaiveMultiplication(Matrix m1, Matrix m2)
{
Matrix resultMatrix
= new Matrix(m1.Height, m2.Width);
for (int i = 0; i < resultMatrix.Height; i++)
{
for (int j = 0; j < resultMatrix.Width; j++)
{
resultMatrix[i, j]
= 0;
for (int k = 0; k < m1.Width; k++)
{
resultMatrix[i, j]
+= m1[i, k] * m2[k, j];
}
}
}
return resultMatrix;
}

Voici le second algorithme qui réalise la même chose, mais cette fois en utilisant du code non sécurisé (unsafe)

   public unsafe static Matrix UnsafeMultiplication(Matrix m1, Matrix m2)
{
int h = m1.Height;
int w = m2.Width;
int l = m1.Width;
Matrix resultMatrix
= new Matrix(h, w);
unsafe
{
fixed (double* pm = resultMatrix._matrix, pm1 = m1._matrix, pm2 = m2._matrix)
{
int i1, i2;
for (int i = 0; i < h; i++)
{
i1
= i * l;
for (int j = 0; j < w; j++)
{
i2
= j;
double res = 0;
for (int k = 0; k < l; k++, i2 += w)
{
res
+= pm1[i1 + k] * pm2[i2];
}
pm[i
* w + j] = res;
}
}
}
}
return resultMatrix;
}

 

Mesure des performances

Il est temps maintenant de comparer les performances des 2 opérations

Programme de test de performance

    class Program
{
[DllImport(
"kernel32.dll")]
static extern void QueryPerformanceCounter(ref long ticks);

static long Measure(Action action, int count)
{
long startTicks = 0;
QueryPerformanceCounter(
ref startTicks);
for (int i = 0; i < count; i++)
{
action();
}
long endTicks = 0;
QueryPerformanceCounter(
ref endTicks);
return endTicks - startTicks;
}

static void Main(string[] args)
{
Random random
= new Random();

Matrix m1
= new Matrix(20, 30);
for (int i = 0; i < m1.Height; i++)
{
for (int j = 0; j < m1.Width; j++)
{
m1[i, j]
= random.Next(-100, 100);
}
}

Matrix m2
= new Matrix(30, 40);
for (int i = 0; i < m2.Height; i++)
{
for (int j = 0; j < m2.Width; j++)
{
m2[i, j]
= random.Next(-100, 100);
}
}

Console.WriteLine(Measure(()
=> Matrix.NaiveMultiplication(m1, m2), 10000));
Console.WriteLine(Measure(()
=> Matrix.UnsafeMultiplication(m1, m2), 10000));
}
}

Dans ce programme de test nous réalisons 10000 multiplications de 2 matrices générées de façon aléatoires avec des tailles de 20x30 et 30x40 éléments.

Résultat du test de performance

Méthode CPU cycles
multiplication unsafe 4485698
multiplication traditionnelle 58762273

Les résultats montrent que la multiplication de matrice réalisée de façon traditionnelle est plus lente d’un facteur de 13 comparée à la multiplication réalisée par le code non sécurisé et travaillant directement avec la mémoire.

Mise à jour le Samedi, 03 Octobre 2009 12:31
 

Transactional NTFS (partie 1/2)

Envoyer Imprimer PDF

Transactional NTFS et DotNet

Microsoft introduit un concept intéressant à partir des versions de Windows Vista et Server 2008.
Cette nouveauté est appelée Transactional NTFS (TxF).
Elle permet aux développeurs d’écrire des fonctions d’Entrée/Sortie garantissant le succès complet ou le rejet complet en cas d’erreur d’un ensemble d’opérations.

Malheureusement il n’existe pas de classe DotNet(au moins jusqu’à la version 3.5 SP1) permettant de manipuler simplement ce type d’opérations.

Pour manipuler ces opérations, nous avons besoin de passer par le P/Invoke pour utiliser ces fonctions :

CreateTransaction, CommitTransaction, RollbackTransaction et DeleteFileTransacted

class Win32Native
{
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
int nLength;
IntPtr lpSecurityDescriptor;
int bInheritHandle;
}

[DllImport(
"ktmw32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern SafeFileHandle CreateTransaction
 (SECURITY_ATTRIBUTES securityAttributes
, IntPtr guid,
int options, int isolationLevel, int isolationFlags,
int milliSeconds, string description);

[DllImport(
"ktmw32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool CommitTransaction(SafeFileHandle transaction);

[DllImport(
"ktmw32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool RollbackTransaction(SafeFileHandle transaction);

[DllImport(
"kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool DeleteFileTransacted
(
string filename, SafeFileHandle transaction);
}

Notez que j’utilise SafeFileHandle dans la signature des méthodes à la place de IntPtr pour les ancienne ressources non managées afin de garantir que les éléments seront bien libérés même si l’application doit s’arrêter.

L’étape suivante est la définition d’une classe permettant d’appeler simplement les fonctions déclarées.

 public class FileManager : IDisposable
{
private bool _commited = false;
private SafeFileHandle _tx = null;

public FileManager()
{
_tx
= Win32Native.CreateTransaction
(
new Win32Native.SECURITY_ATTRIBUTES(), IntPtr.Zero
,
0, 0, 0, 0, null);
}

public bool DeleteFile(string filename)
{
return Win32Native.DeleteFileTransacted
(filename, _tx);
}

public void Commit()
{
if (Win32Native.CommitTransaction(_tx))
_commited
= true;
}

private void Rollback()
{
Win32Native.RollbackTransaction(_tx);
}

protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (!_commited)
{
Rollback();
}
}
}

public void Dispose()
{
Dispose(
true);
}
}

Exemple avec la suppression de 2 fichiers

 

Supposons que nous devons supprimer automatiquement 2 fichiers. Les 2 fichiers doivent être supprimés en même temps. Si un des 2 fichiers ne peut pas être supprimé, les 2 fichiers doivent être conservés.

    using (FileManager manager = new FileManager())
{
manager.DeleteFile(
"file1.txt");
Console.WriteLine(
"file1.txt is marked for deletion in current transaction. Press Enter...");
Console.ReadLine();

//throw new Exception("something very bad happens here");

manager.DeleteFile(
"file2.txt");
Console.WriteLine(
"file2.txt is marked for deletion in current transaction.");

manager.Commit();
}

La méthode DeleteFile marque le fichier pour la suppression dans le transaction courante, mais ne la supprimera uniquement si la méthode Commit est appelée.

Grâce à TFX et les transactions distribuées, les opérations sur les fichiers et les opérations SQL peuvent s’effectuer dans une même opération.

Dans la 2ème partie, nous verrons comment utiliser la fonction CreateFileTransacted pour traiter de façon unique la lecture et l’écriture d’un fichier.

Mise à jour le Mardi, 18 Mai 2010 22:09
 

Méthodes dynamiques (classe DynamicMethod) en .NET

Envoyer Imprimer PDF
Note des utilisateurs: / 11
MauvaisTrès bien 

Utiliser la réflexion pour invoquer des méthodes non connues à la compilation peut être problématique en terme de performances dans des applications critiques. L’exécution de ces méthodes est environ 2,5 à 3 fois plus lente qu’un appel directe.
Voici un exemple :

 

    class Program
{
[DllImport(
"kernel32.dll")]
static extern void QueryPerformanceCounter(ref long ticks);

static PropertyInfo _intProp = typeof(Foo).GetProperty("IntProp", BindingFlags.Public | BindingFlags.Instance);

static void Main(string[] args)
{
Foo foo
= new Foo { IntProp = 10 };
const int COUNT = 1;
Console.WriteLine(Measure(()
=> ReadPropertyWithReflection(foo), COUNT));
Console.WriteLine(Measure(()
=> ReadPropertyDirectly(foo), COUNT));
}

static void ReadPropertyWithReflection(Foo foo)
{
int intProp = (int)_intProp.GetValue(foo, null);
}

static void ReadPropertyDirectly(Foo foo)
{
int intProp = foo.IntProp;
}

static long Measure(Action action, int count)
{
long startTicks = 0;
QueryPerformanceCounter(
ref startTicks);
for (int i = 0; i < count; i++)
{
action();
}
long endTicks = 0;
QueryPerformanceCounter(
ref endTicks);
return endTicks - startTicks;
}

class Foo
{
public int IntProp { get; set; }
}
}

Et voici les résultats :

Type d’accès unités CPU
Invocation par accès directe 796
Invocation par Réflexion 1986

Ainsi, l’utilisation de la réflexion pour lire une propriété est 2,5 fois plus lente que l’accès directe à cette propriété.

Les méthodes dynamiques peuvent être utilisées pour générer et exécuter une méthode à l’exécution sans devoir déclarer une assemblie dynamique et un type dynamique qui contiendront la méthode. Elles représentent un moyen plus efficace pour générer et exécuter ce type de code.
Voici un exemple d’utilisation de la classe de méthode dynamique (DynamicMethod) pour générer un accès en lecture à la propriété.

    static Func<Arg0, TReturn> EmitGetter<Arg0, TReturn>(PropertyInfo propertyInfo)
{
MethodInfo mi
= propertyInfo.GetGetMethod();
DynamicMethod dm
= new DynamicMethod(
"_get",
typeof(TReturn),
new Type[] { typeof(Arg0) },
propertyInfo.DeclaringType);

ILGenerator il
= dm.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, propertyInfo.DeclaringType);
il.EmitCall(OpCodes.Callvirt, mi,
null);
il.Emit(OpCodes.Ret);

return (Func<Arg0, TReturn>)dm.CreateDelegate(typeof(Func<Arg0, TReturn>));
}

Utilisons maintenant cette méthode pour définir un accès en lecture à PropertyInfo en exécution et retourner le délégué.

    Func<Foo, int> getter = EmitGetter<Foo, int>(_intProp);
Console.WriteLine(Measure(()
=> getter(foo), COUNT));

Et voici les résultats obtenus avec les 3 type d’accès différents pour lire la valeur de la propriété :

Type d’accès unités CPU
Invocation par accès directe 796
Invocation avec Dynamic method 1190
Invocation par Réflexion 1986
Mise à jour le Mercredi, 19 Mai 2010 21:12
 

LINQ to XML et la lecture des très gros fichiers

Envoyer Imprimer PDF
Note des utilisateurs: / 12
MauvaisTrès bien 

LINQ to XML est relativement facile à implémenter pour lire de gros fichiers et pour requêter des fichiers XML.
Par exemple, considérons ce fichier XML :

    <?xml version="1.0" encoding="utf-8" ?>
<users>
<user name="User1" groupid="4" />
<user name="User2" groupid="1" />
<user name="User3" groupid="3" />
<user name="User4" groupid="1" />
<user name="User5" groupid="1" />
<user name="User6" groupid="2" />
<user name="User7" groupid="1" />
</users>

Supposons que vous souhaitez trouver tous les enregistrements avec groupid > 2. Vous pouvez être tenté d’implémenter la requête suivante :

    XElement doc = XElement.Load("users.xml");
var users
= from u in doc.Elements("user")
where u.Attribute("groupid") != null &&
int.Parse(u.Attribute("groupid").Value) > 2
select u;
Console.WriteLine(
"{0} users match query", users.Count());

Il y a un piège dans cette implémentation. La méthode XElement.Load va lire tout le fichier XML en mémoire avant de s’exécuter, et ce fichier peut être très gros. Non seulement, la requête va prendre beaucoup de temps à s’exécuter mais elle risque en plus de consommer tout la mémoire. Si vous avez un très gros fichier XML, vous devez utiliser un système de cache pour lire l’essentiel plutôt que de lire une première fois l’ensemble du contenu en mémoire. XmlReader est une jolie alternative pour nous permettre d’avoir uniquement l’enregistrement courant au lieu de l’ensemble de la mémoire et ainsi considérablement améliorer les performances.

Nous commençons par la définition d’une class “User” qui sera utilisée pour représenter une simple record:

    public class User 
{
public string Name { get; set; }
public int GroupId { get; set; }
}

Ensuite, nous étendons la classe XmlReader avec la méthode User:

    public static IEnumerable<User> Users(this XmlReader source)
{
while (source.Read())
{
if (source.NodeType == XmlNodeType.Element &&
source.Name
== "user")
{
int groupId;
int.TryParse(source.GetAttribute("groupid"), out groupId);
yield return new User
{
GroupId
= groupId,
Name
= source.GetAttribute("name")
};
}
}
}

Et finalement nous exécutons la requête:

    using (XmlReader reader = XmlReader.Create("users.xml"))
{
var users
= from u in reader.Users()
where u.GroupId > 2
select u;
Console.WriteLine(
"{0} users match query", users.Count());
}

Conclusion: La seconde approche s’exécute plus rapidement et utilise beaucoup moins de mémoire que la première.
La différence est significative sur de très gros fichier XML. Ainsi, si vous devez manipuler de très gros fichiers XML, faites très attention avec LINQ to XML.

Mise à jour le Mercredi, 19 Mai 2010 21:07