当前位置: 首页 > article >正文

WebApi使用 (.Net Framework版)

1 创建

使用.Net做web后端,推荐使用.Net Core,微软在此基础上做了很多适配,包括内置Swagger,可以直接启动等等。而.Net Framework版,需要手动配置很多内容。

如果需要调用的项目是基于.Net Framework,那么web项目也应基于.Net Framework开发。或者其他原因不得不使用.Net Framework开发web项目,可以参考本文。

打开VS,在搜索栏输入“ASP.NET Web”,选择.Net Framework版,注意,这里要创建的是空白API项目,在前后端分离的项目中只作为后端接口,而不是MVC(模型-视图-控制器)

填写项目名,选择位置,选择需要的框架

创建一个空白项目,勾选“Web API”,取消勾选“HTTPS配置”

添加完成后,会创建以下目录结构:

  • “App_Data”目录用于方式一些资源文件;
  • “App_Start”目录下用于放置一些配置资源,默认已有一个配置类“WebApiConfig”,内容如下:
public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}
- config.MapHttpAttributeRoutes();表示启用了属性路由,允许在控制器和操作方法上直接使用特性(如 [Route])来定义路由规则。
- 下半部分表示定义默认路由规则。
  • “Controllers”目录下放置对外接口;
  • “Models”目录下放置后端接口的内部逻辑,比如要接入数据库的操作等等。这些目录作为一个规范,如果违反这个规范随意放置,也可以正常运行,只不过看着比较杂乱。

2 测试

项目创建完成后,并没有提供任何对外接口,添加一个测试接口。选中“Controllers”目录=>右键=>添加=>Web API控制器类

填写名称,建议名称为“xxxController”(xxx为需要写的名称),此名称会被上文提到的“默认路由规则”匹配,将“xxx”作为api的一部分。

类创建完成后,会自动生成示例程序,包含Get, Post, Put, Delete请求

public class TestController : ApiController
{
    // GET api/<controller>
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }

    // GET api/<controller>/5
    public string Get(int id)
    {
        return "value";
    }

    // POST api/<controller>
    public void Post([FromBody] string value)
    {
    }

    // PUT api/<controller>/5
    public void Put(int id, [FromBody] string value)
    {
    }

    // DELETE api/<controller>/5
    public void Delete(int id)
    {
    }
}

启动项目,基于.Net Framework的web项目需要借助于服务启动,vs调试默认使用IIS服务。

启动完成后,没有配置默认的访问地址就会显示如下界面。

测试Api访问。

3 配置属性路由规则

上文提到,配置类“WebApiConfig”中配置了默认路由规则,启用了属性路由。属性路由就是使用特性标记路由,使用属性路由代替了默认路由。

示例如下:

[RoutePrefix("api/TestABC")]
public class TestController : ApiController
{
    [HttpGet]
    [Route("GetValue")]
    // GET api/<controller>
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }
}

启动,测试访问,可以看到,路由规则已经由默认路由规则变为了属性路由规则。

4 配置Swagger

4.1 基本配置

在NuGet中下载安装“Swashbuckle”

安装完成后,在“App_Start”目录下会自动生成“SwaggerConfig”配置类。可以修改需要显示的内容,下图这个语句包含两条信息,“版本”和“Title”。

在项目属性中,勾选生成“XML文档文件”,本质上是Swagger将此xml转换为Swagger格式的内容。

安装完之后,再访问本地URL,可能会报一个错,这里不要慌,一般是安装的“Swashbuckle”包依赖的内容与现有安装的包不相符,在NuGet包管理器中全部更到最新即可。

启动后在原有url后加入/swagger即可访问文档。

展开后,可以点击“Try it out”按钮进行测试。

请求与相应如下:

测试Post,字符串一定要带""

程序中获取到浏览器发送的内容。

4.2 为程序添加注释

上文提到,勾选了生成“XML文档文件”,此xml是将写的注释记录下来。

比如为Get请求添加注释。

/// <summary>
/// 测试请求
/// </summary>
/// <returns>返回示例数据</returns>
public IEnumerable<string> Get()
{
    return new string[] { "value1", "value2" };
}

然后在SwaggerConfig配置类中添加一条配置。

c.IncludeXmlComments(Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "bin\\TestWebApi.xml"));

再次访问,可以看到,有了注释的内容。

4.3 汉化处理

安装“Swagger.Net.UI”

安装完成后,在“App_Start”目录下新增了一个SwaggerNet类

打开SwaggerNet类,注释掉这两行(这里我没做深究,参考的几篇文章都说注释掉这两行,可能后续运行有报错)

创建一个“SwaggerControllerDescProvider”类,用于对swagger文档中的内容进行汉化处理。

/// <summary>
/// swagger显示控制器的描述
/// </summary>
public class SwaggerControllerDescProvider : ISwaggerProvider
{
    private readonly ISwaggerProvider _swaggerProvider;
    private static ConcurrentDictionary<string, SwaggerDocument> _cache = new ConcurrentDictionary<string, SwaggerDocument>();
    private readonly string _xml;
    /// <summary>
    /// 
    /// </summary>
    /// <param name="swaggerProvider"></param>
    /// <param name="xml">xml文档路径</param>
    public SwaggerControllerDescProvider(ISwaggerProvider swaggerProvider, string xml)
    {
        _swaggerProvider = swaggerProvider;
        _xml = xml;
    }

    public SwaggerDocument GetSwagger(string rootUrl, string apiVersion)
    {
        var cacheKey = string.Format("{0}_{1}", rootUrl, apiVersion);
        SwaggerDocument srcDoc = null;
        //只读取一次
        if (!_cache.TryGetValue(cacheKey, out srcDoc))
        {
            srcDoc = _swaggerProvider.GetSwagger(rootUrl, apiVersion);

            srcDoc.vendorExtensions = new Dictionary<string, object> { { "ControllerDesc", GetControllerDesc() } };
            _cache.TryAdd(cacheKey, srcDoc);
        }
        return srcDoc;
    }

    /// <summary>
    /// 从API文档中读取控制器描述
    /// </summary>
    /// <returns>所有控制器描述</returns>
    public ConcurrentDictionary<string, string> GetControllerDesc()
    {
        string xmlpath = _xml;
        ConcurrentDictionary<string, string> controllerDescDict = new ConcurrentDictionary<string, string>();
        if (File.Exists(xmlpath))
        {
            XmlDocument xmldoc = new XmlDocument();
            xmldoc.Load(xmlpath);
            string type = string.Empty, path = string.Empty, controllerName = string.Empty;

            string[] arrPath;
            int length = -1, cCount = "Controller".Length;
            XmlNode summaryNode = null;
            foreach (XmlNode node in xmldoc.SelectNodes("//member"))
            {
                type = node.Attributes["name"].Value;
                if (type.StartsWith("T:"))
                {
                    //控制器
                    arrPath = type.Split('.');
                    length = arrPath.Length;
                    controllerName = arrPath[length - 1];
                    if (controllerName.EndsWith("Controller"))
                    {
                        //获取控制器注释
                        summaryNode = node.SelectSingleNode("summary");
                        string key = controllerName.Remove(controllerName.Length - cCount, cCount);
                        if (summaryNode != null && !string.IsNullOrEmpty(summaryNode.InnerText) && !controllerDescDict.ContainsKey(key))
                        {
                            controllerDescDict.TryAdd(key, summaryNode.InnerText.Trim());
                        }
                    }
                }
            }
        }
        return controllerDescDict;
    }
}

在SwaggerUI文件夹中,创建一个swagger_lang.js的js,用于对swagger进行汉化处理(注:这个文件必须添加,否则汉化将失败)

swagger_lang.js 文件中的js内容如下。在最后几行有“公司名称”和对应的Url,可以自行更改,这里我写了百度的链接作为测试。

/// <summary>
/// 中文转换
/// </summary>
var SwaggerTranslator = (function () {
    //定时执行检测是否转换成中文,最多执行500次  即500*50/1000=25s
    var iexcute = 0,
        //中文语言包
        _words = {
            "Warning: Deprecated": "警告:已过时",
            "Implementation Notes": "实现备注",
            "Response Class": "响应类",
            "Status": "状态",
            "Parameters": "参数",
            "Parameter": "参数",
            "Value": "值",
            "Description": "描述",
            "Parameter Type": "参数类型",
            "Data Type": "数据类型",
            "Response Messages": "响应消息",
            "HTTP Status Code": "HTTP状态码",
            "Reason": "原因",
            "Response Model": "响应模型",
            "Request URL": "请求URL",
            "Response Body": "响应体",
            "Response Code": "响应码",
            "Response Headers": "响应头",
            "Hide Response": "隐藏响应",
            "Headers": "头",
            "Try it out!": "试一下!",
            "Show/Hide": "显示/隐藏",
            "List Operations": "显示操作",
            "Expand Operations": "展开操作",
            "Raw": "原始",
            "can't parse JSON.  Raw result": "无法解析JSON. 原始结果",
            "Model Schema": "模型架构",
            "Model": "模型",
            "apply": "应用",
            "Username": "用户名",
            "Password": "密码",
            "Terms of service": "服务条款",
            "Created by": "创建者",
            "See more at": "查看更多:",
            "Contact the developer": "联系开发者",
            "api version": "api版本",
            "Response Content Type": "响应Content Type",
            "fetching resource": "正在获取资源",
            "fetching resource list": "正在获取资源列表",
            "Explore": "浏览",
            "Show Swagger Petstore Example Apis": "显示 Swagger Petstore 示例 Apis",
            "Can't read from server.  It may not have the appropriate access-control-origin settings.": "无法从服务器读取。可能没有正确设置access-control-origin。",
            "Please specify the protocol for": "请指定协议:",
            "Can't read swagger JSON from": "无法读取swagger JSON于",
            "Finished Loading Resource Information. Rendering Swagger UI": "已加载资源信息。正在渲染Swagger UI",
            "Unable to read api": "无法读取api",
            "from path": "从路径",
            "Click to set as parameter value": "点击设置参数",
            "server returned": "服务器返回"
        },
 
        //定时执行转换
        _translator2Cn = function () {
            if ($("#resources_container .resource").length > 0) {
                _tryTranslate();
            }
 
            if ($("#explore").text() == "Explore" && iexcute < 500) {
                iexcute++;
                setTimeout(_translator2Cn, 50);
            }
        },
 
        //设置控制器注释
        _setControllerSummary = function () {
            $.ajax({
                type: "get",
                async: true,
                url: $("#input_baseUrl").val(),
                dataType: "json",
                success: function (data) {
                    var summaryDict = data.ControllerDesc;
                    var id, controllerName, strSummary;
                    $("#resources_container .resource").each(function (i, item) {
                        id = $(item).attr("id");
                        if (id) {
                            controllerName = id.substring(9);
                            strSummary = summaryDict[controllerName];
                            if (strSummary) {
                                var option = $(item).children(".heading").children(".options");
                                if ($(option).children(".controller-summary").length > 0) {
                                    $(option).children(".controller-summary").remove();
                                }
                                $(option).prepend('<li class="controller-summary" title="' + strSummary + '">' + strSummary + '</li>');
                            }
                        }
                    });
                }
            });
        },
 
        //尝试将英文转换成中文
        _tryTranslate = function () {
            $('[data-sw-translate]').each(function () {
                $(this).html(_getLangDesc($(this).html()));
                $(this).val(_getLangDesc($(this).val()));
                $(this).attr('title', _getLangDesc($(this).attr('title')));
            });
        },
        _getLangDesc = function (word) {
            return _words[$.trim(word)] !== undefined ? _words[$.trim(word)] : word;
        };
 
    return {
        Translator: function () {
            $("#logo").html("公司名称").attr("href", "https://www.baidu.com");
            $('body').append('<style type="text/css">.controller-summary{color:#10a54a !important;word-break:keep-all;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:250px;text-align:right;cursor:default;} </style>');
            //设置控制器描述
            _setControllerSummary();
            _translator2Cn();
        },
        translate: function () {
            this.Translator();
        }
    }
})();
//执行转换
SwaggerTranslator.Translator();

新增的swagger_lang.js文件需要修改文件属性,将文件生成操作修改为“嵌入的资源”。

将创建的swagger_lang.js在SwaggerConfig文件中进行引用。注意文件的路径。

c.InjectJavaScript(thisAssembly, "TestWebApi.SwaggerUI.swagger_lang.js");  //引用中文包

汉化结果:

5 包装返回结果

5.1 IHttpActionResult接口

默认生成的测试程序,请求到的数据都直接返回的数据内容。

public IEnumerable<string> Get()
{
    return new string[] { "value1", "value2" };
}

// GET api/<controller>/5
public string Get(int id)
{
    return "value";
}

如果需要自主决定状态码或者返回错误结果内容时携带异常信息等,可以使用C#提供的IHttpActionResult接口。

public IHttpActionResult Get()
{
    return Ok(new string[] { "value1", "value2" });
}

其中Ok()是ASP.NET Web API 提供了一些常用的IHttpActionResult实现,代表200状态码,只使用Ok(),与不使用IHttpActionResult接口并无明显的区别。

5.2 其它方法

除了常见的 Ok 方法外,ASP.NET Web API 还提供了多个 IHttpActionResult 的实现类或方法,用于构建特定的 HTTP 响应。以下是常用的 IHttpActionResult 实现及其对应的用途:

5.2.1 Ok
  • 返回 HTTP 状态码:200 OK
  • 用法
    • 用于返回一个成功的响应,并可以附带一个对象作为响应体。
public IHttpActionResult Get()
{
    var data = new { Id = 1, Name = "Example" };
    return Ok(data);
}

5.2.2 BadRequest
  • 返回 HTTP 状态码:400 Bad Request
  • 用法
    • 用于表示客户端发送的请求无效,例如参数验证失败或格式错误。
public IHttpActionResult Post(string value)
{
    if (string.IsNullOrEmpty(value))
    {
        return BadRequest("Value cannot be null or empty.");
    }
    return Ok();
}

5.2.3 Unauthorized
  • 返回 HTTP 状态码:401 Unauthorized
  • 用法
    • 用于指示需要身份验证或身份验证失败。
public IHttpActionResult Get()
{
    if (!User.Identity.IsAuthenticated)
    {
        return Unauthorized();
    }
    return Ok();
}

5.2.4 NotFound
  • 返回 HTTP 状态码:404 Not Found
  • 用法
    • 用于表示所请求的资源不存在。
public IHttpActionResult Get(int id)
{
    var item = _repository.GetItem(id);
    if (item == null)
    {
        return NotFound();
    }
    return Ok(item);
}

5.2.5 Conflict
  • 返回 HTTP 状态码:409 Conflict
  • 用法
    • 用于表示请求无法完成,因为发生了冲突(例如重复数据或违反约束)。
public IHttpActionResult Post(Item item)
{
    if (_repository.Contains(item.Id))
    {
        return Conflict();
    }
    _repository.Add(item);
    return Ok();
}

5.2.6 Created / CreatedAtRoute
  • 返回 HTTP 状态码:201 Created
  • 用法
    • 用于表示资源已成功创建,并可以附带新资源的 URI。
public IHttpActionResult Post(Item item)
{
    _repository.Add(item);
    return Created(new Uri(Request.RequestUri + "/" + item.Id), item);
}

// 或者使用 CreatedAtRoute 指定路由名称
public IHttpActionResult Post(Item item)
{
    _repository.Add(item);
    return CreatedAtRoute("DefaultApi", new { id = item.Id }, item);
}

5.2.7 NoContent
  • 返回 HTTP 状态码:204 No Content
  • 用法
    • 用于表示请求已成功处理,但不需要返回响应体内容(例如更新操作)。
public IHttpActionResult Put(int id, Item item)
{
    if (!_repository.Update(id, item))
    {
        return NotFound();
    }
    return StatusCode(HttpStatusCode.NoContent); // 或者直接 NoContent()
}

5.2.8 Redirect / RedirectToRoute
  • 返回 HTTP 状态码:302 Found 或其他重定向状态码
  • 用法
    • 用于表示需要重定向到另一个 URI。
public IHttpActionResult Get()
{
    return Redirect("https://www.example.com");
}

// 使用特定路由
public IHttpActionResult Get()
{
    return RedirectToRoute("DefaultApi", new { id = 1 });
}

5.2.9 InternalServerError
  • 返回 HTTP 状态码:500 Internal Server Error
  • 用法
    • 用于表示服务器内部发生错误。
public IHttpActionResult Get()
{
    try
    {
        // 处理逻辑
    }
    catch (Exception ex)
    {
        return InternalServerError(ex);
    }
}

5.2.10 ResponseMessage
  • 返回自定义的 HTTP 响应消息
  • 用法
    • 用于完全自定义 HTTP 响应,灵活构建响应消息。
public IHttpActionResult Get()
{
    var response = Request.CreateResponse(HttpStatusCode.OK, "Custom Message");
    return ResponseMessage(response);
}

5.2.11 StatusCode
  • 返回任意 HTTP 状态码
  • 用法
    • 用于返回特定的 HTTP 状态码,而不需要返回额外的内容。
public IHttpActionResult Delete(int id)
{
    _repository.Remove(id);
    return StatusCode(HttpStatusCode.NoContent); // 返回 204 No Content
}

5.2.12 Json
  • 返回 JSON 格式的响应
  • 用法
    • 用于直接返回 JSON 数据,而不依赖模型绑定。
public IHttpActionResult Get()
{
    var data = new { Id = 1, Name = "Example" };
    return Json(data);
}

5.2.13 ExceptionResult
  • 返回异常结果
  • 用法
    • 用于返回一个表示异常的响应。
public IHttpActionResult Get()
{
    try
    {
        throw new InvalidOperationException("An unexpected error occurred.");
    }
    catch (Exception ex)
    {
        return InternalServerError(ex); // 适用于返回异常信息的场景
    }
}

5.2.14 NotImplemented
  • 返回 HTTP 状态码:501 Not Implemented
  • 用法
    • 用于表示服务端还未实现某个功能。
public IHttpActionResult Get()
{
    return StatusCode(HttpStatusCode.NotImplemented);
}

5.2.15 总结

以下是常见的 IHttpActionResult 方法及其对应的 HTTP 状态码:

方法HTTP 状态码描述
Ok200 OK请求成功并返回数据。
BadRequest400 Bad Request客户端请求无效。
Unauthorized401 Unauthorized表示未通过身份验证。
NotFound404 Not Found资源不存在。
Conflict409 Conflict请求冲突(如违反约束)。
Created201 Created成功创建资源,并返回资源 URI。
NoContent204 No Content请求成功,但没有返回内容。
Redirect302 Found重定向到另一个 URI。
InternalServerError500 Internal Server Error服务器内部错误。
ResponseMessage自定义状态码返回自定义的 HTTP 响应消息。
StatusCode任意状态码返回指定的 HTTP 状态码。
Json任意状态码返回 JSON 响应内容。

通过这些方法,开发者可以灵活地编写符合 HTTP 规范的响应,满足各种 RESTful API 的需求。

6 标明返回类型

书接第五部分,返回类型如果使用IHttpActionResult接口,Swagger文档中无法解析出响应的具体内容,如下图所示。

如果希望显示响应内容,可以使用特性标明。

[SwaggerResponse(200, "Success", typeof(string[]))]
public IHttpActionResult Get()
{
    return Ok(new string[] { "value1", "value2" });
}

有关这方面的扩展内容很多,感兴趣可以自行查阅。

7 一键启动

在项目的Web.config文件同目录下创建一个.bat文件

.bat文件的内容如下,相关信息修改为适合本项目的内容。这里有一点,正常来说应该先启动IIS Express,再执行“浏览器访问URL”,但是启动IIS Express这个行为会阻塞到当前语句,不再往下执行,所以这里将“浏览器访问URL”语句提前,浏览器会等待IIS Express启动后访问成功。

@echo off
:: 设置IIS Express的路径(通常位于Program Files中,如果安装在其他位置,请调整路径)
set IIS_EXPRESS_PATH="C:\Program Files\IIS Express\iisexpress.exe"

:: 项目的物理路径,这条语句不需要修改,意为访问bat文件所在目录
cd /d "%~dp0"

:: Web项目的端口
set PORT=63027

:: 项目的启动URL(如果需要)
set URL=http://localhost:%PORT%/swagger/ui/index#/

:: 打开默认浏览器访问URL(可选)
start %URL%

:: 启动IIS Express
%IIS_EXPRESS_PATH% /path:"%cd%" /port:%PORT%

pause

双击该bat文件即可将项目内容自动配置到IIS服务中。

8 打包

选择“发布”。

发布位置选择“文件夹”。

点击“发布”。

生成的内容如下:

将“配置Swagger”中生成的xml文件拷到bin目录下,这是Swagger文档的基础,发布操作不会自动复制该文件,需要手动复制。然后将“一键启动”生成的.bat文件复制到Web.config文件同目录下,双击即可打开。

9 参考

.net framework中webapi使用swagger进行接口文档展示

ASP.NET WebApi项目框架搭建(一):创建项目

WebApi 接口返回值类型详解 ( 转 )

如果觉得文章还不错的话,请点一个大大的赞吧,感谢支持!!
在这里插入图片描述


http://www.kler.cn/a/463503.html

相关文章:

  • 【Pytorch报错】AttributeError: cannot assign module before Module.__init__() call
  • 路由基本配置实验
  • Redis面试相关
  • docker 安装influxdb
  • Golang的并发编程实战经验
  • k8s系列--docker拉取镜像导入k8s的containerd中
  • 【AIGC】COT思维链:让AI学会拆解问题,像人一样思考
  • 【golang】go errors 处理错误追踪打印堆栈信息
  • idea 开发Gradle 项目
  • Linux:基础IO
  • HTML入门教程|| HTML 基本标签(2)
  • 第 28 章 - ES 源码篇 - Elasticsearch 启动与插件加载机制解析
  • 【每日学点鸿蒙知识】输入框光标显示问题、web组件回调async问题、图片加载流程监控、背景图片大小不生效问题、alert无效
  • 像素的访问和算术运算
  • 【R语言】校准曲线,绘制原理
  • 游戏关卡设计方法的杂感
  • 【Unity3d】C#浮点数丢失精度问题
  • 如何查询快手IP归属地?如何关闭
  • HTML——46.制作课程表
  • 鸿蒙应用开发 - 如何去掉字符串中空格
  • 使用 `Celery` 与 `RabbitMQ` 实现异步任务队列:构建高效、可靠的任务调度系统
  • 深度学习在光学成像中是如何发挥作用的?
  • [创业之路-222]:波士顿矩阵与GE矩阵在业务组合选中作用、优缺点比较
  • 如何通过深度学习提升大分辨率图像预测准确率?
  • Ajax阶段总结(二维表+思维导图+四种请求方式)
  • 数据库概念(MySQL第一期)