搭建WebApi框架步骤

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_31971935/article/details/53172724

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都可以找的到)

    展开阅读全文

    没有更多推荐了,返回首页