From 15ddc833faee93ec6a1e80d16e5d880796fc86ab Mon Sep 17 00:00:00 2001
From: "SmallChi(Koike)" <564952747@qq.com>
Date: Wed, 18 Dec 2019 17:44:48 +0800
Subject: [PATCH] =?UTF-8?q?=E7=94=A8=E7=AE=80=E5=8D=95=E7=B2=97=E6=9A=B4?=
 =?UTF-8?q?=E7=9A=84=E6=96=B9=E5=BC=8F=E5=AE=9E=E7=8E=B0pipeline?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 README.md                                     |    7 +-
 src/.dockerignore                             |   25 +
 .../Enums/JT808TransportProtocolType.cs       |   15 +
 .../IJT808ClientBuilder.cs                    |   14 +
 .../IJT808GatewayBuilder.cs                   |   14 +
 .../IJT808MsgConsumer.cs                      |   15 +
 .../IJT808MsgProducer.cs                      |   17 +
 .../IJT808MsgReplyConsumer.cs                 |   15 +
 .../IJT808MsgReplyProducer.cs                 |   17 +
 .../IJT808PubSub.cs                           |   11 +
 .../IJT808SessionConsumer.cs                  |   18 +
 .../IJT808SessionProducer.cs                  |   13 +
 .../JT808.Gateway.Abstractions.csproj         |   33 +
 .../JT808GatewayConstants.cs                  |   11 +
 .../Protos/JT808Gateway.proto                 |   63 +
 .../JT808.Gateway.Test.csproj                 |   28 +
 src/JT808.Gateway.Test/PipeTest.cs            |  100 +
 .../Session/JT808SessionManagerTest.cs        |  187 +
 .../Configs/NLog.xsd                          | 3106 +++++++++++++++++
 .../Configs/nlog.Unix.config                  |   36 +
 .../Configs/nlog.Win32NT.config               |   36 +
 src/JT808.Gateway.TestHosting/Dockerfile      |   23 +
 .../JT808.Gateway.TestHosting.csproj          |   35 +
 .../Jobs/CallGrpcClientJob.cs                 |   69 +
 src/JT808.Gateway.TestHosting/Program.cs      |   46 +
 src/JT808.Gateway.TestHosting/startup.txt     |    4 +
 src/JT808.Gateway.sln                         |   43 +
 .../Configurations/JT808Configuration.cs      |   43 +
 .../Enums/JT808MessageQueueType.cs            |   18 +
 src/JT808.Gateway/Interfaces/IJT808Session.cs |   26 +
 .../Internal/JT808GatewayBuilderDefault.cs    |   20 +
 .../Internal/JT808MsgProducerDefault.cs       |   28 +
 .../Internal/JT808MsgReplyConsumerDefault.cs  |  201 ++
 src/JT808.Gateway/Internal/JT808MsgService.cs |   11 +
 src/JT808.Gateway/JT808.Gateway.csproj        |   31 +
 src/JT808.Gateway/JT808GatewayExtensions.cs   |   75 +
 src/JT808.Gateway/JT808GrpcServer.cs          |   54 +
 src/JT808.Gateway/JT808TcpServer.cs           |  226 ++
 src/JT808.Gateway/JT808UdpServer.cs           |  134 +
 .../Metadata/JT808AtomicCounter.cs            |   49 +
 .../Services/JT808AtomicCounterService.cs     |   52 +
 .../JT808AtomicCounterServiceFactory.cs       |   30 +
 .../Services/JT808GatewayService.cs           |  144 +
 .../Services/JT808MsgReplyHostedService.cs    |   52 +
 .../JT808TcpReceiveTimeoutHostedService.cs    |   58 +
 .../JT808UdpReceiveTimeoutHostedService.cs    |   63 +
 .../Session/JT808SessionManager.cs            |  224 ++
 src/JT808.Gateway/Session/JT808TcpSession.cs  |   47 +
 src/JT808.Gateway/Session/JT808UdpSession.cs  |   41 +
 49 files changed, 5625 insertions(+), 3 deletions(-)
 create mode 100644 src/.dockerignore
 create mode 100644 src/JT808.Gateway.Abstractions/Enums/JT808TransportProtocolType.cs
 create mode 100644 src/JT808.Gateway.Abstractions/IJT808ClientBuilder.cs
 create mode 100644 src/JT808.Gateway.Abstractions/IJT808GatewayBuilder.cs
 create mode 100644 src/JT808.Gateway.Abstractions/IJT808MsgConsumer.cs
 create mode 100644 src/JT808.Gateway.Abstractions/IJT808MsgProducer.cs
 create mode 100644 src/JT808.Gateway.Abstractions/IJT808MsgReplyConsumer.cs
 create mode 100644 src/JT808.Gateway.Abstractions/IJT808MsgReplyProducer.cs
 create mode 100644 src/JT808.Gateway.Abstractions/IJT808PubSub.cs
 create mode 100644 src/JT808.Gateway.Abstractions/IJT808SessionConsumer.cs
 create mode 100644 src/JT808.Gateway.Abstractions/IJT808SessionProducer.cs
 create mode 100644 src/JT808.Gateway.Abstractions/JT808.Gateway.Abstractions.csproj
 create mode 100644 src/JT808.Gateway.Abstractions/JT808GatewayConstants.cs
 create mode 100644 src/JT808.Gateway.Abstractions/Protos/JT808Gateway.proto
 create mode 100644 src/JT808.Gateway.Test/JT808.Gateway.Test.csproj
 create mode 100644 src/JT808.Gateway.Test/PipeTest.cs
 create mode 100644 src/JT808.Gateway.Test/Session/JT808SessionManagerTest.cs
 create mode 100644 src/JT808.Gateway.TestHosting/Configs/NLog.xsd
 create mode 100644 src/JT808.Gateway.TestHosting/Configs/nlog.Unix.config
 create mode 100644 src/JT808.Gateway.TestHosting/Configs/nlog.Win32NT.config
 create mode 100644 src/JT808.Gateway.TestHosting/Dockerfile
 create mode 100644 src/JT808.Gateway.TestHosting/JT808.Gateway.TestHosting.csproj
 create mode 100644 src/JT808.Gateway.TestHosting/Jobs/CallGrpcClientJob.cs
 create mode 100644 src/JT808.Gateway.TestHosting/Program.cs
 create mode 100644 src/JT808.Gateway.TestHosting/startup.txt
 create mode 100644 src/JT808.Gateway.sln
 create mode 100644 src/JT808.Gateway/Configurations/JT808Configuration.cs
 create mode 100644 src/JT808.Gateway/Enums/JT808MessageQueueType.cs
 create mode 100644 src/JT808.Gateway/Interfaces/IJT808Session.cs
 create mode 100644 src/JT808.Gateway/Internal/JT808GatewayBuilderDefault.cs
 create mode 100644 src/JT808.Gateway/Internal/JT808MsgProducerDefault.cs
 create mode 100644 src/JT808.Gateway/Internal/JT808MsgReplyConsumerDefault.cs
 create mode 100644 src/JT808.Gateway/Internal/JT808MsgService.cs
 create mode 100644 src/JT808.Gateway/JT808.Gateway.csproj
 create mode 100644 src/JT808.Gateway/JT808GatewayExtensions.cs
 create mode 100644 src/JT808.Gateway/JT808GrpcServer.cs
 create mode 100644 src/JT808.Gateway/JT808TcpServer.cs
 create mode 100644 src/JT808.Gateway/JT808UdpServer.cs
 create mode 100644 src/JT808.Gateway/Metadata/JT808AtomicCounter.cs
 create mode 100644 src/JT808.Gateway/Services/JT808AtomicCounterService.cs
 create mode 100644 src/JT808.Gateway/Services/JT808AtomicCounterServiceFactory.cs
 create mode 100644 src/JT808.Gateway/Services/JT808GatewayService.cs
 create mode 100644 src/JT808.Gateway/Services/JT808MsgReplyHostedService.cs
 create mode 100644 src/JT808.Gateway/Services/JT808TcpReceiveTimeoutHostedService.cs
 create mode 100644 src/JT808.Gateway/Services/JT808UdpReceiveTimeoutHostedService.cs
 create mode 100644 src/JT808.Gateway/Session/JT808SessionManager.cs
 create mode 100644 src/JT808.Gateway/Session/JT808TcpSession.cs
 create mode 100644 src/JT808.Gateway/Session/JT808UdpSession.cs

diff --git a/README.md b/README.md
index 62abed7..e7a5fcb 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 
 基于DotNetty封装的JT808DotNetty支持TCP/UDP通用消息业务处理
 
-基于Pipeline封装的JT808DotNetty支持TCP/UDP通用消息业务处理
+基于Pipeline封装的JT808Pipeline支持TCP/UDP通用消息业务处理
 
 [了解JT808协议进这边](https://github.com/SmallChi/JT808)
 
@@ -81,6 +81,7 @@
 
 | Package Name          | Version                                            | Downloads                                           |
 | --------------------- | -------------------------------------------------- | --------------------------------------------------- |
+| Install-Package JT808.Gateway.Abstractions| ![JT808.Gateway.Abstractions](https://img.shields.io/nuget/v/JT808.Gateway.Abstractions.svg) | ![JT808.Gateway.Abstractions](https://img.shields.io/nuget/dt/JT808.Gateway.Abstractions.svg) |
 | Install-Package JT808.Gateway | ![JT808.Gateway](https://img.shields.io/nuget/v/JT808.Gateway.svg) | ![JT808.Gateway](https://img.shields.io/nuget/dt/JT808.Gateway.svg) |
 | Install-Package JT808.Gateway.Kafka| ![JT808.Gateway.Kafka](https://img.shields.io/nuget/v/JT808.Gateway.Kafka.svg) | ![JT808.Gateway.Kafka](https://img.shields.io/nuget/dt/JT808.Gateway.Kafka.svg) |
 
@@ -133,7 +134,7 @@ static async Task Main(string[] args)
 ```
 
 如图所示:
-![demo1](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/img/demo1.png)
+![demo1](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/dotnetty/demo1.png)
 
 ## 举个栗子2
 
@@ -144,4 +145,4 @@ static async Task Main(string[] args)
 3.进入JT808.DotNetty.SimpleClient项目下的Debug目录运行客户端
 
 如图所示:
-![demo2](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/img/demo2.png)
\ No newline at end of file
+![demo2](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/dotnetty/demo2.png)
diff --git a/src/.dockerignore b/src/.dockerignore
new file mode 100644
index 0000000..3729ff0
--- /dev/null
+++ b/src/.dockerignore
@@ -0,0 +1,25 @@
+**/.classpath
+**/.dockerignore
+**/.env
+**/.git
+**/.gitignore
+**/.project
+**/.settings
+**/.toolstarget
+**/.vs
+**/.vscode
+**/*.*proj.user
+**/*.dbmdl
+**/*.jfm
+**/azds.yaml
+**/bin
+**/charts
+**/docker-compose*
+**/Dockerfile*
+**/node_modules
+**/npm-debug.log
+**/obj
+**/secrets.dev.yaml
+**/values.dev.yaml
+LICENSE
+README.md
\ No newline at end of file
diff --git a/src/JT808.Gateway.Abstractions/Enums/JT808TransportProtocolType.cs b/src/JT808.Gateway.Abstractions/Enums/JT808TransportProtocolType.cs
new file mode 100644
index 0000000..4924be1
--- /dev/null
+++ b/src/JT808.Gateway.Abstractions/Enums/JT808TransportProtocolType.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JT808.Gateway.Abstractions.Enums
+{
+    /// <summary>
+    /// 传输协议类型
+    /// </summary>
+    public enum JT808TransportProtocolType
+    {
+        tcp=1,
+        udp = 2
+    }
+}
diff --git a/src/JT808.Gateway.Abstractions/IJT808ClientBuilder.cs b/src/JT808.Gateway.Abstractions/IJT808ClientBuilder.cs
new file mode 100644
index 0000000..9574094
--- /dev/null
+++ b/src/JT808.Gateway.Abstractions/IJT808ClientBuilder.cs
@@ -0,0 +1,14 @@
+using JT808.Protocol;
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JT808.Gateway.Abstractions
+{
+    public interface IJT808ClientBuilder
+    {
+        IJT808Builder JT808Builder { get; }
+        IJT808Builder Builder();
+    }
+}
diff --git a/src/JT808.Gateway.Abstractions/IJT808GatewayBuilder.cs b/src/JT808.Gateway.Abstractions/IJT808GatewayBuilder.cs
new file mode 100644
index 0000000..72f6bbd
--- /dev/null
+++ b/src/JT808.Gateway.Abstractions/IJT808GatewayBuilder.cs
@@ -0,0 +1,14 @@
+using JT808.Protocol;
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JT808.Gateway.Abstractions
+{
+    public interface IJT808GatewayBuilder
+    {
+        IJT808Builder JT808Builder { get; }
+        IJT808Builder Builder();
+    }
+}
diff --git a/src/JT808.Gateway.Abstractions/IJT808MsgConsumer.cs b/src/JT808.Gateway.Abstractions/IJT808MsgConsumer.cs
new file mode 100644
index 0000000..1e38db3
--- /dev/null
+++ b/src/JT808.Gateway.Abstractions/IJT808MsgConsumer.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+
+namespace JT808.Gateway.Abstractions
+{
+    public interface IJT808MsgConsumer : IJT808PubSub, IDisposable
+    {
+        void OnMessage(Action<(string TerminalNo, byte[] Data)> callback);
+        CancellationTokenSource Cts { get; }
+        void Subscribe();
+        void Unsubscribe();
+    }
+}
diff --git a/src/JT808.Gateway.Abstractions/IJT808MsgProducer.cs b/src/JT808.Gateway.Abstractions/IJT808MsgProducer.cs
new file mode 100644
index 0000000..1962f55
--- /dev/null
+++ b/src/JT808.Gateway.Abstractions/IJT808MsgProducer.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace JT808.Gateway.Abstractions
+{
+    public interface IJT808MsgProducer : IJT808PubSub, IDisposable
+    {
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="terminalNo">设备终端号</param>
+        /// <param name="data">808 hex data</param>
+        ValueTask ProduceAsync(string terminalNo, byte[] data);
+    }
+}
diff --git a/src/JT808.Gateway.Abstractions/IJT808MsgReplyConsumer.cs b/src/JT808.Gateway.Abstractions/IJT808MsgReplyConsumer.cs
new file mode 100644
index 0000000..3b5acb5
--- /dev/null
+++ b/src/JT808.Gateway.Abstractions/IJT808MsgReplyConsumer.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+
+namespace JT808.Gateway.Abstractions
+{
+    public interface IJT808MsgReplyConsumer : IJT808PubSub, IDisposable
+    {
+        void OnMessage(Action<(string TerminalNo, byte[] Data)> callback);
+        CancellationTokenSource Cts { get; }
+        void Subscribe();
+        void Unsubscribe();
+    }
+}
diff --git a/src/JT808.Gateway.Abstractions/IJT808MsgReplyProducer.cs b/src/JT808.Gateway.Abstractions/IJT808MsgReplyProducer.cs
new file mode 100644
index 0000000..39f0366
--- /dev/null
+++ b/src/JT808.Gateway.Abstractions/IJT808MsgReplyProducer.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace JT808.Gateway.Abstractions
+{
+    public interface IJT808MsgReplyProducer : IJT808PubSub, IDisposable
+    {
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="terminalNo">设备终端号</param>
+        /// <param name="data">808 hex data</param>
+        ValueTask ProduceAsync(string terminalNo, byte[] data);
+    }
+}
diff --git a/src/JT808.Gateway.Abstractions/IJT808PubSub.cs b/src/JT808.Gateway.Abstractions/IJT808PubSub.cs
new file mode 100644
index 0000000..7b1a327
--- /dev/null
+++ b/src/JT808.Gateway.Abstractions/IJT808PubSub.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JT808.Gateway.Abstractions
+{
+    public interface IJT808PubSub
+    {
+        string TopicName { get; }
+    }
+}
diff --git a/src/JT808.Gateway.Abstractions/IJT808SessionConsumer.cs b/src/JT808.Gateway.Abstractions/IJT808SessionConsumer.cs
new file mode 100644
index 0000000..78f405f
--- /dev/null
+++ b/src/JT808.Gateway.Abstractions/IJT808SessionConsumer.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+
+namespace JT808.Gateway.Abstractions
+{
+    /// <summary>
+    /// 会话通知(在线/离线)
+    /// </summary>
+    public interface IJT808SessionConsumer : IJT808PubSub, IDisposable
+    {
+        void OnMessage(Action<(string Notice, string TerminalNo)> callback);
+        CancellationTokenSource Cts { get; }
+        void Subscribe();
+        void Unsubscribe();
+    }
+}
diff --git a/src/JT808.Gateway.Abstractions/IJT808SessionProducer.cs b/src/JT808.Gateway.Abstractions/IJT808SessionProducer.cs
new file mode 100644
index 0000000..cecae48
--- /dev/null
+++ b/src/JT808.Gateway.Abstractions/IJT808SessionProducer.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Threading.Tasks;
+
+namespace JT808.Gateway.Abstractions
+{
+    /// <summary>
+    /// 会话通知(在线/离线)
+    /// </summary>
+    public interface IJT808SessionProducer : IJT808PubSub, IDisposable
+    {
+        ValueTask ProduceAsync(string notice,string terminalNo);
+    }
+}
diff --git a/src/JT808.Gateway.Abstractions/JT808.Gateway.Abstractions.csproj b/src/JT808.Gateway.Abstractions/JT808.Gateway.Abstractions.csproj
new file mode 100644
index 0000000..de3eb76
--- /dev/null
+++ b/src/JT808.Gateway.Abstractions/JT808.Gateway.Abstractions.csproj
@@ -0,0 +1,33 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <TargetFramework>netstandard2.1</TargetFramework>
+    <LangVersion>8.0</LangVersion>
+    <Copyright>Copyright 2019.</Copyright>
+    <Authors>SmallChi(Koike)</Authors>
+    <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
+    <SignAssembly>false</SignAssembly>
+    <PackageLicenseFile>LICENSE</PackageLicenseFile>
+    <PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
+    <Description>基于Pipeline实现的JT808Gateway的抽象库</Description>
+    <PackageReleaseNotes>基于Pipeline实现的JT808Gateway的抽象库</PackageReleaseNotes>
+    <PackageId>JT808.Gateway.Abstractions</PackageId>
+    <Product>JT808.Gateway.Abstractions</Product>
+    <Version>1.0.0-preview2</Version>
+  </PropertyGroup>
+  <ItemGroup>
+    <Protobuf Include="Protos\JT808Gateway.proto" />
+  </ItemGroup>
+  <ItemGroup>
+    <PackageReference Include="Google.Protobuf" Version="3.11.2" />
+    <PackageReference Include="Grpc.Core" Version="2.25.0" />
+    <PackageReference Include="Grpc.Tools" Version="2.25.0">
+      <PrivateAssets>all</PrivateAssets>
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+    </PackageReference>
+    <PackageReference Include="JT808" Version="2.2.2" />
+    <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.0" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="..\..\LICENSE" Pack="true" PackagePath="" />
+  </ItemGroup>
+</Project>
diff --git a/src/JT808.Gateway.Abstractions/JT808GatewayConstants.cs b/src/JT808.Gateway.Abstractions/JT808GatewayConstants.cs
new file mode 100644
index 0000000..6c631de
--- /dev/null
+++ b/src/JT808.Gateway.Abstractions/JT808GatewayConstants.cs
@@ -0,0 +1,11 @@
+namespace JT808.Gateway.Abstractions
+{
+    public static class JT808GatewayConstants
+    {
+        public const string SessionOnline= "JT808SessionOnline";
+        public const string SessionOffline = "JT808SessionOffline";
+        public const string SessionTopic = "jt808session";
+        public const string MsgTopic = "jt808msgdefault";
+        public const string MsgReplyTopic = "jt808msgreplydefault";
+    }
+}
diff --git a/src/JT808.Gateway.Abstractions/Protos/JT808Gateway.proto b/src/JT808.Gateway.Abstractions/Protos/JT808Gateway.proto
new file mode 100644
index 0000000..042fc89
--- /dev/null
+++ b/src/JT808.Gateway.Abstractions/Protos/JT808Gateway.proto
@@ -0,0 +1,63 @@
+syntax = "proto3";
+
+option csharp_namespace = "JT808.Gateway.GrpcService";
+
+package JT808GatewayGrpc;
+
+service JT808Gateway{
+	// 会话服务-获取会话服务集合
+	rpc GetTcpSessionAll(Empty) returns (TcpSessionInfoReply); 
+	// 会话服务-通过设备终端号移除对应会话
+	rpc RemoveSessionByTerminalPhoneNo(SessionRemoveRequest) returns (SessionRemoveReply);
+	// 统一下发信息
+	rpc UnificationSend(UnificationSendRequest) returns (UnificationSendReply);
+	// 获取Tcp包计数器
+	rpc GetTcpAtomicCounter(Empty) returns (TcpAtomicCounterReply);
+	// 会话服务-获取会话服务集合
+	rpc GetUdpSessionAll(Empty) returns (UdpSessionInfoReply);
+	// 获取Udp包计数器
+	rpc GetUdpAtomicCounter(Empty) returns (UdpAtomicCounterReply);
+}
+
+message Empty{}
+
+message TcpSessionInfoReply{
+	repeated SessionInfo TcpSessions=1;
+}
+message UdpSessionInfoReply{
+	repeated SessionInfo UdpSessions=1;
+}
+
+message SessionInfo{
+	string StartTime=1;
+	string LastActiveTime=2;
+	string TerminalPhoneNo=3;
+	string RemoteAddressIP=4;
+}
+
+message SessionRemoveRequest{
+	string TerminalPhoneNo=1; 
+}
+
+message SessionRemoveReply{
+	bool Success = 1;
+}
+
+message UnificationSendRequest{
+	string TerminalPhoneNo=1;
+	bytes Data=2;
+}
+
+message UnificationSendReply{
+	bool Success = 1;
+}
+
+message TcpAtomicCounterReply{
+	int64 MsgSuccessCount=1;
+	int64 MsgFailCount=2;
+}
+
+message UdpAtomicCounterReply{
+	int64 MsgSuccessCount=1;
+	int64 MsgFailCount=2;
+}
\ No newline at end of file
diff --git a/src/JT808.Gateway.Test/JT808.Gateway.Test.csproj b/src/JT808.Gateway.Test/JT808.Gateway.Test.csproj
new file mode 100644
index 0000000..e07a52b
--- /dev/null
+++ b/src/JT808.Gateway.Test/JT808.Gateway.Test.csproj
@@ -0,0 +1,28 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
+
+    <IsPackable>false</IsPackable>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.1.0" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
+    <PackageReference Include="System.IO.Pipelines" Version="4.7.0" />
+    <PackageReference Include="xunit" Version="2.4.1" />
+    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
+      <PrivateAssets>all</PrivateAssets>
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+    </PackageReference>
+    <PackageReference Include="coverlet.collector" Version="1.1.0">
+      <PrivateAssets>all</PrivateAssets>
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+    </PackageReference>
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\JT808.Gateway\JT808.Gateway.csproj" />
+  </ItemGroup>
+
+</Project>
diff --git a/src/JT808.Gateway.Test/PipeTest.cs b/src/JT808.Gateway.Test/PipeTest.cs
new file mode 100644
index 0000000..470de6d
--- /dev/null
+++ b/src/JT808.Gateway.Test/PipeTest.cs
@@ -0,0 +1,100 @@
+using System;
+using System.Buffers;
+using System.Collections.Generic;
+using System.IO.Pipelines;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace JT808.Gateway.Test
+{
+    public class PipeTest
+    {
+        [Fact]
+        public void Test1()
+        {
+            var reader = new ReadOnlySequence<byte>(new byte[] { 0x7E, 0, 1, 2, 0x7E});
+            SequenceReader<byte> seqReader = new SequenceReader<byte>(reader);
+            int index = 0;
+            byte mark = 0;
+            long totalConsumed = 0;
+            List<byte[]> packages = new List<byte[]>();
+            while (!seqReader.End)
+            {
+                if (seqReader.IsNext(0x7E, advancePast: true))
+                {
+                    if (mark == 1)
+                    {
+                        var package = seqReader.Sequence.Slice(totalConsumed, seqReader.Consumed - totalConsumed).ToArray();
+                        packages.Add(package);
+                        totalConsumed += (seqReader.Consumed - totalConsumed);
+                        index++;
+                        if (seqReader.End) break;
+                        seqReader.Advance(1);
+                        mark = 0;
+                    }
+                    mark++;
+                }
+                else
+                {
+                    seqReader.Advance(1);
+                }
+                index++;
+            }
+            Assert.Equal(5, index);
+            Assert.Single(packages);
+            Assert.Equal(5, seqReader.Consumed);
+        }
+
+        [Fact]
+        public void Test2()
+        {
+            var reader = new ReadOnlySequence<byte>(new byte[] { 0x7E, 0, 1, 2, 0x7E, 0x7E, 0, 1, 0x7E, 0x7E, 2, 2, 2 });
+            SequenceReader<byte> seqReader = new SequenceReader<byte>(reader);
+            int index = 0;
+            byte mark = 0;
+            long totalConsumed = 0;
+            List<byte[]> packages = new List<byte[]>();
+            while (!seqReader.End)
+            {
+                if (seqReader.IsNext(0x7E, advancePast: true))
+                {
+                    if (mark == 1)
+                    {
+                        var package = seqReader.Sequence.Slice(totalConsumed, seqReader.Consumed - totalConsumed).ToArray();
+                        packages.Add(package);
+                        totalConsumed += (seqReader.Consumed - totalConsumed);
+                        index++;
+                        if (seqReader.End) break;
+                        seqReader.Advance(1);
+                        mark = 0;
+                    }
+                    mark++;
+                }
+                else
+                {
+                    seqReader.Advance(1);
+                }
+                index++;
+            }
+            Assert.Equal(13, index);
+            Assert.Equal(2,packages.Count);
+            Assert.Equal(9, totalConsumed);
+            Assert.Equal(13, seqReader.Consumed);
+        }
+
+        [Fact]
+        public void Test3()
+        {
+            Assert.Throws<Exception>(() => 
+            {
+                var reader = new ReadOnlySequence<byte>(new byte[] { 0, 1, 2, 0x7E });
+                SequenceReader<byte> seqReader = new SequenceReader<byte>(reader);
+                if (seqReader.TryPeek(out byte beginMark))
+                {
+                    if (beginMark != 0x7E) throw new ArgumentException("not 808 packages");
+                }
+            });
+        }
+    }
+}
diff --git a/src/JT808.Gateway.Test/Session/JT808SessionManagerTest.cs b/src/JT808.Gateway.Test/Session/JT808SessionManagerTest.cs
new file mode 100644
index 0000000..6c2eabd
--- /dev/null
+++ b/src/JT808.Gateway.Test/Session/JT808SessionManagerTest.cs
@@ -0,0 +1,187 @@
+using JT808.Gateway.Session;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Xunit;
+using Microsoft.Extensions.Logging;
+using System.Net.Sockets;
+
+namespace JT808.Gateway.Test.Session
+{
+    public class JT808SessionManagerTest
+    {
+        [Fact]
+        public void TryAddTest()
+        {
+            JT808SessionManager jT808SessionManager = new JT808SessionManager(new LoggerFactory());
+            var result=jT808SessionManager.TryAdd(new JT808TcpSession(new Socket(SocketType.Stream, ProtocolType.Tcp)));
+            Assert.True(result);
+            Assert.Equal(1, jT808SessionManager.TotalSessionCount);
+        }
+
+        [Fact]
+        public void TryLinkTest()
+        {
+            string tno = "123456";
+            JT808SessionManager jT808SessionManager = new JT808SessionManager(new LoggerFactory());
+            var session = new JT808TcpSession(new Socket(SocketType.Stream, ProtocolType.Tcp));
+            var result1 = jT808SessionManager.TryAdd(session);
+            jT808SessionManager.TryLink(tno, session);
+            Assert.True(result1);
+            Assert.Equal(1, jT808SessionManager.TotalSessionCount);
+            Assert.True(jT808SessionManager.TerminalPhoneNoSessions.ContainsKey(tno));
+        }
+
+        /// <summary>
+        /// 用于转发过来的车辆
+        /// </summary>
+        [Fact]
+        public void TryLinkTest1_1_N()
+        {
+            string tno1 = "123456";
+            string tno2 = "123457";
+            string tno3 = "123458";
+            JT808SessionManager jT808SessionManager = new JT808SessionManager(new LoggerFactory());
+            var session = new JT808TcpSession(new Socket(SocketType.Stream, ProtocolType.Tcp));
+            var result1 = jT808SessionManager.TryAdd(session);
+            jT808SessionManager.TryLink(tno1, session);
+            jT808SessionManager.TryLink(tno2, session);
+            jT808SessionManager.TryLink(tno3, session);
+            Assert.True(result1);
+            Assert.Equal(1, jT808SessionManager.TotalSessionCount);
+            Assert.Equal(3,jT808SessionManager.TerminalPhoneNoSessions.Count);
+            jT808SessionManager.RemoveBySessionId(session.SessionID);
+            Assert.Equal(0, jT808SessionManager.TotalSessionCount);
+            Assert.Empty(jT808SessionManager.TerminalPhoneNoSessions);
+        }
+
+        /// <summary>
+        /// 用于转发过来的车辆
+        /// </summary>
+        [Fact]
+        public void TryLinkTest2_1_N()
+        {
+            string tno1 = "123456";
+            string tno2 = "123457";
+            string tno3 = "123458";
+            JT808SessionManager jT808SessionManager = new JT808SessionManager(new LoggerFactory());
+            var session = new JT808TcpSession(new Socket(SocketType.Stream, ProtocolType.Tcp));
+            var result1 = jT808SessionManager.TryAdd(session);
+            jT808SessionManager.TryLink(tno1, session);
+            jT808SessionManager.TryLink(tno2, session);
+            jT808SessionManager.TryLink(tno3, session);
+            Assert.True(result1);
+            Assert.Equal(1, jT808SessionManager.TotalSessionCount);
+            Assert.Equal(3, jT808SessionManager.TerminalPhoneNoSessions.Count);
+            jT808SessionManager.RemoveByTerminalPhoneNo(tno1);
+            Assert.Equal(0, jT808SessionManager.TotalSessionCount);
+            Assert.Empty(jT808SessionManager.TerminalPhoneNoSessions);
+        }
+
+        /// <summary>
+        /// 转发过来的车辆切换为直连车辆
+        /// </summary>
+        [Fact]
+        public void UpdateLinkTest2_1_N()
+        {
+            string tno1 = "123456";
+            string tno2 = "123457";
+            string tno3 = "123458";
+            JT808SessionManager jT808SessionManager = new JT808SessionManager(new LoggerFactory());
+            var session1 = new JT808TcpSession(new Socket(SocketType.Stream, ProtocolType.Tcp));
+            var session2 = new JT808TcpSession(new Socket(SocketType.Stream, ProtocolType.Tcp));
+            var result1 = jT808SessionManager.TryAdd(session1);
+            var result2 = jT808SessionManager.TryAdd(session2);
+            //转发车辆
+            jT808SessionManager.TryLink(tno1, session1);
+            jT808SessionManager.TryLink(tno2, session1);
+            //直连车辆
+            jT808SessionManager.TryLink(tno3, session2);
+
+            Assert.True(result1);
+            Assert.True(result2);
+            Assert.Equal(2, jT808SessionManager.TotalSessionCount);
+            Assert.Equal(3, jT808SessionManager.TerminalPhoneNoSessions.Count);
+
+            //将tno2切换为直连车辆
+            var session3 = new JT808TcpSession(new Socket(SocketType.Stream, ProtocolType.Tcp));
+            var result3 = jT808SessionManager.TryAdd(session3);
+            jT808SessionManager.TryLink(tno2, session3);
+            Assert.True(result3);
+            if (jT808SessionManager.TerminalPhoneNoSessions.TryGetValue(tno2,out string sessionid))
+            {
+                //实际的通道Id
+                Assert.Equal(session3.SessionID, sessionid);
+            }
+            Assert.Equal(3, jT808SessionManager.TotalSessionCount);
+            Assert.Equal(3, jT808SessionManager.TerminalPhoneNoSessions.Count);
+
+            jT808SessionManager.RemoveByTerminalPhoneNo(tno1);
+            Assert.Equal(2, jT808SessionManager.TotalSessionCount);
+            Assert.Equal(2,jT808SessionManager.TerminalPhoneNoSessions.Count);
+        }
+
+        [Fact]
+        public void RemoveBySessionIdTest()
+        {
+            JT808SessionManager jT808SessionManager = new JT808SessionManager(new LoggerFactory());
+            var session = new JT808TcpSession(new Socket(SocketType.Stream, ProtocolType.Tcp));
+            var result1 = jT808SessionManager.TryAdd(session);
+            Assert.True(result1);
+            Assert.Equal(1, jT808SessionManager.TotalSessionCount);
+            jT808SessionManager.RemoveBySessionId(session.SessionID);
+            Assert.Equal(0, jT808SessionManager.TotalSessionCount);
+        }
+
+        [Fact]
+        public void RemoveByTerminalPhoneNoTest()
+        {
+            string tno = "123456";
+            JT808SessionManager jT808SessionManager = new JT808SessionManager(new LoggerFactory());
+            var session = new JT808TcpSession(new Socket(SocketType.Stream, ProtocolType.Tcp));
+            var result1 = jT808SessionManager.TryAdd(session);
+            jT808SessionManager.TryLink(tno, session);
+            Assert.True(result1);
+            Assert.Equal(1, jT808SessionManager.TotalSessionCount);
+            jT808SessionManager.RemoveByTerminalPhoneNo(tno);
+            Assert.False(jT808SessionManager.TerminalPhoneNoSessions.ContainsKey(tno));
+            Assert.Equal(0, jT808SessionManager.TotalSessionCount);
+        }
+
+        [Fact]
+        public void SendTest()
+        {
+            Assert.Throws<SocketException>(() => 
+            {
+                string tno = "123456";
+                JT808SessionManager jT808SessionManager = new JT808SessionManager(new LoggerFactory());
+                var session = new JT808TcpSession(new Socket(SocketType.Stream, ProtocolType.Tcp));
+                var result1 = jT808SessionManager.TryAdd(session);
+                jT808SessionManager.TryLink(tno, session);
+                jT808SessionManager.TrySendByTerminalPhoneNo(tno, new byte[] { 0x7e, 0, 0, 0x7e });
+            });
+        }
+
+        [Fact]
+        public void GetTcpAllTest()
+        {
+            string tno1 = "123456";
+            string tno2 = "123457";
+            JT808SessionManager jT808SessionManager = new JT808SessionManager(new LoggerFactory());
+            var session1 = new JT808TcpSession(new Socket(SocketType.Stream, ProtocolType.Tcp));
+            var session2 = new JT808TcpSession(new Socket(SocketType.Stream, ProtocolType.Tcp));
+            var result1 = jT808SessionManager.TryAdd(session1);
+            var result2 = jT808SessionManager.TryAdd(session2);
+            jT808SessionManager.TryLink(tno1, session1);
+            jT808SessionManager.TryLink(tno2, session2);
+            Assert.True(result1);
+            Assert.True(result2);
+            Assert.Equal(2, jT808SessionManager.TotalSessionCount);
+            Assert.True(jT808SessionManager.TerminalPhoneNoSessions.ContainsKey(tno1));
+            Assert.True(jT808SessionManager.TerminalPhoneNoSessions.ContainsKey(tno2));
+            var sessions = jT808SessionManager.GetTcpAll();
+            Assert.Equal(session1.SessionID, sessions[0].SessionID);
+            Assert.Equal(session2.SessionID, sessions[1].SessionID);
+        }
+    }
+}
diff --git a/src/JT808.Gateway.TestHosting/Configs/NLog.xsd b/src/JT808.Gateway.TestHosting/Configs/NLog.xsd
new file mode 100644
index 0000000..2f57d09
--- /dev/null
+++ b/src/JT808.Gateway.TestHosting/Configs/NLog.xsd
@@ -0,0 +1,3106 @@
+<?xml version="1.0" encoding="utf-8"?>
+<xs:schema id="NLog" targetNamespace="http://www.nlog-project.org/schemas/NLog.xsd" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www.nlog-project.org/schemas/NLog.xsd">
+  <xs:element name="nlog" type="NLogConfiguration" />
+  <xs:complexType name="NLogConfiguration">
+    <xs:choice minOccurs="0" maxOccurs="unbounded">
+      <xs:element name="extensions" type="NLogExtensions" />
+      <xs:element name="include" type="NLogInclude" />
+      <xs:element name="variable" type="NLogVariable" />
+      <xs:element name="targets" type="NLogTargets" />
+      <xs:element name="rules" type="NLogRules" />
+      <xs:element name="time" type="TimeSource" />
+    </xs:choice>
+    <xs:attribute name="autoReload" type="xs:boolean">
+      <xs:annotation>
+        <xs:documentation>Watch config file for changes and reload automatically.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="internalLogToConsole" type="xs:boolean">
+      <xs:annotation>
+        <xs:documentation>Print internal NLog messages to the console. Default value is: false</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="internalLogToConsoleError" type="xs:boolean">
+      <xs:annotation>
+        <xs:documentation>Print internal NLog messages to the console error output. Default value is: false</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="internalLogFile" type="xs:string">
+      <xs:annotation>
+        <xs:documentation>Write internal NLog messages to the specified file.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="internalLogLevel" type="NLogLevel">
+      <xs:annotation>
+        <xs:documentation>Log level threshold for internal log messages. Default value is: Info.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="globalThreshold" type="NLogLevel">
+      <xs:annotation>
+        <xs:documentation>Global log level threshold for application log messages. Messages below this level won't be logged..</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="throwExceptions" type="xs:boolean">
+      <xs:annotation>
+        <xs:documentation>Throw an exception when there is an internal error. Default value is: false.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="throwConfigExceptions" type="xs:boolean">
+      <xs:annotation>
+        <xs:documentation>Throw an exception when there is a configuration error. If not set, determined by throwExceptions.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="keepVariablesOnReload" type="xs:boolean">
+      <xs:annotation>
+        <xs:documentation>Gets or sets a value indicating whether Variables should be kept on configuration reload. Default value is: false.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="internalLogToTrace" type="xs:boolean">
+      <xs:annotation>
+        <xs:documentation>Write internal NLog messages to the System.Diagnostics.Trace. Default value is: false.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="internalLogIncludeTimestamp" type="xs:boolean">
+      <xs:annotation>
+        <xs:documentation>Write timestamps for internal NLog messages. Default value is: true.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="useInvariantCulture" type="xs:boolean">
+      <xs:annotation>
+        <xs:documentation>Use InvariantCulture as default culture instead of CurrentCulture.  Default value is: false.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="messageTemplateParser" type="xs:boolean">
+      <xs:annotation>
+        <xs:documentation>Perform mesage template parsing and formatting of LogEvent messages (true = Always, false = Never, empty = Auto Detect). Default value is: empty.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:complexType>
+  <xs:complexType name="NLogTargets">
+    <xs:choice minOccurs="0" maxOccurs="unbounded">
+      <xs:element name="default-wrapper" type="WrapperTargetBase" />
+      <xs:element name="default-target-parameters" type="Target" />
+      <xs:element name="target" type="Target" />
+      <xs:element name="wrapper-target" type="WrapperTargetBase" />
+      <xs:element name="compound-target" type="CompoundTargetBase" />
+    </xs:choice>
+    <xs:attribute name="async" type="xs:boolean">
+      <xs:annotation>
+        <xs:documentation>Make all targets within this section asynchronous (creates additional threads but the calling thread isn't blocked by any target writes).</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:complexType>
+  <xs:complexType name="NLogRules">
+    <xs:sequence minOccurs="0" maxOccurs="unbounded">
+      <xs:element name="logger" type="NLogLoggerRule" />
+    </xs:sequence>
+  </xs:complexType>
+  <xs:complexType name="NLogExtensions">
+    <xs:choice minOccurs="0" maxOccurs="unbounded">
+      <xs:element name="add" type="NLogExtensionsAdd" />
+    </xs:choice>
+  </xs:complexType>
+  <xs:complexType name="NLogExtensionsAdd">
+    <xs:attribute name="prefix" type="xs:string">
+      <xs:annotation>
+        <xs:documentation>Prefix for targets/layout renderers/filters/conditions loaded from this assembly.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="assemblyFile" type="xs:string">
+      <xs:annotation>
+        <xs:documentation>Load NLog extensions from the specified file (*.dll)</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="assembly" type="xs:string">
+      <xs:annotation>
+        <xs:documentation>Load NLog extensions from the specified assembly. Assembly name should be fully qualified.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:complexType>
+  <xs:complexType name="NLogLoggerRule">
+    <xs:choice minOccurs="0" maxOccurs="unbounded">
+      <xs:element name="filters" type="NLogFilters" />
+    </xs:choice>
+    <xs:attribute name="name" use="optional">
+      <xs:annotation>
+        <xs:documentation>Name of the logger. May include '*' character which acts like a wildcard. Allowed forms are: *, Name, *Name, Name* and *Name*</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="levels" type="NLogLevelList">
+      <xs:annotation>
+        <xs:documentation>Comma separated list of levels that this rule matches.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="minlevel" type="NLogLevel">
+      <xs:annotation>
+        <xs:documentation>Minimum level that this rule matches.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="maxlevel" type="NLogLevel">
+      <xs:annotation>
+        <xs:documentation>Maximum level that this rule matches.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="level" type="NLogLevel">
+      <xs:annotation>
+        <xs:documentation>Level that this rule matches.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="writeTo" type="NLogTargetIDList">
+      <xs:annotation>
+        <xs:documentation>Comma separated list of target names.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="final" type="xs:boolean" default="false">
+      <xs:annotation>
+        <xs:documentation>Ignore further rules if this one matches.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="enabled" type="xs:boolean" default="true">
+      <xs:annotation>
+        <xs:documentation>Enable or disable logging rule. Disabled rules are ignored.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:complexType>
+  <xs:complexType name="NLogFilters">
+    <xs:choice minOccurs="0" maxOccurs="unbounded">
+      <xs:element name="when" type="when" />
+      <xs:element name="whenContains" type="whenContains" />
+      <xs:element name="whenEqual" type="whenEqual" />
+      <xs:element name="whenNotContains" type="whenNotContains" />
+      <xs:element name="whenNotEqual" type="whenNotEqual" />
+      <xs:element name="whenRepeated" type="whenRepeated" />
+    </xs:choice>
+  </xs:complexType>
+  <xs:simpleType name="NLogLevel">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="Off" />
+      <xs:enumeration value="Trace" />
+      <xs:enumeration value="Debug" />
+      <xs:enumeration value="Info" />
+      <xs:enumeration value="Warn" />
+      <xs:enumeration value="Error" />
+      <xs:enumeration value="Fatal" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="LineEndingMode">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="Default" />
+      <xs:enumeration value="CRLF" />
+      <xs:enumeration value="CR" />
+      <xs:enumeration value="LF" />
+      <xs:enumeration value="None" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="NLogLevelList">
+    <xs:restriction base="xs:string">
+      <xs:pattern value="(|Trace|Debug|Info|Warn|Error|Fatal)(,(Trace|Debug|Info|Warn|Error|Fatal))*" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:complexType name="NLogInclude">
+    <xs:attribute name="file" type="SimpleLayoutAttribute" use="required">
+      <xs:annotation>
+        <xs:documentation>Name of the file to be included. You could use * wildcard. The name is relative to the name of the current config file.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="ignoreErrors" type="xs:boolean" use="optional" default="false">
+      <xs:annotation>
+        <xs:documentation>Ignore any errors in the include file.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:complexType>
+  <xs:complexType name="NLogVariable">
+    <xs:attribute name="name" type="xs:string" use="required">
+      <xs:annotation>
+        <xs:documentation>Variable name.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="value" type="SimpleLayoutAttribute" use="required">
+      <xs:annotation>
+        <xs:documentation>Variable value.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:complexType>
+  <xs:simpleType name="NLogTargetIDList">
+    <xs:restriction base="xs:string">
+      <xs:pattern value="(|([a-zA-Z][a-zA-Z0-9_\-]*))(,([a-zA-Z][a-zA-Z0-9_\-]*))*" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:complexType name="Target" abstract="true"></xs:complexType>
+  <xs:complexType name="TargetRef">
+    <xs:attribute name="name" type="xs:string" use="required" />
+  </xs:complexType>
+  <xs:complexType name="WrapperTargetBase" abstract="true">
+    <xs:complexContent>
+      <xs:extension base="Target">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="target" type="Target" minOccurs="1" maxOccurs="1" />
+          <xs:element name="wrapper-target" type="WrapperTargetBase" minOccurs="1" maxOccurs="1" />
+          <xs:element name="compound-target" type="CompoundTargetBase" minOccurs="1" maxOccurs="1" />
+          <xs:element name="target-ref" type="TargetRef" minOccurs="1" maxOccurs="1" />
+          <xs:element name="wrapper-target-ref" type="TargetRef" minOccurs="1" maxOccurs="1" />
+          <xs:element name="compound-target-ref" type="TargetRef" minOccurs="1" maxOccurs="1" />
+        </xs:choice>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="CompoundTargetBase" abstract="true">
+    <xs:complexContent>
+      <xs:extension base="Target">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="target" type="Target" minOccurs="1" maxOccurs="unbounded" />
+          <xs:element name="wrapper-target" type="WrapperTargetBase" minOccurs="1" maxOccurs="1" />
+          <xs:element name="compound-target" type="CompoundTargetBase" minOccurs="1" maxOccurs="1" />
+          <xs:element name="target-ref" type="TargetRef" minOccurs="1" maxOccurs="1" />
+          <xs:element name="wrapper-target-ref" type="TargetRef" minOccurs="1" maxOccurs="1" />
+          <xs:element name="compound-target-ref" type="TargetRef" minOccurs="1" maxOccurs="1" />
+        </xs:choice>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="Filter" abstract="true"></xs:complexType>
+  <xs:complexType name="TimeSource" abstract="true"></xs:complexType>
+  <xs:simpleType name="SimpleLayoutAttribute">
+    <xs:restriction base="xs:string">
+      <xs:pattern value=".*" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="Condition">
+    <xs:restriction base="xs:string">
+      <xs:minLength value="1" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:complexType name="AsyncWrapper">
+    <xs:complexContent>
+      <xs:extension base="WrapperTargetBase">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="batchSize" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="fullBatchSizeWriteLimit" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="overflowAction" minOccurs="0" maxOccurs="1" type="NLog.Targets.Wrappers.AsyncTargetWrapperOverflowAction" />
+          <xs:element name="queueLimit" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="timeToSleepBetweenBatches" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="batchSize" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Number of log events that should be processed in a batch by the lazy writer thread.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="fullBatchSizeWriteLimit" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Limit of full s to write before yielding into  Performance is better when writing many small batches, than writing a single large batch</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="overflowAction" type="NLog.Targets.Wrappers.AsyncTargetWrapperOverflowAction">
+          <xs:annotation>
+            <xs:documentation>Action to be taken when the lazy writer thread request queue count exceeds the set limit.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="queueLimit" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Limit on the number of requests in the lazy writer thread request queue.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="timeToSleepBetweenBatches" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Time in milliseconds to sleep between batches.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:simpleType name="NLog.Targets.Wrappers.AsyncTargetWrapperOverflowAction">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="Grow" />
+      <xs:enumeration value="Discard" />
+      <xs:enumeration value="Block" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:complexType name="AutoFlushWrapper">
+    <xs:complexContent>
+      <xs:extension base="WrapperTargetBase">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="asyncFlush" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="condition" minOccurs="0" maxOccurs="1" type="Condition" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="asyncFlush" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Delay the flush until the LogEvent has been confirmed as written</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="condition" type="Condition">
+          <xs:annotation>
+            <xs:documentation>Condition expression. Log events who meet this condition will cause a flush on the wrapped target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="BufferingWrapper">
+    <xs:complexContent>
+      <xs:extension base="WrapperTargetBase">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="bufferSize" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="flushTimeout" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="slidingTimeout" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="overflowAction" minOccurs="0" maxOccurs="1" type="NLog.Targets.Wrappers.BufferingTargetWrapperOverflowAction" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="bufferSize" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Number of log events to be buffered.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="flushTimeout" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Timeout (in milliseconds) after which the contents of buffer will be flushed if there's no write in the specified period of time. Use -1 to disable timed flushes.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="slidingTimeout" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to use sliding timeout.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="overflowAction" type="NLog.Targets.Wrappers.BufferingTargetWrapperOverflowAction">
+          <xs:annotation>
+            <xs:documentation>Action to take if the buffer overflows.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:simpleType name="NLog.Targets.Wrappers.BufferingTargetWrapperOverflowAction">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="Flush" />
+      <xs:enumeration value="Discard" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:complexType name="Chainsaw">
+    <xs:complexContent>
+      <xs:extension base="Target">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="encoding" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="layout" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="lineEnding" minOccurs="0" maxOccurs="1" type="LineEndingMode" />
+          <xs:element name="maxMessageSize" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="newLine" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="onConnectionOverflow" minOccurs="0" maxOccurs="1" type="NLog.Targets.NetworkTargetConnectionsOverflowAction" />
+          <xs:element name="onOverflow" minOccurs="0" maxOccurs="1" type="NLog.Targets.NetworkTargetOverflowAction" />
+          <xs:element name="maxConnections" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="keepConnection" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="connectionCacheSize" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="address" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="maxQueueSize" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="parameter" minOccurs="0" maxOccurs="unbounded" type="NLog.Targets.NLogViewerParameterInfo" />
+          <xs:element name="ndcItemSeparator" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="includeSourceInfo" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="includeMdlc" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="includeNdlc" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="includeNdc" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="includeMdc" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="includeCallSite" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="includeAllProperties" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="appInfo" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="includeNLogData" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="encoding" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Encoding to be used.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="layout" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Instance of  that is used to format log messages.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="lineEnding" type="LineEndingMode">
+          <xs:annotation>
+            <xs:documentation>End of line value if a newline is appended at the end of log message .</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="maxMessageSize" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Maximum message size in bytes.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="newLine" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to append newline at the end of log message.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="onConnectionOverflow" type="NLog.Targets.NetworkTargetConnectionsOverflowAction">
+          <xs:annotation>
+            <xs:documentation>Action that should be taken if the will be more connections than .</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="onOverflow" type="NLog.Targets.NetworkTargetOverflowAction">
+          <xs:annotation>
+            <xs:documentation>Action that should be taken if the message is larger than maxMessageSize.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="maxConnections" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Maximum current connections. 0 = no maximum.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="keepConnection" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to keep connection open whenever possible.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="connectionCacheSize" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Size of the connection cache (number of connections which are kept alive).</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="address" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Network address.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="maxQueueSize" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Maximum queue size.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="ndcItemSeparator" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>NDC item separator.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="includeSourceInfo" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to include source info (file name and line number) in the information sent over the network.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="includeMdlc" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to include  dictionary contents.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="includeNdlc" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to include contents of the  stack.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="includeNdc" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to include  stack contents.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="includeMdc" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to include  dictionary contents.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="includeCallSite" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to include call site (class and method name) in the information sent over the network.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="includeAllProperties" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Option to include all properties from the log events</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="appInfo" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>AppInfo field. By default it's the friendly name of the current AppDomain.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="includeNLogData" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to include NLog-specific extensions to log4j schema.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:simpleType name="NLog.Targets.NetworkTargetConnectionsOverflowAction">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="AllowNewConnnection" />
+      <xs:enumeration value="DiscardMessage" />
+      <xs:enumeration value="Block" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="NLog.Targets.NetworkTargetOverflowAction">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="Error" />
+      <xs:enumeration value="Split" />
+      <xs:enumeration value="Discard" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:complexType name="NLog.Targets.NLogViewerParameterInfo">
+    <xs:choice minOccurs="0" maxOccurs="unbounded">
+      <xs:element name="layout" minOccurs="0" maxOccurs="1" type="Layout" />
+      <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+    </xs:choice>
+    <xs:attribute name="layout" type="SimpleLayoutAttribute">
+      <xs:annotation>
+        <xs:documentation>Layout that should be use to calcuate the value for the parameter.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="name" type="xs:string">
+      <xs:annotation>
+        <xs:documentation>Viewer parameter name.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:complexType>
+  <xs:complexType name="ColoredConsole">
+    <xs:complexContent>
+      <xs:extension base="Target">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="layout" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="header" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="footer" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="useDefaultRowHighlightingRules" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="highlight-row" minOccurs="0" maxOccurs="unbounded" type="NLog.Targets.ConsoleRowHighlightingRule" />
+          <xs:element name="highlight-word" minOccurs="0" maxOccurs="unbounded" type="NLog.Targets.ConsoleWordHighlightingRule" />
+          <xs:element name="detectConsoleAvailable" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="encoding" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="errorStream" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="layout" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Text to be rendered.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="header" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Header.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="footer" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Footer.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="useDefaultRowHighlightingRules" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to use default row highlighting rules.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="detectConsoleAvailable" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to auto-check if the console is available. - Disables console writing if Environment.UserInteractive = False (Windows Service) - Disables console writing if Console Standard Input is not available (Non-Console-App)</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="encoding" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>The encoding for writing messages to the .</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="errorStream" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether the error stream (stderr) should be used instead of the output stream (stdout).</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:simpleType name="NLog.Targets.ConsoleOutputColor">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="Black" />
+      <xs:enumeration value="DarkBlue" />
+      <xs:enumeration value="DarkGreen" />
+      <xs:enumeration value="DarkCyan" />
+      <xs:enumeration value="DarkRed" />
+      <xs:enumeration value="DarkMagenta" />
+      <xs:enumeration value="DarkYellow" />
+      <xs:enumeration value="Gray" />
+      <xs:enumeration value="DarkGray" />
+      <xs:enumeration value="Blue" />
+      <xs:enumeration value="Green" />
+      <xs:enumeration value="Cyan" />
+      <xs:enumeration value="Red" />
+      <xs:enumeration value="Magenta" />
+      <xs:enumeration value="Yellow" />
+      <xs:enumeration value="White" />
+      <xs:enumeration value="NoChange" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:complexType name="NLog.Targets.ConsoleRowHighlightingRule">
+    <xs:choice minOccurs="0" maxOccurs="unbounded">
+      <xs:element name="condition" minOccurs="0" maxOccurs="1" type="Condition" />
+      <xs:element name="backgroundColor" minOccurs="0" maxOccurs="1" type="NLog.Targets.ConsoleOutputColor" />
+      <xs:element name="foregroundColor" minOccurs="0" maxOccurs="1" type="NLog.Targets.ConsoleOutputColor" />
+    </xs:choice>
+    <xs:attribute name="condition" type="Condition">
+      <xs:annotation>
+        <xs:documentation>Condition that must be met in order to set the specified foreground and background color.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="backgroundColor" type="NLog.Targets.ConsoleOutputColor">
+      <xs:annotation>
+        <xs:documentation>Background color.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="foregroundColor" type="NLog.Targets.ConsoleOutputColor">
+      <xs:annotation>
+        <xs:documentation>Foreground color.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:complexType>
+  <xs:complexType name="NLog.Targets.ConsoleWordHighlightingRule">
+    <xs:choice minOccurs="0" maxOccurs="unbounded">
+      <xs:element name="ignoreCase" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+      <xs:element name="regex" minOccurs="0" maxOccurs="1" type="xs:string" />
+      <xs:element name="text" minOccurs="0" maxOccurs="1" type="xs:string" />
+      <xs:element name="wholeWords" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+      <xs:element name="compileRegex" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+      <xs:element name="backgroundColor" minOccurs="0" maxOccurs="1" type="NLog.Targets.ConsoleOutputColor" />
+      <xs:element name="foregroundColor" minOccurs="0" maxOccurs="1" type="NLog.Targets.ConsoleOutputColor" />
+    </xs:choice>
+    <xs:attribute name="ignoreCase" type="xs:boolean">
+      <xs:annotation>
+        <xs:documentation>Indicates whether to ignore case when comparing texts.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="regex" type="xs:string">
+      <xs:annotation>
+        <xs:documentation>Regular expression to be matched. You must specify either text or regex.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="text" type="xs:string">
+      <xs:annotation>
+        <xs:documentation>Text to be matched. You must specify either text or regex.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="wholeWords" type="xs:boolean">
+      <xs:annotation>
+        <xs:documentation>Indicates whether to match whole words only.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="compileRegex" type="xs:boolean">
+      <xs:annotation>
+        <xs:documentation>Compile the ? This can improve the performance, but at the costs of more memory usage. If false, the Regex Cache is used.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="backgroundColor" type="NLog.Targets.ConsoleOutputColor">
+      <xs:annotation>
+        <xs:documentation>Background color.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="foregroundColor" type="NLog.Targets.ConsoleOutputColor">
+      <xs:annotation>
+        <xs:documentation>Foreground color.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:complexType>
+  <xs:complexType name="Console">
+    <xs:complexContent>
+      <xs:extension base="Target">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="layout" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="header" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="footer" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="error" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="detectConsoleAvailable" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="encoding" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="layout" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Text to be rendered.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="header" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Header.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="footer" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Footer.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="error" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to send the log messages to the standard error instead of the standard output.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="detectConsoleAvailable" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to auto-check if the console is available - Disables console writing if Environment.UserInteractive = False (Windows Service) - Disables console writing if Console Standard Input is not available (Non-Console-App)</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="encoding" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>The encoding for writing messages to the .</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="Database">
+    <xs:complexContent>
+      <xs:extension base="Target">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="useTransactions" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="dbUserName" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="dbProvider" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="dbPassword" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="keepConnection" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="dbDatabase" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="connectionStringName" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="connectionString" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="dbHost" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="installConnectionString" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="install-command" minOccurs="0" maxOccurs="unbounded" type="NLog.Targets.DatabaseCommandInfo" />
+          <xs:element name="uninstall-command" minOccurs="0" maxOccurs="unbounded" type="NLog.Targets.DatabaseCommandInfo" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="parameter" minOccurs="0" maxOccurs="unbounded" type="NLog.Targets.DatabaseParameterInfo" />
+          <xs:element name="commandText" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="commandType" minOccurs="0" maxOccurs="1" type="System.Data.CommandType" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="useTransactions" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Obsolete - value will be ignored! The logging code always runs outside of transaction. Gets or sets a value indicating whether to use database transactions. Some data providers require this.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="dbUserName" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Database user name. If the ConnectionString is not provided this value will be used to construct the "User ID=" part of the connection string.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="dbProvider" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the database provider.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="dbPassword" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Database password. If the ConnectionString is not provided this value will be used to construct the "Password=" part of the connection string.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="keepConnection" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to keep the database connection open between the log events.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="dbDatabase" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Database name. If the ConnectionString is not provided this value will be used to construct the "Database=" part of the connection string.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="connectionStringName" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the connection string (as specified in &lt;connectionStrings&gt; configuration section.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="connectionString" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Connection string. When provided, it overrides the values specified in DBHost, DBUserName, DBPassword, DBDatabase.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="dbHost" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Database host name. If the ConnectionString is not provided this value will be used to construct the "Server=" part of the connection string.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="installConnectionString" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Connection string using for installation and uninstallation. If not provided, regular ConnectionString is being used.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="commandText" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Text of the SQL command to be run on each log level.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="commandType" type="System.Data.CommandType">
+          <xs:annotation>
+            <xs:documentation>Type of the SQL command to be run on each log level.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:simpleType name="System.Data.CommandType">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="Text" />
+      <xs:enumeration value="StoredProcedure" />
+      <xs:enumeration value="TableDirect" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:complexType name="NLog.Targets.DatabaseCommandInfo">
+    <xs:choice minOccurs="0" maxOccurs="unbounded">
+      <xs:element name="commandType" minOccurs="0" maxOccurs="1" type="System.Data.CommandType" />
+      <xs:element name="connectionString" minOccurs="0" maxOccurs="1" type="Layout" />
+      <xs:element name="ignoreFailures" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+      <xs:element name="parameter" minOccurs="0" maxOccurs="unbounded" type="NLog.Targets.DatabaseParameterInfo" />
+      <xs:element name="text" minOccurs="0" maxOccurs="1" type="Layout" />
+    </xs:choice>
+    <xs:attribute name="commandType" type="System.Data.CommandType">
+      <xs:annotation>
+        <xs:documentation>Type of the command.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="connectionString" type="SimpleLayoutAttribute">
+      <xs:annotation>
+        <xs:documentation>Connection string to run the command against. If not provided, connection string from the target is used.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="ignoreFailures" type="xs:boolean">
+      <xs:annotation>
+        <xs:documentation>Indicates whether to ignore failures.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="text" type="SimpleLayoutAttribute">
+      <xs:annotation>
+        <xs:documentation>Command text.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:complexType>
+  <xs:complexType name="NLog.Targets.DatabaseParameterInfo">
+    <xs:choice minOccurs="0" maxOccurs="unbounded">
+      <xs:element name="layout" minOccurs="0" maxOccurs="1" type="Layout" />
+      <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+      <xs:element name="precision" minOccurs="0" maxOccurs="1" type="xs:byte" />
+      <xs:element name="scale" minOccurs="0" maxOccurs="1" type="xs:byte" />
+      <xs:element name="size" minOccurs="0" maxOccurs="1" type="xs:integer" />
+    </xs:choice>
+    <xs:attribute name="layout" type="SimpleLayoutAttribute">
+      <xs:annotation>
+        <xs:documentation>Layout that should be use to calcuate the value for the parameter.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="name" type="xs:string">
+      <xs:annotation>
+        <xs:documentation>Database parameter name.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="precision" type="xs:byte">
+      <xs:annotation>
+        <xs:documentation>Database parameter precision.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="scale" type="xs:byte">
+      <xs:annotation>
+        <xs:documentation>Database parameter scale.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="size" type="xs:integer">
+      <xs:annotation>
+        <xs:documentation>Database parameter size.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:complexType>
+  <xs:complexType name="Debugger">
+    <xs:complexContent>
+      <xs:extension base="Target">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="layout" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="header" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="footer" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="layout" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Text to be rendered.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="header" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Header.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="footer" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Footer.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="Debug">
+    <xs:complexContent>
+      <xs:extension base="Target">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="layout" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="layout" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Layout used to format log messages.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="EventLog">
+    <xs:complexContent>
+      <xs:extension base="Target">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="layout" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="category" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="eventId" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="log" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="machineName" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="source" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="onOverflow" minOccurs="0" maxOccurs="1" type="NLog.Targets.EventLogTargetOverflowAction" />
+          <xs:element name="entryType" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="maxKilobytes" minOccurs="0" maxOccurs="1" type="xs:long" />
+          <xs:element name="maxMessageLength" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="layout" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Layout used to format log messages.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="category" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Layout that renders event Category.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="eventId" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Layout that renders event ID.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="log" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the Event Log to write to. This can be System, Application or any user-defined name.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="machineName" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the machine on which Event Log service is running.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="source" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Value to be used as the event Source.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="onOverflow" type="NLog.Targets.EventLogTargetOverflowAction">
+          <xs:annotation>
+            <xs:documentation>Action to take if the message is larger than the  option.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="entryType" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Optional entrytype. When not set, or when not convertable to  then determined by </xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="maxKilobytes" type="xs:long">
+          <xs:annotation>
+            <xs:documentation>Maximum Event log size in kilobytes. If null, the value won't be set. Default is 512 Kilobytes as specified by Eventlog API</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="maxMessageLength" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Message length limit to write to the Event Log.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:simpleType name="NLog.Targets.EventLogTargetOverflowAction">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="Truncate" />
+      <xs:enumeration value="Split" />
+      <xs:enumeration value="Discard" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:complexType name="FallbackGroup">
+    <xs:complexContent>
+      <xs:extension base="CompoundTargetBase">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="returnToFirstOnSuccess" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="returnToFirstOnSuccess" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to return to the first target after any successful write.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="File">
+    <xs:complexContent>
+      <xs:extension base="Target">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="layout" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="header" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="footer" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="encoding" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="lineEnding" minOccurs="0" maxOccurs="1" type="LineEndingMode" />
+          <xs:element name="archiveNumbering" minOccurs="0" maxOccurs="1" type="NLog.Targets.ArchiveNumberingMode" />
+          <xs:element name="archiveFileName" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="archiveEvery" minOccurs="0" maxOccurs="1" type="NLog.Targets.FileArchivePeriod" />
+          <xs:element name="archiveAboveSize" minOccurs="0" maxOccurs="1" type="xs:long" />
+          <xs:element name="enableArchiveFileCompression" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="maxArchiveFiles" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="forceManaged" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="archiveFileKind" minOccurs="0" maxOccurs="1" type="NLog.Targets.FilePathKind" />
+          <xs:element name="cleanupFileName" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="discardAll" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="fileNameKind" minOccurs="0" maxOccurs="1" type="NLog.Targets.FilePathKind" />
+          <xs:element name="forceMutexConcurrentWrites" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="maxLogFilenames" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="writeFooterOnArchivingOnly" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="fileName" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="archiveDateFormat" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="archiveOldFileOnStartup" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="createDirs" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="fileAttributes" minOccurs="0" maxOccurs="1" type="NLog.Targets.Win32FileAttributes" />
+          <xs:element name="deleteOldFileOnStartup" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="replaceFileContentsOnEachWrite" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="enableFileDelete" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="concurrentWriteAttempts" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="concurrentWrites" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="keepFileOpen" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="networkWrites" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="openFileCacheSize" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="openFileCacheTimeout" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="bufferSize" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="autoFlush" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="concurrentWriteAttemptDelay" minOccurs="0" maxOccurs="1" type="xs:integer" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="layout" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Text to be rendered.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="header" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Header.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="footer" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Footer.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="encoding" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>File encoding.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="lineEnding" type="LineEndingMode">
+          <xs:annotation>
+            <xs:documentation>Line ending mode.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="archiveNumbering" type="NLog.Targets.ArchiveNumberingMode">
+          <xs:annotation>
+            <xs:documentation>Way file archives are numbered.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="archiveFileName" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Name of the file to be used for an archive.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="archiveEvery" type="NLog.Targets.FileArchivePeriod">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to automatically archive log files every time the specified time passes.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="archiveAboveSize" type="xs:long">
+          <xs:annotation>
+            <xs:documentation>Size in bytes above which log files will be automatically archived. Warning: combining this with  isn't supported. We cannot create multiple archive files, if they should have the same name. Choose: </xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="enableArchiveFileCompression" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to compress archive files into the zip archive format.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="maxArchiveFiles" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Maximum number of archive files that should be kept.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="forceManaged" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Gets or set a value indicating whether a managed file stream is forced, instead of using the native implementation.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="archiveFileKind" type="NLog.Targets.FilePathKind">
+          <xs:annotation>
+            <xs:documentation>Is the  an absolute or relative path?</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="cleanupFileName" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Cleanup invalid values in a filename, e.g. slashes in a filename. If set to true, this can impact the performance of massive writes. If set to false, nothing gets written when the filename is wrong.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="discardAll" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Whether or not this target should just discard all data that its asked to write. Mostly used for when testing NLog Stack except final write</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="fileNameKind" type="NLog.Targets.FilePathKind">
+          <xs:annotation>
+            <xs:documentation>Is the  an absolute or relative path?</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="forceMutexConcurrentWrites" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Value indicationg whether file creation calls should be synchronized by a system global mutex.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="maxLogFilenames" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Maximum number of log filenames that should be stored as existing.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="writeFooterOnArchivingOnly" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether the footer should be written only when the file is archived.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="fileName" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Name of the file to write to.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="archiveDateFormat" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Value specifying the date format to use when archiving files.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="archiveOldFileOnStartup" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to archive old log file on startup.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="createDirs" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to create directories if they do not exist.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="fileAttributes" type="NLog.Targets.Win32FileAttributes">
+          <xs:annotation>
+            <xs:documentation>File attributes (Windows only).</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="deleteOldFileOnStartup" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to delete old log file on startup.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="replaceFileContentsOnEachWrite" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to replace file contents on each write instead of appending log message at the end.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="enableFileDelete" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to enable log file(s) to be deleted.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="concurrentWriteAttempts" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Number of times the write is appended on the file before NLog discards the log message.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="concurrentWrites" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether concurrent writes to the log file by multiple processes on the same host.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="keepFileOpen" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to keep log file open instead of opening and closing it on each logging event.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="networkWrites" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether concurrent writes to the log file by multiple processes on different network hosts.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="openFileCacheSize" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Number of files to be kept open. Setting this to a higher value may improve performance in a situation where a single File target is writing to many files (such as splitting by level or by logger).</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="openFileCacheTimeout" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Maximum number of seconds that files are kept open. If this number is negative the files are not automatically closed after a period of inactivity.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="bufferSize" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Log file buffer size in bytes.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="autoFlush" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to automatically flush the file buffers after each log message.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="concurrentWriteAttemptDelay" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Delay in milliseconds to wait before attempting to write to the file again.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:simpleType name="NLog.Targets.ArchiveNumberingMode">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="Sequence" />
+      <xs:enumeration value="Rolling" />
+      <xs:enumeration value="Date" />
+      <xs:enumeration value="DateAndSequence" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="NLog.Targets.FileArchivePeriod">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="None" />
+      <xs:enumeration value="Year" />
+      <xs:enumeration value="Month" />
+      <xs:enumeration value="Day" />
+      <xs:enumeration value="Hour" />
+      <xs:enumeration value="Minute" />
+      <xs:enumeration value="Sunday" />
+      <xs:enumeration value="Monday" />
+      <xs:enumeration value="Tuesday" />
+      <xs:enumeration value="Wednesday" />
+      <xs:enumeration value="Thursday" />
+      <xs:enumeration value="Friday" />
+      <xs:enumeration value="Saturday" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="NLog.Targets.FilePathKind">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="Unknown" />
+      <xs:enumeration value="Relative" />
+      <xs:enumeration value="Absolute" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="NLog.Targets.Win32FileAttributes">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="ReadOnly" />
+      <xs:enumeration value="Hidden" />
+      <xs:enumeration value="System" />
+      <xs:enumeration value="Archive" />
+      <xs:enumeration value="Device" />
+      <xs:enumeration value="Normal" />
+      <xs:enumeration value="Temporary" />
+      <xs:enumeration value="SparseFile" />
+      <xs:enumeration value="ReparsePoint" />
+      <xs:enumeration value="Compressed" />
+      <xs:enumeration value="NotContentIndexed" />
+      <xs:enumeration value="Encrypted" />
+      <xs:enumeration value="WriteThrough" />
+      <xs:enumeration value="NoBuffering" />
+      <xs:enumeration value="DeleteOnClose" />
+      <xs:enumeration value="PosixSemantics" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:complexType name="FilteringWrapper">
+    <xs:complexContent>
+      <xs:extension base="WrapperTargetBase">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="condition" minOccurs="0" maxOccurs="1" type="Condition" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="condition" type="Condition">
+          <xs:annotation>
+            <xs:documentation>Condition expression. Log events who meet this condition will be forwarded to the wrapped target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="ImpersonatingWrapper">
+    <xs:complexContent>
+      <xs:extension base="WrapperTargetBase">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="domain" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="impersonationLevel" minOccurs="0" maxOccurs="1" type="NLog.Targets.Wrappers.SecurityImpersonationLevel" />
+          <xs:element name="logOnProvider" minOccurs="0" maxOccurs="1" type="NLog.Targets.Wrappers.LogOnProviderType" />
+          <xs:element name="logOnType" minOccurs="0" maxOccurs="1" type="NLog.Targets.Wrappers.SecurityLogOnType" />
+          <xs:element name="password" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="revertToSelf" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="userName" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="domain" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Windows domain name to change context to.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="impersonationLevel" type="NLog.Targets.Wrappers.SecurityImpersonationLevel">
+          <xs:annotation>
+            <xs:documentation>Required impersonation level.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="logOnProvider" type="NLog.Targets.Wrappers.LogOnProviderType">
+          <xs:annotation>
+            <xs:documentation>Type of the logon provider.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="logOnType" type="NLog.Targets.Wrappers.SecurityLogOnType">
+          <xs:annotation>
+            <xs:documentation>Logon Type.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="password" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>User account password.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="revertToSelf" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to revert to the credentials of the process instead of impersonating another user.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="userName" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Username to change context to.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:simpleType name="NLog.Targets.Wrappers.SecurityImpersonationLevel">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="Anonymous" />
+      <xs:enumeration value="Identification" />
+      <xs:enumeration value="Impersonation" />
+      <xs:enumeration value="Delegation" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="NLog.Targets.Wrappers.LogOnProviderType">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="Default" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="NLog.Targets.Wrappers.SecurityLogOnType">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="Interactive" />
+      <xs:enumeration value="Network" />
+      <xs:enumeration value="Batch" />
+      <xs:enumeration value="Service" />
+      <xs:enumeration value="NetworkClearText" />
+      <xs:enumeration value="NewCredentials" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:complexType name="LimitingWrapper">
+    <xs:complexContent>
+      <xs:extension base="WrapperTargetBase">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="interval" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="messageLimit" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="interval" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Interval in which messages will be written up to the  number of messages.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="messageLimit" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Maximum allowed number of messages written per .</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="LogReceiverService">
+    <xs:complexContent>
+      <xs:extension base="Target">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="endpointAddress" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="endpointConfigurationName" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="useOneWayContract" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="clientId" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="includeEventProperties" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="parameter" minOccurs="0" maxOccurs="unbounded" type="NLog.Targets.MethodCallParameter" />
+          <xs:element name="useBinaryEncoding" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="endpointAddress" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Endpoint address.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="endpointConfigurationName" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the endpoint configuration in WCF configuration file.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="useOneWayContract" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to use a WCF service contract that is one way (fire and forget) or two way (request-reply)</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="clientId" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Client ID.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="includeEventProperties" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to include per-event properties in the payload sent to the server.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="useBinaryEncoding" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to use binary message encoding.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="NLog.Targets.MethodCallParameter">
+    <xs:choice minOccurs="0" maxOccurs="unbounded">
+      <xs:element name="layout" minOccurs="0" maxOccurs="1" type="Layout" />
+      <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+      <xs:element name="parameterType" minOccurs="0" maxOccurs="1" type="xs:string" />
+      <xs:element name="type" minOccurs="0" maxOccurs="1" type="xs:string" />
+      <xs:element name="enableGroupLayout" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+    </xs:choice>
+    <xs:attribute name="layout" type="SimpleLayoutAttribute">
+      <xs:annotation>
+        <xs:documentation>Layout that should be use to calculate the value for the parameter.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="name" type="xs:string">
+      <xs:annotation>
+        <xs:documentation>Name of the parameter.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="parameterType" type="xs:string">
+      <xs:annotation>
+        <xs:documentation>Type of the parameter.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="type" type="xs:string">
+      <xs:annotation>
+        <xs:documentation>Type of the parameter. Obsolete alias for </xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="enableGroupLayout" type="xs:boolean">
+      <xs:annotation>
+        <xs:documentation>Parameter can combine multiple LogEvents into a single parameter value</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:complexType>
+  <xs:complexType name="Mail">
+    <xs:complexContent>
+      <xs:extension base="Target">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="layout" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="header" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="footer" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="html" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="encoding" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="addNewLines" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="cc" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="to" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="bcc" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="body" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="subject" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="from" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="timeout" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="priority" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="replaceNewlineWithBrTagInHtml" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="smtpServer" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="smtpAuthentication" minOccurs="0" maxOccurs="1" type="NLog.Targets.SmtpAuthenticationMode" />
+          <xs:element name="smtpUserName" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="smtpPassword" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="enableSsl" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="smtpPort" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="useSystemNetMailSettings" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="pickupDirectoryLocation" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="deliveryMethod" minOccurs="0" maxOccurs="1" type="System.Net.Mail.SmtpDeliveryMethod" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="layout" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Text to be rendered.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="header" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Header.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="footer" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Footer.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="html" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to send message as HTML instead of plain text.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="encoding" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Encoding to be used for sending e-mail.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="addNewLines" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to add new lines between log entries.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="cc" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>CC email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com).</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="to" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Recipients' email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com).</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="bcc" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>BCC email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com).</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="body" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Mail message body (repeated for each log message send in one mail).</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="subject" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Mail subject.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="from" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Sender's email address (e.g. joe@domain.com).</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="timeout" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Indicates the SMTP client timeout.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="priority" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Priority used for sending mails.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="replaceNewlineWithBrTagInHtml" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether NewLine characters in the body should be replaced with  tags.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="smtpServer" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>SMTP Server to be used for sending.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="smtpAuthentication" type="NLog.Targets.SmtpAuthenticationMode">
+          <xs:annotation>
+            <xs:documentation>SMTP Authentication mode.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="smtpUserName" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Username used to connect to SMTP server (used when SmtpAuthentication is set to "basic").</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="smtpPassword" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Password used to authenticate against SMTP server (used when SmtpAuthentication is set to "basic").</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="enableSsl" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether SSL (secure sockets layer) should be used when communicating with SMTP server.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="smtpPort" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Port number that SMTP Server is listening on.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="useSystemNetMailSettings" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether the default Settings from System.Net.MailSettings should be used.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="pickupDirectoryLocation" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Folder where applications save mail messages to be processed by the local SMTP server.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="deliveryMethod" type="System.Net.Mail.SmtpDeliveryMethod">
+          <xs:annotation>
+            <xs:documentation>Specifies how outgoing email messages will be handled.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:simpleType name="NLog.Targets.SmtpAuthenticationMode">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="None" />
+      <xs:enumeration value="Basic" />
+      <xs:enumeration value="Ntlm" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="System.Net.Mail.SmtpDeliveryMethod">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="Network" />
+      <xs:enumeration value="SpecifiedPickupDirectory" />
+      <xs:enumeration value="PickupDirectoryFromIis" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:complexType name="Memory">
+    <xs:complexContent>
+      <xs:extension base="Target">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="layout" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="layout" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Layout used to format log messages.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="MethodCall">
+    <xs:complexContent>
+      <xs:extension base="Target">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="className" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="methodName" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="parameter" minOccurs="0" maxOccurs="unbounded" type="NLog.Targets.MethodCallParameter" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="className" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Class name.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="methodName" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Method name. The method must be public and static. Use the AssemblyQualifiedName , https://msdn.microsoft.com/en-us/library/system.type.assemblyqualifiedname(v=vs.110).aspx e.g.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="Network">
+    <xs:complexContent>
+      <xs:extension base="Target">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="layout" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="encoding" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="lineEnding" minOccurs="0" maxOccurs="1" type="LineEndingMode" />
+          <xs:element name="maxMessageSize" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="newLine" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="onConnectionOverflow" minOccurs="0" maxOccurs="1" type="NLog.Targets.NetworkTargetConnectionsOverflowAction" />
+          <xs:element name="onOverflow" minOccurs="0" maxOccurs="1" type="NLog.Targets.NetworkTargetOverflowAction" />
+          <xs:element name="address" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="connectionCacheSize" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="keepConnection" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="maxConnections" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="maxQueueSize" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="layout" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Layout used to format log messages.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="encoding" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Encoding to be used.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="lineEnding" type="LineEndingMode">
+          <xs:annotation>
+            <xs:documentation>End of line value if a newline is appended at the end of log message .</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="maxMessageSize" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Maximum message size in bytes.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="newLine" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to append newline at the end of log message.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="onConnectionOverflow" type="NLog.Targets.NetworkTargetConnectionsOverflowAction">
+          <xs:annotation>
+            <xs:documentation>Action that should be taken if the will be more connections than .</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="onOverflow" type="NLog.Targets.NetworkTargetOverflowAction">
+          <xs:annotation>
+            <xs:documentation>Action that should be taken if the message is larger than maxMessageSize.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="address" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Network address.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="connectionCacheSize" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Size of the connection cache (number of connections which are kept alive).</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="keepConnection" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to keep connection open whenever possible.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="maxConnections" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Maximum current connections. 0 = no maximum.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="maxQueueSize" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Maximum queue size.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="NLogViewer">
+    <xs:complexContent>
+      <xs:extension base="Target">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="encoding" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="layout" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="lineEnding" minOccurs="0" maxOccurs="1" type="LineEndingMode" />
+          <xs:element name="maxMessageSize" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="newLine" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="onConnectionOverflow" minOccurs="0" maxOccurs="1" type="NLog.Targets.NetworkTargetConnectionsOverflowAction" />
+          <xs:element name="onOverflow" minOccurs="0" maxOccurs="1" type="NLog.Targets.NetworkTargetOverflowAction" />
+          <xs:element name="maxConnections" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="keepConnection" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="connectionCacheSize" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="address" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="maxQueueSize" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="parameter" minOccurs="0" maxOccurs="unbounded" type="NLog.Targets.NLogViewerParameterInfo" />
+          <xs:element name="ndcItemSeparator" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="includeSourceInfo" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="includeMdlc" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="includeNdlc" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="includeNdc" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="includeMdc" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="includeCallSite" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="includeAllProperties" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="appInfo" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="includeNLogData" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="encoding" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Encoding to be used.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="layout" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Instance of  that is used to format log messages.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="lineEnding" type="LineEndingMode">
+          <xs:annotation>
+            <xs:documentation>End of line value if a newline is appended at the end of log message .</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="maxMessageSize" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Maximum message size in bytes.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="newLine" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to append newline at the end of log message.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="onConnectionOverflow" type="NLog.Targets.NetworkTargetConnectionsOverflowAction">
+          <xs:annotation>
+            <xs:documentation>Action that should be taken if the will be more connections than .</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="onOverflow" type="NLog.Targets.NetworkTargetOverflowAction">
+          <xs:annotation>
+            <xs:documentation>Action that should be taken if the message is larger than maxMessageSize.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="maxConnections" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Maximum current connections. 0 = no maximum.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="keepConnection" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to keep connection open whenever possible.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="connectionCacheSize" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Size of the connection cache (number of connections which are kept alive).</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="address" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Network address.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="maxQueueSize" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Maximum queue size.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="ndcItemSeparator" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>NDC item separator.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="includeSourceInfo" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to include source info (file name and line number) in the information sent over the network.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="includeMdlc" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to include  dictionary contents.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="includeNdlc" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to include contents of the  stack.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="includeNdc" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to include  stack contents.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="includeMdc" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to include  dictionary contents.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="includeCallSite" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to include call site (class and method name) in the information sent over the network.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="includeAllProperties" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Option to include all properties from the log events</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="appInfo" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>AppInfo field. By default it's the friendly name of the current AppDomain.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="includeNLogData" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to include NLog-specific extensions to log4j schema.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="Null">
+    <xs:complexContent>
+      <xs:extension base="Target">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="layout" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="formatMessage" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="layout" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Layout used to format log messages.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="formatMessage" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to perform layout calculation.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="OutputDebugString">
+    <xs:complexContent>
+      <xs:extension base="Target">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="layout" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="layout" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Layout used to format log messages.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="PerfCounter">
+    <xs:complexContent>
+      <xs:extension base="Target">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="autoCreate" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="categoryName" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="counterHelp" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="counterName" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="counterType" minOccurs="0" maxOccurs="1" type="System.Diagnostics.PerformanceCounterType" />
+          <xs:element name="incrementValue" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="instanceName" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="autoCreate" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether performance counter should be automatically created.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="categoryName" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the performance counter category.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="counterHelp" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Counter help text.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="counterName" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the performance counter.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="counterType" type="System.Diagnostics.PerformanceCounterType">
+          <xs:annotation>
+            <xs:documentation>Performance counter type.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="incrementValue" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>The value by which to increment the counter.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="instanceName" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Performance counter instance name.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:simpleType name="System.Diagnostics.PerformanceCounterType">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="NumberOfItems32" />
+      <xs:enumeration value="NumberOfItems64" />
+      <xs:enumeration value="NumberOfItemsHEX32" />
+      <xs:enumeration value="NumberOfItemsHEX64" />
+      <xs:enumeration value="RateOfCountsPerSecond32" />
+      <xs:enumeration value="RateOfCountsPerSecond64" />
+      <xs:enumeration value="CountPerTimeInterval32" />
+      <xs:enumeration value="CountPerTimeInterval64" />
+      <xs:enumeration value="RawFraction" />
+      <xs:enumeration value="RawBase" />
+      <xs:enumeration value="AverageTimer32" />
+      <xs:enumeration value="AverageBase" />
+      <xs:enumeration value="AverageCount64" />
+      <xs:enumeration value="SampleFraction" />
+      <xs:enumeration value="SampleCounter" />
+      <xs:enumeration value="SampleBase" />
+      <xs:enumeration value="CounterTimer" />
+      <xs:enumeration value="CounterTimerInverse" />
+      <xs:enumeration value="Timer100Ns" />
+      <xs:enumeration value="Timer100NsInverse" />
+      <xs:enumeration value="ElapsedTime" />
+      <xs:enumeration value="CounterMultiTimer" />
+      <xs:enumeration value="CounterMultiTimerInverse" />
+      <xs:enumeration value="CounterMultiTimer100Ns" />
+      <xs:enumeration value="CounterMultiTimer100NsInverse" />
+      <xs:enumeration value="CounterMultiBase" />
+      <xs:enumeration value="CounterDelta32" />
+      <xs:enumeration value="CounterDelta64" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:complexType name="PostFilteringWrapper">
+    <xs:complexContent>
+      <xs:extension base="WrapperTargetBase">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="defaultFilter" minOccurs="0" maxOccurs="1" type="Condition" />
+          <xs:element name="when" minOccurs="0" maxOccurs="unbounded" type="NLog.Targets.Wrappers.FilteringRule" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="defaultFilter" type="Condition">
+          <xs:annotation>
+            <xs:documentation>Default filter to be applied when no specific rule matches.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="NLog.Targets.Wrappers.FilteringRule">
+    <xs:choice minOccurs="0" maxOccurs="unbounded">
+      <xs:element name="exists" minOccurs="0" maxOccurs="1" type="Condition" />
+      <xs:element name="filter" minOccurs="0" maxOccurs="1" type="Condition" />
+    </xs:choice>
+    <xs:attribute name="exists" type="Condition">
+      <xs:annotation>
+        <xs:documentation>Condition to be tested.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="filter" type="Condition">
+      <xs:annotation>
+        <xs:documentation>Resulting filter to be applied when the condition matches.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:complexType>
+  <xs:complexType name="RandomizeGroup">
+    <xs:complexContent>
+      <xs:extension base="CompoundTargetBase">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="RepeatingWrapper">
+    <xs:complexContent>
+      <xs:extension base="WrapperTargetBase">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="repeatCount" minOccurs="0" maxOccurs="1" type="xs:integer" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="repeatCount" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Number of times to repeat each log message.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="RetryingWrapper">
+    <xs:complexContent>
+      <xs:extension base="WrapperTargetBase">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="retryCount" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="retryDelayMilliseconds" minOccurs="0" maxOccurs="1" type="xs:integer" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="retryCount" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Number of retries that should be attempted on the wrapped target in case of a failure.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="retryDelayMilliseconds" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Time to wait between retries in milliseconds.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="RoundRobinGroup">
+    <xs:complexContent>
+      <xs:extension base="CompoundTargetBase">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="SplitGroup">
+    <xs:complexContent>
+      <xs:extension base="CompoundTargetBase">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="Trace">
+    <xs:complexContent>
+      <xs:extension base="Target">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="layout" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="rawWrite" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="layout" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Layout used to format log messages.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="rawWrite" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Always use  independent of </xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="WebService">
+    <xs:complexContent>
+      <xs:extension base="Target">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="includeBOM" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="parameter" minOccurs="0" maxOccurs="unbounded" type="NLog.Targets.MethodCallParameter" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="encoding" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="escapeDataNLogLegacy" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="escapeDataRfc3986" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="header" minOccurs="0" maxOccurs="unbounded" type="NLog.Targets.MethodCallParameter" />
+          <xs:element name="methodName" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="namespace" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="preAuthenticate" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="protocol" minOccurs="0" maxOccurs="1" type="NLog.Targets.WebServiceProtocol" />
+          <xs:element name="url" minOccurs="0" maxOccurs="1" type="xs:anyURI" />
+          <xs:element name="xmlRoot" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="xmlRootNamespace" minOccurs="0" maxOccurs="1" type="xs:string" />
+        </xs:choice>
+        <xs:attribute name="name" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the target.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="includeBOM" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Should we include the BOM (Byte-order-mark) for UTF? Influences the  property. This will only work for UTF-8.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="encoding" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Encoding.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="escapeDataNLogLegacy" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Value whether escaping be done according to the old NLog style (Very non-standard)</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="escapeDataRfc3986" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Value whether escaping be done according to Rfc3986 (Supports Internationalized Resource Identifiers - IRIs)</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="methodName" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Web service method name. Only used with Soap.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="namespace" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Web service namespace. Only used with Soap.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="preAuthenticate" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to pre-authenticate the HttpWebRequest (Requires 'Authorization' in  parameters)</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="protocol" type="NLog.Targets.WebServiceProtocol">
+          <xs:annotation>
+            <xs:documentation>Protocol to be used when calling web service.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="url" type="xs:anyURI">
+          <xs:annotation>
+            <xs:documentation>Web service URL.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="xmlRoot" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Name of the root XML element, if POST of XML document chosen. If so, this property must not be null. (see  and ).</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="xmlRootNamespace" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>(optional) root namespace of the XML document, if POST of XML document chosen. (see  and ).</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:simpleType name="NLog.Targets.WebServiceProtocol">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="Soap11" />
+      <xs:enumeration value="Soap12" />
+      <xs:enumeration value="HttpPost" />
+      <xs:enumeration value="HttpGet" />
+      <xs:enumeration value="JsonPost" />
+      <xs:enumeration value="XmlPost" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:complexType name="CompoundLayout">
+    <xs:complexContent>
+      <xs:extension base="Layout">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="layout" minOccurs="0" maxOccurs="unbounded" type="Layout" />
+        </xs:choice>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="Layout">
+    <xs:choice minOccurs="0" maxOccurs="unbounded" />
+  </xs:complexType>
+  <xs:complexType name="CsvLayout">
+    <xs:complexContent>
+      <xs:extension base="Layout">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="footer" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="header" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="layout" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="column" minOccurs="0" maxOccurs="unbounded" type="NLog.Layouts.CsvColumn" />
+          <xs:element name="customColumnDelimiter" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="delimiter" minOccurs="0" maxOccurs="1" type="NLog.Layouts.CsvColumnDelimiterMode" />
+          <xs:element name="quoteChar" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="quoting" minOccurs="0" maxOccurs="1" type="NLog.Layouts.CsvQuotingMode" />
+          <xs:element name="withHeader" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="footer" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Footer layout.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="header" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Header layout.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="layout" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Body layout (can be repeated multiple times).</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="customColumnDelimiter" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Custom column delimiter value (valid when ColumnDelimiter is set to 'Custom').</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="delimiter" type="NLog.Layouts.CsvColumnDelimiterMode">
+          <xs:annotation>
+            <xs:documentation>Column delimiter.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="quoteChar" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Quote Character.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="quoting" type="NLog.Layouts.CsvQuotingMode">
+          <xs:annotation>
+            <xs:documentation>Quoting mode.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="withHeader" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether CVS should include header.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:simpleType name="NLog.Layouts.CsvColumnDelimiterMode">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="Auto" />
+      <xs:enumeration value="Comma" />
+      <xs:enumeration value="Semicolon" />
+      <xs:enumeration value="Tab" />
+      <xs:enumeration value="Pipe" />
+      <xs:enumeration value="Space" />
+      <xs:enumeration value="Custom" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="NLog.Layouts.CsvQuotingMode">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="All" />
+      <xs:enumeration value="Nothing" />
+      <xs:enumeration value="Auto" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:complexType name="NLog.Layouts.CsvColumn">
+    <xs:choice minOccurs="0" maxOccurs="unbounded">
+      <xs:element name="layout" minOccurs="0" maxOccurs="1" type="Layout" />
+      <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+    </xs:choice>
+    <xs:attribute name="layout" type="SimpleLayoutAttribute">
+      <xs:annotation>
+        <xs:documentation>Layout of the column.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="name" type="xs:string">
+      <xs:annotation>
+        <xs:documentation>Name of the column.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:complexType>
+  <xs:complexType name="JsonLayout">
+    <xs:complexContent>
+      <xs:extension base="Layout">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="attribute" minOccurs="0" maxOccurs="unbounded" type="NLog.Layouts.JsonAttribute" />
+          <xs:element name="excludeProperties" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="includeAllProperties" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="includeMdc" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="includeMdlc" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="renderEmptyObject" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="suppressSpaces" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="excludeProperties" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>List of property names to exclude when  is true</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="includeAllProperties" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Option to include all properties from the log events</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="includeMdc" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to include contents of the  dictionary.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="includeMdlc" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to include contents of the  dictionary.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="renderEmptyObject" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Option to render the empty object value {}</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="suppressSpaces" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Option to suppress the extra spaces in the output json</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="NLog.Layouts.JsonAttribute">
+    <xs:choice minOccurs="0" maxOccurs="unbounded">
+      <xs:element name="encode" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+      <xs:element name="escapeUnicode" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+      <xs:element name="layout" minOccurs="0" maxOccurs="1" type="Layout" />
+      <xs:element name="name" minOccurs="0" maxOccurs="1" type="xs:string" />
+    </xs:choice>
+    <xs:attribute name="encode" type="xs:boolean">
+      <xs:annotation>
+        <xs:documentation>Determines wether or not this attribute will be Json encoded.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="escapeUnicode" type="xs:boolean">
+      <xs:annotation>
+        <xs:documentation>Indicates whether to escape non-ascii characters</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="layout" type="SimpleLayoutAttribute">
+      <xs:annotation>
+        <xs:documentation>Layout that will be rendered as the attribute's value.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="name" type="xs:string">
+      <xs:annotation>
+        <xs:documentation>Name of the attribute.</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:complexType>
+  <xs:complexType name="LayoutWithHeaderAndFooter">
+    <xs:complexContent>
+      <xs:extension base="Layout">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="footer" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="header" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="layout" minOccurs="0" maxOccurs="1" type="Layout" />
+        </xs:choice>
+        <xs:attribute name="footer" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Footer layout.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="header" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Header layout.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="layout" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Body layout (can be repeated multiple times).</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="Log4JXmlEventLayout">
+    <xs:complexContent>
+      <xs:extension base="Layout">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="includeAllProperties" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="includeMdc" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="includeMdlc" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="includeNdc" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="includeNdlc" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+        </xs:choice>
+        <xs:attribute name="includeAllProperties" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Option to include all properties from the log events</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="includeMdc" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to include contents of the  dictionary.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="includeMdlc" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to include contents of the  dictionary.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="includeNdc" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to include contents of the  stack.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="includeNdlc" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to include contents of the  stack.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="SimpleLayout">
+    <xs:complexContent>
+      <xs:extension base="Layout">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="text" minOccurs="0" maxOccurs="1" type="xs:string" />
+        </xs:choice>
+        <xs:attribute name="text" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Layout text.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="when">
+    <xs:complexContent>
+      <xs:extension base="Filter">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="action" minOccurs="0" maxOccurs="1" type="FilterResult" />
+          <xs:element name="condition" minOccurs="0" maxOccurs="1" type="Condition" />
+        </xs:choice>
+        <xs:attribute name="action" type="FilterResult">
+          <xs:annotation>
+            <xs:documentation>Action to be taken when filter matches.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="condition" type="Condition">
+          <xs:annotation>
+            <xs:documentation>Condition expression.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:simpleType name="FilterResult">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="Neutral" />
+      <xs:enumeration value="Log" />
+      <xs:enumeration value="Ignore" />
+      <xs:enumeration value="LogFinal" />
+      <xs:enumeration value="IgnoreFinal" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:complexType name="whenContains">
+    <xs:complexContent>
+      <xs:extension base="Filter">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="action" minOccurs="0" maxOccurs="1" type="FilterResult" />
+          <xs:element name="ignoreCase" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="layout" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="substring" minOccurs="0" maxOccurs="1" type="xs:string" />
+        </xs:choice>
+        <xs:attribute name="action" type="FilterResult">
+          <xs:annotation>
+            <xs:documentation>Action to be taken when filter matches.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="ignoreCase" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to ignore case when comparing strings.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="layout" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Layout to be used to filter log messages.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="substring" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Substring to be matched.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="whenEqual">
+    <xs:complexContent>
+      <xs:extension base="Filter">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="action" minOccurs="0" maxOccurs="1" type="FilterResult" />
+          <xs:element name="compareTo" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="ignoreCase" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="layout" minOccurs="0" maxOccurs="1" type="Layout" />
+        </xs:choice>
+        <xs:attribute name="action" type="FilterResult">
+          <xs:annotation>
+            <xs:documentation>Action to be taken when filter matches.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="compareTo" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>String to compare the layout to.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="ignoreCase" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to ignore case when comparing strings.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="layout" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Layout to be used to filter log messages.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="whenNotContains">
+    <xs:complexContent>
+      <xs:extension base="Filter">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="action" minOccurs="0" maxOccurs="1" type="FilterResult" />
+          <xs:element name="ignoreCase" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="layout" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="substring" minOccurs="0" maxOccurs="1" type="xs:string" />
+        </xs:choice>
+        <xs:attribute name="action" type="FilterResult">
+          <xs:annotation>
+            <xs:documentation>Action to be taken when filter matches.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="ignoreCase" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to ignore case when comparing strings.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="layout" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Layout to be used to filter log messages.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="substring" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Substring to be matched.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="whenNotEqual">
+    <xs:complexContent>
+      <xs:extension base="Filter">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="action" minOccurs="0" maxOccurs="1" type="FilterResult" />
+          <xs:element name="compareTo" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="ignoreCase" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="layout" minOccurs="0" maxOccurs="1" type="Layout" />
+        </xs:choice>
+        <xs:attribute name="action" type="FilterResult">
+          <xs:annotation>
+            <xs:documentation>Action to be taken when filter matches.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="compareTo" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>String to compare the layout to.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="ignoreCase" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Indicates whether to ignore case when comparing strings.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="layout" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Layout to be used to filter log messages.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="whenRepeated">
+    <xs:complexContent>
+      <xs:extension base="Filter">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+          <xs:element name="action" minOccurs="0" maxOccurs="1" type="FilterResult" />
+          <xs:element name="layout" minOccurs="0" maxOccurs="1" type="Layout" />
+          <xs:element name="defaultFilterCacheSize" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="filterCountMessageAppendFormat" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="filterCountPropertyName" minOccurs="0" maxOccurs="1" type="xs:string" />
+          <xs:element name="includeFirst" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="maxFilterCacheSize" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="maxLength" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="optimizeBufferDefaultLength" minOccurs="0" maxOccurs="1" type="xs:integer" />
+          <xs:element name="optimizeBufferReuse" minOccurs="0" maxOccurs="1" type="xs:boolean" />
+          <xs:element name="timeoutSeconds" minOccurs="0" maxOccurs="1" type="xs:integer" />
+        </xs:choice>
+        <xs:attribute name="action" type="FilterResult">
+          <xs:annotation>
+            <xs:documentation>Action to be taken when filter matches.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="layout" type="SimpleLayoutAttribute">
+          <xs:annotation>
+            <xs:documentation>Layout to be used to filter log messages.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="defaultFilterCacheSize" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Default number of unique filter values to expect, will automatically increase if needed</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="filterCountMessageAppendFormat" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Append FilterCount to the  when an event is no longer filtered</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="filterCountPropertyName" type="xs:string">
+          <xs:annotation>
+            <xs:documentation>Insert FilterCount value into  when an event is no longer filtered</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="includeFirst" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Applies the configured action to the initial logevent that starts the timeout period. Used to configure that it should ignore all events until timeout.</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="maxFilterCacheSize" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Max number of unique filter values to expect simultaneously</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="maxLength" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Max length of filter values, will truncate if above limit</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferDefaultLength" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>Default buffer size for the internal buffers</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="optimizeBufferReuse" type="xs:boolean">
+          <xs:annotation>
+            <xs:documentation>Reuse internal buffers, and doesn't have to constantly allocate new buffers</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="timeoutSeconds" type="xs:integer">
+          <xs:annotation>
+            <xs:documentation>How long before a filter expires, and logging is accepted again</xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="AccurateLocal">
+    <xs:complexContent>
+      <xs:extension base="TimeSource">
+        <xs:choice minOccurs="0" maxOccurs="unbounded" />
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="AccurateUTC">
+    <xs:complexContent>
+      <xs:extension base="TimeSource">
+        <xs:choice minOccurs="0" maxOccurs="unbounded" />
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="FastLocal">
+    <xs:complexContent>
+      <xs:extension base="TimeSource">
+        <xs:choice minOccurs="0" maxOccurs="unbounded" />
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="FastUTC">
+    <xs:complexContent>
+      <xs:extension base="TimeSource">
+        <xs:choice minOccurs="0" maxOccurs="unbounded" />
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+</xs:schema>
\ No newline at end of file
diff --git a/src/JT808.Gateway.TestHosting/Configs/nlog.Unix.config b/src/JT808.Gateway.TestHosting/Configs/nlog.Unix.config
new file mode 100644
index 0000000..8e74617
--- /dev/null
+++ b/src/JT808.Gateway.TestHosting/Configs/nlog.Unix.config
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8" ?>
+  <!--
+      参考:http://www.cnblogs.com/fuchongjundream/p/3936431.html
+      autoReload:自动再配置
+      internalLogFile:可以让NLog把内部的调试和异常信息都写入指定文件里程序没问题了,日志却出了问题。这个该怎么办,到底是哪里不正确了?假如日志本身除了bug该如何解决?这就需要日志排错。把日志的错误信息写入日志。
+      <nlog throwExceptions="true" />    
+      <nlog internalLogFile="file.txt" />- 设置internalLogFile属性可以让NLog把内部的调试和异常信息都写入指定文件里。
+      <nlog internalLogLevel="Trace|Debug|Info|Warn|Error|Fatal" /> - 决定内部日志的级别,级别越高,输出的日志信息越简洁。
+      <nlog internalLogToConsole="false|true" /> - 是否把内部日志输出到标准控制台。
+      <nlog internalLogToConsoleError="false|true" /> - 是否把内部日志输出到标准错误控制台 (stderr)。
+      设置throwExceptions属性为“true”可以让NLog不再阻挡这类异常,而是把它们抛给调用者。在部署是这样做可以帮我们快速定位问题。一旦应用程序已经正确配置了,我们建议把throwExceptions的值设为“false”,这样由于日志引发的问题不至于导致应用程序的崩溃。
+  -->
+  <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xsi:schemaLocation="NLog NLog.xsd"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      autoReload="true"
+      internalLogFile="/data/serviceslogs/JT808.Gateway/internalLog.txt"
+      internalLogLevel="Debug" >
+    <variable name="Directory" value="/data/serviceslogs/JT808.Gateway"/>
+    <targets>
+           <target name="Gateway" xsi:type="File"
+              fileName="${Directory}/Gateway.${shortdate}.log"
+              layout="${date:format=yyyyMMddHHmmss} ${callsite} ${level}:${message} ${onexception:${exception:format=tostring} ${newline} ${stacktrace} ${newline}"/>
+      <target name="console" xsi:type="ColoredConsole"
+             useDefaultRowHighlightingRules="false"
+             layout="${date:format=yyyyMMddHHmmss} ${callsite} ${level} ${message} ${onexception:${exception:format=tostring} ${newline} ${stacktrace} ${newline}">
+        <highlight-row condition="level == LogLevel.Debug" foregroundColor="DarkGray" />
+        <highlight-row condition="level == LogLevel.Info" foregroundColor="Gray" />
+        <highlight-row condition="level == LogLevel.Warn" foregroundColor="Yellow" />
+        <highlight-row condition="level == LogLevel.Error" foregroundColor="Red" />
+        <highlight-row condition="level == LogLevel.Fatal" foregroundColor="Red" backgroundColor="White" />
+      </target>
+    </targets>
+    <rules>
+      <logger name="*" minlevel="Debug" maxlevel="Fatal" writeTo="Gateway"/>
+    </rules>
+  </nlog>
\ No newline at end of file
diff --git a/src/JT808.Gateway.TestHosting/Configs/nlog.Win32NT.config b/src/JT808.Gateway.TestHosting/Configs/nlog.Win32NT.config
new file mode 100644
index 0000000..5a7e44e
--- /dev/null
+++ b/src/JT808.Gateway.TestHosting/Configs/nlog.Win32NT.config
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8" ?>
+  <!--
+      参考:http://www.cnblogs.com/fuchongjundream/p/3936431.html
+      autoReload:自动再配置
+      internalLogFile:可以让NLog把内部的调试和异常信息都写入指定文件里程序没问题了,日志却出了问题。这个该怎么办,到底是哪里不正确了?假如日志本身除了bug该如何解决?这就需要日志排错。把日志的错误信息写入日志。
+      <nlog throwExceptions="true" />    
+      <nlog internalLogFile="file.txt" />- 设置internalLogFile属性可以让NLog把内部的调试和异常信息都写入指定文件里。
+      <nlog internalLogLevel="Trace|Debug|Info|Warn|Error|Fatal" /> - 决定内部日志的级别,级别越高,输出的日志信息越简洁。
+      <nlog internalLogToConsole="false|true" /> - 是否把内部日志输出到标准控制台。
+      <nlog internalLogToConsoleError="false|true" /> - 是否把内部日志输出到标准错误控制台 (stderr)。
+      设置throwExceptions属性为“true”可以让NLog不再阻挡这类异常,而是把它们抛给调用者。在部署是这样做可以帮我们快速定位问题。一旦应用程序已经正确配置了,我们建议把throwExceptions的值设为“false”,这样由于日志引发的问题不至于导致应用程序的崩溃。
+  -->
+  <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xsi:schemaLocation="NLog NLog.xsd"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      autoReload="true"
+      internalLogFile="wwwroot/logs/JT808.Gateway/internalLog.txt"
+      internalLogLevel="Debug" >
+    <variable name="Directory" value="/data/logs/JT808.Gateway"/>
+    <targets>
+      <target name="Gateway" xsi:type="File"
+              fileName="${Directory}/Gateway.${shortdate}.log"
+              layout="${date:format=yyyyMMddHHmmss} ${callsite} ${level}:${message} ${onexception:${exception:format=tostring} ${newline} ${stacktrace} ${newline}"/>
+      <target name="console" xsi:type="ColoredConsole"
+             useDefaultRowHighlightingRules="false"
+             layout="${date:format=yyyyMMddHHmmss} ${callsite} ${level} ${message} ${onexception:${exception:format=tostring} ${newline} ${stacktrace} ${newline}">
+        <highlight-row condition="level == LogLevel.Debug" foregroundColor="DarkGray" />
+        <highlight-row condition="level == LogLevel.Info" foregroundColor="Gray" />
+        <highlight-row condition="level == LogLevel.Warn" foregroundColor="Yellow" />
+        <highlight-row condition="level == LogLevel.Error" foregroundColor="Red" />
+        <highlight-row condition="level == LogLevel.Fatal" foregroundColor="Red" backgroundColor="White" />
+      </target>
+    </targets>
+    <rules>
+      <logger name="*" minlevel="Debug" maxlevel="Fatal" writeTo="Gateway,console"/>
+    </rules>
+  </nlog>
\ No newline at end of file
diff --git a/src/JT808.Gateway.TestHosting/Dockerfile b/src/JT808.Gateway.TestHosting/Dockerfile
new file mode 100644
index 0000000..6a33faf
--- /dev/null
+++ b/src/JT808.Gateway.TestHosting/Dockerfile
@@ -0,0 +1,23 @@
+#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
+
+FROM mcr.microsoft.com/dotnet/core/runtime:3.1-buster-slim AS base
+EXPOSE 808/tcp
+WORKDIR /app
+
+FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
+WORKDIR /src
+COPY ["JT808.Gateway.TestHosting/JT808.Gateway.TestHosting.csproj", "JT808.Gateway.TestHosting/"]
+COPY ["JT808.Gateway/JT808.Gateway.csproj", "JT808.Gateway/"]
+COPY ["JT808.Gateway.Abstractions/JT808.Gateway.Abstractions.csproj", "JT808.Gateway.Abstractions/"]
+RUN dotnet restore "JT808.Gateway.TestHosting/JT808.Gateway.TestHosting.csproj"
+COPY . .
+WORKDIR "/src/JT808.Gateway.TestHosting"
+RUN dotnet build "JT808.Gateway.TestHosting.csproj" -c Release -o /app/build
+
+FROM build AS publish
+RUN dotnet publish "JT808.Gateway.TestHosting.csproj" -c Release -o /app/publish
+
+FROM base AS final
+WORKDIR /app
+COPY --from=publish /app/publish .
+ENTRYPOINT ["dotnet", "JT808.Gateway.TestHosting.dll"]
\ No newline at end of file
diff --git a/src/JT808.Gateway.TestHosting/JT808.Gateway.TestHosting.csproj b/src/JT808.Gateway.TestHosting/JT808.Gateway.TestHosting.csproj
new file mode 100644
index 0000000..8d084b2
--- /dev/null
+++ b/src/JT808.Gateway.TestHosting/JT808.Gateway.TestHosting.csproj
@@ -0,0 +1,35 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
+    <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.0" />
+    <PackageReference Include="Microsoft.Extensions.Hosting" Version="3.1.0" />
+    <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.9.10" />
+    <PackageReference Include="NLog.Extensions.Logging" Version="1.6.1" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\JT808.Gateway\JT808.Gateway.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <None Update="appsettings.json">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Configs\nlog.Unix.config">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Configs\nlog.Win32NT.config">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Update="Configs\NLog.xsd">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+  </ItemGroup>
+
+</Project>
diff --git a/src/JT808.Gateway.TestHosting/Jobs/CallGrpcClientJob.cs b/src/JT808.Gateway.TestHosting/Jobs/CallGrpcClientJob.cs
new file mode 100644
index 0000000..c233069
--- /dev/null
+++ b/src/JT808.Gateway.TestHosting/Jobs/CallGrpcClientJob.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+using JT808.Gateway.Configurations;
+using JT808.Gateway.GrpcService;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using System.Text.Json;
+
+namespace JT808.Gateway.TestHosting.Jobs
+{
+    public class CallGrpcClientJob :IHostedService
+    {
+        private Channel channel;
+        private readonly ILogger Logger;
+        private Grpc.Core.Metadata AuthMetadata;
+        public CallGrpcClientJob(
+            ILoggerFactory loggerFactory,
+            JT808Configuration configuration)
+        {
+            Logger = loggerFactory.CreateLogger("CallGrpcClientJob");
+            channel = new Channel($"{configuration.WebApiHost}:{configuration.WebApiPort}",
+                ChannelCredentials.Insecure);
+            AuthMetadata = new Grpc.Core.Metadata();
+            AuthMetadata.Add("token", configuration.WebApiToken);
+        }
+
+        public Task StartAsync(CancellationToken cancellationToken)
+        {
+            Task.Run(() =>
+            {
+                while (!cancellationToken.IsCancellationRequested)
+                {
+                    JT808Gateway.JT808GatewayClient jT808GatewayClient = new JT808Gateway.JT808GatewayClient(channel);
+                    try
+                    {
+                        var result1 = jT808GatewayClient.GetTcpAtomicCounter(new Empty(), AuthMetadata);
+                        var result2 = jT808GatewayClient.GetTcpSessionAll(new Empty(), AuthMetadata);
+                        Logger.LogInformation($"[GetTcpAtomicCounter]:{JsonSerializer.Serialize(result1)}");
+                        Logger.LogInformation($"[GetTcpSessionAll]:{JsonSerializer.Serialize(result2)}");
+                    }
+                    catch (Exception ex)
+                    {
+                        Logger.LogError(ex, "Call Grpc Error");
+                    }
+                    try
+                    {
+                        var result1 = jT808GatewayClient.GetTcpAtomicCounter(new Empty());
+                    }
+                    catch (RpcException ex)
+                    {
+                        Logger.LogError($"{ex.StatusCode.ToString()}-{ex.Message}");
+                    }
+                    Thread.Sleep(3000);
+                }
+            }, cancellationToken);
+            return Task.CompletedTask;
+        }
+
+        public Task StopAsync(CancellationToken cancellationToken)
+        {
+            channel.ShutdownAsync();
+            return Task.CompletedTask;
+        }
+    }
+}
diff --git a/src/JT808.Gateway.TestHosting/Program.cs b/src/JT808.Gateway.TestHosting/Program.cs
new file mode 100644
index 0000000..7d8573e
--- /dev/null
+++ b/src/JT808.Gateway.TestHosting/Program.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Threading.Tasks;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using JT808.Protocol;
+using Microsoft.Extensions.Configuration;
+using NLog.Extensions.Logging;
+using JT808.Gateway.TestHosting.Jobs;
+
+namespace JT808.Gateway.TestHosting
+{
+    class Program
+    {
+        static async Task Main(string[] args)
+        {
+            var serverHostBuilder = new HostBuilder()
+                .ConfigureAppConfiguration((hostingContext, config) =>
+                {
+                    config.SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
+                          .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
+                          .AddJsonFile($"appsettings.{ hostingContext.HostingEnvironment.EnvironmentName}.json", optional: true, reloadOnChange: true);
+                })
+                .ConfigureLogging((context, logging) =>
+                {
+                    Console.WriteLine($"Environment.OSVersion.Platform:{Environment.OSVersion.Platform.ToString()}");
+                    NLog.LogManager.LoadConfiguration($"Configs/nlog.{Environment.OSVersion.Platform.ToString()}.config");
+                    logging.AddNLog(new NLogProviderOptions { CaptureMessageTemplates = true, CaptureMessageProperties = true });
+                    logging.SetMinimumLevel(LogLevel.Trace);
+                })
+                .ConfigureServices((hostContext, services) =>
+                {
+                    services.AddSingleton<ILoggerFactory, LoggerFactory>();
+                    services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
+                    services.AddJT808Configure()
+                            .AddJT808Gateway()
+                            .AddTcp()
+                            .AddUdp()
+                            .AddGrpc();
+                    //services.AddHostedService<CallGrpcClientJob>();
+                });
+
+            await serverHostBuilder.RunConsoleAsync();
+        }
+    }
+}
diff --git a/src/JT808.Gateway.TestHosting/startup.txt b/src/JT808.Gateway.TestHosting/startup.txt
new file mode 100644
index 0000000..0a51e3b
--- /dev/null
+++ b/src/JT808.Gateway.TestHosting/startup.txt
@@ -0,0 +1,4 @@
+pm2 start "dotnet JT808.DotNetty.CleintBenchmark.dll ASPNETCORE_ENVIRONMENT=Production" --max-restarts=1 -n "JT808.DotNetty.CleintBenchmark" -o "/data/pm2Logs/JT808.DotNetty.CleintBenchmark/out.log" -e "/data/pm2Logs/JT808.DotNetty.CleintBenchmark/error.log"
+
+
+pm2 start "dotnet JT808.Gateway.TestHosting.dll ASPNETCORE_ENVIRONMENT=Production" --max-restarts=1 -n "JT808.Gateway.808" -o "/data/pm2Logs/JT808.Gateway/out.log" -e "/data/pm2Logs/JT808.Gateway/error.log"
\ No newline at end of file
diff --git a/src/JT808.Gateway.sln b/src/JT808.Gateway.sln
new file mode 100644
index 0000000..3719e74
--- /dev/null
+++ b/src/JT808.Gateway.sln
@@ -0,0 +1,43 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29409.12
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway", "JT808.Gateway\JT808.Gateway.csproj", "{4C8A2546-8333-416D-B123-91062B630087}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.TestHosting", "JT808.Gateway.TestHosting\JT808.Gateway.TestHosting.csproj", "{AE40AFE0-0950-442C-A74C-10CDF53E9F36}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.Test", "JT808.Gateway.Test\JT808.Gateway.Test.csproj", "{28C9BC4D-7B28-4E65-971A-7156E5EE0ADF}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.Abstractions", "JT808.Gateway.Abstractions\JT808.Gateway.Abstractions.csproj", "{3AA17DF7-A1B3-449C-93C2-45B051C32933}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{4C8A2546-8333-416D-B123-91062B630087}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{4C8A2546-8333-416D-B123-91062B630087}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{4C8A2546-8333-416D-B123-91062B630087}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{4C8A2546-8333-416D-B123-91062B630087}.Release|Any CPU.Build.0 = Release|Any CPU
+		{AE40AFE0-0950-442C-A74C-10CDF53E9F36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AE40AFE0-0950-442C-A74C-10CDF53E9F36}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AE40AFE0-0950-442C-A74C-10CDF53E9F36}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AE40AFE0-0950-442C-A74C-10CDF53E9F36}.Release|Any CPU.Build.0 = Release|Any CPU
+		{28C9BC4D-7B28-4E65-971A-7156E5EE0ADF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{28C9BC4D-7B28-4E65-971A-7156E5EE0ADF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{28C9BC4D-7B28-4E65-971A-7156E5EE0ADF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{28C9BC4D-7B28-4E65-971A-7156E5EE0ADF}.Release|Any CPU.Build.0 = Release|Any CPU
+		{3AA17DF7-A1B3-449C-93C2-45B051C32933}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{3AA17DF7-A1B3-449C-93C2-45B051C32933}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{3AA17DF7-A1B3-449C-93C2-45B051C32933}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{3AA17DF7-A1B3-449C-93C2-45B051C32933}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {AA9303A7-6FB3-4572-88AA-3302E85330D1}
+	EndGlobalSection
+EndGlobal
diff --git a/src/JT808.Gateway/Configurations/JT808Configuration.cs b/src/JT808.Gateway/Configurations/JT808Configuration.cs
new file mode 100644
index 0000000..c6d3edd
--- /dev/null
+++ b/src/JT808.Gateway/Configurations/JT808Configuration.cs
@@ -0,0 +1,43 @@
+using JT808.Gateway.Enums;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JT808.Gateway.Configurations
+{
+    public class JT808Configuration
+    {
+        public int TcpPort { get; set; } = 808;
+        public int UdpPort { get; set; } = 808;
+        public int WebApiPort { get; set; } = 828;
+        public string WebApiHost{ get; set; } = "localhost";
+        /// <summary>
+        /// WebApi 默认token 123456 
+        /// </summary>
+        public string WebApiToken { get; set; } = "123456";
+        public int SoBacklog { get; set; } = 8192;
+        public int MiniNumBufferSize { get; set; } = 8096;
+        /// <summary>
+        /// Tcp读超时 
+        /// 默认10分钟检查一次
+        /// </summary>
+        public int TcpReaderIdleTimeSeconds { get; set; } = 60*10;
+        /// <summary>
+        /// Tcp 60s检查一次
+        /// </summary>
+        public int TcpReceiveTimeoutCheckTimeSeconds { get; set; } = 60;
+        /// <summary>
+        /// Udp读超时
+        /// </summary>
+        public int UdpReaderIdleTimeSeconds { get; set; } = 60;
+        /// <summary>
+        /// Udp 60s检查一次
+        /// </summary>
+        public int UdpReceiveTimeoutCheckTimeSeconds { get; set; } = 60;
+        /// <summary>
+        /// 队列类型
+        /// 默认内存队列
+        /// </summary>
+        public JT808MessageQueueType MessageQueueType { get; set; } = JT808MessageQueueType.InMemory;
+    }
+}
diff --git a/src/JT808.Gateway/Enums/JT808MessageQueueType.cs b/src/JT808.Gateway/Enums/JT808MessageQueueType.cs
new file mode 100644
index 0000000..a83f6a0
--- /dev/null
+++ b/src/JT808.Gateway/Enums/JT808MessageQueueType.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JT808.Gateway.Enums
+{
+    public enum JT808MessageQueueType:byte
+    {
+        /// <summary>
+        /// 使用内存队列
+        /// </summary>
+        InMemory=1,
+        /// <summary>
+        /// 使用第三方队列
+        /// </summary>
+        InPlug=2
+    }
+}
diff --git a/src/JT808.Gateway/Interfaces/IJT808Session.cs b/src/JT808.Gateway/Interfaces/IJT808Session.cs
new file mode 100644
index 0000000..14e1b0d
--- /dev/null
+++ b/src/JT808.Gateway/Interfaces/IJT808Session.cs
@@ -0,0 +1,26 @@
+using JT808.Gateway.Abstractions.Enums;
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading;
+
+namespace JT808.Gateway.Interfaces
+{
+    public interface IJT808Session
+    {
+        /// <summary>
+        /// 终端手机号
+        /// </summary>
+        string TerminalPhoneNo { get; set; }
+        string SessionID { get; }
+        Socket Client { get; set; }
+        DateTime StartTime { get; set; }
+        DateTime ActiveTime { get; set; }
+        JT808TransportProtocolType TransportProtocolType { get;}
+        CancellationTokenSource ReceiveTimeout { get; set; }
+        EndPoint RemoteEndPoint { get; set; }
+        void Close();
+    }
+}
diff --git a/src/JT808.Gateway/Internal/JT808GatewayBuilderDefault.cs b/src/JT808.Gateway/Internal/JT808GatewayBuilderDefault.cs
new file mode 100644
index 0000000..1ef7110
--- /dev/null
+++ b/src/JT808.Gateway/Internal/JT808GatewayBuilderDefault.cs
@@ -0,0 +1,20 @@
+using JT808.Gateway.Abstractions;
+using JT808.Protocol;
+
+namespace JT808.Gateway.Internal
+{
+    public class JT808GatewayBuilderDefault : IJT808GatewayBuilder
+    {
+        public IJT808Builder JT808Builder { get; }
+
+        public JT808GatewayBuilderDefault(IJT808Builder builder)
+        {
+            JT808Builder = builder;
+        }
+
+        public IJT808Builder Builder()
+        {
+            return JT808Builder;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/JT808.Gateway/Internal/JT808MsgProducerDefault.cs b/src/JT808.Gateway/Internal/JT808MsgProducerDefault.cs
new file mode 100644
index 0000000..610dd97
--- /dev/null
+++ b/src/JT808.Gateway/Internal/JT808MsgProducerDefault.cs
@@ -0,0 +1,28 @@
+using JT808.Gateway.Abstractions;
+using JT808.Gateway.Internal;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace JT808.Gateway.Internal
+{
+    internal class JT808MsgProducerDefault : IJT808MsgProducer
+    {
+        private readonly JT808MsgService JT808MsgService;
+        public string TopicName => JT808GatewayConstants.MsgTopic;
+        public JT808MsgProducerDefault(JT808MsgService jT808MsgService)
+        {
+            JT808MsgService = jT808MsgService;
+        }
+        public void Dispose()
+        {
+            
+        }
+        public ValueTask ProduceAsync(string terminalNo, byte[] data)
+        {
+            JT808MsgService.MsgQueue.Add((terminalNo, data));
+            return default;
+        }
+    }
+}
diff --git a/src/JT808.Gateway/Internal/JT808MsgReplyConsumerDefault.cs b/src/JT808.Gateway/Internal/JT808MsgReplyConsumerDefault.cs
new file mode 100644
index 0000000..4276be3
--- /dev/null
+++ b/src/JT808.Gateway/Internal/JT808MsgReplyConsumerDefault.cs
@@ -0,0 +1,201 @@
+using JT808.Gateway.Abstractions;
+using JT808.Protocol;
+using JT808.Protocol.Enums;
+using JT808.Protocol.Extensions;
+using JT808.Protocol.MessageBody;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace JT808.Gateway.Internal
+{
+    internal class JT808MsgReplyConsumerDefault : IJT808MsgReplyConsumer
+    {
+        private readonly JT808MsgService JT808MsgService;
+
+        private readonly JT808Serializer JT808Serializer;
+
+        private delegate byte[] MethodDelegate(JT808HeaderPackage headerPackage);
+
+        private Dictionary<ushort, MethodDelegate> HandlerDict;
+        public JT808MsgReplyConsumerDefault(
+                IJT808Config jT808Config,
+                JT808MsgService jT808MsgService)
+        {
+            JT808MsgService = jT808MsgService;
+            this.JT808Serializer = jT808Config.GetSerializer();
+            HandlerDict = new Dictionary<ushort, MethodDelegate> {
+                {JT808MsgId.终端通用应答.ToUInt16Value(), Msg0x0001},
+                {JT808MsgId.终端鉴权.ToUInt16Value(), Msg0x0102},
+                {JT808MsgId.终端心跳.ToUInt16Value(), Msg0x0002},
+                {JT808MsgId.终端注销.ToUInt16Value(), Msg0x0003},
+                {JT808MsgId.终端注册.ToUInt16Value(), Msg0x0100},
+                {JT808MsgId.位置信息汇报.ToUInt16Value(),Msg0x0200 },
+                {JT808MsgId.定位数据批量上传.ToUInt16Value(),Msg0x0704 },
+                {JT808MsgId.数据上行透传.ToUInt16Value(),Msg0x0900 }
+            };
+        }
+        public CancellationTokenSource Cts =>new CancellationTokenSource();
+
+        public string TopicName => JT808GatewayConstants.MsgReplyTopic;
+
+        public void Dispose()
+        {
+            Cts.Dispose();
+        }
+
+        public void OnMessage(Action<(string TerminalNo, byte[] Data)> callback)
+        {
+            Task.Run(() =>
+            {
+                foreach(var item in JT808MsgService.MsgQueue.GetConsumingEnumerable())
+                {
+                    try
+                    {
+                        var package = JT808Serializer.HeaderDeserialize(item.Data);
+                        if (HandlerDict.TryGetValue(package.Header.MsgId, out var func))
+                        {
+                            var buffer = func(package);
+                            if (buffer != null)
+                            {
+                                callback((item.TerminalNo, buffer));
+                            }
+                        }
+                    }
+                    catch
+                    {
+
+                    }
+                }
+            }, Cts.Token);
+        }
+
+        public void Subscribe()
+        {
+            
+        }
+
+        public void Unsubscribe()
+        {
+            Cts.Cancel();
+        }
+
+        /// <summary>
+        /// 终端通用应答
+        /// 平台无需回复
+        /// 实现自己的业务
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        public byte[] Msg0x0001(JT808HeaderPackage request)
+        {
+            return null;
+        }
+
+        /// <summary>
+        /// 终端心跳
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        public byte[] Msg0x0002(JT808HeaderPackage request)
+        {
+            return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001()
+            {
+                AckMsgId = request.Header.MsgId,
+                JT808PlatformResult = JT808PlatformResult.成功,
+                MsgNum = request.Header.MsgNum
+            }));
+        }
+
+        /// <summary>
+        /// 终端注销
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        public byte[] Msg0x0003(JT808HeaderPackage request)
+        {
+            return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001()
+            {
+                AckMsgId = request.Header.MsgId,
+                JT808PlatformResult = JT808PlatformResult.成功,
+                MsgNum = request.Header.MsgNum
+            }));
+        }
+
+        /// <summary>
+        /// 终端注册
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        public byte[] Msg0x0100(JT808HeaderPackage request)
+        {
+            return JT808Serializer.Serialize(JT808MsgId.终端注册应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8100()
+            {
+                Code = "J" + request.Header.TerminalPhoneNo,
+                JT808TerminalRegisterResult = JT808TerminalRegisterResult.成功,
+                AckMsgNum = request.Header.MsgNum
+            }));
+        }
+        /// <summary>
+        /// 终端鉴权
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        public byte[] Msg0x0102(JT808HeaderPackage request)
+        {
+            return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001()
+            {
+                AckMsgId = request.Header.MsgId,
+                JT808PlatformResult = JT808PlatformResult.成功,
+                MsgNum = request.Header.MsgNum
+            }));
+        }
+
+        /// <summary>
+        /// 位置信息汇报
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        public byte[] Msg0x0200(JT808HeaderPackage request)
+        {
+            return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001()
+            {
+                AckMsgId = request.Header.MsgId,
+                JT808PlatformResult = JT808PlatformResult.成功,
+                MsgNum = request.Header.MsgNum
+            }));
+        }
+
+        /// <summary>
+        /// 定位数据批量上传
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        public byte[] Msg0x0704(JT808HeaderPackage request)
+        {
+            return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001()
+            {
+                AckMsgId = request.Header.MsgId,
+                JT808PlatformResult = JT808PlatformResult.成功,
+                MsgNum = request.Header.MsgNum
+            }));
+        }
+
+        /// <summary>
+        /// 数据上行透传
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
+        public byte[] Msg0x0900(JT808HeaderPackage request)
+        {
+            return JT808Serializer.Serialize(JT808MsgId.平台通用应答.Create(request.Header.TerminalPhoneNo, new JT808_0x8001()
+            {
+                AckMsgId = request.Header.MsgId,
+                JT808PlatformResult = JT808PlatformResult.成功,
+                MsgNum = request.Header.MsgNum
+            }));
+        }
+    }
+}
diff --git a/src/JT808.Gateway/Internal/JT808MsgService.cs b/src/JT808.Gateway/Internal/JT808MsgService.cs
new file mode 100644
index 0000000..c1d6095
--- /dev/null
+++ b/src/JT808.Gateway/Internal/JT808MsgService.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace JT808.Gateway.Internal
+{
+    internal class JT808MsgService
+    {
+        public System.Collections.Concurrent.BlockingCollection<(string TerminalNo, byte[] Data)> MsgQueue { get; set; } = new System.Collections.Concurrent.BlockingCollection<(string TerminalNo, byte[] Data)>();
+    }
+}
diff --git a/src/JT808.Gateway/JT808.Gateway.csproj b/src/JT808.Gateway/JT808.Gateway.csproj
new file mode 100644
index 0000000..fdbfd6e
--- /dev/null
+++ b/src/JT808.Gateway/JT808.Gateway.csproj
@@ -0,0 +1,31 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netstandard2.1</TargetFramework>
+    <LangVersion>8.0</LangVersion>
+    <Copyright>Copyright 2019.</Copyright>
+    <Authors>SmallChi(Koike)</Authors>
+    <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
+    <SignAssembly>false</SignAssembly>
+    <PackageLicenseFile>LICENSE</PackageLicenseFile>
+    <PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
+    <Description>基于Pipeline实现的JT808Gateway的网络库</Description>
+    <PackageReleaseNotes>基于Pipeline实现的JT808Gateway的网络库</PackageReleaseNotes>
+    <PackageId>JT808.Gateway</PackageId>
+    <Product>JT808.Gateway</Product>
+    <Version>1.0.0-preview2</Version>
+  </PropertyGroup>
+  
+  <ItemGroup>
+    <PackageReference Include="Microsoft.Extensions.Options" Version="3.1.0" />
+    <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="3.1.0" />
+    <PackageReference Include="System.IO.Pipelines" Version="4.7.0" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\JT808.Gateway.Abstractions\JT808.Gateway.Abstractions.csproj" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="..\..\LICENSE" Pack="true" PackagePath="" />
+  </ItemGroup>
+</Project>
diff --git a/src/JT808.Gateway/JT808GatewayExtensions.cs b/src/JT808.Gateway/JT808GatewayExtensions.cs
new file mode 100644
index 0000000..0f2891d
--- /dev/null
+++ b/src/JT808.Gateway/JT808GatewayExtensions.cs
@@ -0,0 +1,75 @@
+using JT808.Gateway.Abstractions;
+using JT808.Gateway.Configurations;
+using JT808.Gateway.Internal;
+using JT808.Gateway.Services;
+using JT808.Gateway.Session;
+using JT808.Protocol;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using System;
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("JT808.Gateway.TestHosting")]
+[assembly: InternalsVisibleTo("JT808.Gateway.Test")]
+namespace JT808.Gateway
+{
+    public static partial class JT808GatewayExtensions
+    {
+        public static IJT808GatewayBuilder AddJT808Gateway(this IJT808Builder jt808Builder)
+        {
+            IJT808GatewayBuilder server = new JT808GatewayBuilderDefault(jt808Builder);
+            server.JT808Builder.Services.TryAddSingleton<JT808Configuration>();
+            server.AddJT808Core();
+            return server;
+        }
+
+        public static IJT808GatewayBuilder AddJT808Gateway(this IJT808Builder jt808Builder,Action<JT808Configuration> config)
+        {
+            IJT808GatewayBuilder server = new JT808GatewayBuilderDefault(jt808Builder);
+            server.JT808Builder.Services.Configure(config);
+            server.AddJT808Core();
+            return server;
+        }
+
+        public static IJT808GatewayBuilder AddJT808Gateway(this IJT808Builder jt808Builder, IConfiguration  configuration)
+        {
+            IJT808GatewayBuilder server = new JT808GatewayBuilderDefault(jt808Builder);
+            server.JT808Builder.Services.Configure<JT808Configuration>(configuration.GetSection("JT808Configuration"));
+            server.AddJT808Core();
+            return server;
+        }
+
+        public static IJT808GatewayBuilder AddTcp(this IJT808GatewayBuilder config)
+        {
+            config.JT808Builder.Services.AddHostedService<JT808TcpServer>();
+            config.JT808Builder.Services.AddHostedService<JT808TcpReceiveTimeoutHostedService>();
+            return config;
+        }
+
+        public static IJT808GatewayBuilder AddUdp(this IJT808GatewayBuilder config)
+        {
+            config.JT808Builder.Services.AddHostedService<JT808UdpServer>();
+            config.JT808Builder.Services.AddHostedService<JT808UdpReceiveTimeoutHostedService>();
+            return config;
+        }
+
+        public static IJT808GatewayBuilder AddGrpc(this IJT808GatewayBuilder config)
+        {
+            config.JT808Builder.Services.AddHostedService<JT808GrpcServer>();
+            return config;
+        }
+
+        private static IJT808GatewayBuilder AddJT808Core(this IJT808GatewayBuilder config)
+        {
+            config.JT808Builder.Services.TryAddSingleton<JT808Configuration>();
+            config.JT808Builder.Services.TryAddSingleton<JT808AtomicCounterServiceFactory>();
+            config.JT808Builder.Services.TryAddSingleton<IJT808MsgProducer, JT808MsgProducerDefault>();
+            config.JT808Builder.Services.TryAddSingleton<IJT808MsgReplyConsumer, JT808MsgReplyConsumerDefault>();
+            config.JT808Builder.Services.TryAddSingleton<JT808SessionManager>();
+            config.JT808Builder.Services.TryAddSingleton<JT808MsgService>();
+            config.JT808Builder.Services.AddHostedService<JT808MsgReplyHostedService>();
+            return config;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/JT808.Gateway/JT808GrpcServer.cs b/src/JT808.Gateway/JT808GrpcServer.cs
new file mode 100644
index 0000000..e430873
--- /dev/null
+++ b/src/JT808.Gateway/JT808GrpcServer.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+using JT808.Gateway.Configurations;
+using JT808.Gateway.GrpcService;
+using JT808.Gateway.Services;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace JT808.Gateway
+{
+    public class JT808GrpcServer : IHostedService
+    {
+        private readonly ILogger Logger;
+        private readonly JT808Configuration Configuration;
+        private readonly IServiceProvider ServiceProvider;
+        private Server server;
+        public JT808GrpcServer(
+                IServiceProvider serviceProvider,
+                JT808Configuration jT808Configuration,
+                ILoggerFactory loggerFactory)
+        {
+            Logger = loggerFactory.CreateLogger("JT808GrpcServer");
+            Configuration = jT808Configuration;
+            ServiceProvider = serviceProvider;
+        }
+
+        public Task StartAsync(CancellationToken cancellationToken)
+        {
+            server = new Server
+            {
+                Services = { JT808Gateway.BindService(new JT808GatewayService(ServiceProvider)) },
+                Ports = { new ServerPort(Configuration.WebApiHost, Configuration.WebApiPort, ServerCredentials.Insecure) }
+            };
+            Logger.LogInformation($"JT808 Grpc Server start at {Configuration.WebApiHost}:{Configuration.WebApiPort}.");
+            try
+            {
+                server.Start();
+            }
+            catch (Exception ex)
+            {
+                Logger.LogError(ex, "JT808 Grpc Server start error");
+            }
+            return Task.CompletedTask;
+        }
+        public Task StopAsync(CancellationToken cancellationToken)
+        {
+            Logger.LogInformation("JT808 Grpc Server Stop");
+            server.ShutdownAsync();
+            return Task.CompletedTask;
+        }
+    }
+}
diff --git a/src/JT808.Gateway/JT808TcpServer.cs b/src/JT808.Gateway/JT808TcpServer.cs
new file mode 100644
index 0000000..969cab8
--- /dev/null
+++ b/src/JT808.Gateway/JT808TcpServer.cs
@@ -0,0 +1,226 @@
+using System;
+using System.Buffers;
+using System.Collections.Generic;
+using System.IO.Pipelines;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using JT808.Gateway.Abstractions;
+using JT808.Gateway.Abstractions.Enums;
+using JT808.Gateway.Configurations;
+using JT808.Gateway.Enums;
+using JT808.Gateway.Services;
+using JT808.Gateway.Session;
+using JT808.Protocol;
+using JT808.Protocol.Exceptions;
+using JT808.Protocol.Extensions;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace JT808.Gateway
+{
+    public class JT808TcpServer:IHostedService
+    {
+        private Socket server;
+
+        private const byte beginAndEndMark = 0x7e;
+
+        private readonly ILogger Logger;
+
+        private readonly JT808SessionManager SessionManager;
+
+        private readonly IJT808MsgProducer MsgProducer;
+
+        private readonly JT808Serializer Serializer;
+
+        private readonly JT808AtomicCounterService AtomicCounterService;
+
+        private readonly JT808Configuration Configuration;
+
+        public JT808TcpServer(
+                JT808Configuration jT808Configuration,
+                IJT808Config jT808Config,
+                ILoggerFactory loggerFactory,
+                JT808SessionManager jT808SessionManager,
+                IJT808MsgProducer jT808MsgProducer,
+                JT808AtomicCounterServiceFactory jT808AtomicCounterServiceFactory)
+            {
+                SessionManager = jT808SessionManager;
+                Logger = loggerFactory.CreateLogger("JT808TcpServer");
+                Serializer = jT808Config.GetSerializer();
+                MsgProducer = jT808MsgProducer;
+                AtomicCounterService = jT808AtomicCounterServiceFactory.Create(JT808TransportProtocolType.tcp);
+                Configuration = jT808Configuration;
+                var IPEndPoint = new System.Net.IPEndPoint(IPAddress.Any, jT808Configuration.TcpPort);
+                server = new Socket(IPEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
+                server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, true);
+                server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
+                server.LingerState = new LingerOption(false, 0);
+                server.Bind(IPEndPoint);
+                server.Listen(jT808Configuration.SoBacklog);
+            }
+
+        public Task StartAsync(CancellationToken cancellationToken)
+        {
+            Logger.LogInformation($"JT808 TCP Server start at {IPAddress.Any}:{Configuration.TcpPort}.");
+            Task.Run(async() => {
+                while (!cancellationToken.IsCancellationRequested)
+                {
+                    var socket = await server.AcceptAsync();
+                    JT808TcpSession jT808TcpSession = new JT808TcpSession(socket);
+                    await Task.Factory.StartNew(async (state) =>
+                    {
+                        var session = (JT808TcpSession)state;
+                        SessionManager.TryAdd(session);
+                        if (Logger.IsEnabled(LogLevel.Information))
+                        {
+                            Logger.LogInformation($"[Connected]:{session.Client.RemoteEndPoint}");
+                        }
+                        var pipe = new Pipe();
+                        Task writing = FillPipeAsync(session, pipe.Writer);
+                        Task reading = ReadPipeAsync(session, pipe.Reader);
+                        await Task.WhenAll(reading, writing);
+                        SessionManager.RemoveBySessionId(session.SessionID);
+                    }, jT808TcpSession);
+                }
+            }, cancellationToken);
+            return Task.CompletedTask;
+        }
+        private  async Task FillPipeAsync(JT808TcpSession session, PipeWriter writer)
+        {
+            while (true)
+            {
+                try
+                {
+                    Memory<byte> memory = writer.GetMemory(Configuration.MiniNumBufferSize);
+                    //设备多久没发数据就断开连接 Receive Timeout.
+                    int bytesRead = await session.Client.ReceiveAsync(memory, SocketFlags.None, session.ReceiveTimeout.Token);
+                    if (bytesRead == 0)
+                    {
+                        break;
+                    }
+                    writer.Advance(bytesRead);
+                }
+                catch(OperationCanceledException)
+                {
+                    Logger.LogError($"[Receive Timeout]:{session.Client.RemoteEndPoint}");
+                    break;
+                }
+                catch (Exception ex)
+                {
+                    Logger.LogError(ex, $"[Receive Error]:{session.Client.RemoteEndPoint}");
+                    break;
+                }
+                FlushResult result = await writer.FlushAsync();
+                if (result.IsCompleted)
+                {
+                    break;
+                }
+            }
+            writer.Complete();
+        }
+        private  async Task ReadPipeAsync(JT808TcpSession session, PipeReader reader)
+        {
+            while (true)
+            {
+                ReadResult result = await reader.ReadAsync();
+                if (result.IsCompleted)
+                {
+                    break;
+                }
+                ReadOnlySequence<byte> buffer = result.Buffer;
+                SequencePosition consumed = buffer.Start;
+                SequencePosition examined = buffer.End;
+                try
+                {
+                    if (result.IsCanceled) break;
+                    if (buffer.Length > 0)
+                    {
+                        ReaderBuffer(ref buffer, session,out consumed, out examined);
+                    }
+                }
+                catch (Exception ex)
+                {
+                    SessionManager.RemoveBySessionId(session.SessionID);
+                    break;
+                }
+                finally
+                {
+                    reader.AdvanceTo(consumed, examined);
+                }
+            }
+            reader.Complete();
+        }
+        private  void ReaderBuffer(ref ReadOnlySequence<byte> buffer, JT808TcpSession session, out SequencePosition consumed, out SequencePosition examined)
+        {
+            consumed = buffer.Start;
+            examined = buffer.End;
+            SequenceReader<byte> seqReader = new SequenceReader<byte>(buffer);
+            if (seqReader.TryPeek(out byte beginMark))
+            {
+                if (beginMark != beginAndEndMark) throw new ArgumentException("Not JT808 Packages.");
+            }
+            byte mark = 0;
+            long totalConsumed = 0;
+            while (!seqReader.End)
+            {
+                if (seqReader.IsNext(beginAndEndMark, advancePast: true))
+                {
+                    if (mark == 1)
+                    {
+                        try
+                        {
+                            var package = Serializer.HeaderDeserialize(seqReader.Sequence.Slice(totalConsumed, seqReader.Consumed - totalConsumed).FirstSpan);
+                            AtomicCounterService.MsgSuccessIncrement();
+                            if (Logger.IsEnabled(LogLevel.Debug)) Logger.LogDebug($"[Atomic Success Counter]:{AtomicCounterService.MsgSuccessCount}");
+                            if (Logger.IsEnabled(LogLevel.Trace)) Logger.LogTrace($"[Accept Hex {session.Client.RemoteEndPoint}]:{package.OriginalData.ToArray().ToHexString()}");
+                            //设直连模式和转发模式的会话如何处理
+                            SessionManager.TryLink(package.Header.TerminalPhoneNo, session);
+                            if(Configuration.MessageQueueType == JT808MessageQueueType.InMemory)
+                            {
+                                MsgProducer.ProduceAsync(session.SessionID, package.OriginalData.ToArray());
+                            }
+                            else
+                            {
+                                MsgProducer.ProduceAsync(package.Header.TerminalPhoneNo, package.OriginalData.ToArray());
+                            }
+                        }
+                        catch (JT808Exception ex)
+                        {
+                            AtomicCounterService.MsgFailIncrement();
+                            if (Logger.IsEnabled(LogLevel.Debug)) Logger.LogDebug($"[Atomic Fail Counter]:{AtomicCounterService.MsgFailCount}");
+                            Logger.LogError(ex,$"[HeaderDeserialize ErrorCode]:{ ex.ErrorCode}"); 
+                        }
+                        totalConsumed += (seqReader.Consumed - totalConsumed);
+                        if (seqReader.End) break;
+                        seqReader.Advance(1);
+                        mark = 0;
+                    }
+                    mark++;
+                }
+                else
+                {
+                    seqReader.Advance(1);
+                }
+            }
+            if (seqReader.Length== totalConsumed)
+            {
+                examined = consumed = buffer.End;
+            }
+            else
+            {
+                consumed = buffer.GetPosition(totalConsumed);
+            }
+        }
+        public Task StopAsync(CancellationToken cancellationToken)
+        {
+            Logger.LogInformation("808 Tcp Server Stop");
+            if (server?.Connected ?? false)
+                server.Shutdown(SocketShutdown.Both);
+            server?.Close();
+            return Task.CompletedTask;
+        }
+    }
+}
diff --git a/src/JT808.Gateway/JT808UdpServer.cs b/src/JT808.Gateway/JT808UdpServer.cs
new file mode 100644
index 0000000..749bcb0
--- /dev/null
+++ b/src/JT808.Gateway/JT808UdpServer.cs
@@ -0,0 +1,134 @@
+using System;
+using System.Buffers;
+using System.Collections.Generic;
+using System.IO.Pipelines;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using JT808.Gateway.Abstractions;
+using JT808.Gateway.Abstractions.Enums;
+using JT808.Gateway.Configurations;
+using JT808.Gateway.Enums;
+using JT808.Gateway.Services;
+using JT808.Gateway.Session;
+using JT808.Protocol;
+using JT808.Protocol.Exceptions;
+using JT808.Protocol.Extensions;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace JT808.Gateway
+{
+    public class JT808UdpServer : IHostedService
+    {
+        private Socket server;
+
+        private readonly ILogger Logger;
+
+        private readonly JT808SessionManager SessionManager;
+
+        private readonly IJT808MsgProducer MsgProducer;
+
+        private readonly JT808Serializer Serializer;
+
+        private readonly JT808AtomicCounterService AtomicCounterService;
+
+        private readonly JT808Configuration Configuration;
+
+        private IPEndPoint LocalIPEndPoint;
+
+        public JT808UdpServer(
+                JT808Configuration jT808Configuration,
+                IJT808Config jT808Config,
+                ILoggerFactory loggerFactory,
+                JT808SessionManager jT808SessionManager,
+                IJT808MsgProducer jT808MsgProducer,
+                JT808AtomicCounterServiceFactory jT808AtomicCounterServiceFactory)
+            {
+                SessionManager = jT808SessionManager;
+                Logger = loggerFactory.CreateLogger("JT808UdpServer");
+                Serializer = jT808Config.GetSerializer();
+                MsgProducer = jT808MsgProducer;
+                AtomicCounterService = jT808AtomicCounterServiceFactory.Create(JT808TransportProtocolType.udp);
+                Configuration = jT808Configuration;
+                LocalIPEndPoint = new System.Net.IPEndPoint(IPAddress.Any, jT808Configuration.UdpPort);
+                server = new Socket(LocalIPEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
+                server.Bind(LocalIPEndPoint);
+            }
+
+        public Task StartAsync(CancellationToken cancellationToken)
+        {
+            Logger.LogInformation($"JT808 Udp Server start at {IPAddress.Any}:{Configuration.UdpPort}.");
+            Task.Run(async() => {
+                while (!cancellationToken.IsCancellationRequested)
+                {
+                    var buffer = ArrayPool<byte>.Shared.Rent(Configuration.MiniNumBufferSize);
+                    try
+                    {
+                        var segment = new ArraySegment<byte>(buffer);
+                        SocketReceiveMessageFromResult result = await server.ReceiveMessageFromAsync(segment, SocketFlags.None, LocalIPEndPoint);
+                        ReaderBuffer(buffer.AsSpan(0, result.ReceivedBytes), server, result);
+                    }
+                    catch(AggregateException ex)
+                    {
+                        Logger.LogError(ex, "Receive MessageFrom Async");
+                    }
+                    catch(Exception ex)
+                    {
+                        Logger.LogError(ex, $"Received Bytes");
+                    }
+                    finally
+                    {
+                        ArrayPool<byte>.Shared.Return(buffer);
+                    }
+                }
+            }, cancellationToken);
+            return Task.CompletedTask;
+        }
+        private void ReaderBuffer(ReadOnlySpan<byte> buffer, Socket socket,SocketReceiveMessageFromResult receiveMessageFromResult)
+        {
+            try
+            {
+                var package = Serializer.HeaderDeserialize(buffer);
+                AtomicCounterService.MsgSuccessIncrement();
+                if (Logger.IsEnabled(LogLevel.Debug)) Logger.LogDebug($"[Atomic Success Counter]:{AtomicCounterService.MsgSuccessCount}");
+                if (Logger.IsEnabled(LogLevel.Trace)) Logger.LogTrace($"[Accept Hex {receiveMessageFromResult.RemoteEndPoint}]:{package.OriginalData.ToArray().ToHexString()}");
+                //设直连模式和转发模式的会话如何处理
+                string sessionId= SessionManager.TryLink(package.Header.TerminalPhoneNo, socket, receiveMessageFromResult.RemoteEndPoint);
+                if (Logger.IsEnabled(LogLevel.Information))
+                {
+                    Logger.LogInformation($"[Connected]:{receiveMessageFromResult.RemoteEndPoint}");
+                }
+                if (Configuration.MessageQueueType == JT808MessageQueueType.InMemory)
+                {
+                    MsgProducer.ProduceAsync(sessionId, package.OriginalData.ToArray());
+                }
+                else
+                {
+                    MsgProducer.ProduceAsync(package.Header.TerminalPhoneNo, package.OriginalData.ToArray());
+                }
+            }
+            catch (JT808Exception ex)
+            {
+                AtomicCounterService.MsgFailIncrement();
+                if (Logger.IsEnabled(LogLevel.Debug)) Logger.LogDebug($"[Atomic Fail Counter]:{AtomicCounterService.MsgFailCount}");
+                Logger.LogError(ex, $"[HeaderDeserialize ErrorCode]:{ ex.ErrorCode}-{buffer.ToArray().ToHexString()}");
+            }
+            catch (Exception ex)
+            {
+                if (Logger.IsEnabled(LogLevel.Debug)) Logger.LogDebug($"[Atomic Fail Counter]:{AtomicCounterService.MsgFailCount}");
+                Logger.LogError(ex, $"[ReaderBuffer]:{ buffer.ToArray().ToHexString()}");
+            }
+        }
+        public Task StopAsync(CancellationToken cancellationToken)
+        {
+            Logger.LogInformation("808 Udp Server Stop");
+            if (server?.Connected ?? false)
+                server.Shutdown(SocketShutdown.Both);
+            server?.Close();
+            return Task.CompletedTask;
+        }
+    }
+}
diff --git a/src/JT808.Gateway/Metadata/JT808AtomicCounter.cs b/src/JT808.Gateway/Metadata/JT808AtomicCounter.cs
new file mode 100644
index 0000000..6362905
--- /dev/null
+++ b/src/JT808.Gateway/Metadata/JT808AtomicCounter.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+
+namespace JT808.Gateway.Metadata
+{
+    /// <summary>
+    /// 
+    /// <see cref="Grpc.Core.Internal"/>
+    /// </summary>
+    internal class JT808AtomicCounter
+    {
+        long counter = 0;
+
+        public JT808AtomicCounter(long initialCount = 0)
+        {
+            this.counter = initialCount;
+        }
+
+        public void Reset()
+        {
+            Interlocked.Exchange(ref counter, 0);
+        }
+
+        public long Increment()
+        {
+            return Interlocked.Increment(ref counter);
+        }
+
+        public long Add(long len)
+        {
+            return Interlocked.Add(ref counter,len);
+        }
+
+        public long Decrement()
+        {
+            return Interlocked.Decrement(ref counter);
+        }
+
+        public long Count
+        {
+            get
+            {
+                return Interlocked.Read(ref counter);
+            }
+        }
+    }
+}
diff --git a/src/JT808.Gateway/Services/JT808AtomicCounterService.cs b/src/JT808.Gateway/Services/JT808AtomicCounterService.cs
new file mode 100644
index 0000000..cddd31f
--- /dev/null
+++ b/src/JT808.Gateway/Services/JT808AtomicCounterService.cs
@@ -0,0 +1,52 @@
+using JT808.Gateway.Metadata;
+
+namespace JT808.Gateway.Services
+{
+    /// <summary>
+    /// 计数包服务
+    /// </summary>
+    public class JT808AtomicCounterService
+    {
+        private readonly JT808AtomicCounter MsgSuccessCounter;
+
+        private readonly JT808AtomicCounter MsgFailCounter;
+
+        public JT808AtomicCounterService()
+        {
+            MsgSuccessCounter=new JT808AtomicCounter();
+            MsgFailCounter = new JT808AtomicCounter();
+        }
+
+        public void Reset()
+        {
+            MsgSuccessCounter.Reset();
+            MsgFailCounter.Reset();
+        }
+
+        public long MsgSuccessIncrement()
+        {
+            return MsgSuccessCounter.Increment();
+        }
+
+        public long MsgSuccessCount
+        {
+            get
+            {
+                return MsgSuccessCounter.Count;
+            }
+        }
+
+        public long MsgFailIncrement()
+        {
+            return MsgFailCounter.Increment();
+        }
+
+        public long MsgFailCount
+        {
+            get
+            {
+                return MsgFailCounter.Count;
+            }
+        }
+    }
+}
diff --git a/src/JT808.Gateway/Services/JT808AtomicCounterServiceFactory.cs b/src/JT808.Gateway/Services/JT808AtomicCounterServiceFactory.cs
new file mode 100644
index 0000000..e4c9536
--- /dev/null
+++ b/src/JT808.Gateway/Services/JT808AtomicCounterServiceFactory.cs
@@ -0,0 +1,30 @@
+using JT808.Gateway.Abstractions.Enums;
+using System;
+using System.Collections.Concurrent;
+
+namespace JT808.Gateway.Services
+{
+    public class JT808AtomicCounterServiceFactory
+    {
+        private readonly ConcurrentDictionary<JT808TransportProtocolType, JT808AtomicCounterService> cache;
+
+        public JT808AtomicCounterServiceFactory()
+        {
+            cache = new ConcurrentDictionary<JT808TransportProtocolType, JT808AtomicCounterService>();
+        }
+
+        public JT808AtomicCounterService Create(JT808TransportProtocolType type)
+        {
+            if(cache.TryGetValue(type,out var service))
+            {
+                return service;
+            }
+            else
+            {
+                var serviceNew = new JT808AtomicCounterService();
+                cache.TryAdd(type, serviceNew);
+                return serviceNew;
+            }
+        }
+    }
+}
diff --git a/src/JT808.Gateway/Services/JT808GatewayService.cs b/src/JT808.Gateway/Services/JT808GatewayService.cs
new file mode 100644
index 0000000..cf0b7d5
--- /dev/null
+++ b/src/JT808.Gateway/Services/JT808GatewayService.cs
@@ -0,0 +1,144 @@
+using System;
+using System.Linq;
+using JT808.Gateway.GrpcService;
+using Grpc.Core;
+using System.Threading.Tasks;
+using JT808.Gateway.Abstractions.Enums;
+using JT808.Gateway.Session;
+using Microsoft.Extensions.DependencyInjection;
+using static Grpc.Core.Metadata;
+using Microsoft.Extensions.Options;
+using JT808.Gateway.Configurations;
+
+namespace JT808.Gateway.Services
+{
+    public class JT808GatewayService: JT808Gateway.JT808GatewayBase
+    {
+        private readonly JT808AtomicCounterService jT808TcpAtomicCounterService;
+
+        private readonly JT808AtomicCounterService jT808UdpAtomicCounterService;
+
+        private readonly JT808SessionManager jT808SessionManager;
+
+        private readonly IOptionsMonitor<JT808Configuration> ConfigurationOptionsMonitor;
+
+        public JT808GatewayService(
+            IOptionsMonitor<JT808Configuration> configurationOptionsMonitor,
+            JT808SessionManager jT808SessionManager,
+            JT808AtomicCounterServiceFactory jT808AtomicCounterServiceFactory
+            )
+        {
+            this.jT808SessionManager = jT808SessionManager;
+            this.ConfigurationOptionsMonitor = configurationOptionsMonitor;
+            this.jT808TcpAtomicCounterService = jT808AtomicCounterServiceFactory.Create(JT808TransportProtocolType.tcp);
+            this.jT808UdpAtomicCounterService = jT808AtomicCounterServiceFactory.Create(JT808TransportProtocolType.udp);
+        }
+
+        public JT808GatewayService(IServiceProvider serviceProvider)
+        {
+            this.jT808SessionManager = serviceProvider.GetRequiredService<JT808SessionManager>();
+            this.jT808TcpAtomicCounterService = serviceProvider.GetRequiredService<JT808AtomicCounterServiceFactory>().Create(JT808TransportProtocolType.tcp);
+            this.jT808UdpAtomicCounterService = serviceProvider.GetRequiredService<JT808AtomicCounterServiceFactory>().Create(JT808TransportProtocolType.udp);
+            this.ConfigurationOptionsMonitor = serviceProvider.GetRequiredService<IOptionsMonitor<JT808Configuration>>();
+        }
+
+        public override Task<TcpSessionInfoReply> GetTcpSessionAll(Empty request, ServerCallContext context)
+        {
+            Auth(context);
+            var result = jT808SessionManager.GetTcpAll();
+            TcpSessionInfoReply reply = new TcpSessionInfoReply();
+            foreach (var item in result)
+            {
+                reply.TcpSessions.Add(new SessionInfo
+                {
+                    LastActiveTime = item.ActiveTime.ToString("yyyy-MM-dd HH:mm:ss"),
+                    StartTime = item.StartTime.ToString("yyyy-MM-dd HH:mm:ss"),
+                    RemoteAddressIP = item.RemoteEndPoint.ToString(),
+                    TerminalPhoneNo = item.TerminalPhoneNo
+                });
+            }     
+            return Task.FromResult(reply);
+        }
+
+        public override Task<SessionRemoveReply> RemoveSessionByTerminalPhoneNo(SessionRemoveRequest request, ServerCallContext context)
+        {
+            Auth(context);
+            try
+            {
+                jT808SessionManager.RemoveByTerminalPhoneNo(request.TerminalPhoneNo);
+                return Task.FromResult(new SessionRemoveReply { Success = true });
+            }
+            catch (Exception)
+            {
+                return Task.FromResult(new SessionRemoveReply { Success = false });
+            }
+        }
+
+        public override Task<UdpSessionInfoReply> GetUdpSessionAll(Empty request, ServerCallContext context)
+        {
+            Auth(context);
+            var result = jT808SessionManager.GetUdpAll();
+            UdpSessionInfoReply reply = new UdpSessionInfoReply();
+            foreach (var item in result)
+            {
+                reply.UdpSessions.Add(new SessionInfo
+                {
+                    LastActiveTime = item.ActiveTime.ToString("yyyy-MM-dd HH:mm:ss"),
+                    StartTime = item.StartTime.ToString("yyyy-MM-dd HH:mm:ss"),
+                    RemoteAddressIP = item.RemoteEndPoint.ToString(),
+                    TerminalPhoneNo = item.TerminalPhoneNo
+                });
+            }
+          
+            return Task.FromResult(reply);
+        }
+
+        public override Task<UnificationSendReply> UnificationSend(UnificationSendRequest request, ServerCallContext context)
+        {
+            Auth(context);
+            try
+            {
+                var flag = jT808SessionManager.TrySendByTerminalPhoneNo(request.TerminalPhoneNo, request.Data.ToByteArray());
+                return Task.FromResult(new UnificationSendReply { Success = flag });
+            }
+            catch (Exception)
+            {
+                return Task.FromResult(new UnificationSendReply { Success = false });
+            }
+        }
+
+        public override Task<TcpAtomicCounterReply> GetTcpAtomicCounter(Empty request, ServerCallContext context)
+        {
+            Auth(context);
+            TcpAtomicCounterReply reply = new TcpAtomicCounterReply();
+            reply.MsgFailCount=jT808TcpAtomicCounterService.MsgFailCount;
+            reply.MsgSuccessCount=jT808TcpAtomicCounterService.MsgSuccessCount;
+            return Task.FromResult(reply);
+        }
+
+        public override Task<UdpAtomicCounterReply> GetUdpAtomicCounter(Empty request, ServerCallContext context)
+        {
+            Auth(context);
+            UdpAtomicCounterReply reply = new UdpAtomicCounterReply();
+            reply.MsgFailCount = jT808UdpAtomicCounterService.MsgFailCount;
+            reply.MsgSuccessCount = jT808UdpAtomicCounterService.MsgSuccessCount;
+            return Task.FromResult(reply);
+        }
+
+        private void Auth(ServerCallContext context)
+        {
+            Entry tokenEntry = context.RequestHeaders.FirstOrDefault(w => w.Key == "token");
+            if (tokenEntry != null)
+            {
+                if(tokenEntry.Value != ConfigurationOptionsMonitor.CurrentValue.WebApiToken)
+                {
+                    throw new Grpc.Core.RpcException(new Status(StatusCode.Unauthenticated, "token error"));
+                }
+            }
+            else
+            {
+                throw new Grpc.Core.RpcException(new Status(StatusCode.Unauthenticated,"token empty"));
+            }
+        }
+    }
+}
diff --git a/src/JT808.Gateway/Services/JT808MsgReplyHostedService.cs b/src/JT808.Gateway/Services/JT808MsgReplyHostedService.cs
new file mode 100644
index 0000000..d163715
--- /dev/null
+++ b/src/JT808.Gateway/Services/JT808MsgReplyHostedService.cs
@@ -0,0 +1,52 @@
+using JT808.Gateway.Abstractions;
+using JT808.Gateway.Configurations;
+using JT808.Gateway.Enums;
+using JT808.Gateway.Session;
+using Microsoft.Extensions.Hosting;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace JT808.Gateway.Services
+{
+    internal class JT808MsgReplyHostedService : IHostedService
+    {
+        private readonly JT808SessionManager JT808SessionManager;
+
+        private readonly IJT808MsgReplyConsumer JT808MsgReplyConsumer;
+        private readonly JT808Configuration Configuration;
+        public JT808MsgReplyHostedService(
+            JT808Configuration  jT808Configuration,
+            IJT808MsgReplyConsumer jT808MsgReplyConsumer,
+            JT808SessionManager jT808SessionManager)
+        {
+            JT808MsgReplyConsumer = jT808MsgReplyConsumer;
+            JT808SessionManager = jT808SessionManager;
+            Configuration = jT808Configuration;
+        }
+
+        public Task StartAsync(CancellationToken cancellationToken)
+        {
+            if(Configuration.MessageQueueType== JT808MessageQueueType.InMemory)
+            {
+                JT808MsgReplyConsumer.OnMessage(item =>
+                {
+                    JT808SessionManager.TrySendBySessionId(item.TerminalNo, item.Data);
+                });
+                JT808MsgReplyConsumer.Subscribe();
+            }
+            return Task.CompletedTask;    
+        }
+
+        public Task StopAsync(CancellationToken cancellationToken)
+        {
+            if (Configuration.MessageQueueType == JT808MessageQueueType.InMemory)
+            {
+                JT808MsgReplyConsumer.Unsubscribe();
+            }
+            return Task.CompletedTask;
+        }
+    }
+}
diff --git a/src/JT808.Gateway/Services/JT808TcpReceiveTimeoutHostedService.cs b/src/JT808.Gateway/Services/JT808TcpReceiveTimeoutHostedService.cs
new file mode 100644
index 0000000..8fdda8c
--- /dev/null
+++ b/src/JT808.Gateway/Services/JT808TcpReceiveTimeoutHostedService.cs
@@ -0,0 +1,58 @@
+using JT808.Gateway.Configurations;
+using JT808.Gateway.Session;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace JT808.Gateway.Services
+{
+    internal class JT808TcpReceiveTimeoutHostedService : BackgroundService
+    {
+        private readonly ILogger Logger;
+
+        private readonly JT808SessionManager SessionManager;
+
+        private readonly JT808Configuration Configuration;
+        public JT808TcpReceiveTimeoutHostedService(
+                JT808Configuration jT808Configuration,
+                ILoggerFactory loggerFactory,
+                JT808SessionManager jT808SessionManager
+            )
+        {
+            SessionManager = jT808SessionManager;
+            Logger = loggerFactory.CreateLogger("JT808TcpReceiveTimeout");
+            Configuration = jT808Configuration;
+        }
+
+        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
+        {
+            while (!stoppingToken.IsCancellationRequested)
+            {
+                try
+                {
+                    foreach (var item in SessionManager.GetTcpAll())
+                    {
+                        if (item.ActiveTime.AddSeconds(Configuration.TcpReaderIdleTimeSeconds) < DateTime.Now)
+                        {
+                            item.ReceiveTimeout.Cancel();
+                        }
+                    }
+                    Logger.LogInformation($"[Check Receive Timeout]");
+                    Logger.LogInformation($"[Session Online Count]:{SessionManager.TcpSessionCount}");
+                }
+                catch (Exception ex)
+                {
+                    Logger.LogError(ex, $"[Receive Timeout]");
+                }
+                finally
+                {
+                    await Task.Delay(TimeSpan.FromSeconds(Configuration.TcpReceiveTimeoutCheckTimeSeconds), stoppingToken);
+                }
+            }
+        }
+    }
+}
diff --git a/src/JT808.Gateway/Services/JT808UdpReceiveTimeoutHostedService.cs b/src/JT808.Gateway/Services/JT808UdpReceiveTimeoutHostedService.cs
new file mode 100644
index 0000000..3f04f30
--- /dev/null
+++ b/src/JT808.Gateway/Services/JT808UdpReceiveTimeoutHostedService.cs
@@ -0,0 +1,63 @@
+using JT808.Gateway.Configurations;
+using JT808.Gateway.Session;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace JT808.Gateway.Services
+{
+    internal class JT808UdpReceiveTimeoutHostedService : BackgroundService
+    {
+        private readonly ILogger Logger;
+
+        private readonly JT808SessionManager SessionManager;
+
+        private readonly JT808Configuration Configuration;
+        public JT808UdpReceiveTimeoutHostedService(
+                JT808Configuration jT808Configuration,
+                ILoggerFactory loggerFactory,
+                JT808SessionManager jT808SessionManager
+            )
+        {
+            SessionManager = jT808SessionManager;
+            Logger = loggerFactory.CreateLogger("JT808UdpReceiveTimeout");
+            Configuration = jT808Configuration;
+        }
+
+        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
+        {
+            while (!stoppingToken.IsCancellationRequested)
+            {
+                try
+                {
+                    List<string> sessionIds = new List<string>();
+                    foreach (var item in SessionManager.GetUdpAll())
+                    {
+                        if (item.ActiveTime.AddSeconds(Configuration.UdpReaderIdleTimeSeconds) < DateTime.Now)
+                        {
+                            sessionIds.Add(item.SessionID);
+                        }
+                    }
+                    foreach(var item in sessionIds)
+                    {
+                        SessionManager.RemoveBySessionId(item);
+                    }
+                    Logger.LogInformation($"[Check Receive Timeout]");
+                    Logger.LogInformation($"[Session Online Count]:{SessionManager.UdpSessionCount}");
+                }
+                catch (Exception ex)
+                {
+                    Logger.LogError(ex, $"[Receive Timeout]");
+                }
+                finally
+                {
+                    await Task.Delay(TimeSpan.FromSeconds(Configuration.UdpReceiveTimeoutCheckTimeSeconds), stoppingToken);
+                }
+            }
+        }
+    }
+}
diff --git a/src/JT808.Gateway/Session/JT808SessionManager.cs b/src/JT808.Gateway/Session/JT808SessionManager.cs
new file mode 100644
index 0000000..a7f74cc
--- /dev/null
+++ b/src/JT808.Gateway/Session/JT808SessionManager.cs
@@ -0,0 +1,224 @@
+using JT808.Gateway.Abstractions;
+using JT808.Gateway.Abstractions.Enums;
+using JT808.Gateway.Interfaces;
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace JT808.Gateway.Session
+{
+    /// <summary>
+    /// 
+    /// <remark>不支持变态类型:既发TCP和UDP</remark>
+    /// </summary>
+    public class JT808SessionManager
+    {
+        private readonly ILogger logger;
+        private readonly IJT808SessionProducer JT808SessionProducer;
+        public ConcurrentDictionary<string, IJT808Session> Sessions { get; }
+        public ConcurrentDictionary<string, string> TerminalPhoneNoSessions { get; }
+        public JT808SessionManager(
+            IJT808SessionProducer jT808SessionProducer,
+            ILoggerFactory loggerFactory
+            )
+        {
+            JT808SessionProducer = jT808SessionProducer;
+            Sessions = new ConcurrentDictionary<string, IJT808Session>(StringComparer.OrdinalIgnoreCase);
+            TerminalPhoneNoSessions = new ConcurrentDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+            logger = loggerFactory.CreateLogger("JT808SessionManager");
+        }
+
+        public JT808SessionManager(ILoggerFactory loggerFactory)
+        {
+            Sessions = new ConcurrentDictionary<string, IJT808Session>(StringComparer.OrdinalIgnoreCase);
+            TerminalPhoneNoSessions = new ConcurrentDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+            logger = loggerFactory.CreateLogger("JT808SessionManager");
+        }
+
+        public int TotalSessionCount
+        {
+            get
+            {
+                return Sessions.Count;
+            }
+        }
+
+        public int TcpSessionCount
+        {
+            get
+            {
+                return Sessions.Where(w => w.Value.TransportProtocolType == JT808TransportProtocolType.tcp).Count();
+            }
+        }
+
+        public int UdpSessionCount
+        {
+            get
+            {
+                return Sessions.Where(w => w.Value.TransportProtocolType == JT808TransportProtocolType.udp).Count();
+            }
+        }
+
+        internal void TryLink(string terminalPhoneNo, IJT808Session session)
+        {
+            session.ActiveTime = DateTime.Now;
+            session.TerminalPhoneNo = terminalPhoneNo;
+            Sessions.TryUpdate(session.SessionID, session, session);
+            TerminalPhoneNoSessions.AddOrUpdate(terminalPhoneNo, session.SessionID, (key, oldValue)=> 
+            {
+                if(session.SessionID!= oldValue)
+                {
+                    //会话通知
+                    JT808SessionProducer?.ProduceAsync(JT808GatewayConstants.SessionOnline, key);
+                    return session.SessionID;
+                }
+                return oldValue;
+            });
+        }
+
+        public string TryLink(string terminalPhoneNo, Socket socket, EndPoint remoteEndPoint)
+        {
+            string sessionId = string.Empty;
+            if(TerminalPhoneNoSessions.TryGetValue(terminalPhoneNo,out sessionId))
+            {
+                if (Sessions.TryGetValue(sessionId, out IJT808Session sessionInfo))
+                {
+                    sessionInfo.ActiveTime = DateTime.Now;
+                    sessionInfo.TerminalPhoneNo = terminalPhoneNo;
+                    sessionInfo.RemoteEndPoint = remoteEndPoint;
+                    Sessions.TryUpdate(sessionId, sessionInfo, sessionInfo);
+                }
+            }
+            else
+            {
+                JT808UdpSession session = new JT808UdpSession(socket, remoteEndPoint);
+                Sessions.TryAdd(session.SessionID, session);
+                TerminalPhoneNoSessions.TryAdd(terminalPhoneNo, session.SessionID);
+                sessionId = session.SessionID;
+            }
+            //会话通知
+            //使用场景:
+            //部标的超长待机设备,不会像正常的设备一样一直连着,可能10几分钟连上了,然后发完就关闭连接,
+            //这时候想下发数据需要知道设备什么时候上线,在这边做通知最好不过了。
+            //有设备关联上来可以进行通知 例如:使用Redis发布订阅
+            JT808SessionProducer?.ProduceAsync(JT808GatewayConstants.SessionOnline, terminalPhoneNo);
+            return sessionId;
+        }
+
+        internal bool TryAdd(IJT808Session session)
+        {
+            return Sessions.TryAdd(session.SessionID, session);
+        }
+
+        public bool TrySendByTerminalPhoneNo(string terminalPhoneNo, byte[] data)
+        {
+            if(TerminalPhoneNoSessions.TryGetValue(terminalPhoneNo,out var sessionid))
+            {
+                if (Sessions.TryGetValue(sessionid, out var session))
+                {
+                    if (session.TransportProtocolType == JT808TransportProtocolType.tcp)
+                    {
+                        session.Client.Send(data, SocketFlags.None);
+                    }
+                    else
+                    {
+                        session.Client.SendTo(data, SocketFlags.None, session.RemoteEndPoint);
+                    }
+                    return true;
+                }
+                else
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        public bool TrySendBySessionId(string sessionId, byte[] data)
+        {
+            if (Sessions.TryGetValue(sessionId, out var session))
+            {
+                if(session.TransportProtocolType== JT808TransportProtocolType.tcp)
+                {
+                    session.Client.Send(data, SocketFlags.None);
+                }
+                else
+                {
+                    session.Client.SendTo(data, SocketFlags.None, session.RemoteEndPoint);
+                }
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        public void RemoveByTerminalPhoneNo(string terminalPhoneNo)
+        {
+            if (TerminalPhoneNoSessions.TryGetValue(terminalPhoneNo, out var removeSessionId))
+            {
+                // 处理转发过来的是数据 这时候通道对设备是1对多关系,需要清理垃圾数据
+                //1.用当前会话的通道Id找出通过转发过来的其他设备的终端号
+                var terminalPhoneNos = TerminalPhoneNoSessions.Where(w => w.Value == removeSessionId).Select(s => s.Key).ToList();
+                //2.存在则一个个移除 
+                string tmpTerminalPhoneNo = terminalPhoneNo;
+                if (terminalPhoneNos.Count > 0)
+                {
+                    //3.移除包括当前的设备号
+                    foreach (var item in terminalPhoneNos)
+                    {
+                        TerminalPhoneNoSessions.TryRemove(item, out _);
+                    }
+                    tmpTerminalPhoneNo = string.Join(",", terminalPhoneNos);
+                }
+                if (Sessions.TryRemove(removeSessionId, out var removeSession))
+                {
+                    removeSession.Close();
+                    if(logger.IsEnabled(LogLevel.Information))
+                        logger.LogInformation($"[Session Remove]:{terminalPhoneNo}-{tmpTerminalPhoneNo}");
+                    JT808SessionProducer?.ProduceAsync(JT808GatewayConstants.SessionOffline, tmpTerminalPhoneNo);
+                }
+            }
+        }
+
+        public void RemoveBySessionId(string sessionId)
+        {
+            if(Sessions.TryRemove(sessionId,out var removeSession))
+            {
+                var terminalPhoneNos = TerminalPhoneNoSessions.Where(w => w.Value == sessionId).Select(s => s.Key).ToList();
+                if (terminalPhoneNos.Count > 0)
+                {
+                    foreach (var item in terminalPhoneNos)
+                    {
+                        TerminalPhoneNoSessions.TryRemove(item, out _);
+                    }
+                    var tmpTerminalPhoneNo = string.Join(",", terminalPhoneNos);
+                    JT808SessionProducer?.ProduceAsync(JT808GatewayConstants.SessionOffline, tmpTerminalPhoneNo);
+                    if (logger.IsEnabled(LogLevel.Information))
+                        logger.LogInformation($"[Session Remove]:{tmpTerminalPhoneNo}");
+                }
+                removeSession.Close();
+            }
+        }
+
+        public List<JT808TcpSession> GetTcpAll()
+        {
+            return Sessions.Where(w => w.Value.TransportProtocolType == JT808TransportProtocolType.tcp).Select(s => (JT808TcpSession)s.Value).ToList();
+        }
+
+        public List<JT808UdpSession> GetUdpAll()
+        {
+            return Sessions.Where(w => w.Value.TransportProtocolType == JT808TransportProtocolType.udp).Select(s => (JT808UdpSession)s.Value).ToList();
+        }
+    }
+}
diff --git a/src/JT808.Gateway/Session/JT808TcpSession.cs b/src/JT808.Gateway/Session/JT808TcpSession.cs
new file mode 100644
index 0000000..70d044a
--- /dev/null
+++ b/src/JT808.Gateway/Session/JT808TcpSession.cs
@@ -0,0 +1,47 @@
+using JT808.Gateway.Abstractions.Enums;
+using JT808.Gateway.Interfaces;
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+
+namespace JT808.Gateway.Session
+{
+    public class JT808TcpSession: IJT808Session
+    {
+        public JT808TcpSession(Socket client)
+        {
+            Client = client;
+            RemoteEndPoint = client.RemoteEndPoint;
+            ActiveTime = DateTime.Now;
+            StartTime = DateTime.Now;
+            SessionID = Guid.NewGuid().ToString("N");
+            ReceiveTimeout = new CancellationTokenSource();
+        }
+
+        /// <summary>
+        /// 终端手机号
+        /// </summary>
+        public string TerminalPhoneNo { get; set; }
+        public DateTime ActiveTime { get; set; }
+        public DateTime StartTime { get; set; }
+        public JT808TransportProtocolType TransportProtocolType { get;} = JT808TransportProtocolType.tcp;
+        public string SessionID { get; }
+        public Socket Client { get; set; }
+        public CancellationTokenSource ReceiveTimeout { get; set; }
+        public EndPoint RemoteEndPoint { get ; set; }
+
+        public void Close()
+        {
+            try
+            {
+                Client.Shutdown(SocketShutdown.Both);
+            }
+            catch { }
+            finally
+            {
+                Client.Close();
+            }
+        }
+    }
+}
diff --git a/src/JT808.Gateway/Session/JT808UdpSession.cs b/src/JT808.Gateway/Session/JT808UdpSession.cs
new file mode 100644
index 0000000..bdd4c87
--- /dev/null
+++ b/src/JT808.Gateway/Session/JT808UdpSession.cs
@@ -0,0 +1,41 @@
+using JT808.Gateway.Abstractions.Enums;
+using JT808.Gateway.Interfaces;
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+
+namespace JT808.Gateway.Session
+{
+    public class JT808UdpSession: IJT808Session
+    {
+        public JT808UdpSession(Socket socket, EndPoint sender)
+        {
+            ActiveTime = DateTime.Now;
+            StartTime = DateTime.Now;
+            SessionID = Guid.NewGuid().ToString("N");
+            ReceiveTimeout = new CancellationTokenSource();
+            RemoteEndPoint = sender;
+            Client = socket;
+        }
+
+        /// <summary>
+        /// 终端手机号
+        /// </summary>
+        public string TerminalPhoneNo { get; set; }
+        public DateTime ActiveTime { get; set; }
+        public DateTime StartTime { get; set; }
+        public JT808TransportProtocolType TransportProtocolType { get; set; } = JT808TransportProtocolType.udp;
+
+        public string SessionID { get; }
+
+        public Socket Client { get; set; }
+        public CancellationTokenSource ReceiveTimeout { get; set; }
+        public EndPoint RemoteEndPoint { get; set ; }
+
+        public void Close()
+        {
+            
+        }
+    }
+}