第02章-环境准备与客户端配置
第02章:环境准备与客户端配置
2.1 GeoServer 环境准备
在使用 GeoServerDesktop.GeoServerClient 之前,需要确保有一个可用的 GeoServer 实例。本节将介绍如何准备 GeoServer 环境。
2.1.1 GeoServer 安装
方式一:使用预编译版本
- 访问 GeoServer 官方下载页面
- 下载适合您操作系统的版本(推荐使用 Platform Independent Binary)
- 解压下载的文件
- 运行启动脚本:
- Windows:
bin\startup.bat - Linux/Mac:
bin/startup.sh
- Windows:
方式二:使用 Docker
# 拉取 GeoServer 镜像
docker pull docker.osgeo.org/geoserver:2.24.0
# 运行 GeoServer 容器
docker run -d \
--name geoserver \
-p 8080:8080 \
-e GEOSERVER_ADMIN_USER=admin \
-e GEOSERVER_ADMIN_PASSWORD=geoserver \
docker.osgeo.org/geoserver:2.24.0
方式三:使用 Docker Compose
创建 docker-compose.yml 文件:
version: '3.8'
services:
geoserver:
image: docker.osgeo.org/geoserver:2.24.0
container_name: geoserver
ports:
- "8080:8080"
environment:
- GEOSERVER_ADMIN_USER=admin
- GEOSERVER_ADMIN_PASSWORD=geoserver
- GEOSERVER_DATA_DIR=/opt/geoserver/data_dir
volumes:
- geoserver-data:/opt/geoserver/data_dir
restart: unless-stopped
volumes:
geoserver-data:
启动服务:
docker-compose up -d
2.1.2 验证 GeoServer 安装
- 打开浏览器访问:
http://localhost:8080/geoserver - 使用默认凭据登录:
- 用户名:
admin - 密码:
geoserver
- 用户名:
- 验证 REST API 可用性:
- 访问:
http://localhost:8080/geoserver/rest/about/version.json - 应该返回 GeoServer 版本信息的 JSON
- 访问:
2.1.3 配置 REST API 访问
GeoServer 的 REST API 默认是启用的,但需要确保:
- 允许 CORS(跨域资源共享)(可选)
编辑 webapps/geoserver/WEB-INF/web.xml,添加:
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
<init-param>
<param-name>cors.allowed.origins</param-name>
<param-value>*</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.methods</param-name>
<param-value>GET,POST,PUT,DELETE,OPTIONS,HEAD</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- 配置安全策略
GeoServer 默认配置已经允许管理员用户访问 REST API。如需自定义,可以在 Web 界面中配置:
- 导航到:Security → Users, Groups, and Roles
- 添加用户和角色
- 配置访问规则
2.2 .NET 开发环境配置
2.2.1 安装 .NET SDK
- 访问 .NET 官方下载页面
- 下载并安装 .NET 8.0 SDK(或更高版本)
- 验证安装:
dotnet --version
# 输出示例:8.0.100
2.2.2 创建项目
使用命令行创建控制台项目
# 创建解决方案
dotnet new sln -n GeoServerDemo
# 创建控制台项目
dotnet new console -n GeoServerDemo.Console
dotnet sln add GeoServerDemo.Console/GeoServerDemo.Console.csproj
# 进入项目目录
cd GeoServerDemo.Console
使用 Visual Studio 创建项目
- 打开 Visual Studio 2022
- 点击"创建新项目"
- 选择"控制台应用程序"(Console App)
- 设置项目名称和位置
- 选择 .NET 8.0 框架
2.2.3 添加 GeoServerClient 引用
由于 GeoServerDesktop.GeoServerClient 是一个开源项目,有两种方式集成:
方式一:源码引用(推荐用于开发和学习)
# 克隆 GeoServerDesktop 项目
git clone https://github.com/znlgis/GeoServerDesktop.git
# 在您的解决方案中添加项目引用
dotnet add reference ../GeoServerDesktop/src/GeoServerDesktop.GeoServerClient/GeoServerDesktop.GeoServerClient.csproj
方式二:手动添加源文件
将 GeoServerClient 的源文件复制到您的项目中,并添加必要的 NuGet 包:
dotnet add package Newtonsoft.Json --version 13.0.3
2.2.4 项目文件配置
编辑 .csproj 文件,确保配置正确:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<LangVersion>12.0</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<!-- 如果使用项目引用 -->
<ItemGroup>
<ProjectReference Include="..\GeoServerDesktop.GeoServerClient\GeoServerDesktop.GeoServerClient.csproj" />
</ItemGroup>
</Project>
2.3 客户端配置详解
2.3.1 GeoServerClientOptions 配置项
GeoServerClientOptions 类提供了所有必要的配置选项:
public class GeoServerClientOptions
{
/// <summary>
/// GeoServer 实例的基础 URL
/// </summary>
public string BaseUrl { get; set; }
/// <summary>
/// 基本身份验证的用户名
/// </summary>
public string Username { get; set; }
/// <summary>
/// 基本身份验证的密码
/// </summary>
public string Password { get; set; }
/// <summary>
/// HTTP 请求超时时间(秒)
/// </summary>
public int TimeoutSeconds { get; set; } = 30;
}
2.3.2 基本配置示例
本地开发环境配置
var options = new GeoServerClientOptions
{
BaseUrl = "http://localhost:8080/geoserver",
Username = "admin",
Password = "geoserver",
TimeoutSeconds = 30
};
生产环境配置
var options = new GeoServerClientOptions
{
BaseUrl = "https://geoserver.example.com/geoserver",
Username = Environment.GetEnvironmentVariable("GEOSERVER_USER") ?? "admin",
Password = Environment.GetEnvironmentVariable("GEOSERVER_PASSWORD") ?? "geoserver",
TimeoutSeconds = 60 // 生产环境可能需要更长的超时时间
};
Docker 环境配置
var options = new GeoServerClientOptions
{
BaseUrl = "http://geoserver:8080/geoserver", // 使用容器名称
Username = "admin",
Password = "geoserver",
TimeoutSeconds = 45
};
2.3.3 配置文件管理
使用 appsettings.json
创建 appsettings.json 文件:
{
"GeoServer": {
"BaseUrl": "http://localhost:8080/geoserver",
"Username": "admin",
"Password": "geoserver",
"TimeoutSeconds": 30
}
}
添加配置包:
dotnet add package Microsoft.Extensions.Configuration
dotnet add package Microsoft.Extensions.Configuration.Json
读取配置:
using Microsoft.Extensions.Configuration;
// 构建配置
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false)
.Build();
// 绑定到配置对象
var options = new GeoServerClientOptions();
configuration.GetSection("GeoServer").Bind(options);
// 或使用强类型配置
var options = configuration.GetSection("GeoServer").Get<GeoServerClientOptions>();
使用环境变量
var options = new GeoServerClientOptions
{
BaseUrl = Environment.GetEnvironmentVariable("GEOSERVER_BASE_URL")
?? "http://localhost:8080/geoserver",
Username = Environment.GetEnvironmentVariable("GEOSERVER_USERNAME")
?? "admin",
Password = Environment.GetEnvironmentVariable("GEOSERVER_PASSWORD")
?? "geoserver",
TimeoutSeconds = int.TryParse(
Environment.GetEnvironmentVariable("GEOSERVER_TIMEOUT"),
out var timeout) ? timeout : 30
};
设置环境变量:
Windows (PowerShell):
$env:GEOSERVER_BASE_URL="http://localhost:8080/geoserver"
$env:GEOSERVER_USERNAME="admin"
$env:GEOSERVER_PASSWORD="geoserver"
Linux/Mac:
export GEOSERVER_BASE_URL="http://localhost:8080/geoserver"
export GEOSERVER_USERNAME="admin"
export GEOSERVER_PASSWORD="geoserver"
2.3.4 配置验证
创建配置验证方法:
public static class GeoServerOptionsValidator
{
public static void Validate(GeoServerClientOptions options)
{
var errors = new List<string>();
if (string.IsNullOrWhiteSpace(options.BaseUrl))
{
errors.Add("BaseUrl 不能为空");
}
else if (!Uri.TryCreate(options.BaseUrl, UriKind.Absolute, out var uri))
{
errors.Add("BaseUrl 格式不正确");
}
if (string.IsNullOrWhiteSpace(options.Username))
{
errors.Add("Username 不能为空");
}
if (string.IsNullOrWhiteSpace(options.Password))
{
errors.Add("Password 不能为空");
}
if (options.TimeoutSeconds <= 0)
{
errors.Add("TimeoutSeconds 必须大于 0");
}
if (errors.Any())
{
throw new ArgumentException(
$"配置验证失败:\n{string.Join("\n", errors)}");
}
}
}
// 使用验证
try
{
GeoServerOptionsValidator.Validate(options);
Console.WriteLine("配置验证通过");
}
catch (ArgumentException ex)
{
Console.WriteLine($"配置错误: {ex.Message}");
return;
}
2.4 客户端初始化
2.4.1 使用工厂模式创建客户端
using GeoServerDesktop.GeoServerClient.Configuration;
// 创建配置
var options = new GeoServerClientOptions
{
BaseUrl = "http://localhost:8080/geoserver",
Username = "admin",
Password = "geoserver",
TimeoutSeconds = 30
};
// 创建工厂实例
var factory = new GeoServerClientFactory(options);
// 使用完毕后释放资源
factory.Dispose();
2.4.2 使用 using 语句自动释放资源
using (var factory = new GeoServerClientFactory(options))
{
// 在这里使用 factory
var workspaceService = factory.CreateWorkspaceService();
var workspaces = await workspaceService.GetWorkspacesAsync();
foreach (var workspace in workspaces)
{
Console.WriteLine(workspace.Name);
}
} // factory 自动释放
2.4.3 在 ASP.NET Core 中使用依赖注入
注册服务
在 Program.cs 或 Startup.cs 中:
using GeoServerDesktop.GeoServerClient.Configuration;
using Microsoft.Extensions.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
// 注册 GeoServer 配置
builder.Services.Configure<GeoServerClientOptions>(
builder.Configuration.GetSection("GeoServer"));
// 注册 GeoServerClientFactory 为单例
builder.Services.AddSingleton<GeoServerClientFactory>(sp =>
{
var options = sp.GetRequiredService<IOptions<GeoServerClientOptions>>().Value;
return new GeoServerClientFactory(options);
});
// 或注册为 Scoped(每次请求创建新实例)
builder.Services.AddScoped<GeoServerClientFactory>(sp =>
{
var options = sp.GetRequiredService<IOptions<GeoServerClientOptions>>().Value;
return new GeoServerClientFactory(options);
});
var app = builder.Build();
在控制器中使用
using Microsoft.AspNetCore.Mvc;
using GeoServerDesktop.GeoServerClient.Configuration;
[ApiController]
[Route("api/[controller]")]
public class WorkspacesController : ControllerBase
{
private readonly GeoServerClientFactory _factory;
public WorkspacesController(GeoServerClientFactory factory)
{
_factory = factory;
}
[HttpGet]
public async Task<IActionResult> GetWorkspaces()
{
var service = _factory.CreateWorkspaceService();
var workspaces = await service.GetWorkspacesAsync();
return Ok(workspaces);
}
}
2.4.4 创建单例管理器
对于需要在整个应用程序生命周期中复用同一个工厂实例的场景:
public class GeoServerManager
{
private static readonly Lazy<GeoServerManager> _instance =
new Lazy<GeoServerManager>(() => new GeoServerManager());
private readonly GeoServerClientFactory _factory;
private GeoServerManager()
{
var options = new GeoServerClientOptions
{
BaseUrl = "http://localhost:8080/geoserver",
Username = "admin",
Password = "geoserver",
TimeoutSeconds = 30
};
_factory = new GeoServerClientFactory(options);
}
public static GeoServerManager Instance => _instance.Value;
public GeoServerClientFactory Factory => _factory;
public void Dispose()
{
_factory?.Dispose();
}
}
// 使用单例
var manager = GeoServerManager.Instance;
var workspaceService = manager.Factory.CreateWorkspaceService();
2.5 连接测试
2.5.1 基本连接测试
using System;
using System.Threading.Tasks;
using GeoServerDesktop.GeoServerClient.Configuration;
using GeoServerDesktop.GeoServerClient.Http;
public static class ConnectionTester
{
public static async Task<bool> TestConnectionAsync(GeoServerClientOptions options)
{
try
{
Console.WriteLine("正在测试 GeoServer 连接...");
Console.WriteLine($"URL: {options.BaseUrl}");
Console.WriteLine($"用户名: {options.Username}");
using (var factory = new GeoServerClientFactory(options))
{
// 使用 AboutService 测试连接
var aboutService = factory.CreateAboutService();
// 尝试获取版本信息
var version = await aboutService.GetVersionAsync();
Console.WriteLine("✓ 连接成功!");
Console.WriteLine($"GeoServer 版本: {version}");
return true;
}
}
catch (GeoServerRequestException ex)
{
Console.WriteLine($"✗ GeoServer 请求失败");
Console.WriteLine($"状态码: {ex.StatusCode}");
Console.WriteLine($"错误信息: {ex.Message}");
return false;
}
catch (HttpRequestException ex)
{
Console.WriteLine($"✗ 网络连接失败");
Console.WriteLine($"错误信息: {ex.Message}");
Console.WriteLine("请检查:");
Console.WriteLine("1. GeoServer 是否正在运行");
Console.WriteLine("2. URL 是否正确");
Console.WriteLine("3. 网络连接是否正常");
return false;
}
catch (Exception ex)
{
Console.WriteLine($"✗ 未知错误");
Console.WriteLine($"错误信息: {ex.Message}");
return false;
}
}
}
// 使用连接测试
var options = new GeoServerClientOptions
{
BaseUrl = "http://localhost:8080/geoserver",
Username = "admin",
Password = "geoserver"
};
var isConnected = await ConnectionTester.TestConnectionAsync(options);
if (!isConnected)
{
Console.WriteLine("请修复连接问题后重试");
return;
}
2.5.2 详细诊断测试
public class GeoServerDiagnostics
{
public static async Task RunDiagnosticsAsync(GeoServerClientOptions options)
{
Console.WriteLine("========== GeoServer 诊断测试 ==========\n");
// 测试 1: 基础连接
Console.WriteLine("测试 1: 基础连接");
await TestBasicConnection(options);
// 测试 2: 认证
Console.WriteLine("\n测试 2: 身份认证");
await TestAuthentication(options);
// 测试 3: REST API 可用性
Console.WriteLine("\n测试 3: REST API 可用性");
await TestRestApiAvailability(options);
// 测试 4: 权限
Console.WriteLine("\n测试 4: 管理员权限");
await TestAdminPermissions(options);
Console.WriteLine("\n========== 诊断完成 ==========");
}
private static async Task TestBasicConnection(GeoServerClientOptions options)
{
try
{
using var client = new HttpClient
{
Timeout = TimeSpan.FromSeconds(options.TimeoutSeconds)
};
var response = await client.GetAsync($"{options.BaseUrl}/web/");
if (response.IsSuccessStatusCode)
{
Console.WriteLine("✓ GeoServer 可访问");
}
else
{
Console.WriteLine($"✗ HTTP 状态码: {response.StatusCode}");
}
}
catch (Exception ex)
{
Console.WriteLine($"✗ 连接失败: {ex.Message}");
}
}
private static async Task TestAuthentication(GeoServerClientOptions options)
{
try
{
using var factory = new GeoServerClientFactory(options);
var aboutService = factory.CreateAboutService();
await aboutService.GetVersionAsync();
Console.WriteLine("✓ 身份认证成功");
}
catch (GeoServerRequestException ex) when (ex.StatusCode == 401)
{
Console.WriteLine("✗ 认证失败: 用户名或密码错误");
}
catch (Exception ex)
{
Console.WriteLine($"✗ 认证测试失败: {ex.Message}");
}
}
private static async Task TestRestApiAvailability(GeoServerClientOptions options)
{
try
{
using var factory = new GeoServerClientFactory(options);
var workspaceService = factory.CreateWorkspaceService();
await workspaceService.GetWorkspacesAsync();
Console.WriteLine("✓ REST API 可用");
}
catch (Exception ex)
{
Console.WriteLine($"✗ REST API 不可用: {ex.Message}");
}
}
private static async Task TestAdminPermissions(GeoServerClientOptions options)
{
try
{
using var factory = new GeoServerClientFactory(options);
var settingsService = factory.CreateSettingsService();
await settingsService.GetGlobalSettingsAsync();
Console.WriteLine("✓ 具有管理员权限");
}
catch (GeoServerRequestException ex) when (ex.StatusCode == 403)
{
Console.WriteLine("✗ 权限不足: 不是管理员账户");
}
catch (Exception ex)
{
Console.WriteLine($"✗ 权限测试失败: {ex.Message}");
}
}
}
// 运行诊断
await GeoServerDiagnostics.RunDiagnosticsAsync(options);
2.6 常见问题与解决方案
2.6.1 连接超时
问题:请求超时,抛出 TaskCanceledException
解决方案:
// 增加超时时间
var options = new GeoServerClientOptions
{
BaseUrl = "http://localhost:8080/geoserver",
Username = "admin",
Password = "geoserver",
TimeoutSeconds = 120 // 增加到 120 秒
};
2.6.2 认证失败 (401)
问题:收到 401 Unauthorized 错误
解决方案:
- 检查用户名和密码是否正确
- 确认用户账户是否启用
- 检查 GeoServer 安全配置
// 确保凭据正确
var options = new GeoServerClientOptions
{
BaseUrl = "http://localhost:8080/geoserver",
Username = "admin", // 确认用户名
Password = "geoserver" // 确认密码
};
// 测试认证
try
{
using var factory = new GeoServerClientFactory(options);
var aboutService = factory.CreateAboutService();
await aboutService.GetVersionAsync();
Console.WriteLine("认证成功");
}
catch (GeoServerRequestException ex) when (ex.StatusCode == 401)
{
Console.WriteLine("认证失败,请检查用户名和密码");
}
2.6.3 权限不足 (403)
问题:收到 403 Forbidden 错误
解决方案:
// 确保使用管理员账户
// 或在 GeoServer 中为用户分配适当的角色和权限
2.6.4 资源未找到 (404)
问题:收到 404 Not Found 错误
解决方案:
// 确保资源名称正确
try
{
var workspace = await workspaceService.GetWorkspaceAsync("myWorkspace");
}
catch (GeoServerRequestException ex) when (ex.StatusCode == 404)
{
Console.WriteLine("工作空间不存在");
// 创建工作空间
await workspaceService.CreateWorkspaceAsync("myWorkspace");
}
2.6.5 连接被拒绝
问题:Connection refused 错误
解决方案:
- 确认 GeoServer 正在运行
- 检查端口号是否正确
- 检查防火墙设置
# Linux: 检查 GeoServer 进程
ps aux | grep geoserver
# 检查端口占用
netstat -tuln | grep 8080
# Windows: 检查端口占用
netstat -ano | findstr 8080
2.6.6 SSL/TLS 证书问题
问题:HTTPS 连接时出现证书验证错误
解决方案(仅用于开发环境):
// 警告:仅用于开发环境,生产环境应使用有效证书
public class GeoServerHttpClientHandler
{
public static HttpClientHandler CreateHandler(bool ignoreSslErrors = false)
{
var handler = new HttpClientHandler();
if (ignoreSslErrors)
{
handler.ServerCertificateCustomValidationCallback =
(message, cert, chain, errors) => true;
}
return handler;
}
}
2.7 完整配置示例
2.7.1 生产级配置类
using System;
using System.ComponentModel.DataAnnotations;
using Microsoft.Extensions.Configuration;
public class GeoServerConfiguration
{
[Required(ErrorMessage = "BaseUrl 是必需的")]
[Url(ErrorMessage = "BaseUrl 必须是有效的 URL")]
public string BaseUrl { get; set; }
[Required(ErrorMessage = "Username 是必需的")]
public string Username { get; set; }
[Required(ErrorMessage = "Password 是必需的")]
public string Password { get; set; }
[Range(1, 300, ErrorMessage = "TimeoutSeconds 必须在 1 到 300 之间")]
public int TimeoutSeconds { get; set; } = 30;
[Range(1, 10, ErrorMessage = "RetryCount 必须在 1 到 10 之间")]
public int RetryCount { get; set; } = 3;
public bool EnableLogging { get; set; } = true;
public string LogLevel { get; set; } = "Information";
public GeoServerClientOptions ToClientOptions()
{
return new GeoServerClientOptions
{
BaseUrl = BaseUrl,
Username = Username,
Password = Password,
TimeoutSeconds = TimeoutSeconds
};
}
public static GeoServerConfiguration FromConfiguration(IConfiguration configuration)
{
var config = new GeoServerConfiguration();
configuration.GetSection("GeoServer").Bind(config);
// 验证配置
var validationContext = new ValidationContext(config);
var validationResults = new List<ValidationResult>();
if (!Validator.TryValidateObject(config, validationContext, validationResults, true))
{
var errors = string.Join("\n", validationResults.Select(r => r.ErrorMessage));
throw new InvalidOperationException($"GeoServer 配置无效:\n{errors}");
}
return config;
}
}
2.7.2 完整的 appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"GeoServer": "Debug"
}
},
"GeoServer": {
"BaseUrl": "http://localhost:8080/geoserver",
"Username": "admin",
"Password": "geoserver",
"TimeoutSeconds": 30,
"RetryCount": 3,
"EnableLogging": true,
"LogLevel": "Information"
},
"GeoServerEnvironments": {
"Development": {
"BaseUrl": "http://localhost:8080/geoserver",
"Username": "admin",
"Password": "geoserver"
},
"Staging": {
"BaseUrl": "https://staging-geoserver.example.com/geoserver",
"Username": "${GEOSERVER_USERNAME}",
"Password": "${GEOSERVER_PASSWORD}"
},
"Production": {
"BaseUrl": "https://geoserver.example.com/geoserver",
"Username": "${GEOSERVER_USERNAME}",
"Password": "${GEOSERVER_PASSWORD}",
"TimeoutSeconds": 60
}
}
}
2.7.3 配置管理器
public class GeoServerConfigurationManager
{
private readonly IConfiguration _configuration;
private readonly string _environment;
public GeoServerConfigurationManager(
IConfiguration configuration,
string environment = "Development")
{
_configuration = configuration;
_environment = environment;
}
public GeoServerClientOptions GetOptions()
{
// 尝试从环境特定配置读取
var envSection = _configuration.GetSection($"GeoServerEnvironments:{_environment}");
if (envSection.Exists())
{
var options = new GeoServerClientOptions();
envSection.Bind(options);
// 替换环境变量占位符
options.Username = ResolveEnvironmentVariable(options.Username);
options.Password = ResolveEnvironmentVariable(options.Password);
return options;
}
// 回退到默认配置
var defaultOptions = new GeoServerClientOptions();
_configuration.GetSection("GeoServer").Bind(defaultOptions);
return defaultOptions;
}
private string ResolveEnvironmentVariable(string value)
{
if (string.IsNullOrEmpty(value))
return value;
// 支持 ${VAR_NAME} 格式
var regex = new Regex(@"\$\{([^}]+)\}");
return regex.Replace(value, match =>
{
var varName = match.Groups[1].Value;
return Environment.GetEnvironmentVariable(varName) ?? match.Value;
});
}
}
2.8 本章小结
本章详细介绍了使用 GeoServerDesktop.GeoServerClient 的环境准备和配置:
- GeoServer 环境:学习了如何安装和配置 GeoServer
- .NET 环境:了解了 .NET SDK 的安装和项目创建
- 客户端配置:掌握了各种配置选项和最佳实践
- 连接测试:学会了如何测试和诊断连接问题
- 问题排查:了解了常见问题的解决方案
- 生产配置:掌握了生产级别的配置管理
下一章将深入学习 HTTP 客户端的实现细节和高级用法。
相关资源:

浙公网安备 33010602011771号