Summary: This post explores how to integrate AI-powered code generation and assistance capabilities into .NET applications. Learn how to leverage large language models to create tools that can generate code, provide intelligent code completion, and assist developers throughout the development lifecycle.
Introduction
Artificial Intelligence has revolutionized many aspects of software development, and one of the most impactful applications is AI-powered code generation and assistance. These tools can significantly enhance developer productivity by automating repetitive coding tasks, providing intelligent suggestions, and even generating entire code blocks or functions based on natural language descriptions.
In this post, we’ll explore how to implement AI-powered code generation and assistance capabilities in .NET applications. We’ll cover everything from integrating with large language models (LLMs) to building specialized tools for code completion, refactoring, documentation generation, and more. By the end of this article, you’ll have the knowledge to create your own AI-powered development tools that can boost productivity and code quality.
Understanding AI-Powered Code Generation
Before diving into implementation, let’s understand the key concepts behind AI-powered code generation and assistance.
What is AI-Powered Code Generation?
AI-powered code generation refers to the use of artificial intelligence, particularly large language models, to automatically generate code based on various inputs such as:
- Natural Language Descriptions: Converting plain English requirements into functional code
- Code Comments: Generating implementation based on function signatures and comments
- Partial Code: Completing code snippets or functions based on context
- Test Cases: Creating implementations that satisfy given test cases
- Design Patterns: Applying common design patterns to specific use cases
Types of AI Code Assistance
AI code assistance can take many forms, including:
- Code Completion: Suggesting the next lines of code as you type
- Code Generation: Creating entire functions or classes based on descriptions
- Code Refactoring: Suggesting improvements to existing code
- Bug Detection: Identifying potential issues in code
- Documentation Generation: Creating documentation from code or vice versa
- Test Generation: Creating unit tests for existing code
- Code Explanation: Providing natural language explanations of complex code
Benefits and Limitations
AI-powered code tools offer several benefits:
- Increased Productivity: Automating repetitive coding tasks
- Reduced Boilerplate: Generating common patterns and structures
- Knowledge Sharing: Providing access to best practices
- Learning Aid: Helping developers learn new languages or frameworks
- Consistency: Maintaining coding standards across projects
However, they also have limitations:
- Code Quality Varies: Generated code may not always follow best practices
- Context Understanding: AI may miss project-specific context
- Security Concerns: Generated code might introduce vulnerabilities
- Dependency on Training Data: Limited by what the model has been trained on
- Need for Review: Human review is still essential
Setting Up the Development Environment
Let’s start by setting up our development environment for building AI-powered code tools.
Prerequisites
To follow along with this tutorial, you’ll need:
- Visual Studio 2022 or Visual Studio Code
- .NET 8 SDK
- An Azure subscription
- Access to Azure OpenAI Service or OpenAI API
- Basic understanding of C# and .NET development
Creating a New Project
Let’s create a new .NET project for our AI code assistant:
bash
dotnet new console -n AICodeAssistant
cd AICodeAssistant
Installing Required Packages
Add the necessary packages to your project:
bash
dotnet add package Azure.AI.OpenAI
dotnet add package Microsoft.Extensions.Configuration
dotnet add package Microsoft.Extensions.Configuration.Json
dotnet add package Microsoft.Extensions.Configuration.EnvironmentVariables
dotnet add package Microsoft.Extensions.DependencyInjection
dotnet add package Microsoft.Extensions.Logging
dotnet add package Microsoft.Extensions.Logging.Console
dotnet add package Microsoft.CodeAnalysis.CSharp
Setting Up Configuration
Create an appsettings.json file to store your configuration:
json
{
"AzureOpenAI": {
"Endpoint": "https://your-openai-service.openai.azure.com/",
"Key": "your-openai-api-key",
"DeploymentName": "your-gpt-4-deployment"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning"
}
}
}
Creating a Configuration Helper
Let’s create a helper class to load our configuration:
csharp
// Configuration/ConfigurationHelper.cs
using Microsoft.Extensions.Configuration;
namespace AICodeAssistant.Configuration
{
public static class ConfigurationHelper
{
public static IConfiguration GetConfiguration( )
{
return new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
}
}
}
Building Core AI Code Generation Services
Now, let’s implement the core services for AI-powered code generation.
Creating the AI Service
First, let’s create a service to interact with the AI model:
csharp
// Services/AIService.cs
using Azure;
using Azure.AI.OpenAI;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System.Text;
namespace AICodeAssistant.Services
{
public class AIService
{
private readonly OpenAIClient _client;
private readonly string _deploymentName;
private readonly ILogger<AIService> _logger;
public AIService(IConfiguration configuration, ILogger<AIService> logger)
{
_logger = logger;
var endpoint = new Uri(configuration["AzureOpenAI:Endpoint"]);
var key = configuration["AzureOpenAI:Key"];
_deploymentName = configuration["AzureOpenAI:DeploymentName"];
_client = new OpenAIClient(endpoint, new AzureKeyCredential(key));
}
public async Task<string> GenerateCompletionAsync(
string prompt,
float temperature = 0.2f,
int maxTokens = 2000)
{
try
{
_logger.LogInformation("Generating completion for prompt");
var chatCompletionsOptions = new ChatCompletionsOptions
{
Temperature = temperature,
MaxTokens = maxTokens,
NucleusSamplingFactor = 0.95f, // Top-p
FrequencyPenalty = 0,
PresencePenalty = 0
};
// Add system message
chatCompletionsOptions.Messages.Add(new ChatMessage(ChatRole.System,
"You are an expert .NET developer assistant specialized in generating high-quality, " +
"secure, and efficient C# code. Provide only the code without explanations unless " +
"specifically asked for explanations."));
// Add user message
chatCompletionsOptions.Messages.Add(new ChatMessage(ChatRole.User, prompt));
// Get completion
var response = await _client.GetChatCompletionsAsync(_deploymentName, chatCompletionsOptions);
var completion = response.Value;
return completion.Choices[0].Message.Content;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error generating completion");
throw;
}
}
public async Task<string> GenerateStreamingCompletionAsync(
string prompt,
Action<string> onPartialResponse,
float temperature = 0.2f,
int maxTokens = 2000)
{
try
{
_logger.LogInformation("Generating streaming completion for prompt");
var chatCompletionsOptions = new ChatCompletionsOptions
{
Temperature = temperature,
MaxTokens = maxTokens,
NucleusSamplingFactor = 0.95f, // Top-p
FrequencyPenalty = 0,
PresencePenalty = 0
};
// Add system message
chatCompletionsOptions.Messages.Add(new ChatMessage(ChatRole.System,
"You are an expert .NET developer assistant specialized in generating high-quality, " +
"secure, and efficient C# code. Provide only the code without explanations unless " +
"specifically asked for explanations."));
// Add user message
chatCompletionsOptions.Messages.Add(new ChatMessage(ChatRole.User, prompt));
// Get streaming completion
var response = await _client.GetChatCompletionsStreamingAsync(_deploymentName, chatCompletionsOptions);
var responseBuilder = new StringBuilder();
await foreach (var update in response)
{
if (update.ContentUpdate != null)
{
responseBuilder.Append(update.ContentUpdate);
onPartialResponse(update.ContentUpdate);
}
}
return responseBuilder.ToString();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error generating streaming completion");
throw;
}
}
}
}
Creating the Code Generation Service
Now, let’s create a specialized service for code generation:
csharp
// Services/CodeGenerationService.cs
using Microsoft.Extensions.Logging;
using System.Text;
namespace AICodeAssistant.Services
{
public class CodeGenerationService
{
private readonly AIService _aiService;
private readonly ILogger<CodeGenerationService> _logger;
public CodeGenerationService(AIService aiService, ILogger<CodeGenerationService> logger)
{
_aiService = aiService;
_logger = logger;
}
public async Task<string> GenerateCodeFromDescriptionAsync(
string description,
string language = "csharp",
string framework = ".NET 8")
{
_logger.LogInformation("Generating code from description");
var prompt = new StringBuilder();
prompt.AppendLine($"Generate {language} code for the following description:");
prompt.AppendLine();
prompt.AppendLine(description);
prompt.AppendLine();
prompt.AppendLine($"Use {framework} and follow best practices for clean, efficient, and secure code.");
prompt.AppendLine("Include appropriate error handling, comments, and documentation.");
return await _aiService.GenerateCompletionAsync(prompt.ToString(), 0.2f);
}
public async Task<string> CompleteCodeSnippetAsync(string partialCode, string language = "csharp")
{
_logger.LogInformation("Completing code snippet");
var prompt = new StringBuilder();
prompt.AppendLine($"Complete the following {language} code snippet:");
prompt.AppendLine("```");
prompt.AppendLine(partialCode);
prompt.AppendLine("```");
prompt.AppendLine();
prompt.AppendLine("Provide the complete implementation following best practices for clean, efficient, and secure code.");
return await _aiService.GenerateCompletionAsync(prompt.ToString(), 0.2f);
}
public async Task<string> GenerateUnitTestsAsync(string codeToTest, string testFramework = "xUnit")
{
_logger.LogInformation("Generating unit tests");
var prompt = new StringBuilder();
prompt.AppendLine($"Generate {testFramework} unit tests for the following C# code:");
prompt.AppendLine("```");
prompt.AppendLine(codeToTest);
prompt.AppendLine("```");
prompt.AppendLine();
prompt.AppendLine("Provide comprehensive test coverage with appropriate test cases, assertions, and mocking where necessary.");
return await _aiService.GenerateCompletionAsync(prompt.ToString(), 0.3f);
}
public async Task<string> RefactorCodeAsync(string codeToRefactor, string refactoringGoal)
{
_logger.LogInformation("Refactoring code");
var prompt = new StringBuilder();
prompt.AppendLine("Refactor the following C# code:");
prompt.AppendLine("```");
prompt.AppendLine(codeToRefactor);
prompt.AppendLine("```");
prompt.AppendLine();
prompt.AppendLine($"Refactoring goal: {refactoringGoal}");
prompt.AppendLine();
prompt.AppendLine("Provide the refactored code with improvements that address the refactoring goal while maintaining the original functionality.");
return await _aiService.GenerateCompletionAsync(prompt.ToString(), 0.2f);
}
public async Task<string> GenerateDocumentationAsync(string codeToDocument)
{
_logger.LogInformation("Generating documentation");
var prompt = new StringBuilder();
prompt.AppendLine("Generate comprehensive XML documentation comments for the following C# code:");
prompt.AppendLine("```");
prompt.AppendLine(codeToDocument);
prompt.AppendLine("```");
prompt.AppendLine();
prompt.AppendLine("Include detailed descriptions, parameter explanations, return value documentation, and exception documentation where appropriate.");
return await _aiService.GenerateCompletionAsync(prompt.ToString(), 0.2f);
}
public async Task<string> ExplainCodeAsync(string codeToExplain)
{
_logger.LogInformation("Explaining code");
var prompt = new StringBuilder();
prompt.AppendLine("Explain the following C# code in detail:");
prompt.AppendLine("```");
prompt.AppendLine(codeToExplain);
prompt.AppendLine("```");
prompt.AppendLine();
prompt.AppendLine("Provide a comprehensive explanation including:");
prompt.AppendLine("1. Overall purpose of the code");
prompt.AppendLine("2. Breakdown of key components and their functions");
prompt.AppendLine("3. Any design patterns or important techniques used");
prompt.AppendLine("4. Potential performance considerations");
prompt.AppendLine("5. Any security implications");
return await _aiService.GenerateCompletionAsync(prompt.ToString(), 0.3f, 3000);
}