AIDE .NET

C# (Comment ça marche pour les développeurs)

Publié octobre 29, 2023
Partager:

Dans le monde du développement de logiciels, les tests sont un processus indispensable. Il garantit que votre code fonctionne comme prévu et permet de détecter les bogues avant qu'ils n'atteignent la production. L'un des aspects essentiels des tests est le mocking, et lorsqu'il s'agit de tests C#, le MOQ est un outil puissant dans l'arsenal d'un développeur. Il prend en charge les expressions lambda. MOQ, abréviation de "Mock Object Framework for .NET", simplifie le processus de création d'objets fictifs pour les tests unitaires. Dans cet article, nous allons nous pencher sur la question du MOQ dans C# ;

Qu'est-ce que le MOQ ?

MOQ est un Framework .NET qui permet aux développeurs de créer des objets fictifs rapidement et efficacement. Les objets fantaisie sont des objets qui simulent le comportement d'objets réels dans votre application, ce qui permet d'isoler et de tester plus facilement des parties spécifiques de votre code. MOQ simplifie le processus de création et d'utilisation de ces objets fictifs.

Principales caractéristiques du MOQ

  • Interface fluide: MOQ fournit une API fluide et expressive pour définir les attentes et les vérifications. Cela rend votre code de test plus lisible et plus facile à comprendre.
  • Type fort: MOQ exploite les caractéristiques du langage C# pour fournir un typage fort et un support IntelliSense lors de la définition des mocks et des attentes. Cela réduit les risques d'erreurs d'exécution dans vos tests.
  • Loose Mocking: MOQ supporte à la fois le strict et le loose mocking. La simulation libre permet de créer des objets fictifs qui répondent à n'importe quel appel de méthode, tandis que la simulation stricte garantit que seules les méthodes attendues sont appelées.
  • Comportement vérifiable: MOQ vous permet de vérifier que des méthodes spécifiques sur vos objets fantaisie ont été appelées avec les arguments attendus et dans le bon ordre.
  • Callbacks et Returns: Vous pouvez définir des callbacks pour exécuter un code personnalisé lorsqu'une méthode simulée est appelée et spécifier des valeurs de retour pour les méthodes simulées.

Démarrer avec le MOQ

Dans ce tutoriel, nous verrons comment utiliser MOQ, un framework de mocking populaire pour C#, afin de faciliter les tests unitaires. Nous allons voir un exemple dans lequel nous créons et testons un scénario de transaction ATM simple en utilisant MOQ pour simuler des dépendances.

Créer un nouveau C# ;

Suivez les étapes suivantes pour créer un nouveau projet

  1. Ouvrir Visual Studioallez dans "Fichier" > "Nouveau" > "Projet..."

  2. Choisissez un modèle de projet, configurez les paramètres et cliquez sur "Créer"

    C# (Comment ça marche pour les développeurs) Figure 1 - Créer une nouvelle application console dans Visual Studio 2022

    Supposons que vous développiez un logiciel pour un distributeur automatique de billets (Distributeur automatique de billets)et vous devez tester la fonctionnalité d'authentification et de retrait. L'ATM dépend de deux interfaces : IHostBank et IHSMModule. Nous voulons tester la classe ATMCashWithdrawal, qui représente la fonctionnalité de retrait d'argent du distributeur.

    Créer deux interfaces, IHostBank et IHSMModule, qui représentent les dépendances du système ATM. Définir des méthodes pertinentes telles que authenticateAmount et validatePIN.

// IHostBank.cs
public interface IHostBank
{
    bool AuthenticateAmount(string accountNumber, int amount);
}

// IHSMModule.cs
public interface IHSMModule
{
    bool ValidatePIN(string cardNumber, int pin);
}
// IHostBank.cs
public interface IHostBank
{
    bool AuthenticateAmount(string accountNumber, int amount);
}

// IHSMModule.cs
public interface IHSMModule
{
    bool ValidatePIN(string cardNumber, int pin);
}
' IHostBank.cs
Public Interface IHostBank
	Function AuthenticateAmount(ByVal accountNumber As String, ByVal amount As Integer) As Boolean
End Interface

' IHSMModule.cs
Public Interface IHSMModule
	Function ValidatePIN(ByVal cardNumber As String, ByVal pin As Integer) As Boolean
End Interface
VB   C#

Créer la classe ATMCashWithdrawal, qui utilise les dépendances mentionnées ci-dessus pour effectuer des opérations ATM. Dans cette classe, vous allez implémenter une certaine méthode comme WithdrawAmount.

// ATMCashWithdrawal.cs
public class ATMCashWithdrawal
{
    private readonly IHSMModule hsmModule;
    private readonly IHostBank hostBank;

    public ATMCashWithdrawal(IHSMModule hsmModule, IHostBank hostBank)
    {
        this.hsmModule = hsmModule;
        this.hostBank = hostBank;
    }
// non static method
    public bool WithdrawAmount(string cardNumber, int pin, int amount)
    {
        if (!hsmModule.ValidatePIN(cardNumber, pin))
        {
            return false;
        }

        if (!hostBank.AuthenticateAmount(cardNumber, amount))
        {
            return false;
        }

        // Withdraw the specified amount and perform other operations
        return true;
    }
}
// ATMCashWithdrawal.cs
public class ATMCashWithdrawal
{
    private readonly IHSMModule hsmModule;
    private readonly IHostBank hostBank;

    public ATMCashWithdrawal(IHSMModule hsmModule, IHostBank hostBank)
    {
        this.hsmModule = hsmModule;
        this.hostBank = hostBank;
    }
// non static method
    public bool WithdrawAmount(string cardNumber, int pin, int amount)
    {
        if (!hsmModule.ValidatePIN(cardNumber, pin))
        {
            return false;
        }

        if (!hostBank.AuthenticateAmount(cardNumber, amount))
        {
            return false;
        }

        // Withdraw the specified amount and perform other operations
        return true;
    }
}
' ATMCashWithdrawal.cs
Public Class ATMCashWithdrawal
	Private ReadOnly hsmModule As IHSMModule
	Private ReadOnly hostBank As IHostBank

	Public Sub New(ByVal hsmModule As IHSMModule, ByVal hostBank As IHostBank)
		Me.hsmModule = hsmModule
		Me.hostBank = hostBank
	End Sub
' non static method
	Public Function WithdrawAmount(ByVal cardNumber As String, ByVal pin As Integer, ByVal amount As Integer) As Boolean
		If Not hsmModule.ValidatePIN(cardNumber, pin) Then
			Return False
		End If

		If Not hostBank.AuthenticateAmount(cardNumber, amount) Then
			Return False
		End If

		' Withdraw the specified amount and perform other operations
		Return True
	End Function
End Class
VB   C#

Créer un projet de test unitaire

Maintenant, créons des tests unitaires pour la classe ATMCashWithdrawal en utilisant MOQ pour simuler les dépendances.

Créez un nouveau projet de test unitaire dans votre solution et nommez-le ATMSystem.Tests.

Pour ajouter un projet de test NUnit à votre solution Visual Studio, procédez comme suit :

  1. Cliquez avec le bouton droit de la souris sur la solution: Dans l'explorateur de solutions (généralement du côté droit)cliquez avec le bouton droit de la souris sur le nom de la solution.

  2. Ajouter > Nouveau projet: Dans le menu contextuel, sélectionnez "Ajouter" puis "Nouveau projet..."

  3. Créer un nouveau projet: Dans la boîte de dialogue "Ajouter un nouveau projet", vous pouvez rechercher "NUnit" pour trouver les modèles NUnit disponibles. Choisissez le projet de test NUnit comme indiqué ci-dessous.

    C# (Comment ça marche pour les développeurs) Figure 2 - Ajoutez un nouveau projet de test NUnit dans votre solution.

  4. Configurer le projet: Configurer les paramètres du projet selon les besoins, y compris le nom et l'emplacement du projet.

  5. Cliquez sur OK: Cliquez sur le bouton "Créer" ou "OK" pour ajouter le projet de test NUnit à votre solution.

    Vous disposez désormais d'un projet de test NUnit distinct au sein de votre solution, dans lequel vous pouvez écrire et gérer vos tests unitaires. Vous pouvez également ajouter des références aux projets que vous souhaitez tester et commencer à écrire vos cas de test NUnit dans ce projet.

    Pour commencer à utiliser MOQ dans le projet de test, vous devez ajouter le paquetage NuGet MOQ à votre solution. Vous pouvez le faire en utilisant le gestionnaire de paquets NuGet dans Visual Studio ou en exécutant la commande suivante dans la console du gestionnaire de paquets :

Install-package moq

Cette commande installera le paquet et ajoutera toutes les dépendances nécessaires au projet.

Écrire des tests unitaires en utilisant NUnit et MOQ pour simuler les dépendances (IHostBank et IHSMModule) de la classe ATMCashWithdrawal.

using Moq;
using MOQTestProject;

namespace UnitTest
{
    public class Tests
    {
        ATMCashWithdrawal atmCash;
        [SetUp]
        public void Setup()
        {
            // Arrange
            var hsmModuleMock = new Mock<IHSMModule>();
            hsmModuleMock.Setup(h => h.ValidatePIN("123456781234", 1234)).Returns(true);

            var hostBankMock = new Mock<IHostBank>();
            hostBankMock.Setup(h => h.AuthenticateAmount("123456781234", 500)).Returns(true);
            var atmCash = new ATMCashWithdrawal(hsmModuleMock.Object, hostBankMock.Object); // Object property
        }

        [Test]
        public void WithdrawAmount_ValidTransaction_ReturnsTrue()
        {
            // Act
            bool result = atmCash.WithdrawAmount("123456781234", 1234, 500);

            // Assert
            Assert.IsTrue(result); // Verify method 
        }

        // Add more test cases for different scenarios (e.g., invalid PIN, insufficient funds, etc.)
    }
}
using Moq;
using MOQTestProject;

namespace UnitTest
{
    public class Tests
    {
        ATMCashWithdrawal atmCash;
        [SetUp]
        public void Setup()
        {
            // Arrange
            var hsmModuleMock = new Mock<IHSMModule>();
            hsmModuleMock.Setup(h => h.ValidatePIN("123456781234", 1234)).Returns(true);

            var hostBankMock = new Mock<IHostBank>();
            hostBankMock.Setup(h => h.AuthenticateAmount("123456781234", 500)).Returns(true);
            var atmCash = new ATMCashWithdrawal(hsmModuleMock.Object, hostBankMock.Object); // Object property
        }

        [Test]
        public void WithdrawAmount_ValidTransaction_ReturnsTrue()
        {
            // Act
            bool result = atmCash.WithdrawAmount("123456781234", 1234, 500);

            // Assert
            Assert.IsTrue(result); // Verify method 
        }

        // Add more test cases for different scenarios (e.g., invalid PIN, insufficient funds, etc.)
    }
}
Imports Moq
Imports MOQTestProject

Namespace UnitTest
	Public Class Tests
		Private atmCash As ATMCashWithdrawal
		<SetUp>
		Public Sub Setup()
			' Arrange
			Dim hsmModuleMock = New Mock(Of IHSMModule)()
			hsmModuleMock.Setup(Function(h) h.ValidatePIN("123456781234", 1234)).Returns(True)

			Dim hostBankMock = New Mock(Of IHostBank)()
			hostBankMock.Setup(Function(h) h.AuthenticateAmount("123456781234", 500)).Returns(True)
			Dim atmCash = New ATMCashWithdrawal(hsmModuleMock.Object, hostBankMock.Object) ' Object property
		End Sub

		<Test>
		Public Sub WithdrawAmount_ValidTransaction_ReturnsTrue()
			' Act
			Dim result As Boolean = atmCash.WithdrawAmount("123456781234", 1234, 500)

			' Assert
			Assert.IsTrue(result) ' Verify method
		End Sub

		' Add more test cases for different scenarios (e.g., invalid PIN, insufficient funds, etc.)
	End Class
End Namespace
VB   C#

Dans ce code de test, nous utilisons MOQ pour créer des objets fantaisie pour IHSMModule et IHostBank et spécifier leur comportement lorsqu'ils sont appelés pendant le test.

Dans l'exemple de code ci-dessus, nous avons démontré le concept de l'imitation d'objets à l'aide de MOQ en C#. Nous créons des objets fictifs pour les interfaces IHSMModule et IHostBank, afin de simuler leur comportement pendant les tests unitaires. Cela nous permet d'isoler et de tester en profondeur la classe ATMCashWithdrawal en contrôlant les réponses de ces objets fictifs. Grâce au mocking, nous pouvons nous assurer que notre code interagit correctement avec ces dépendances, ce qui rend nos tests ciblés, prévisibles et efficaces dans l'identification des problèmes au sein de l'unité spécifique de code examinée. Cette pratique améliore la fiabilité et la maintenabilité globales, et facilite le test du code.

Étape 3 Exécution des tests

  1. Construisez votre solution pour vous assurer que tout est à jour.

  2. Ouvrez l'explorateur de tests dans Visual Studio (Test > Test Explorer).

  3. Cliquez sur le bouton "Exécuter tout" dans l'explorateur de tests pour exécuter vos tests unitaires.

  4. Examiner les résultats des tests. Vous devriez voir le test que vous avez écrit (WithdrawAmount\NValidTransaction\NReturnsTrue (Montant du retrait\NValideTransaction\N)) passer.

    Moq C# (Comment cela fonctionne-t-il pour les développeurs ?)  Figure 3 - Pour exécuter les tests, vous devez d'abord créer la solution. Une fois la compilation réussie, ouvrez l'Explorateur de tests dans Visual Studio et cliquez sur le bouton Exécuter tout pour lancer l'exécution de vos tests unitaires.

    De cette manière, nous pouvons isoler le code que nous voulons tester et nous assurer qu'il se comporte comme prévu dans différents scénarios en simulant efficacement les dépendances. Cette pratique améliore la fiabilité et la maintenabilité de votre logiciel, en facilitant l'identification et la correction des problèmes dès le début du processus de développement.

Présentation d'IronPDF

IronPDF est une puissante bibliothèque C# qui permet aux développeurs de travailler avec des documents PDF dans leurs applications. Il offre un large éventail de fonctionnalités, notamment la création, la modification et la conversion de fichiers PDF à partir de diverses sources, telles que le HTML, les images et les PDF existants. Combiné au concept d'objets mocking abordé dans le tutoriel précédent, IronPDF peut être un outil précieux pour générer et manipuler des documents PDF dans vos tests unitaires.

La principale caractéristique d'IronPDF est son HTML vers PDF en veillant à ce que les mises en page et les styles soient intacts. Il transforme le contenu web en PDF, ce qui est idéal pour les rapports, les factures et la documentation. Cette fonction permet de convertir des fichiers HTML, des URL et des chaînes HTML en PDF.

using IronPdf;

class Program
{
    static void Main(string[] args)
    {
        var renderer = new ChromePdfRenderer();

        // 1. Convert HTML String to PDF
        var htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>";
        var pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent);
        pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf");

        // 2. Convert HTML File to PDF
        var htmlFilePath = "path_to_your_html_file.html"; // Specify the path to your HTML file
        var pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath);
        pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf");

        // 3. Convert URL to PDF
        var url = "http://ironpdf.com"; // Specify the URL
        var pdfFromUrl = renderer.RenderUrlAsPdf(url);
        pdfFromUrl.SaveAs("URLToPDF.pdf");
    }
}
using IronPdf;

class Program
{
    static void Main(string[] args)
    {
        var renderer = new ChromePdfRenderer();

        // 1. Convert HTML String to PDF
        var htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>";
        var pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent);
        pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf");

        // 2. Convert HTML File to PDF
        var htmlFilePath = "path_to_your_html_file.html"; // Specify the path to your HTML file
        var pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath);
        pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf");

        // 3. Convert URL to PDF
        var url = "http://ironpdf.com"; // Specify the URL
        var pdfFromUrl = renderer.RenderUrlAsPdf(url);
        pdfFromUrl.SaveAs("URLToPDF.pdf");
    }
}
Imports IronPdf

Friend Class Program
	Shared Sub Main(ByVal args() As String)
		Dim renderer = New ChromePdfRenderer()

		' 1. Convert HTML String to PDF
		Dim htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>"
		Dim pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent)
		pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf")

		' 2. Convert HTML File to PDF
		Dim htmlFilePath = "path_to_your_html_file.html" ' Specify the path to your HTML file
		Dim pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath)
		pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf")

		' 3. Convert URL to PDF
		Dim url = "http://ironpdf.com" ' Specify the URL
		Dim pdfFromUrl = renderer.RenderUrlAsPdf(url)
		pdfFromUrl.SaveAs("URLToPDF.pdf")
	End Sub
End Class
VB   C#

Par exemple, si vous avez un projet impliquant la génération ou le traitement de PDF, vous pouvez utiliser IronPDF pour créer des documents PDF fictifs qui imitent des scénarios réels. Cela peut être particulièrement utile pour tester et valider la façon dont votre code interagit avec les fichiers PDF. Vous pouvez générer des PDF fictifs avec un contenu, une mise en page et des propriétés spécifiques, puis les utiliser comme montages de test pour vous assurer que votre code produit les sorties PDF souhaitées ou gère correctement les opérations liées aux PDF.

Créer des objets MOCK pour générer des PDF

Supposons que vous développiez une application qui génère des rapports financiers et que ces rapports doivent être enregistrés et distribués sous forme de documents PDF. Dans ce cas, vous voudrez peut-être tester la génération du PDF et vous assurer que le contenu et la mise en forme sont corrects.

Tout d'abord, nous devons ajouter IronPDF à notre projet. Ecrivez la commande suivante dans la console du gestionnaire de paquets NuGet pour installer IronPDF.

Install-Package IronPdf

Cette commande va installer et ajouter les dépendances nécessaires à notre projet.

Voici comment IronPDF peut être intégré au processus de test unitaire :

Générer des PDF fictifs

Vous pouvez utiliser IronPDF pour créer des documents PDF fictifs avec un contenu et un style spécifiques afin d'imiter les rapports financiers réels. Ces faux PDF peuvent servir de supports de test pour vos tests unitaires, comme le montre l'extrait de code suivant :

public class PDFGenerator
{
    public void GenerateFinancialReport(string reportData)
    {
        var renderer = new ChromePdfRenderer();
        // Generate the report HTML
        string reportHtml = GenerateReportHtml(reportData);
        PdfDocument pdfDocument = renderer.RenderHtmlAsPdf(reportHtml);
        // Save the PDF to a file or memory stream
        pdfDocument.SaveAsPdfA("FinancialReport.pdf");
    }

    private string GenerateReportHtml(string reportData)
    {
        // Generate the report HTML based on the provided data
        // (e.g., using Razor views or any HTML templating mechanism)
        // Return the HTML as a string

        return "<h1>my Report</h1>";
    }
}
public class PDFGenerator
{
    public void GenerateFinancialReport(string reportData)
    {
        var renderer = new ChromePdfRenderer();
        // Generate the report HTML
        string reportHtml = GenerateReportHtml(reportData);
        PdfDocument pdfDocument = renderer.RenderHtmlAsPdf(reportHtml);
        // Save the PDF to a file or memory stream
        pdfDocument.SaveAsPdfA("FinancialReport.pdf");
    }

    private string GenerateReportHtml(string reportData)
    {
        // Generate the report HTML based on the provided data
        // (e.g., using Razor views or any HTML templating mechanism)
        // Return the HTML as a string

        return "<h1>my Report</h1>";
    }
}
Public Class PDFGenerator
	Public Sub GenerateFinancialReport(ByVal reportData As String)
		Dim renderer = New ChromePdfRenderer()
		' Generate the report HTML
		Dim reportHtml As String = GenerateReportHtml(reportData)
		Dim pdfDocument As PdfDocument = renderer.RenderHtmlAsPdf(reportHtml)
		' Save the PDF to a file or memory stream
		pdfDocument.SaveAsPdfA("FinancialReport.pdf")
	End Sub

	Private Function GenerateReportHtml(ByVal reportData As String) As String
		' Generate the report HTML based on the provided data
		' (e.g., using Razor views or any HTML templating mechanism)
		' Return the HTML as a string

		Return "<h1>my Report</h1>"
	End Function
End Class
VB   C#

Test unitaire avec des PDF fictifs

Nous allons écrire des tests pour utiliser IronPDF afin de générer des PDF fictifs représentant divers scénarios de rapports. Ensuite, nous comparerons les PDF réels générés par notre code avec ces PDF fictifs pour nous assurer que le contenu, le formatage et la structure sont conformes aux attentes.

internal class PDFGeneratorTests
{
    [Test]
    public void GenerateFinancialReport_CreatesCorrectPDF()
    {
        // Arrange
        var mock = new PDFGenerator();
        var expectedPdf = PdfDocument.FromFile("ExpectedFinancialReport.pdf"); // Load a mock PDF

        // Act
        mock.GenerateFinancialReport("Sample report data");
        var actualPdf = PdfDocument.FromFile("FinancialReport.pdf");

        // Assert
        Assert.AreEqual(actualPdf.ExtractAllText() , expectedPdf.ExtractAllText());
    }

}
internal class PDFGeneratorTests
{
    [Test]
    public void GenerateFinancialReport_CreatesCorrectPDF()
    {
        // Arrange
        var mock = new PDFGenerator();
        var expectedPdf = PdfDocument.FromFile("ExpectedFinancialReport.pdf"); // Load a mock PDF

        // Act
        mock.GenerateFinancialReport("Sample report data");
        var actualPdf = PdfDocument.FromFile("FinancialReport.pdf");

        // Assert
        Assert.AreEqual(actualPdf.ExtractAllText() , expectedPdf.ExtractAllText());
    }

}
Friend Class PDFGeneratorTests
	<Test>
	Public Sub GenerateFinancialReport_CreatesCorrectPDF()
		' Arrange
		Dim mock = New PDFGenerator()
		Dim expectedPdf = PdfDocument.FromFile("ExpectedFinancialReport.pdf") ' Load a mock PDF

		' Act
		mock.GenerateFinancialReport("Sample report data")
		Dim actualPdf = PdfDocument.FromFile("FinancialReport.pdf")

		' Assert
		Assert.AreEqual(actualPdf.ExtractAllText(), expectedPdf.ExtractAllText())
	End Sub

End Class
VB   C#

Dans ce code de test, nous générons un PDF fictif (expectedPdf) représentant la sortie attendue et la comparer avec le PDF (actualPDF) généré par le PDFGenerator. Nous avons extrait le contenu des deux PDF pour vérifier s'ils ont le même contenu.

Conclusion

En conclusion, l'effet de levier du MOQ, ainsi que l'effet de levier du IronPDF dans notre processus de test unitaire, nous permet de vérifier de manière exhaustive le comportement de nos applications logicielles. MOQ nous permet d'isoler des composants de code spécifiques, de contrôler les dépendances et de simuler des scénarios complexes, ce qui nous permet d'écrire des tests ciblés et fiables.

En attendant, IronPDF améliore nos capacités de test en facilitant la génération et la manipulation de documents PDF, garantissant ainsi un examen approfondi de nos fonctionnalités liées aux PDF. En intégrant ces outils dans notre boîte à outils de test, nous pouvons développer en toute confiance des logiciels robustes et de haute qualité qui répondent aux exigences de fonctionnalité et de performance. Cette combinaison de tests unitaires robustes avec MOQ et de validation des PDF avec IronPDF contribue de manière significative à la qualité et à la fiabilité globales de nos applications.

Il est intéressant de noter qu'IronPDF propose un service de essai gratuit pour tester ses fonctionnalités. Si vous estimez qu'il répond à vos besoins, vous avez la possibilité d'acheter une licence commerciale. Vous pouvez ainsi continuer à utiliser les fonctionnalités d'IronPDF dans vos projets en bénéficiant de tous les avantages et de l'assistance offerts par une version sous licence, ce qui garantit l'intégration harmonieuse des fonctionnalités liées au format PDF dans vos applications.

< PRÉCÉDENT
Entity Framework C# (Comment ça marche pour les développeurs)
SUIVANT >
Cadre Web C# (Comment ça marche pour les développeurs)