服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - C# WebApi 接口返回值不困惑:返回值类型详解

C# WebApi 接口返回值不困惑:返回值类型详解

2022-02-25 14:15懒得安分 C#

这篇文章主要介绍了C# WebApi 接口返回值不困惑:返回值类型详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

前言:已经有一个月没写点什么了,感觉心里空落落的。今天再来篇干货,想要学习webapi的园友们速速动起来,跟着博主一起来学习吧。之前分享过一篇c#进阶系列——webapi接口传参不再困惑:传参详解,这篇博文内容本身很基础,没想到引起很多园友关注,感谢大家的支持。作为程序猿,我们都知道参数和返回值是编程领域不可分割的两大块,此前分享了下webapi的传参机制,今天再来看看webapi里面另一个重要而又基础的知识点:返回值。还是那句话:本篇针对初初使用webapi的同学们,比较基础,有兴趣的且看看。

使用过webapi的园友应该都知道,webapi的接口返回值主要有四种类型

  1. void无返回值
  2. ihttpactionresult
  3. httpresponsemessage
  4. 自定义类型

此篇就围绕这四块分别来看看它们的使用。

一、void无返回值

void关键字我们都不陌生,它申明方法没有返回值。它的使用也很简单,我们来看一个示例就能明白。

?
1
2
3
4
5
6
7
8
9
10
public class order
 {
  public string id { get; set; }
 
  public string no { get; set; }
 
  public string name { get; set; }
 
  public string desc { get; set; }
 }
?
1
2
3
4
5
6
7
8
9
public class ordercontroller : apicontroller
 {
  [httppost]
  public void saveorder(order name)
  {
   //处理业务逻辑
 
  }
 }

在web里面调用

?
1
2
3
4
5
6
7
8
9
10
$(function () {
 $.ajax({
  type: 'post',
  url: 'http://localhost:21528/api/order/saveorder',
  data: { id: "aaa", name: "test" },
  success: function (data, status) {
   alert(data);
  }
 });
});

得到结果

C# WebApi 接口返回值不困惑:返回值类型详解

可以看到,使用void申明的方法,在success方法里面得不到返回值,并且会返回http状态码204,告诉客户端此请求没有返回值。

二、ihttpactionresult

ihttpactionresult类型是webapi里面非常重要的一种返回值类型。下面博主就根据平时在项目里面使用最多的几种方式来讲解下这种类型的返回值的一些用法。

1、json<t>(t content)

使用mvc开发过的朋友一定记得,在mvc里面,请求数据的接口的返回值类型大部分使用的是jsonresult,在mvc里面你一定也写过类似这样的接口:

?
1
2
3
4
public jsonresult getresult()
 {
  return json(new { }, jsonrequestbehavior.allowget);
 }

那么,在webapi里面是否也存在类似的用法呢。呵呵,在这点上面,微软总是贴心的。在webapi的apicontroller这个抽象类里面,为我们封装了json<t>(t content)这个方法,它的用法和mvc里面的jsonresult基本类似。我们通过一个例子来说明它的用法:

?
1
2
3
4
5
6
7
8
9
10
11
[httpget]
  public ihttpactionresult getorder()
  {
   var lstres = new list<order>();
 
   //实际项目中,通过后台取到集合赋值给lstres变量。这里只是测试。
   lstres.add(new order() { id = "aaaa", no = "111", name = "111", desc = "1111" });
   lstres.add(new order() { id = "bbbb", no = "222", name = "222", desc = "2222" });
 
   return json<list<order>>(lstres);
  }

看到这个代码,有人就疑惑了,我们定义的返回值类型是ihttpactionresult类型,直接返回json<t>(t content)这样可行么?我们将json转到定义看看:

?
1
protected internal jsonresult<t> json<t>(t content);

我们继续将jsonresult<t>转到定义

C# WebApi 接口返回值不困惑:返回值类型详解

原来jsonresult<t>是实现了ihttpactionresult接口的,难怪可以直接返回呢。

知道了这个,我们直接在web里面通过ajax请求来调用:

?
1
2
3
4
5
6
7
8
9
10
$(function () {
 $.ajax({
  type: 'get',
  url: 'http://localhost:21528/api/order/getorder',
  data: {},
  success: function (data, status) {
   alert(data);
  }
 });
});

来看结果:

C# WebApi 接口返回值不困惑:返回值类型详解

既然实体类可以直接这样传递,那么如果我们想要传递一些匿名类型呢,因为很多情况下,我们需要返回到前端的对象都没有对应的实体来对应,如果我们想要返回匿名对象怎么办呢?我们知道,这里的json<t>(t content)必须要传一个对应的泛型类型,如果是匿名类型这里肯定不好传。还好有我们的object类型,当然你可以使用dynamic,我们来试一把。

?
1
2
3
4
5
6
[httpget]
  public ihttpactionresult getorder()
  {
   
   return json<dynamic>(new { aa = "", bb = "cc" });
  }

同样的来看测试结果:

C# WebApi 接口返回值不困惑:返回值类型详解

2、ok()、ok<t>(t content)

除了json<t>(t content),在apicontroller里面还有另外一个比较常用的方法:ok()。同样,我们将ok()转到定义

?
1
protected internal virtual okresult ok();

okresult转到定义

C# WebApi 接口返回值不困惑:返回值类型详解

有了这个作为基础,我们就可以放心大胆的使用了。

?
1
2
3
4
5
[httpget]
 public ihttpactionresult getokresult()
 {
  return ok();
 }

得到结果

C# WebApi 接口返回值不困惑:返回值类型详解

如果返回ok(),就表示不向客户端返回任何信息,只告诉客户端请求成功。

除了ok()之外,还有另外一个重载ok<t>(t content)。

?
1
2
3
4
5
[httpget]
 public ihttpactionresult getokresult(string name)
 {
  return ok<string>(name);
 }

C# WebApi 接口返回值不困惑:返回值类型详解

这种用法和json<t>(t content)比较类似,如果你非要问这两者有什么区别,或者说怎么选择两者。那么我的理解是如果是返回实体或者实体集合,建议使用json<t>(t content),如果是返回基础类型(如int、string等),使用ok<t>(t content)。

3、notfound()

当需要向客户端返回找不到记录时,有时需要用到notfound()方法。

?
1
protected internal virtual notfoundresult notfound();

C# WebApi 接口返回值不困惑:返回值类型详解

来看看它的使用场景

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[httpget]
  public ihttpactionresult getnotfoundresult(string id)
  {
   var lstres = new list<order>();
 
   //实际项目中,通过后台取到集合赋值给lstres变量。这里只是测试。
   lstres.add(new order() { id = "aaaa", no = "111", name = "111", desc = "1111" });
   lstres.add(new order() { id = "bbbb", no = "222", name = "222", desc = "2222" });
   var ofind = lstres.firstordefault(x => x.id == id) ;
   if (ofind == null)
   {
    return notfound();
   }
   else
   {
    return json<order>(ofind);
   }
  }

得到结果

C# WebApi 接口返回值不困惑:返回值类型详解

notfound()方法会返回一个404的错误到客户端。

4、其他

其他还有一些方法,都有它特定的用途。在此贴出来。

4.1、content<t>(httpstatuscode statuscode, t value)

?
1
2
3
4
5
[httpget]
 public ihttpactionresult getcontentresult()
 {
  return content<string>(httpstatuscode.ok, "ok");
 }

向客户端返回值和http状态码。

4.2、badrequest()

?
1
2
3
4
5
6
7
[httpget]
  public ihttpactionresult getbadrequest(order order)
  {
   if (string.isnullorempty(order.id))
    return badrequest();
   return ok();
  }

向客户端返回400的http错误。

4.3、redirect(string location)

?
1
2
3
4
5
[httpget]
 public ihttpactionresult redirectresult()
 {
  return redirect("http://localhost:21528/api/order/getcontentresult");
 }

将请求重定向到其他地方。

5、自定义ihttpactionresult接口的实现

上面介绍了一些系统内置的常用的实现ihttpactionresult接口的方法。如果我们需要自定义ihttpactionresult的返回呢?

在介绍之前,我们有必要先来看看ihttpactionresult类型的定义,将ihttpactionresult转到定义可以看到:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
namespace system.web.http
{
 // 摘要:
 //  defines a command that asynchronously creates an system.net.http.httpresponsemessage.
 public interface ihttpactionresult
 {
  // 摘要:
  //  creates an system.net.http.httpresponsemessage asynchronously.
  //
  // 参数:
  // cancellationtoken:
  //  the token to monitor for cancellation requests.
  //
  // 返回结果:
  //  a task that, when completed, contains the system.net.http.httpresponsemessage.
  task<system.net.http.httpresponsemessage> executeasync(cancellationtoken cancellationtoken);
 }
}

这个接口包含唯一的一个方法executeasync(),此方法将以异步方式创建一个httpresponsemessage实例返回给客户端。

有了这个作为基础,下面,我们自定义一个bootstraptable服务端分页的子类去展示自定义ihttpactionresult的用法。

首先,自定义一个实现类

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class pageresult : ihttpactionresult
 {
  object _value;
  httprequestmessage _request;
 
  public pageresult(object value, httprequestmessage request)
  {
   _value = value;
   _request = request;
  }
 
  public task<httpresponsemessage> executeasync(system.threading.cancellationtoken cancellationtoken)
  {
   var response = new httpresponsemessage()
   {
    content = new objectcontent(typeof(object), _value, new jsonmediatypeformatter()),
    requestmessage = _request
   };
   return task.fromresult(response);
  }
 }

然后,在api接口里面返回pageresult对象

?
1
2
3
4
5
6
7
8
9
10
11
12
[httpget]
  public ihttpactionresult getpagerow(int limit, int offset)
  {
   var lstres = new list<order>();
 
   //实际项目中,通过后台取到集合赋值给lstres变量。这里只是测试。
   lstres.add(new order() { id = "aaaa", no = "111", name = "111", desc = "1111" });
   lstres.add(new order() { id = "bbbb", no = "222", name = "222", desc = "2222" });
 
   var odata = new { total = lstres.count, rows = lstres.skip(offset).take(limit).tolist() };
   return new pageresult(odata, request);
  }

最好,ajax调用

?
1
2
3
4
5
6
7
8
9
10
$(function () {
 $.ajax({
  type: 'get',
  url: 'http://localhost:21528/api/order/getpagerow',
  data: { limit:1,offset:1},
  success: function (data, status) {
   alert(data);
  }
 });
});

得到结果

C# WebApi 接口返回值不困惑:返回值类型详解

三、httpresponsemessage

在上文自定义ihttpactionresult返回类型的时候,提到过httpresponsemessage这个对象。它表示向客户端返回一个http响应的消息对象(包含http状态码和需要返回客户端的消息)。这个对象也有它独特的使用场景:需要向客户端返回httpresponse时就要用到这个对象。以导出为例,由于需要将导出的excel文件输出到客户端浏览器,webapi的服务端需要向web的客户端输出文件流,这个时候一般的ihttpactionresult对象不方便解决这个问题,于是httpreponsemessage派上了用场。我们来看看它的使用示例。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public httpresponsemessage export()
  {
   //取数据
   var lstres = orderbll.export();
 
   //向excel里面填充数据
   hssfworkbook workbook = new hssfworkbook();
   createandfillsheet(workbook, lstres);
   
   //保存到服务
   var filename = "excel" + datetime.now.tostring("yyyymmddhhmmss") + ".xls";
   var strpath = path.combine(appdomain.currentdomain.basedirectory, @"data" + filename);
   using (filestream fs = new filestream(strpath, filemode.create))
   {
    workbook.write(fs);
    using (memorystream ms = new memorystream())
    {
     workbook.write(ms);
    }
   }
 
   //输出到浏览器
   try
   {
    var stream = new filestream(strpath, filemode.open);
    httpresponsemessage response = new httpresponsemessage(httpstatuscode.ok);
    response.content = new streamcontent(stream);
    response.content.headers.contenttype = new mediatypeheadervalue("application/octet-stream");
    response.content.headers.contentdisposition = new contentdispositionheadervalue("attachment")
    {
     filename = filename
    };
 
    return response;
   }
   catch
   {
    return new httpresponsemessage(httpstatuscode.nocontent);
   }
  }

将文件流保存在streamcontent对象里面,然后输出到浏览器。在浏览器端即可将excel输出。

四、自定义类型

以上几种返回值类型能解决我们大部分返回值的问题,当然,你也可以将webapi的接口和普通方法一样,返回任意的类型,webapi会自动序列化你自定义任何返回类型,然后将序列化的值写到响应正文里,状态码统一返回200。比如:

?
1
2
3
4
5
6
7
8
9
10
11
[httpget]
  public object getother()
  {
   var lstres = new list<order>();
 
   //实际项目中,通过后台取到集合赋值给lstres变量。这里只是测试。
   lstres.add(new order() { id = "aaaa", no = "111", name = "111", desc = "1111" });
   lstres.add(new order() { id = "bbbb", no = "222", name = "222", desc = "2222" });
 
   return lstres;
  }

得到结果

C# WebApi 接口返回值不困惑:返回值类型详解

和上面的json、ok等用法在效果上面没有太大区别。

五、总结

以上通过四个方面详细分享了下webapi里面返回值的常见用法,不能说哪种方式最好,因为每种方式都有其特定的使用场景。博主觉得为了规范webapi接口,对于一般接口的返回值,尽量使用ihttpactionresult类型作为返回值,毕竟是微软内置的东西,可能为我们考虑了很多我们考虑不到的东西。当然,你可能会觉得麻烦,你可能会说直接和普通方法一样来使用不是更爽,博主当初也有这种想法,可是学习微软的东西多了之后发现很多东西还是遵守一定的标准比较好,至少维护起来方便。这就像博主最近正在努力学习的webapi+odata一样,为什么要搞这么一套标准性的东西,还不是为了更加方便地规范restful风格。也希望大家多多支持服务器之家。

原文链接:http://www.cnblogs.com/landeanfen/p/5501487.html

延伸 · 阅读

精彩推荐
  • C#VS2012 程序打包部署图文详解

    VS2012 程序打包部署图文详解

    VS2012虽然没有集成打包工具,但它为我们提供了下载的端口,需要我们手动安装一个插件InstallShield。网上有很多第三方的打包工具,但为什么偏要使用微软...

    张信秀7712021-12-15
  • C#如何使用C#将Tensorflow训练的.pb文件用在生产环境详解

    如何使用C#将Tensorflow训练的.pb文件用在生产环境详解

    这篇文章主要给大家介绍了关于如何使用C#将Tensorflow训练的.pb文件用在生产环境的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴...

    bbird201811792022-03-05
  • C#深入理解C#的数组

    深入理解C#的数组

    本篇文章主要介绍了C#的数组,数组是一种数据结构,详细的介绍了数组的声明和访问等,有兴趣的可以了解一下。...

    佳园9492021-12-10
  • C#三十分钟快速掌握C# 6.0知识点

    三十分钟快速掌握C# 6.0知识点

    这篇文章主要介绍了C# 6.0的相关知识点,文中介绍的非常详细,通过这篇文字可以让大家在三十分钟内快速的掌握C# 6.0,需要的朋友可以参考借鉴,下面来...

    雨夜潇湘8272021-12-28
  • C#C#微信公众号与订阅号接口开发示例代码

    C#微信公众号与订阅号接口开发示例代码

    这篇文章主要介绍了C#微信公众号与订阅号接口开发示例代码,结合实例形式简单分析了C#针对微信接口的调用与处理技巧,需要的朋友可以参考下...

    smartsmile20127762021-11-25
  • C#利用C#实现网络爬虫

    利用C#实现网络爬虫

    这篇文章主要介绍了利用C#实现网络爬虫,完整的介绍了C#实现网络爬虫详细过程,感兴趣的小伙伴们可以参考一下...

    C#教程网11852021-11-16
  • C#SQLite在C#中的安装与操作技巧

    SQLite在C#中的安装与操作技巧

    SQLite,是一款轻型的数据库,用于本地的数据储存。其优点有很多,下面通过本文给大家介绍SQLite在C#中的安装与操作技巧,感兴趣的的朋友参考下吧...

    蓝曈魅11162022-01-20
  • C#C#设计模式之Strategy策略模式解决007大破密码危机问题示例

    C#设计模式之Strategy策略模式解决007大破密码危机问题示例

    这篇文章主要介绍了C#设计模式之Strategy策略模式解决007大破密码危机问题,简单描述了策略模式的定义并结合加密解密算法实例分析了C#策略模式的具体使用...

    GhostRider10972022-01-21