.NET Core调用丹青识画REST APIC#实现跨平台图像分析客户端最近在做一个智能相册管理的小工具需要给海量图片自动打标签。手动处理那简直是噩梦。找了一圈发现丹青识画这个服务挺有意思能识别图片里的物体、场景、文字甚至能理解图片内容。作为一个.NET开发者我第一反应就是能不能用C#写个客户端来调用它答案是肯定的而且用.NET Core来做这件事特别合适。你想想现在开发环境五花八门有人用Windows有人用macOS还有人用Linux。.NET Core的跨平台特性正好派上用场写一套代码到处都能跑。今天我就来分享一下怎么用C#和.NET Core从零开始构建一个能调用丹青识画服务的图像分析客户端。不管是做成带界面的桌面程序还是轻量级的命令行工具思路都是相通的。1. 准备工作理解服务与搭建环境在动手写代码之前我们得先搞清楚两件事丹青识画服务能干什么以及我们的开发环境需要什么。丹青识画本质上是一个提供图像识别能力的REST API。你给它一张图片它就能返回识别结果比如图片里有什么物体、属于什么场景、有没有文字、文字内容是什么等等。这对于内容审核、图片分类、信息提取这些场景来说非常实用。我们的目标是用C#写个程序把图片“送”给这个API然后把返回的“答案”拿回来处理。整个过程会涉及到几个关键技术点用HttpClient来发送网络请求、用System.Text.Json来处理返回的JSON数据、用async/await来保证程序在等待网络响应时不会卡住。开发环境很简单。首先确保你安装了.NET SDK6.0或以上版本都行。打开你的命令行输入dotnet --version看看。然后找个顺手的IDEVisual Studio、Visual Studio Code或者Rider都可以。项目类型嘛根据你的需求来选如果想做个带按钮和图片预览的窗口程序可以用WPF或WinForms.NET Core 3.0之后都支持如果只是想做个后台处理图片的脚本用控制台应用就够了。这里为了演示最核心的API调用流程我们先从控制台应用开始理解了原理加界面就是水到渠成的事。2. 核心实战用HttpClient调用识别API理论说再多不如一行代码。我们直接创建一个新的控制台项目然后一步步实现调用。打开终端创建一个新项目dotnet new console -n ImageAnalysisClient cd ImageAnalysisClient2.1 构建请求准备图片和参数调用API第一步是构造一个正确的HTTP请求。通常这类图像识别API都要求以POST方式提交并且图片数据要么以multipart/form-data形式放在表单里要么将图片转换成Base64编码的字符串放在JSON请求体中。我们假设丹青识画API接受Base64格式。那么我们需要先读取图片文件把它转换成Base64字符串。using System; using System.IO; using System.Threading.Tasks; namespace ImageAnalysisClient { class Program { static async Task Main(string[] args) { // 1. 读取图片并转换为Base64 string imagePath C:\path\to\your\image.jpg; // 替换成你的图片路径 string imageBase64; try { byte[] imageBytes await File.ReadAllBytesAsync(imagePath); imageBase64 Convert.ToBase64String(imageBytes); Console.WriteLine(图片已成功读取并编码。); } catch (Exception ex) { Console.WriteLine($读取图片文件失败: {ex.Message}); return; } // 接下来的步骤构建请求JSON并发送 } } }2.2 发送请求使用HttpClient与异步编程有了图片数据我们就要构造一个JSON对象里面包含Base64字符串和其他可能的参数比如是否需要识别文字、置信度阈值等。然后使用HttpClient发送这个请求。这里有个最佳实践对于需要频繁创建HttpClient的应用应该考虑使用IHttpClientFactory来管理生命周期。但对于我们这种简单的示例直接实例化一个也可以。关键是要记得设置请求头比如Content-Type和Authorization如果你的API需要密钥。using System; using System.IO; using System.Net.Http; using System.Text; using System.Text.Json; using System.Threading.Tasks; namespace ImageAnalysisClient { class Program { // 假设的API端点与密钥请替换为实际值 private const string ApiEndpoint https://api.example.com/v1/image/recognize; private const string ApiKey your_api_key_here; static async Task Main(string[] args) { // ... 上面的图片读取代码 ... // 2. 构建请求JSON数据 var requestData new { image imageBase64, detect_text true, // 是否识别文字 max_concepts 5 // 返回最可能的5个标签 }; string jsonContent JsonSerializer.Serialize(requestData); // 3. 创建并发送HTTP请求 using (var httpClient new HttpClient()) { // 设置请求头 httpClient.DefaultRequestHeaders.Add(Authorization, $Bearer {ApiKey}); var content new StringContent(jsonContent, Encoding.UTF8, application/json); Console.WriteLine(正在向识别API发送请求...); HttpResponseMessage response; try { response await httpClient.PostAsync(ApiEndpoint, content); } catch (HttpRequestException ex) { Console.WriteLine($网络请求失败: {ex.Message}); return; } // 检查响应状态 if (response.IsSuccessStatusCode) { string responseBody await response.Content.ReadAsStringAsync(); Console.WriteLine(API调用成功); // 接下来处理响应体 } else { Console.WriteLine($API请求失败状态码: {(int)response.StatusCode} - {response.ReasonPhrase}); string errorBody await response.Content.ReadAsStringAsync(); Console.WriteLine($错误详情: {errorBody}); } } } } }2.3 处理响应解析JSON与结果展示API调用成功我们会拿到一个JSON格式的响应。现在我们需要反序列化这个JSON把里面的识别结果提取出来并以一种友好的方式展示。我们需要根据丹青识画API的实际响应格式来定义对应的C#类也叫POCO类。假设返回的格式大致如下{ request_id: req_123, results: { tags: [ {name: 天空, confidence: 0.98}, {name: 建筑, confidence: 0.87} ], text: 欢迎来到上海, scene: 城市风光 } }那么我们可以定义这样的类来匹配using System.Collections.Generic; using System.Text.Json.Serialization; namespace ImageAnalysisClient { // 定义与API响应JSON结构对应的C#类 public class ApiResponse { [JsonPropertyName(request_id)] public string RequestId { get; set; } public RecognitionResults Results { get; set; } } public class RecognitionResults { public ListImageTag Tags { get; set; } public string Text { get; set; } public string Scene { get; set; } } public class ImageTag { public string Name { get; set; } public double Confidence { get; set; } // 置信度0~1之间 } }然后在收到响应后用System.Text.Json进行反序列化// 接上面的成功响应处理部分 if (response.IsSuccessStatusCode) { string responseBody await response.Content.ReadAsStringAsync(); Console.WriteLine(API调用成功); // 4. 解析JSON响应 try { var options new JsonSerializerOptions { PropertyNameCaseInsensitive true }; var apiResponse JsonSerializer.DeserializeApiResponse(responseBody, options); // 5. 展示结果 Console.WriteLine($\n 图片分析结果 ); Console.WriteLine($请求ID: {apiResponse.RequestId}); Console.WriteLine($场景分类: {apiResponse.Results.Scene}); if (!string.IsNullOrEmpty(apiResponse.Results.Text)) { Console.WriteLine($识别文字: {apiResponse.Results.Text}); } Console.WriteLine(\n识别标签:); if (apiResponse.Results.Tags ! null) { foreach (var tag in apiResponse.Results.Tags) { Console.WriteLine($ - {tag.Name} (置信度: {tag.Confidence:P0})); // P0格式显示为百分比 } } } catch (JsonException ex) { Console.WriteLine($解析API响应失败: {ex.Message}); } }运行这个程序你就能在控制台看到图片的分析结果了。从读取图片到发送请求再到解析展示结果一个最基础的客户端就完成了。3. 进阶封装构建可复用的服务类把所有的代码都堆在Main方法里可不是好主意。为了代码更清晰、更易复用我们应该把调用API的逻辑封装成一个独立的服务类。这样无论是在控制台程序里调用还是在WPF、WinForms的界面后台调用都会非常方便。我们来创建一个ImageRecognitionService类using System; using System.IO; using System.Net.Http; using System.Text; using System.Text.Json; using System.Threading.Tasks; namespace ImageAnalysisClient.Services { public class ImageRecognitionService { private readonly HttpClient _httpClient; private readonly string _apiKey; private readonly JsonSerializerOptions _jsonOptions; public ImageRecognitionService(string apiEndpoint, string apiKey) { _httpClient new HttpClient { BaseAddress new Uri(apiEndpoint) }; _httpClient.DefaultRequestHeaders.Add(Authorization, $Bearer {apiKey}); _apiKey apiKey; _jsonOptions new JsonSerializerOptions { PropertyNameCaseInsensitive true }; } // 核心方法识别图片 public async TaskApiResponse RecognizeImageAsync(string imageFilePath, bool detectText true, int maxConcepts 5) { // 1. 读取并编码图片 if (!File.Exists(imageFilePath)) { throw new FileNotFoundException($图片文件未找到: {imageFilePath}); } byte[] imageBytes await File.ReadAllBytesAsync(imageFilePath); string imageBase64 Convert.ToBase64String(imageBytes); // 2. 构建请求体 var requestData new { image imageBase64, detect_text detectText, max_concepts maxConcepts }; string jsonContent JsonSerializer.Serialize(requestData); var content new StringContent(jsonContent, Encoding.UTF8, application/json); // 3. 发送请求 HttpResponseMessage response await _httpClient.PostAsync(, content); // 相对路径因为BaseAddress已设置 if (!response.IsSuccessStatusCode) { string errorBody await response.Content.ReadAsStringAsync(); throw new HttpRequestException($API请求失败 ({(int)response.StatusCode}): {errorBody}); } // 4. 解析并返回响应 string responseBody await response.Content.ReadAsStringAsync(); return JsonSerializer.DeserializeApiResponse(responseBody, _jsonOptions); } // 提供一个从Base64字符串识别的方法适用于图片已在内存中的场景 public async TaskApiResponse RecognizeImageAsync(byte[] imageBytes, bool detectText true, int maxConcepts 5) { string imageBase64 Convert.ToBase64String(imageBytes); // ... 后续构建请求和发送的代码与上面类似可以重构以避免重复 ... // 为简洁起见这里省略重复代码。实际项目中应提取公共逻辑。 throw new NotImplementedException(请参考上面的方法实现此重载。); } } }这样封装之后在Main方法中的调用就变得非常简洁using System; using System.Threading.Tasks; using ImageAnalysisClient.Services; namespace ImageAnalysisClient { class Program { static async Task Main(string[] args) { var service new ImageRecognitionService(https://api.example.com/v1/image/, your_api_key); try { var result await service.RecognizeImageAsync(C:\test.jpg); Console.WriteLine($识别成功场景{result.Results.Scene}); foreach (var tag in result.Results.Tags) { Console.WriteLine($ - {tag.Name}); } } catch (Exception ex) { Console.WriteLine($识别过程中出错: {ex.Message}); } } } }代码是不是清爽多了而且这个服务类可以很容易地被其他项目引用。4. 扩展应用集成到图形界面控制台工具适合批量处理但对于普通用户一个带有图形界面的程序显然更友好。我们来看看如何把刚才封装好的服务用到WPF或WinForms程序中。4.1 WPF应用示例在WPF中我们可以设计一个简单的界面一个按钮用来选择图片一个Image控件用来预览一个ListView或TextBox用来展示识别结果。首先在WPF项目中引用我们之前创建的控制台项目或者将服务类移到类库中。然后在按钮的点击事件处理程序中调用服务。// MainWindow.xaml.cs 部分代码 using System.IO; using System.Windows; using System.Windows.Media.Imaging; using Microsoft.Win32; using ImageAnalysisClient.Services; namespace ImageAnalysisWpfApp { public partial class MainWindow : Window { private readonly ImageRecognitionService _recognitionService; public MainWindow() { InitializeComponent(); // 初始化服务密钥可以从配置文件读取 _recognitionService new ImageRecognitionService(https://api.example.com/v1/image/, your_api_key); } private async void SelectImageButton_Click(object sender, RoutedEventArgs e) { var openFileDialog new OpenFileDialog { Filter 图片文件|*.jpg;*.jpeg;*.png;*.bmp, Title 选择要识别的图片 }; if (openFileDialog.ShowDialog() true) { string filePath openFileDialog.FileName; FilePathTextBox.Text filePath; // 预览图片 var bitmap new BitmapImage(new Uri(filePath)); PreviewImage.Source bitmap; // 禁用按钮显示加载状态 SelectImageButton.IsEnabled false; ResultTextBox.Text 正在分析图片...; try { // 调用识别服务 var result await _recognitionService.RecognizeImageAsync(filePath); // 在UI线程上更新结果 Dispatcher.Invoke(() { DisplayResults(result); }); } catch (Exception ex) { ResultTextBox.Text $识别失败: {ex.Message}; } finally { SelectImageButton.IsEnabled true; } } } private void DisplayResults(ApiResponse response) { var output $场景: {response.Results.Scene}\n\n; output 识别标签:\n; foreach (var tag in response.Results.Tags) { output $ • {tag.Name} ({tag.Confidence:P0})\n; } if (!string.IsNullOrEmpty(response.Results.Text)) { output $\n识别文字: {response.Results.Text}; } ResultTextBox.Text output; } } }4.2 跨平台注意事项我们的服务类是基于.NET Standard 2.0或.NET Core/.NET 5编写的本身是跨平台的。但是图形界面部分需要注意WPF仅支持Windows。如果你写的WPF程序那它只能在Windows上运行。WinForms.NET Core 3.0之后也支持跨平台但在非Windows系统上可能需要额外的运行时支持且某些高级控件可能表现不一致。真正的跨平台UI如果你希望客户端能在Windows、macOS、Linux上都有原生体验可以考虑Avalonia UI或MAUI.NET Multi-platform App UI。将这些UI框架与我们封装好的纯逻辑服务层结合就能构建出真正的全平台客户端。例如使用Avalonia其项目结构和代码模式与WPF非常相似我们的ImageRecognitionService可以原封不动地移植过去。5. 总结与思考走完这一趟你会发现用.NET Core和C#来整合像丹青识画这样的AI服务并没有想象中那么复杂。核心就是几个步骤准备数据、发送HTTP请求、处理JSON响应。.NET Core提供的HttpClient和System.Text.Json让这些操作变得异常简单而async/await模式则保证了应用的流畅性。把核心API调用逻辑封装成独立的服务类是一个非常好的习惯。这不仅能让你在控制台、WPF、Web API等各种项目中复用代码也让你的程序结构更清晰更容易测试和维护。最后想说的是这个例子只是一个起点。在实际项目中你可能还需要考虑更多东西比如如何安全地管理API密钥不要硬编码在代码里可以用环境变量或配置文件、如何实现批量图片处理、如何添加重试机制应对网络波动、如何缓存识别结果以提高性能等等。但只要你掌握了今天这个基础流程后续的这些扩展都是顺理成章的事情。希望这个分享能帮你打开思路用.NET技术栈玩转更多的AI能力。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。
.NET Core调用丹青识画REST API:C#实现跨平台图像分析客户端
发布时间:2026/5/24 5:36:51
.NET Core调用丹青识画REST APIC#实现跨平台图像分析客户端最近在做一个智能相册管理的小工具需要给海量图片自动打标签。手动处理那简直是噩梦。找了一圈发现丹青识画这个服务挺有意思能识别图片里的物体、场景、文字甚至能理解图片内容。作为一个.NET开发者我第一反应就是能不能用C#写个客户端来调用它答案是肯定的而且用.NET Core来做这件事特别合适。你想想现在开发环境五花八门有人用Windows有人用macOS还有人用Linux。.NET Core的跨平台特性正好派上用场写一套代码到处都能跑。今天我就来分享一下怎么用C#和.NET Core从零开始构建一个能调用丹青识画服务的图像分析客户端。不管是做成带界面的桌面程序还是轻量级的命令行工具思路都是相通的。1. 准备工作理解服务与搭建环境在动手写代码之前我们得先搞清楚两件事丹青识画服务能干什么以及我们的开发环境需要什么。丹青识画本质上是一个提供图像识别能力的REST API。你给它一张图片它就能返回识别结果比如图片里有什么物体、属于什么场景、有没有文字、文字内容是什么等等。这对于内容审核、图片分类、信息提取这些场景来说非常实用。我们的目标是用C#写个程序把图片“送”给这个API然后把返回的“答案”拿回来处理。整个过程会涉及到几个关键技术点用HttpClient来发送网络请求、用System.Text.Json来处理返回的JSON数据、用async/await来保证程序在等待网络响应时不会卡住。开发环境很简单。首先确保你安装了.NET SDK6.0或以上版本都行。打开你的命令行输入dotnet --version看看。然后找个顺手的IDEVisual Studio、Visual Studio Code或者Rider都可以。项目类型嘛根据你的需求来选如果想做个带按钮和图片预览的窗口程序可以用WPF或WinForms.NET Core 3.0之后都支持如果只是想做个后台处理图片的脚本用控制台应用就够了。这里为了演示最核心的API调用流程我们先从控制台应用开始理解了原理加界面就是水到渠成的事。2. 核心实战用HttpClient调用识别API理论说再多不如一行代码。我们直接创建一个新的控制台项目然后一步步实现调用。打开终端创建一个新项目dotnet new console -n ImageAnalysisClient cd ImageAnalysisClient2.1 构建请求准备图片和参数调用API第一步是构造一个正确的HTTP请求。通常这类图像识别API都要求以POST方式提交并且图片数据要么以multipart/form-data形式放在表单里要么将图片转换成Base64编码的字符串放在JSON请求体中。我们假设丹青识画API接受Base64格式。那么我们需要先读取图片文件把它转换成Base64字符串。using System; using System.IO; using System.Threading.Tasks; namespace ImageAnalysisClient { class Program { static async Task Main(string[] args) { // 1. 读取图片并转换为Base64 string imagePath C:\path\to\your\image.jpg; // 替换成你的图片路径 string imageBase64; try { byte[] imageBytes await File.ReadAllBytesAsync(imagePath); imageBase64 Convert.ToBase64String(imageBytes); Console.WriteLine(图片已成功读取并编码。); } catch (Exception ex) { Console.WriteLine($读取图片文件失败: {ex.Message}); return; } // 接下来的步骤构建请求JSON并发送 } } }2.2 发送请求使用HttpClient与异步编程有了图片数据我们就要构造一个JSON对象里面包含Base64字符串和其他可能的参数比如是否需要识别文字、置信度阈值等。然后使用HttpClient发送这个请求。这里有个最佳实践对于需要频繁创建HttpClient的应用应该考虑使用IHttpClientFactory来管理生命周期。但对于我们这种简单的示例直接实例化一个也可以。关键是要记得设置请求头比如Content-Type和Authorization如果你的API需要密钥。using System; using System.IO; using System.Net.Http; using System.Text; using System.Text.Json; using System.Threading.Tasks; namespace ImageAnalysisClient { class Program { // 假设的API端点与密钥请替换为实际值 private const string ApiEndpoint https://api.example.com/v1/image/recognize; private const string ApiKey your_api_key_here; static async Task Main(string[] args) { // ... 上面的图片读取代码 ... // 2. 构建请求JSON数据 var requestData new { image imageBase64, detect_text true, // 是否识别文字 max_concepts 5 // 返回最可能的5个标签 }; string jsonContent JsonSerializer.Serialize(requestData); // 3. 创建并发送HTTP请求 using (var httpClient new HttpClient()) { // 设置请求头 httpClient.DefaultRequestHeaders.Add(Authorization, $Bearer {ApiKey}); var content new StringContent(jsonContent, Encoding.UTF8, application/json); Console.WriteLine(正在向识别API发送请求...); HttpResponseMessage response; try { response await httpClient.PostAsync(ApiEndpoint, content); } catch (HttpRequestException ex) { Console.WriteLine($网络请求失败: {ex.Message}); return; } // 检查响应状态 if (response.IsSuccessStatusCode) { string responseBody await response.Content.ReadAsStringAsync(); Console.WriteLine(API调用成功); // 接下来处理响应体 } else { Console.WriteLine($API请求失败状态码: {(int)response.StatusCode} - {response.ReasonPhrase}); string errorBody await response.Content.ReadAsStringAsync(); Console.WriteLine($错误详情: {errorBody}); } } } } }2.3 处理响应解析JSON与结果展示API调用成功我们会拿到一个JSON格式的响应。现在我们需要反序列化这个JSON把里面的识别结果提取出来并以一种友好的方式展示。我们需要根据丹青识画API的实际响应格式来定义对应的C#类也叫POCO类。假设返回的格式大致如下{ request_id: req_123, results: { tags: [ {name: 天空, confidence: 0.98}, {name: 建筑, confidence: 0.87} ], text: 欢迎来到上海, scene: 城市风光 } }那么我们可以定义这样的类来匹配using System.Collections.Generic; using System.Text.Json.Serialization; namespace ImageAnalysisClient { // 定义与API响应JSON结构对应的C#类 public class ApiResponse { [JsonPropertyName(request_id)] public string RequestId { get; set; } public RecognitionResults Results { get; set; } } public class RecognitionResults { public ListImageTag Tags { get; set; } public string Text { get; set; } public string Scene { get; set; } } public class ImageTag { public string Name { get; set; } public double Confidence { get; set; } // 置信度0~1之间 } }然后在收到响应后用System.Text.Json进行反序列化// 接上面的成功响应处理部分 if (response.IsSuccessStatusCode) { string responseBody await response.Content.ReadAsStringAsync(); Console.WriteLine(API调用成功); // 4. 解析JSON响应 try { var options new JsonSerializerOptions { PropertyNameCaseInsensitive true }; var apiResponse JsonSerializer.DeserializeApiResponse(responseBody, options); // 5. 展示结果 Console.WriteLine($\n 图片分析结果 ); Console.WriteLine($请求ID: {apiResponse.RequestId}); Console.WriteLine($场景分类: {apiResponse.Results.Scene}); if (!string.IsNullOrEmpty(apiResponse.Results.Text)) { Console.WriteLine($识别文字: {apiResponse.Results.Text}); } Console.WriteLine(\n识别标签:); if (apiResponse.Results.Tags ! null) { foreach (var tag in apiResponse.Results.Tags) { Console.WriteLine($ - {tag.Name} (置信度: {tag.Confidence:P0})); // P0格式显示为百分比 } } } catch (JsonException ex) { Console.WriteLine($解析API响应失败: {ex.Message}); } }运行这个程序你就能在控制台看到图片的分析结果了。从读取图片到发送请求再到解析展示结果一个最基础的客户端就完成了。3. 进阶封装构建可复用的服务类把所有的代码都堆在Main方法里可不是好主意。为了代码更清晰、更易复用我们应该把调用API的逻辑封装成一个独立的服务类。这样无论是在控制台程序里调用还是在WPF、WinForms的界面后台调用都会非常方便。我们来创建一个ImageRecognitionService类using System; using System.IO; using System.Net.Http; using System.Text; using System.Text.Json; using System.Threading.Tasks; namespace ImageAnalysisClient.Services { public class ImageRecognitionService { private readonly HttpClient _httpClient; private readonly string _apiKey; private readonly JsonSerializerOptions _jsonOptions; public ImageRecognitionService(string apiEndpoint, string apiKey) { _httpClient new HttpClient { BaseAddress new Uri(apiEndpoint) }; _httpClient.DefaultRequestHeaders.Add(Authorization, $Bearer {apiKey}); _apiKey apiKey; _jsonOptions new JsonSerializerOptions { PropertyNameCaseInsensitive true }; } // 核心方法识别图片 public async TaskApiResponse RecognizeImageAsync(string imageFilePath, bool detectText true, int maxConcepts 5) { // 1. 读取并编码图片 if (!File.Exists(imageFilePath)) { throw new FileNotFoundException($图片文件未找到: {imageFilePath}); } byte[] imageBytes await File.ReadAllBytesAsync(imageFilePath); string imageBase64 Convert.ToBase64String(imageBytes); // 2. 构建请求体 var requestData new { image imageBase64, detect_text detectText, max_concepts maxConcepts }; string jsonContent JsonSerializer.Serialize(requestData); var content new StringContent(jsonContent, Encoding.UTF8, application/json); // 3. 发送请求 HttpResponseMessage response await _httpClient.PostAsync(, content); // 相对路径因为BaseAddress已设置 if (!response.IsSuccessStatusCode) { string errorBody await response.Content.ReadAsStringAsync(); throw new HttpRequestException($API请求失败 ({(int)response.StatusCode}): {errorBody}); } // 4. 解析并返回响应 string responseBody await response.Content.ReadAsStringAsync(); return JsonSerializer.DeserializeApiResponse(responseBody, _jsonOptions); } // 提供一个从Base64字符串识别的方法适用于图片已在内存中的场景 public async TaskApiResponse RecognizeImageAsync(byte[] imageBytes, bool detectText true, int maxConcepts 5) { string imageBase64 Convert.ToBase64String(imageBytes); // ... 后续构建请求和发送的代码与上面类似可以重构以避免重复 ... // 为简洁起见这里省略重复代码。实际项目中应提取公共逻辑。 throw new NotImplementedException(请参考上面的方法实现此重载。); } } }这样封装之后在Main方法中的调用就变得非常简洁using System; using System.Threading.Tasks; using ImageAnalysisClient.Services; namespace ImageAnalysisClient { class Program { static async Task Main(string[] args) { var service new ImageRecognitionService(https://api.example.com/v1/image/, your_api_key); try { var result await service.RecognizeImageAsync(C:\test.jpg); Console.WriteLine($识别成功场景{result.Results.Scene}); foreach (var tag in result.Results.Tags) { Console.WriteLine($ - {tag.Name}); } } catch (Exception ex) { Console.WriteLine($识别过程中出错: {ex.Message}); } } } }代码是不是清爽多了而且这个服务类可以很容易地被其他项目引用。4. 扩展应用集成到图形界面控制台工具适合批量处理但对于普通用户一个带有图形界面的程序显然更友好。我们来看看如何把刚才封装好的服务用到WPF或WinForms程序中。4.1 WPF应用示例在WPF中我们可以设计一个简单的界面一个按钮用来选择图片一个Image控件用来预览一个ListView或TextBox用来展示识别结果。首先在WPF项目中引用我们之前创建的控制台项目或者将服务类移到类库中。然后在按钮的点击事件处理程序中调用服务。// MainWindow.xaml.cs 部分代码 using System.IO; using System.Windows; using System.Windows.Media.Imaging; using Microsoft.Win32; using ImageAnalysisClient.Services; namespace ImageAnalysisWpfApp { public partial class MainWindow : Window { private readonly ImageRecognitionService _recognitionService; public MainWindow() { InitializeComponent(); // 初始化服务密钥可以从配置文件读取 _recognitionService new ImageRecognitionService(https://api.example.com/v1/image/, your_api_key); } private async void SelectImageButton_Click(object sender, RoutedEventArgs e) { var openFileDialog new OpenFileDialog { Filter 图片文件|*.jpg;*.jpeg;*.png;*.bmp, Title 选择要识别的图片 }; if (openFileDialog.ShowDialog() true) { string filePath openFileDialog.FileName; FilePathTextBox.Text filePath; // 预览图片 var bitmap new BitmapImage(new Uri(filePath)); PreviewImage.Source bitmap; // 禁用按钮显示加载状态 SelectImageButton.IsEnabled false; ResultTextBox.Text 正在分析图片...; try { // 调用识别服务 var result await _recognitionService.RecognizeImageAsync(filePath); // 在UI线程上更新结果 Dispatcher.Invoke(() { DisplayResults(result); }); } catch (Exception ex) { ResultTextBox.Text $识别失败: {ex.Message}; } finally { SelectImageButton.IsEnabled true; } } } private void DisplayResults(ApiResponse response) { var output $场景: {response.Results.Scene}\n\n; output 识别标签:\n; foreach (var tag in response.Results.Tags) { output $ • {tag.Name} ({tag.Confidence:P0})\n; } if (!string.IsNullOrEmpty(response.Results.Text)) { output $\n识别文字: {response.Results.Text}; } ResultTextBox.Text output; } } }4.2 跨平台注意事项我们的服务类是基于.NET Standard 2.0或.NET Core/.NET 5编写的本身是跨平台的。但是图形界面部分需要注意WPF仅支持Windows。如果你写的WPF程序那它只能在Windows上运行。WinForms.NET Core 3.0之后也支持跨平台但在非Windows系统上可能需要额外的运行时支持且某些高级控件可能表现不一致。真正的跨平台UI如果你希望客户端能在Windows、macOS、Linux上都有原生体验可以考虑Avalonia UI或MAUI.NET Multi-platform App UI。将这些UI框架与我们封装好的纯逻辑服务层结合就能构建出真正的全平台客户端。例如使用Avalonia其项目结构和代码模式与WPF非常相似我们的ImageRecognitionService可以原封不动地移植过去。5. 总结与思考走完这一趟你会发现用.NET Core和C#来整合像丹青识画这样的AI服务并没有想象中那么复杂。核心就是几个步骤准备数据、发送HTTP请求、处理JSON响应。.NET Core提供的HttpClient和System.Text.Json让这些操作变得异常简单而async/await模式则保证了应用的流畅性。把核心API调用逻辑封装成独立的服务类是一个非常好的习惯。这不仅能让你在控制台、WPF、Web API等各种项目中复用代码也让你的程序结构更清晰更容易测试和维护。最后想说的是这个例子只是一个起点。在实际项目中你可能还需要考虑更多东西比如如何安全地管理API密钥不要硬编码在代码里可以用环境变量或配置文件、如何实现批量图片处理、如何添加重试机制应对网络波动、如何缓存识别结果以提高性能等等。但只要你掌握了今天这个基础流程后续的这些扩展都是顺理成章的事情。希望这个分享能帮你打开思路用.NET技术栈玩转更多的AI能力。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。