1.项目准备
一.开发环境 vs2015
二.net framework版本4.5.2
三.Nuget安装SqlSugar(第三方中间件,非常好用) 官网:https://www.donet5.com/Home/Doc?typeId=1226
四.接口要求:请求和响应的主体是JSON结构
五.实例实现功能:添加 (POST),其他功能大同小异
Restful表达行为
- GET(SELECT):从服务器取出资源(一项或多项)
- POST(CREATE):在服务器新建一个资源
- PUT(UPDATE):在服务器更新资源(客户端提供完整资源数据)
- PATCH(UPDATE):在服务器更新资源(客户端提供需要修改的资源数据)
- DELETE(DELETE):从服务器删除资源
2.接下来开始写Restful 服务端,如何实现一个Rest风格的web服务供外部调用。
主要包括以下4点:
- 定义service的契约
- 定义URL Routing
- 实现service
- 为服务编写宿主程序
1、定义service的契约和URL Routing
先定义服务契约,这里我介绍最常见的两种方式,分别采用GET和POST方式访问,使用VS2015创建一个新的控制台工程,命名为RestFulService。
并为该工程添加引用System.ServiceModel 和System.ServiceModel.Web
一,编写接口ITaskInfoQuery
创建一个接口类文件,命名为ITaskInfoQuery。为了让.Net FrameWork识别这是一个service接口,我们需要给接口添加上ServiceContract特性,并且给接口定义的方法添加OperationContract特性。这里我介绍最常见的两种方式,分别采用GET和POST方式访问。我们可以看到,与普通WCF服务契约不同的是,需要额外用WebGet或者WebInvoke指定REST访问的方式。另外还要指定消息包装样式和消息格式,默认的消息请求和响应格式为XML,若选择JSON需要显式声明。 UriTemplate用来将方法映射到具体的Uri上,但如果不指定映射,将映射到默认的Uri。
namespace RestFulService
{
[ServiceContract(Name = "TaskInfoQueryServices")]
public interface ITaskInfoQuery
{
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "TaskInfoInsert/Task", BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
MessagesInfo InstrtInfo(Task task);
}
}
特性说明
ServiceContract 特性里面的Name 填写接口实现类型的名称
UriTemplate 里面相当于是访问路由 (例如,如果InstrtInfo是一个插入的方法,规定接口服务地址是http://127.0.0.1:7788/ 路由定义的访问名称是:TaskInfoInsert/Task)
那么最后第三方就可以外部调用:http://127.0.0.1:7788/TaskInfoInsert/Task 来进行数据插入操作。
WebGet默认请求是GET方式。
WebInvoke请求方式有POST、PUT、DELETE等,所以需要明确指定Method是哪种请求的。
RequestFormat规定客户端必须是什么数据格式请求的(JSon或者XML),不设置默认为XML
ResponseFormat规定服务端返回给客户端是以是什么数据格返回的(JSon或者XML)
MessagesInfo 实体类说明。这个类主要是用来外部调用接口时反馈自定义状态。例子中,当外部调用该接口时,将反馈回任务ID,自定义Status,和消息说明Message
[DataContract]
public class MessagesInfo
{
[DataMember]
public long? Id { get; set; }
[DataMember]
public int Status { get; set; }
[DataMember]
public string Message { get; set; }
}
反馈例子:
{
"Id": 789456139,
"Message": "成功", //执行失败,备注具体失败原因。
"Status": 1
}
Task 实体类说明。这个类的字段跟数据库表结构字段一样,也就是当外部调用接口时,是需要他们往数据库表里面插入一个ID或者是其他一些信息(根据需求定)。
就比如当前我这当表只有两个字段,一个是任务ID,一个是任务类型。那么我就这样定义
[SugarTable("Transport")]
[DataContract]
public class Task
{
[DataMember]
public long? Id { get; set; }
[DataMember]
public int TaskType { get; set; }
}
SugarTable("Transport") 说明:当数据库表明跟实体类定义不一样时,可以用过SugarTable特性来设置。
例如:我的数据库表名是Transport 但是为了安全或者是出于其他考滤,建立的实体类名是Task,那么就可以使用 [SugarTable("Transport")] 进行映射 。
这个特性来自第三方中间件ORM. 官网:https://www.donet5.com/Home/Doc?typeId=1182
因为使用到第三方ORM进行数据库CRUD(增删改查),所以这里需要这样配置。
2、实现service
二.实现service就是实现定义ITaskInfoQuery 接口
上面说到,ServiceContract特性里面的Name 填写接口实现类型的名称,那就建立一个实现类,名称就叫 TaskInfoQueryServices
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single, IncludeExceptionDetailInFaults = true)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class TaskInfoQueryServices : ITaskInfoQuery
{
private SqlSugarClient db;
public TaskInfoQueryServices()
{
db = Singleton.GetInstance();
}
public MessagesInfo InstrtInfo(Task task)
{
bool flag = db.Queryable<Task>().Where(it => it.Id == task.Id).Any();
if (flag) return new MessagesInfo() { Id = task.Id, Status = 0, Message = "存在重复ID" };
if (db.Insertable(task).UseSqlServer().ExecuteBlueCopy() > 0) return new MessagesInfo() { Id = task.Id, Status = 1, Message = "成功" };
return new MessagesInfo() { Id = task.Id, Status = 0, Message = "插入数据到数据库操作失败" };
}
}
/// <summary>
/// 单例模式的实现
/// </summary>
public class Singleton
{
// 定义一个静态变量来保存类的实例
private static SqlSugarClient uniqueInstance;
// 定义一个标识确保线程同步
private static readonly object locker = new object();
// 定义私有构造函数,使外界不能创建该类实例
private Singleton()
{
}
/// <summary>
/// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
/// </summary>
/// <returns></returns>
public static SqlSugarClient GetInstance()
{
// 当第一个线程运行到这里时,此时会对locker对象 "加锁",
// 当第二个线程运行该方法时,首先检测到locker对象为"加锁"状态,该线程就会挂起等待第一个线程解锁
// lock语句运行完之后(即线程运行完之后)会对该对象"解锁"
// 双重锁定只需要一句判断就可以了
if (uniqueInstance == null)
{
lock (locker)
{
// 如果类的实例不存在则创建,否则直接返回
if (uniqueInstance == null)
{
uniqueInstance = new SqlSugarClient(new ConnectionConfig()
{
ConnectionString = "Data Source=.;Initial Catalog=TestDemo;User ID=sa;Password=123",
// ConnectionString = ConfigurationManager.AppSettings["ConnectionString"],
DbType = DbType.SqlServer,
IsAutoCloseConnection = true
});
}
}
}
return uniqueInstance;
}
}
说明:
1.数据库连接使用的单例模式是参考网上的实现,如果有侵权,删除 。
3、服务编写宿主程序
上面我们定义了Service接口,并实现了Service方法,现在我们需要将编写宿主程序,以便能够使客户端通过GET或者POST方法进行请求。
class Program
{
#region 禁用关闭按键
private const int MF_BYCOMMAND = 0x00000000;
public const int SC_CLOSE = 0xF060;
[DllImport("user32.dll")]
public static extern int DeleteMenu(IntPtr hMenu, int nPosition, int wFlags);// 删除菜单
[DllImport("user32.dll")]
private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);// 获取系统菜单句柄
[DllImport("kernel32.dll", ExactSpelling = true)]
private static extern IntPtr GetConsoleWindow();// 获取控制台窗口句柄
#endregion
static void Main(string[] args)
{
try
{
Console.Title = "RestFulService";
WebServiceHost _serviceHost = new WebServiceHost(typeof(TaskInfoQueryServices), new Uri("http://127.0.0.1:7788/"));
_serviceHost.Open();
Console.ForegroundColor = ConsoleColor.DarkCyan;
Console.WriteLine("Web服务已开启...");
Console.ForegroundColor = ConsoleColor.DarkCyan;
Console.WriteLine("输入指令关闭服务程序:");
#region 禁用关闭按键
DeleteMenu(GetSystemMenu(GetConsoleWindow(), false), SC_CLOSE, MF_BYCOMMAND);
//使用命令关闭
while (true)
{
Console.ForegroundColor = ConsoleColor.Green;
if (Console.ReadLine().ToLower() == "exit")
{
_serviceHost.Close();
return;
}
Console.WriteLine("指令不正确!请重新输入");
Console.ForegroundColor = ConsoleColor.Red;
}
#endregion
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Web服务开启失败:{0}\r\n{1}", ex.Message, ex.StackTrace);
}
}
}
}
为了防止控制台关闭,参考了网上实现,禁用控制台程序关闭按钮。链接:https://www.cnblogs.com/xinjian/archive/2010/07/23/1783358.html
Restful 服务端参考链接:https://www.cnblogs.com/xuliangxing/p/8735552.html
上面的实现结合网上例子和个人总结,如有侵权。删除!
接下来第二讲,进行测试Postman测试和客户端调用测试 https://blog.csdn.net/weixin_39237340/article/details/117031046?spm=1001.2014.3001.5502