C/S程序,发布Web接口(WebApi)

上一篇博客介绍了以WCF的方式,在后端程序部署WEB接口,本篇介绍以WebApi的方式以后端程序为宿主部署WEB接口,依旧以本人实际开发的项目进行说明,直接进入正题。

材料:VS2015,框架:.NET FrameWork 4.5.2,接口调试工具:PostMan,数据传输格式:Json。

本人的项目程序是Windows服务程序,各位自测的时候可以新建一个控制台程序,是一样的哈。

下图为本人的项目文件类库:(供参考)

packages.config

下图为项目需要使用的引用文件,除了Lx.CSharp.Common(这个是个人封装的通用方法库文件)不需要管,YiriXXXX是工程下的相关类库依赖引用,也可以不需要管,上图BLL文件夹下为业务处理的代码,读者也可以不用管,其他的引用文件都是项目中需要使用的引用,这些引用文件大部分在本地计算中就可以找到(除非你的.NET FrameWork版本够旧的),找不到的话就网上搜索NUGET方法就可以了(提示:System.Web.Http需要NuGet  “Microsoft.AspNet.WebApi.Core”)。

了解过WebApi的朋友应该知道,有一个叫“路由”的东西很重要,这个东西规定了前端访问接口的调用方法,类库图中的文件夹Api_Start下的类StartUp就是路由代码。代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;
using Newtonsoft.Json;
using System.Net.Http.Formatting;
using Owin;
using System.Web.Http.Cors;

namespace YiriFloodMonitoringSystemService.SendDataToSensor.Api_Start
{
    public class StartUp
    {
        public void Configuration(IAppBuilder appBuilder)
        {
            HttpConfiguration config = new HttpConfiguration();
            config.EnableCors(new EnableCorsAttribute("*", "*", "*"));   //配置跨域(EnableCors方法需要NuGetMicrosoft.AspNet.WebApi.Cors)
            config.MapHttpAttributeRoutes();
            config.Routes.MapHttpRoute(name: "DefaultApi",
               routeTemplate: "api/{controller}/{action}/{id}",
               defaults: new
               {
                   id = RouteParameter.Optional
               }
          );
            //清除xml格式,使用json格式
            config.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
            config.Formatters.Add(new JsonMediaTypeFormatter());
            appBuilder.UseWebApi(config);  //UseWebApi方法需要NuGet "Microsoft.AspNet.WebApi.Owin"
        }
    }
}

其中关键的地方为:"api/{controller}/{action}/{id}",这就是WebApi的路由规则,格式翻译为:api / 控制器名称 / 接口方法名称 / 参数ID,WebApi的相关路由规则,读者可以到网上自行搜索了解,这里不多做赘述.(推荐链接:WebApi路由机制详解——看完不会用你打我_webapi 路由_changuncle的博客-CSDN博客

接下来分别是接口定义和模型的代码(完整代码太多,取部分,供参考):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YiriFloodMonitoringSystemService.SendDataToSensor.Model;

namespace YiriFloodMonitoringSystemService.SendDataToSensor.SendDataInterface
{
    interface RD_600_Interface
    {
        string SetRoundChannalMulti(RoundChannalParamArr_RD600 channalArr);
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace YiriFloodMonitoringSystemService.SendDataToSensor.Model
{
    public struct RoundChannalParam_RD600
    {
        public string siteId;
        public byte port;
        public byte addr;
        public float distance;
        public float radius;
        public DateTime sendTime;
    }
    public class RoundChannalParamArr_RD600
    {
        public RoundChannalParam_RD600[] RoundChannalParamObjArr { get; set; }
    }
}

至此,可以与上一篇以WCF的方式开发Web接口相比,可以发现,无论是接口定义还是数据的结构模型,相比下webapi显得更轻型,没有非常多的契约、规则等相关的书写规定,完完全全的普通的接口和数据模型。这里需要注意的一个参数是RoundChannalParamObjArr ,一会调试的时候就会知道。

接下看接口实现代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Http;
using YiriFloodMonitoringSystemService.SendDataToSensor.Model;
using YiriFloodMonitoringSystemService.SendDataToSensor.SendDataInterface;
using System.Threading;
using YiriFloodMonitoringSystemService.SendDataToSensor.BLL;
using YiriFloodMonitoringSystemService.Common.Logs;
using YiriFloodMonitoringSystemService.Trigger;

namespace YiriFloodMonitoringSystemService.SendDataToSensor.SendDataRealize
{
    public class RD_600_RealizeController : ApiController, RD_600_Interface
    {
        [HttpPost]
        public string SetRoundChannalMulti(RoundChannalParamArr_RD600 channalArr)
        {
            try
            {
                SensorDataTrigger.Instance().Stop();
                StringBuilder jsonBuilder = new StringBuilder();
                jsonBuilder.Append("{\"");
                jsonBuilder.Append("result");
                jsonBuilder.Append("\":[");
                SetChannalParamBusiness_RD600 objSetChannalParamBusiness = new SetChannalParamBusiness_RD600();
                BusinessCommon objBusinessCommon = new BusinessCommon();
                for (int i = 0; i < channalArr.RoundChannalParamObjArr.Length; i++)
                {
                    RoundChannalParam_RD600 objRoundChannalParam = channalArr.RoundChannalParamObjArr[i];
                    int identityId = objBusinessCommon.InsertObject(objRoundChannalParam, EmSendClass.ChannalParam);
                    jsonBuilder.Append("{");
                    jsonBuilder.Append("\"");
                    jsonBuilder.Append(string.Format("{0}|{1}|{2}", objRoundChannalParam.siteId, objRoundChannalParam.port, objRoundChannalParam.addr));
                    jsonBuilder.Append("\":\"");
                    string result = objSetChannalParamBusiness.SetRoundChannalMultiBLL(objRoundChannalParam);
                    Thread.Sleep(500);
                    objBusinessCommon.UpdateObject(identityId, result.Contains("成功") ? true : false, result.Contains("成功") ? string.Empty : result);
                    jsonBuilder.Append(result);
                    jsonBuilder.Append("\"");
                    jsonBuilder.Append("},");
                }
                if (jsonBuilder.ToString().LastIndexOf(',') == jsonBuilder.Length - 1)
                {
                    jsonBuilder.Remove(jsonBuilder.Length - 1, 1);
                }
                jsonBuilder.Append("]");
                jsonBuilder.Append("}");
                string jsonResult = jsonBuilder.ToString();
                return jsonResult;
            }
            catch (Exception ex)
            {
                SendDataLog.LogException(ex);
                Thread.Sleep(10);
                return string.Empty;
            }
            finally
            {
                SensorDataTrigger.Instance().Start();
            }
        }
    }
}

方法里面的业务处理读者在测试时可以自己编写,此处仅仅为了贴上完整代码而已。此处几个关键点为:

1、控制器名称RD_600_RealizeController,我们在路由设置中知道有控制器名称的规定,此处的 RD_600_Realize 即为其控制器名称,是的,不是 RD_600_RealizeController,而是 RD_600_Realize。

2、控制器必须继承ApiController,只有继承ApiController,才能被前端调用到,然后继承 RD_600_Interface 接口只是为了实现接口。(其实是可以不需要写接口代码的,直接写控制器代码就可以,只是为了规范化,所以加了接口代码)。

3、[HttpPost],该处定义了接口的调用方式为POST。其实,WebApi 遵循 RestFul 规则,如果按规则定义方法名称,[HttpPost] 的定义也可以不要,至于什么是 RestFul 规则,读者可以在网上自行搜索。

接下来看,模块的启动类,实际上就是启动了线程中的任务而已,完整代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Owin;
using Microsoft.Owin.Hosting;
using YiriFloodMonitoringSystemService.SendDataToSensor.Api_Start;
using YiriFloodMonitoringSystemService.Common.Logs;

namespace YiriFloodMonitoringSystemService.SendDataToSensor
{
    public class SendDataMain
    {
        private Thread sendDataMainThread = null;
        private static SendDataMain sm_singleInstance = null;
        private static readonly object locks = new object();
        public static SendDataMain Instance() //单例
        {
            if (sm_singleInstance == null)
            {
                lock (locks)
                {
                    if (sm_singleInstance == null)
                    {
                        sm_singleInstance = new SendDataMain();
                    }
                }
            }
            return sm_singleInstance;
        }
        public SendDataMain()
        {
            sendDataMainThread = new Thread(new ThreadStart(StartWebApi));
            sendDataMainThread.IsBackground = true;
        }
        public void Start()
        {
            sendDataMainThread.Start();
        }
        public void Stop()
        {
            sendDataMainThread.Abort();
        }
        private void StartWebApi()
        {
            IPAddress localIp = null;
            IPAddress[] ipArray;
            try
            {
                ipArray = Dns.GetHostAddresses(Dns.GetHostName());
                localIp = ipArray.First(ip => ip.AddressFamily == AddressFamily.InterNetwork);
                if (localIp == null)
                {
                    localIp = IPAddress.Parse("127.0.0.1");
                }
                string ipStr = string.Format("http://{0}:5959", localIp);
                StartOptions options = new StartOptions();
                options.Urls.Add("http://localhost:5959");
                options.Urls.Add("http://127.0.0.1:5959");
                options.Urls.Add(ipStr);
                WebApp.Start<StartUp>(options);
                SendDataLog.LogInfo("WebApi Start......");
            }
            catch (Exception ex)
            {
                SendDataLog.LogException(ex);
            }
        }
    }
}

接下来,在 Main() 方法中启动线程(调用 Start() 方法)就可以启动此 WebApi 服务了。

然后看接口调用(使用POSTMAN接口调试工具):

至此,以后端程序为宿主的WebApi 接口代码就完成了。对比WCF来说,个人感觉 WebApi 的接口更加清爽、简洁,省去了很多契约、规定等等的书写,让程序开发者能更专注于接口业务内容的开发而不是接口的部署。

本文章作者纯手码字,若有引用部分已在文章中注明出处地址,如有侵权,请及时联系作者删除。如有雷同,万分荣幸。如果错误或者疑问,请在留言区留言,本人看到后会及时回复。

感谢阅读!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值