搭建WebApi框架步骤

来源:互联网 发布:hip2p网络摄像机 编辑:程序博客网 时间:2024/06/15 04:00

1、 打开vs-文件-新建项目-web-Asp.net Web应用程序-确定-Web Api-Mvc Web API-确定
2、 查看项目Controller文件夹,下面两个文件:
HomeController.cs—–打开该文件,该文件继承的是Controller.(继承MVC里的Contrller)
ValuesController.cs—打开该文件,该文件继承的是ApiController.(是API的Controller,应调整该控制器的继承,新建一个基类控制器BaseController,继承ApiContrller).在这个基类控制器BaseController中写一些通用的方法。

3、 添加接口帮助文档
第一步:Areas-HelpPage-App_Start-HelpPageconfig.cs打开:第二行注释去掉,改成:
config.SetDocumentationProvider(new XmlDocumentationProvider(HttpContext.Current.Server.MapPath(“~/App_Data/BIMAPI.XML”)));
第二步:右击项目-属性-生成-选中XML文档文件(X):App_Data\BIMAPI.XML
第三步:找个一个接口,在接口上面加上注释,例如:

       /// <summary>        /// Get方法        /// </summary>        /// <returns></returns>        public IEnumerable<string> Get()        {            return new string[] { "value1", "value2" };        }
    运行项目即可看到该接口的注释。

4、 添加测试功能
第一步:项目右击—管理Nuget程序包,联机—Nuget.org下面,查找WebApiTestClient.安装。
第二步:在Areas—HelpPage-Views-Help-Api.cshtml.打开文件,最下面加上如下代码(有的版本安装完自动安装,有的需要自己手动添加代码):

@Html.DisplayForModel("TestClientDialogs")@section Scripts {    @Html.DisplayForModel("TestClientReferences")    <link type="text/css" href="~/Areas/HelpPage/HelpPage.css" rel="stylesheet" />}

5、 添加日志(异常和访问接口记录日志)
1、 右击项目-管理NuGet程序包,安装NLog.
2、 在项目的根目录下新建Loggers文件夹
这里写图片描述
3、 创建三个类文件
2.1、AbnormalFilterAttribute.cs内容:

using System;using System.Collections.Generic;using System.ComponentModel.DataAnnotations;using System.Linq;using System.Net;using System.Net.Http;using System.Web;using System.Web.Http;using System.Web.Http.Filters;using System.Web.Http.Tracing;namespace BIMAPI.Loggers{    public class AbnormalFilterAttribute: ExceptionFilterAttribute    {        public override void OnException(HttpActionExecutedContext actionExecutedContext)        {            GlobalConfiguration.Configuration.Services.Replace(typeof(ITraceWriter), new AppLog());            var trace = GlobalConfiguration.Configuration.Services.GetTraceWriter();            trace.Error(actionExecutedContext.Request, "Controller : " + actionExecutedContext.ActionContext.ControllerContext.ControllerDescriptor.ControllerType.FullName + Environment.NewLine + "Action : " + actionExecutedContext.ActionContext.ActionDescriptor.ActionName, actionExecutedContext.Exception);            var exceptionType = actionExecutedContext.Exception.GetType();            if (exceptionType==typeof(ValidationException))            {                var resp = new HttpResponseMessage(HttpStatusCode.BadRequest) { Content = new StringContent(actionExecutedContext.Exception.Message), ReasonPhrase = "ValidationException" };                throw new HttpResponseException(resp);            }            else if (exceptionType==typeof(UnauthorizedAccessException))            {                throw new HttpResponseException(actionExecutedContext.Request.CreateResponse(HttpStatusCode.Unauthorized));            }            else            {                throw new HttpResponseException(actionExecutedContext.Request.CreateResponse(HttpStatusCode.InternalServerError));            }            //base.OnException(actionExecutedContext);        }    }}

2、2AppLog.cs内容

    using System;using System.Collections.Generic;using System.Linq;using System.Net.Http;using System.Web.Http.Tracing;using NLog;using Newtonsoft.Json;using System.Text;namespace BIMAPI.Loggers{    /// <summary>    /// 日志    /// </summary>    public sealed class AppLog : ITraceWriter    {        //持久连接--日志监听       // private static IPersistentConnectionContext connectContext = GlobalHost.ConnectionManager.GetConnectionContext<LogListenerHub>();        //日志写入        private static readonly Logger AppLogger = LogManager.GetCurrentClassLogger();        private static readonly Lazy<Dictionary<TraceLevel, Action<string>>> LoggingMap = new Lazy<Dictionary<TraceLevel, Action<string>>>(() => new Dictionary<TraceLevel, Action<string>>        {            {TraceLevel.Info,AppLogger.Info },            {TraceLevel.Debug,AppLogger.Debug },            {TraceLevel.Error,AppLogger.Error },            {TraceLevel.Fatal,AppLogger.Fatal },            {TraceLevel.Warn,AppLogger.Warn }        });        private Dictionary<TraceLevel,Action<string>> Logger        {            get { return LoggingMap.Value; }        }        /// <summary>        /// 跟踪编写器接口实现        /// </summary>        /// <param name="request"></param>        /// <param name="category"></param>        /// <param name="level"></param>        /// <param name="traceAction"></param>        public void Trace(HttpRequestMessage request, string category, TraceLevel level, Action<TraceRecord> traceAction)        {            if (level!=TraceLevel.Off)//未禁用日志跟踪            {                if (traceAction != null && traceAction.Target != null)                {                    category = category + Environment.NewLine + "Action Parameters : " + JsonConvert.SerializeObject(traceAction.Target);                }                var record = new TraceRecord(request, category, level);                if (traceAction != null)                {                    traceAction(record);                }              //  traceAction?.Invoke(record);                Log(record);            }            //throw new NotImplementedException();        }        /// <summary>        /// 日志写入        /// </summary>        /// <param name="record"></param>        private void Log(TraceRecord record)        {            var message = new StringBuilder();            /**************************运行日志****************************/            if (!string.IsNullOrWhiteSpace(record.Message))            {                message.Append("").Append(record.Message + Environment.NewLine);            }            if (record.Request!=null)            {                if (record.Request.Method!=null)                {                    message.Append("Method : " + record.Request.Method + Environment.NewLine);                }                if (record.Request.RequestUri!=null)                {                    message.Append("").Append("URL : " + record.Request.RequestUri + Environment.NewLine);                }                if (record.Request.Headers!=null&&record.Request.Headers.Contains("Token")&&record.Request.Headers.GetValues("Token")!=null&&record.Request.Headers.GetValues("Token").FirstOrDefault()!=null)                {                    message.Append("").Append("Token : " + record.Request.Headers.GetValues("Token").FirstOrDefault() + Environment.NewLine);                }            }            if (!string.IsNullOrWhiteSpace(record.Category))            {                message.Append("").Append(record.Category);            }            if (!string.IsNullOrWhiteSpace(record.Operator))            {                message.Append(" ").Append(record.Operator).Append(" ").Append(record.Operation);            }            //***************************异常日志***********************************//            if (record.Exception!=null&&!string.IsNullOrWhiteSpace(record.Exception.GetBaseException().Message))            {                var exceptionType = record.Exception.GetType();                message.Append(Environment.NewLine);                message.Append("").Append("Error : " + record.Exception.GetBaseException().Message + Environment.NewLine);            }            //日志广播         //   connectContext.Connection.Broadcast(Convert.ToString(message));            //日志写入本地文件            Logger[record.Level](Convert.ToString(message) + Environment.NewLine);        }    }}

2、3LogFilterAttribute.cs内容

using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Http;using System.Web.Http.Controllers;using System.Web.Http.Filters;using System.Web.Http.Tracing;namespace BIMAPI.Loggers{    public class LogFilterAttribute: ActionFilterAttribute    {        public override void OnActionExecuting(HttpActionContext actionContext)        {            GlobalConfiguration.Configuration.Services.Replace(typeof(ITraceWriter), new AppLog());            var trace = GlobalConfiguration.Configuration.Services.GetTraceWriter();            trace.Info(actionContext.Request, "Controller : " + actionContext.ControllerContext.ControllerDescriptor.ControllerType.FullName + Environment.NewLine + "Action : " + actionContext.ActionDescriptor.ActionName, "JSON", actionContext.ActionArguments);            //base.OnActionExecuting(actionContext);        }    }}

4、 在项目的App_Start的WebApiConfig.cs文件中添加以下代码:

        //日志配置            config.Filters.Add(new LogFilterAttribute());     config.Filters.Add(new AbnormalFilterAttribute());

最终界面:
这里写图片描述

5、 Web.config中节点下配置以下内容:
在上面:

    <configSections>    <!--日志-->    <section name="nlog" type="NLog.Config.ConfigSectionHandler,NLog" />    </configSections>

在下面日志配置:

<nlog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">    <targets>        <target name="logfile" xsi:type="File" fileName="${basedir}/App_Log/${date:format=yyyy-MM-dd}-api.log" />        <target name="eventlog" xsi:type="EventLog" layout="${message}" log="Application" source="Api Services" />    </targets>    <rules>        <logger name="*" minlevel="Trace" writeTo="logfile" />        <logger name="*" minlevel="Trace" writeTo="eventlog" />    </rules></nlog>

最终效果图:
这里写图片描述
6、 运行后,就会生成如下文件夹:
这里写图片描述
6、 WebApi发布(采用Web Deploy发布,即直接发布到远程服务器上)

6、1、需要在远程服务器上安装WDeploy,从网上下载WDeploy.exe安装文件。
6、2配置http://jingyan.baidu.com/article/642c9d34e614de644a46f783.html
6、3 需要在服务器的IIS上建应用程序池,建网站(目录可以先建个空的)
6.4、右击项目-发布,如下设置:
这里写图片描述

4验证连接,允许。发布即可。
6、5访问服务器上发布后的项目,显示项目.netframework版本不是4.5.需要在微软官方下载.netframework 4.5安装。就没有问题了。

7、 开始写简单的接口
7、1.将App_Start下的WebApiConfig.cs。文件内容:

config.Routes.MapHttpRoute(                name: "DefaultApi",                routeTemplate: "api/{controller}/{id}",                defaults: new { id = RouteParameter.Optional }            );

改为:

   config.Routes.MapHttpRoute(                name: "DefaultApi",                routeTemplate: "api/{controller}/{action}",                defaults: new { id = RouteParameter.Optional }            );

可分别运行下,看下接口地址有什么不同。改成action后更方便查看接口名(方法名)
8、 可以在Controller下面建控制器了,(可写三个返回不同类型的接口,比如:string bool datatable)
9、 添加实时监控日志
第一步:添加引用SignalR程序包,右击项目—管理NuGet程序包。找到SignalR程序包,安装。
第二步:右击项目-添加-类-选择OWIN Startup类-类名为:Startup.cs
内容代码如下:

 using System;using System.Threading.Tasks;using Microsoft.Owin;using Owin;using BIMAPI.Hubs;[assembly: OwinStartup(typeof(BIMAPI.Startup))]namespace BIMAPI{    public class Startup    {        public void Configuration(IAppBuilder app)        {            // 有关如何配置应用程序的详细信息,请访问 http://go.microsoft.com/fwlink/?LinkID=316888            app.MapSignalR();            app.MapSignalR<LogTracer>("/LogTracer"); // LogTracer为第四步新建的类名。        }    }}

第三步:项目右击—新建文件夹Hubs。
第四步:在Hubs文件夹下,新建类-Web下—SignalR永久连接类(v2)–类名为LogTracer.cs
第五步:在上面提到的AppLog.cs中加上代码(代码位置可参照上面的AppLog.cs内容),这样实时监测日志就完成了,接下来在界面展示实时日志内容:
//持久连接–日志监听

      private static IPersistentConnectionContext connectContext = GlobalHost.ConnectionManager.GetConnectionContext<LogTracer>();

//日志广播

    connectContext.Connection.Broadcast(Convert.ToString(message));
      第六步:实时日志显示,在API后面添加实时日志监听:

1、 在Views-Shared-_Layout.cshtml文件中

  • @Html.ActionLink(“实时日志监听”, “Index”, “Log”, new { area = “” }, null)
  • 2、 在Views下新建文件夹Log.
    3、 在Log文件夹下,右击-添加-MVC 5 分布页(Razor)-文件名Index.cshtml
    页面内容如下:

    @{    ViewBag.Title = "实时监听";}<h2>实时监听</h2><div>    <input type="button" id="_start" value="开始监听" />    <input type="button" id="_stop" value="停止监听" />    <input type="button" id="_clear" value="清空记录" /></div><div>    <ul id="_messageList"></ul></div>@section scripts{<script src="~/Scripts/jquery-1.10.2.min.js"></script><script src="~/Scripts/jquery.signalR-2.2.1.js"></script>    <script>        $(function () {            var startBtn = $('#_start');            var stopBtn = $('#_stop');            var listener = $.connection('/LogTracer');            enable(stopBtn, false);            enable(startBtn, true);            //启动            startBtn.click(function () {                startConnection();                enable(stopBtn, true);                enable(startBtn, false);            });            //停止            stopBtn.click(function () {                stopConnection();                enable(startBtn, true);                enable(stopBtn, false);                $('#_messageList').append('<li>监听已停止...</li>');            });            //清空列表            $('#_clear').click(function () {                $('#_messageList').children().remove();            });            //开启连接            function startConnection() {                stopConnection();                listener.start().fail(function () {                    $('#_messageList').append('<li>监听启动失败!</li>');                }).done(function () {                    $('#_messageList').append('<li>监听已启动...</li>');                });                listener.received(function (message) {                    $('#_messageList').append('<li>' + message + '</li>');                });            }            //断开连接            function stopConnection() {                if(listener!=null){                    listener.stop();                }            };            //按钮切换            function enable(button,enabled) {                if (enabled) {                    button.removeAttr("disabled");                }                else {                    button.attr("disabled", "disabled");                }            }        });    </script>}

    注:分布页和布局页的区别是:分布页只是页面的局部展示的内容,基本是元素div中。布局页,则包括html head body标签是一个完整的Html 页面。
    运行后界面如下:

    这里写图片描述

    10、 添加消息发送Hub
    第一步:在Hubs的文件夹下新增类—Web-SignalR集线器类v2—名:MessageHub.cs
    第二步:在Controller文件夹的BaseController.cs里加上代码:如下:

       public class BaseController<T> : ApiController where T :Hub    {        #region signalr集成        protected IHubConnectionContext<dynamic> Clients { get; private set; }        protected IGroupManager Groups { get; private set; }        protected BaseController()        {            var context = GlobalHost.ConnectionManager.GetHubContext<T>();            Clients = context.Clients;            Groups = context.Groups;        }        #endregion}

    第三步:其他有继承BaseController的控制器,修改继承的代码,如下:

      public class PlanController : BaseController<MessageHub>

    第四步:继承完BaseController后,接口就可以发送消息给客户端了,代码如下:

    Clients.All.SendMessage(2, "");//发送给所有设备            Clients.Client("");//发送给指定的连接设备

    注:客户端和服务端的用法规则:定义方法名一致,比如服务端叫SendMessage,客户端也得叫SendMessage,服务端方法中的参数只需要输入值,不需要声明类型,客户端的方法需要声明类型。类型要跟服务端传值一致。

    11、 生成项目遇到的问题
    第一个:整个解决方案都可以生成成功,但是发布BIMAPI接口的时候,一直提示位于Release下的一个dll找不到。(原因是该接口引用这个dll,而不是引用该项目。将该接口在添加引用的时候,选择项目引用即可。因为发布接口的时候,设置项里Configuration里选择Release。在发布项目项目的时候,它去找的引用为Release文件夹下。所以找不到,就无法发布成功。若改为引用项目,不论是debug还是Release都可以找的到)

    0 0