如何在Swagger中为C#参数添加占位符而非默认值?
在Swagger中为C#接口参数添加占位符而非预填默认值
你当前使用[DefaultValue]特性会让Swagger的"Try it out"自动预填参数值,不符合仅显示灰色提示的需求。以下是实现类似HTML输入框占位符效果的方案:
方案一:自定义占位符特性+Swagger过滤器
1. 创建自定义占位符特性
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)] public class SwaggerPlaceholderAttribute : Attribute { public string Placeholder { get; } public SwaggerPlaceholderAttribute(string placeholder) { Placeholder = placeholder; } }
2. 实现Swagger操作过滤器
这个过滤器会读取自定义特性的值,添加到Swagger Schema的扩展字段中:
public class SwaggerPlaceholderFilter : IOperationFilter { public void Apply(OpenApiOperation operation, OperationFilterContext context) { // 处理URL查询参数 foreach (var parameter in operation.Parameters) { var paramInfo = context.ApiDescription.ParameterDescriptions .FirstOrDefault(p => p.Name == parameter.Name); if (paramInfo?.ParameterInfo != null) { var placeholderAttr = paramInfo.ParameterInfo .GetCustomAttribute<SwaggerPlaceholderAttribute>(); if (placeholderAttr != null) { parameter.Schema.Extensions.Add("x-placeholder", new OpenApiString(placeholderAttr.Placeholder)); } } } // 处理请求体中的属性 if (operation.RequestBody != null && operation.RequestBody.Content.TryGetValue("application/json", out var content)) { var schema = content.Schema; if (schema.Properties != null) { foreach (var property in schema.Properties) { var propertyInfo = context.ApiDescription.ActionDescriptor.Parameters .SelectMany(p => p.ParameterType.GetProperties()) .FirstOrDefault(p => p.Name == property.Key); if (propertyInfo != null) { var placeholderAttr = propertyInfo.GetCustomAttribute<SwaggerPlaceholderAttribute>(); if (placeholderAttr != null) { property.Value.Extensions.Add("x-placeholder", new OpenApiString(placeholderAttr.Placeholder)); } } } } } } }
3. 注册过滤器
在Program.cs或Startup.cs中注册这个过滤器:
builder.Services.AddSwaggerGen(c => { c.OperationFilter<SwaggerPlaceholderFilter>(); });
4. 配置Swagger UI读取扩展字段
创建自定义JavaScript脚本,让Swagger UI识别x-placeholder扩展并设置为输入框的占位符:
- 在
wwwroot目录下创建swagger-custom.js,内容如下:
window.addEventListener('load', function() { const observer = new MutationObserver(mutations => { mutations.forEach(mutation => { if (mutation.addedNodes.length) { mutation.addedNodes.forEach(node => { if (node.tagName === 'INPUT' && node.parentElement) { const paramName = node.parentElement.querySelector('.parameter__name')?.textContent.trim(); if (!paramName) return; let placeholder = null; const swaggerPaths = window.ui.getModel().schema.paths; Object.values(swaggerPaths).forEach(path => { Object.values(path).forEach(operation => { // 检查查询参数 if (operation.parameters) { const param = operation.parameters.find(p => p.name === paramName); if (param?.['x-placeholder']) placeholder = param['x-placeholder']; } // 检查请求体属性 if (operation.requestBody?.content?.['application/json']?.schema?.properties) { const prop = operation.requestBody.content['application/json'].schema.properties[paramName]; if (prop?.['x-placeholder']) placeholder = prop['x-placeholder']; } }); }); if (placeholder) node.setAttribute('placeholder', placeholder); } }); } }); }); observer.observe(document.querySelector('.swagger-ui'), { childList: true, subtree: true }); });
- 在Swagger UI配置中引入该脚本:
app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "你的API名称 V1"); c.InjectJavascript("/swagger-custom.js"); });
5. 使用示例
// 接口参数使用 [HttpGet("user-info")] public IActionResult GetUserInfo([SwaggerPlaceholder("请输入用户ID")] string userId) { return Ok(new { UserId = userId }); } // 请求体模型使用 public class UserCreateRequest { [SwaggerPlaceholder("请输入用户名")] public string Username { get; set; } [SwaggerPlaceholder("请输入注册邮箱")] public string Email { get; set; } }
方案二:复用[Display]特性的Prompt属性
如果你不想创建自定义特性,可以直接用.NET内置的[Display(Prompt = "...")]特性,只需要修改过滤器读取Prompt值:
1. 修改过滤器
public class DisplayPromptPlaceholderFilter : IOperationFilter { public void Apply(OpenApiOperation operation, OperationFilterContext context) { // 处理查询参数 foreach (var parameter in operation.Parameters) { var paramDesc = context.ApiDescription.ParameterDescriptions.FirstOrDefault(p => p.Name == parameter.Name); if (paramDesc != null) { var displayAttr = paramDesc.ParameterInfo.GetCustomAttribute<DisplayAttribute>(); if (displayAttr != null && !string.IsNullOrEmpty(displayAttr.Prompt)) { parameter.Schema.Extensions.Add("x-placeholder", new OpenApiString(displayAttr.Prompt)); } } } // 处理请求体属性 if (operation.RequestBody?.Content.TryGetValue("application/json", out var content) == true) { var schema = content.Schema; if (schema.Properties != null) { foreach (var prop in schema.Properties) { var propInfo = context.ApiDescription.ActionDescriptor.Parameters .SelectMany(p => p.ParameterType.GetProperties()) .FirstOrDefault(p => p.Name == prop.Key); if (propInfo != null) { var displayAttr = propInfo.GetCustomAttribute<DisplayAttribute>(); if (displayAttr != null && !string.IsNullOrEmpty(displayAttr.Prompt)) { prop.Value.Extensions.Add("x-placeholder", new OpenApiString(displayAttr.Prompt)); } } } } } } }
2. 使用示例
[HttpGet("user-info")] public IActionResult GetUserInfo([Display(Prompt = "请输入用户ID")] string userId) { return Ok(new { UserId = userId }); }
后续的Swagger UI配置和脚本和方案一完全一致。
内容的提问来源于stack exchange,提问作者Kayomez
相关产品推荐
相关产品推荐

